nodedb_sql/planner/
aggregate_clauses.rs1use sqlparser::ast;
7
8use crate::error::Result;
9use crate::functions::registry::FunctionRegistry;
10use crate::planner::agg_bind::{BindName, bind_aggregate_calls};
11use crate::planner::group_by::{convert_group_by_with_projection, group_by_output_aliases};
12use crate::planner::grouping_sets::expand_group_by;
13use crate::resolver::columns::TableScope;
14use crate::types::{AggOutputSlot, AggregateExpr, ColumnInfo, Filter, SqlExpr};
15
16pub struct AggregateClauses {
18 pub group_by: Vec<SqlExpr>,
20 pub grouping_sets: Option<Vec<Vec<usize>>>,
22 pub aggregates: Vec<AggregateExpr>,
25 pub having: Vec<Filter>,
27 pub group_by_aliases: Vec<Option<String>>,
29 pub output_order: Vec<AggOutputSlot>,
31 pub hidden_aggregates: bool,
34}
35
36pub fn plan_aggregate_clauses(
43 select: &ast::Select,
44 order_by: Option<&ast::OrderBy>,
45 table_columns: &[ColumnInfo],
46 scope: &TableScope,
47 functions: &FunctionRegistry,
48) -> Result<AggregateClauses> {
49 let (group_by, grouping_sets) = match expand_group_by(&select.group_by, scope)? {
50 Some(expansion) => (expansion.canonical_keys, Some(expansion.grouping_sets)),
51 None => (
52 convert_group_by_with_projection(
53 &select.group_by,
54 &select.projection,
55 table_columns,
56 scope,
57 )?,
58 None,
59 ),
60 };
61
62 let mut aggregates =
63 super::aggregate::extract_aggregates_from_projection(&select.projection, functions, scope)?;
64 let projected = aggregates.len();
65 let having = match &select.having {
68 Some(expr) => {
69 super::having::plan_having(expr, &select.projection, &mut aggregates, functions, scope)?
70 }
71 None => Vec::new(),
72 };
73 let hidden_aggregates = aggregates.len() > projected
74 || sort_names_new_aggregate(order_by, &select.projection, &aggregates, functions, scope)?;
75
76 if grouping_sets.is_some() {
77 let grouping_aggs =
78 super::aggregate::extract_grouping_calls(&select.projection, &group_by, scope)?;
79 aggregates.extend(grouping_aggs);
80 }
81
82 let output_order = super::aggregate_order::compute_output_order(
83 &select.projection,
84 &group_by,
85 functions,
86 scope,
87 )?;
88 let group_by_aliases = group_by_output_aliases(&select.projection, &group_by);
89
90 Ok(AggregateClauses {
91 group_by,
92 grouping_sets,
93 aggregates,
94 having,
95 group_by_aliases,
96 output_order,
97 hidden_aggregates,
98 })
99}
100
101fn sort_names_new_aggregate(
104 order_by: Option<&ast::OrderBy>,
105 projection: &[ast::SelectItem],
106 aggregates: &[AggregateExpr],
107 functions: &FunctionRegistry,
108 scope: &TableScope,
109) -> Result<bool> {
110 let Some(ast::OrderBy {
111 kind: ast::OrderByKind::Expressions(exprs),
112 ..
113 }) = order_by
114 else {
115 return Ok(false);
116 };
117 let mut extended = aggregates.to_vec();
118 for o in exprs {
119 bind_aggregate_calls(
120 &o.expr,
121 projection,
122 &mut extended,
123 functions,
124 BindName::Canonical,
125 scope,
126 )?;
127 }
128 Ok(extended.len() > aggregates.len())
129}