uqa_sql/semantics/grouping_sets/
names.rs1use std::borrow::Cow;
10
11use crate::plan::{ProjectionPlan, QueryBlockPlan};
12use crate::routines::RoutineResolution;
13use crate::{RowSchema, SQLError, SQLParam, ScalarExpr};
14
15pub fn resolve_grouping_expression<'a>(
17 routines: &dyn RoutineResolution,
18 expression: &'a ScalarExpr,
19 projections: &'a [ProjectionPlan],
20 schema: &RowSchema,
21 params: &[SQLParam],
22) -> Result<Cow<'a, ScalarExpr>, SQLError> {
23 let mut resolved = expression;
24 if let ScalarExpr::Column(name) = expression {
25 if !schema.has_unqualified_column(name) {
26 let mut matches = projections
27 .iter()
28 .filter(|projection| crate::semantics::projection_label_at(projection) == *name);
29 if let Some(first) = matches.next() {
30 resolved = &first.expr;
31 let mut identity = None;
32 for candidate in matches {
33 let first_identity = match &identity {
34 Some(identity) => identity,
35 None => identity.insert(super::expression_identity(
36 routines, resolved, schema, params,
37 )?),
38 };
39 if *first_identity
40 != super::expression_identity(routines, &candidate.expr, schema, params)?
41 {
42 return Err(SQLError::Routine {
43 sqlstate: "42702".into(),
44 message: format!("GROUP BY \"{name}\" is ambiguous"),
45 });
46 }
47 }
48 }
49 }
50 }
51 if crate::semantics::aggregates::contains_aggregate(
52 &|name: &str| routines.has_registered_aggregate_function(name),
53 resolved,
54 ) {
55 return Err(SQLError::Routine {
56 sqlstate: "42803".into(),
57 message: "aggregate functions are not allowed in GROUP BY".into(),
58 });
59 }
60 if resolved.contains_window() {
61 return Err(SQLError::Routine {
62 sqlstate: "42P20".into(),
63 message: "window functions are not allowed in GROUP BY".into(),
64 });
65 }
66 Ok(if std::ptr::eq(resolved, expression) {
67 Cow::Borrowed(expression)
68 } else {
69 Cow::Owned(resolved.clone())
70 })
71}
72
73pub fn bind_grouping_names(
75 routines: &dyn RoutineResolution,
76 statement: &mut QueryBlockPlan,
77 schema: &RowSchema,
78 params: &[SQLParam],
79) -> Result<bool, SQLError> {
80 let mut changed = false;
81 for expression in statement
82 .group_by
83 .iter_mut()
84 .chain(statement.grouping_sets.iter_mut().flatten())
85 {
86 if let Cow::Owned(resolved) = resolve_grouping_expression(
87 routines,
88 expression,
89 &statement.projections,
90 schema,
91 params,
92 )? {
93 *expression = resolved;
94 changed = true;
95 }
96 }
97 Ok(changed)
98}