1use super::{
10 CommandPlan, CtePlan, CtePlanBody, QueryBlockPlan, QueryPlan, RelationalPlan, SourcePlan,
11 UnifiedPlan,
12};
13use crate::{SQLError, ScalarExpr, ScalarWindowSpec};
14
15pub fn resolved_window_definitions(
17 block: &QueryBlockPlan,
18) -> Result<Vec<ScalarWindowSpec>, SQLError> {
19 let mut resolved: Vec<ScalarWindowSpec> = Vec::with_capacity(block.windows.len());
20 let mut names = std::collections::BTreeSet::new();
21 for (slot, window) in block.windows.iter().enumerate() {
22 if window.spec.definition.is_some() {
23 return Err(invalid("a canonical specification refers to a call slot"));
24 }
25 if let Some(name) = &window.name {
26 if name.is_empty() || !names.insert(name) {
27 return Err(invalid("a canonical window name is empty or repeated"));
28 }
29 }
30 let mut spec = window.spec.clone();
31 if let Some(parent) = window.inherited {
32 let base = resolved
33 .get(parent)
34 .filter(|_| parent < slot && block.windows[parent].name.is_some())
35 .ok_or_else(|| invalid("an inherited window is not an earlier named definition"))?;
36 if !spec.partition_by.is_empty()
37 || (!spec.order_by.is_empty() && !base.order_by.is_empty())
38 || base.frame.is_some()
39 {
40 return Err(invalid(
41 "a canonical window has incompatible inherited clauses",
42 ));
43 }
44 spec.partition_by.clone_from(&base.partition_by);
45 if spec.order_by.is_empty() {
46 spec.order_by.clone_from(&base.order_by);
47 }
48 }
49 spec.definition = Some(slot);
50 resolved.push(spec);
51 }
52 Ok(resolved)
53}
54
55impl UnifiedPlan {
56 pub fn normalize_window_definitions(&mut self) -> Result<(), SQLError> {
58 match self {
59 Self::Query(query) => query.normalize_window_definitions(),
60 Self::Command(command) => normalize_command(command),
61 }
62 }
63}
64
65impl QueryPlan {
66 pub fn normalize_window_definitions(&mut self) -> Result<(), SQLError> {
68 normalize_ctes(&mut self.ctes)?;
69 let result = match &mut self.root {
70 RelationalPlan::QueryBlock(block) => {
71 if let Some(source) = &mut block.from {
72 normalize_source(source)?;
73 }
74 for query in &mut block.subqueries {
75 query.normalize_window_definitions()?;
76 }
77 let resolved = resolved_window_definitions(block)?;
78 let mut result = Ok(());
79 let mut update = |node: &mut ScalarExpr| {
80 if result.is_ok() {
81 if let ScalarExpr::WindowCall { spec, .. } = node {
82 if let Some(slot) = spec.definition {
83 match resolved.get(slot) {
84 Some(canonical) => spec.clone_from(canonical),
85 None => {
86 result = Err(invalid(
87 "a call refers to a missing window definition",
88 ));
89 }
90 }
91 }
92 }
93 }
94 };
95 visit_local_roots_mut(block, &mut |expression| expression.visit_mut(&mut update));
96 result
97 }
98 RelationalPlan::SetOp {
99 left,
100 right,
101 subqueries,
102 ..
103 } => {
104 left.normalize_window_definitions()?;
105 right.normalize_window_definitions()?;
106 for query in subqueries {
107 query.normalize_window_definitions()?;
108 }
109 Ok(())
110 }
111 RelationalPlan::Values { subqueries, .. } => {
112 for query in subqueries {
113 query.normalize_window_definitions()?;
114 }
115 Ok(())
116 }
117 };
118 result?;
119 super::subqueries::prune_query(self);
120 Ok(())
121 }
122}
123
124fn normalize_command(command: &mut CommandPlan) -> Result<(), SQLError> {
125 if let Some(ctes) = command.ctes_mut() {
126 normalize_ctes(ctes)?;
127 }
128 if let Some(source) = command.source_input_mut() {
129 normalize_source(source)?;
130 }
131 for query in command.query_inputs_mut() {
132 query.normalize_window_definitions()?;
133 }
134 match command {
135 CommandPlan::CreateView { query, .. }
136 | CommandPlan::CreateMaterializedView { query, .. }
137 | CommandPlan::CreateTableAs { query, .. }
138 | CommandPlan::DeclareCursor { query, .. } => query.normalize_window_definitions(),
139 CommandPlan::Explain { body, .. } | CommandPlan::Prepare { body, .. } => {
140 body.normalize_window_definitions()
141 }
142 CommandPlan::Execute { params, .. } | CommandPlan::Call { args: params, .. } => {
143 for expression in params {
144 for query in &mut expression.subqueries {
145 query.normalize_window_definitions()?;
146 }
147 }
148 Ok(())
149 }
150 _ => Ok(()),
151 }
152}
153
154fn normalize_ctes(ctes: &mut [CtePlan]) -> Result<(), SQLError> {
155 for cte in ctes {
156 match &mut cte.body {
157 CtePlanBody::Query(query) => query.normalize_window_definitions()?,
158 CtePlanBody::Command(command) => normalize_command(command)?,
159 }
160 }
161 Ok(())
162}
163
164fn normalize_source(source: &mut SourcePlan) -> Result<(), SQLError> {
165 match source {
166 SourcePlan::Subquery { body, .. } => body.normalize_window_definitions(),
167 SourcePlan::Join { left, right, .. } => {
168 normalize_source(left)?;
169 normalize_source(right)
170 }
171 _ => Ok(()),
172 }
173}
174
175fn visit_local_roots_mut(block: &mut QueryBlockPlan, visit: &mut dyn FnMut(&mut ScalarExpr)) {
176 if let Some(source) = &mut block.from {
177 visit_source_roots_mut(source, visit);
178 }
179 for expression in block
180 .projections
181 .iter_mut()
182 .map(|projection| &mut projection.expr)
183 .chain(block.r#where.iter_mut())
184 .chain(block.group_by.iter_mut())
185 .chain(block.grouping_sets.iter_mut().flatten())
186 .chain(block.having.iter_mut())
187 .chain(block.order_by.iter_mut().map(|order| &mut order.expr))
188 .chain(block.limit.iter_mut())
189 .chain(block.offset.iter_mut())
190 .chain(block.distinct_on.iter_mut())
191 {
192 visit(expression);
193 }
194}
195
196fn visit_source_roots_mut(source: &mut SourcePlan, visit: &mut dyn FnMut(&mut ScalarExpr)) {
197 match source {
198 SourcePlan::Table { .. } | SourcePlan::Subquery { .. } => {}
199 SourcePlan::Join {
200 left, right, on, ..
201 } => {
202 visit_source_roots_mut(left, visit);
203 visit_source_roots_mut(right, visit);
204 if let Some(on) = on {
205 visit(on);
206 }
207 }
208 SourcePlan::Values { rows, .. } => {
209 for expression in rows.iter_mut().flatten() {
210 visit(expression);
211 }
212 }
213 SourcePlan::Function { args, .. } => {
214 for expression in args {
215 visit(expression);
216 }
217 }
218 SourcePlan::FunctionGroup { functions, .. } => {
219 for expression in functions.iter_mut().flat_map(|function| &mut function.args) {
220 visit(expression);
221 }
222 }
223 }
224}
225
226fn invalid(message: &str) -> SQLError {
227 SQLError::Internal(format!("invalid stored window definitions: {message}"))
228}
229
230#[cfg(test)]
231mod tests;