1use crate::{
10 ast::{Expr, FrameBound, FromClause, SelectStmt, Statement},
11 SQLError,
12};
13use std::collections::BTreeSet;
14use uqa_core::RelationIdentity;
15mod expressions;
16mod merge;
17mod routines;
18mod sources;
19mod types;
20pub use expressions::*;
21pub use merge::visit_stored_statement_merges;
22pub use routines::*;
23pub use sources::*;
24pub use types::*;
25
26pub type MergeCallback<'a> = &'a mut dyn FnMut(&mut crate::ast::MergeStmt) -> Result<(), SQLError>;
27
28pub type ExpressionCallback<'a> = &'a mut dyn FnMut(&mut Expr) -> Result<(), SQLError>;
29pub type SourceCallback<'a> = &'a mut dyn FnMut(&mut FromClause) -> Result<(), SQLError>;
30
31pub struct StoredAstVisitor<'a, R, F> {
32 pub source: Option<SourceCallback<'a>>,
33 pub merge: Option<MergeCallback<'a>>,
34 pub expression: Option<ExpressionCallback<'a>>,
35 pub ty: Option<&'a mut dyn FnMut(&mut String)>,
36 pub relation: &'a mut R,
37 pub routine: &'a mut F,
38}
39
40impl<R, F> StoredAstVisitor<'_, R, F>
41where
42 R: FnMut(&mut String) -> Result<(), SQLError>,
43 F: FnMut(&mut String, Option<&mut Option<crate::ast::FunctionBinding>>) -> Result<(), SQLError>,
44{
45 pub fn bind_statement(&mut self, statement: &mut Statement) -> Result<(), SQLError> {
46 let ctes = BTreeSet::new();
47 match statement {
48 Statement::Select(query) => self.bind_select(query, &ctes),
49 Statement::Insert(insert) => self.bind_insert(insert, &ctes),
50 Statement::Update(update) => self.bind_update(update, &ctes),
51 Statement::Delete(delete) => self.bind_delete(delete, &ctes),
52 Statement::Notify { .. } => Ok(()),
53 Statement::Values { rows } => {
54 for expression in rows.iter_mut().flatten() {
55 self.bind_expr(expression, &ctes)?;
56 }
57 Ok(())
58 }
59 Statement::Merge(merge) => self.bind_merge(merge, &ctes),
60 _ => Err(SQLError::Internal(
61 "catalog-owned statement has an unsupported dependency shape".into(),
62 )),
63 }
64 }
65
66 fn bind_insert(
67 &mut self,
68 insert: &mut crate::ast::InsertStmt,
69 inherited: &BTreeSet<String>,
70 ) -> Result<(), SQLError> {
71 (self.relation)(&mut insert.table)?;
72 let visible = self.bind_ctes(&mut insert.with, inherited)?;
73 if let Some(source) = insert.select_source.as_deref_mut() {
74 self.bind_select(source, &visible)?;
75 }
76 for expression in insert
77 .columns
78 .iter_mut()
79 .flat_map(crate::ast::AssignmentTarget::expressions_mut)
80 .chain(insert.rows.iter_mut().flatten())
81 {
82 self.bind_expr(expression, &visible)?;
83 }
84 if let Some(conflict) = &mut insert.on_conflict {
85 for expression in &mut conflict.expressions {
86 self.bind_expr(expression, &visible)?;
87 }
88 if let Some(predicate) = conflict.predicate.as_deref_mut() {
89 self.bind_expr(predicate, &visible)?;
90 }
91 if let crate::ast::OnConflictAction::Update {
92 assignments,
93 r#where,
94 } = &mut conflict.action
95 {
96 for expression in assignments.iter_mut().flat_map(|(target, value)| {
97 target.expressions_mut().chain(std::iter::once(value))
98 }) {
99 self.bind_expr(expression, &visible)?;
100 }
101 if let Some(expression) = r#where {
102 self.bind_expr(expression, &visible)?;
103 }
104 }
105 }
106 for projection in &mut insert.returning {
107 self.bind_expr(&mut projection.expr, &visible)?;
108 }
109 Ok(())
110 }
111
112 fn bind_update(
113 &mut self,
114 update: &mut crate::ast::UpdateStmt,
115 inherited: &BTreeSet<String>,
116 ) -> Result<(), SQLError> {
117 (self.relation)(&mut update.table)?;
118 let visible = self.bind_ctes(&mut update.with, inherited)?;
119 if let Some(source) = &mut update.from {
120 self.bind_from(source, &visible)?;
121 }
122 for expression in update
123 .assignments
124 .iter_mut()
125 .flat_map(|(target, value)| target.expressions_mut().chain(std::iter::once(value)))
126 {
127 self.bind_expr(expression, &visible)?;
128 }
129 if let Some(expression) = &mut update.r#where {
130 self.bind_expr(expression, &visible)?;
131 }
132 for projection in &mut update.returning {
133 self.bind_expr(&mut projection.expr, &visible)?;
134 }
135 Ok(())
136 }
137
138 fn bind_delete(
139 &mut self,
140 delete: &mut crate::ast::DeleteStmt,
141 inherited: &BTreeSet<String>,
142 ) -> Result<(), SQLError> {
143 (self.relation)(&mut delete.table)?;
144 let visible = self.bind_ctes(&mut delete.with, inherited)?;
145 if let Some(source) = &mut delete.using {
146 self.bind_from(source, &visible)?;
147 }
148 if let Some(expression) = &mut delete.r#where {
149 self.bind_expr(expression, &visible)?;
150 }
151 for projection in &mut delete.returning {
152 self.bind_expr(&mut projection.expr, &visible)?;
153 }
154 Ok(())
155 }
156
157 fn bind_ctes(
158 &mut self,
159 ctes: &mut [crate::ast::CTE],
160 inherited: &BTreeSet<String>,
161 ) -> Result<BTreeSet<String>, SQLError> {
162 let mut visible = inherited.clone();
163 let recursive = ctes.iter().any(|cte| cte.recursive).then(|| {
164 ctes.iter()
165 .map(|cte| cte.name.clone())
166 .collect::<BTreeSet<_>>()
167 });
168 for cte in ctes {
169 let body_scope = recursive.as_ref().map_or_else(
170 || visible.clone(),
171 |recursive| inherited.union(recursive).cloned().collect(),
172 );
173 match &mut cte.body {
174 crate::ast::CteBody::Query(query) => self.bind_select(query, &body_scope)?,
175 crate::ast::CteBody::Insert(plan) => self.bind_insert(plan, &body_scope)?,
176 crate::ast::CteBody::Update(plan) => self.bind_update(plan, &body_scope)?,
177 crate::ast::CteBody::Delete(plan) => self.bind_delete(plan, &body_scope)?,
178 crate::ast::CteBody::Merge(plan) => self.bind_merge(plan, &body_scope)?,
179 }
180 if let Some(cycle) = &mut cte.cycle {
181 self.bind_expr(&mut cycle.mark_value, &body_scope)?;
182 self.bind_expr(&mut cycle.mark_default, &body_scope)?;
183 }
184 visible.insert(cte.name.clone());
185 }
186 Ok(visible)
187 }
188
189 fn bind_select(
190 &mut self,
191 select: &mut SelectStmt,
192 inherited: &BTreeSet<String>,
193 ) -> Result<(), SQLError> {
194 let visible = self.bind_ctes(&mut select.with, inherited)?;
195 if let Some(source) = &mut select.from {
196 self.bind_from(source, &visible)?;
197 }
198 for projection in &mut select.projections {
199 self.bind_expr(&mut projection.expr, &visible)?;
200 }
201 for expression in select.values.iter_mut().flatten() {
202 self.bind_expr(expression, &visible)?;
203 }
204 if let Some(expression) = &mut select.r#where {
205 self.bind_expr(expression, &visible)?;
206 }
207 for expression in &mut select.group_by {
208 self.bind_expr(expression, &visible)?;
209 }
210 for expression in select.grouping_sets.iter_mut().flatten() {
211 self.bind_expr(expression, &visible)?;
212 }
213 if let Some(expression) = &mut select.having {
214 self.bind_expr(expression, &visible)?;
215 }
216 for order in &mut select.order_by {
217 self.bind_expr(&mut order.expr, &visible)?;
218 }
219 if let Some(expression) = &mut select.limit {
220 self.bind_expr(expression, &visible)?;
221 }
222 if let Some(expression) = &mut select.offset {
223 self.bind_expr(expression, &visible)?;
224 }
225 for expression in &mut select.distinct_on {
226 self.bind_expr(expression, &visible)?;
227 }
228 if let Some(set) = &mut select.set_op {
229 if let Some(left) = &mut set.left {
230 self.bind_select(left, &visible)?;
231 }
232 self.bind_select(&mut set.right, &visible)?;
233 for order in &mut set.combined_order_by {
234 self.bind_expr(&mut order.expr, &visible)?;
235 }
236 if let Some(expression) = &mut set.combined_limit {
237 self.bind_expr(expression, &visible)?;
238 }
239 if let Some(expression) = &mut set.combined_offset {
240 self.bind_expr(expression, &visible)?;
241 }
242 }
243 Ok(())
244 }
245
246 fn bind_from(
247 &mut self,
248 source: &mut FromClause,
249 visible_ctes: &BTreeSet<String>,
250 ) -> Result<(), SQLError> {
251 if let FromClause::Table { name, .. } = source {
252 let is_cte =
253 RelationIdentity::parse_reference(name)
254 .ok()
255 .is_some_and(|(schema, relation)| {
256 schema.is_none() && visible_ctes.contains(&relation)
257 });
258 if is_cte {
259 return Ok(());
260 }
261 }
262 if let Some(visit) = self.source.as_mut() {
263 visit(source)?;
264 }
265 match source {
266 FromClause::Table { name, .. } => {
267 (self.relation)(name)?;
268 }
269 FromClause::Join {
270 left, right, on, ..
271 } => {
272 self.bind_from(left, visible_ctes)?;
273 self.bind_from(right, visible_ctes)?;
274 if let Some(expression) = on {
275 self.bind_expr(expression, visible_ctes)?;
276 }
277 }
278 FromClause::Values { rows, .. } => {
279 for expression in rows.iter_mut().flatten() {
280 self.bind_expr(expression, visible_ctes)?;
281 }
282 }
283 FromClause::Function {
284 name,
285 binding,
286 relations,
287 args,
288 ..
289 } => {
290 (self.routine)(name, Some(binding))?;
291 if let Some(relations) = relations {
292 (self.relation)(&mut relations.left)?;
293 (self.relation)(&mut relations.right)?;
294 }
295 for expression in args {
296 self.bind_expr(expression, visible_ctes)?;
297 }
298 }
299 FromClause::FunctionGroup { functions, .. } => {
300 for function in functions {
301 (self.routine)(&mut function.name, Some(&mut function.binding))?;
302 if let Some(relations) = &mut function.relations {
303 (self.relation)(&mut relations.left)?;
304 (self.relation)(&mut relations.right)?;
305 }
306 for expression in &mut function.args {
307 self.bind_expr(expression, visible_ctes)?;
308 }
309 }
310 }
311 FromClause::Subquery { body, .. } => self.bind_select(body, visible_ctes)?,
312 }
313 Ok(())
314 }
315
316 fn bind_expression_type(&mut self, expression: &mut Expr) -> Result<(), SQLError> {
317 if let Some(visit) = self.expression.as_mut() {
318 visit(expression)?;
319 }
320 if let (Some(visit), Expr::Cast { ty, .. } | Expr::TypedLiteral { ty, .. }) =
321 (self.ty.as_mut(), expression)
322 {
323 visit(ty);
324 }
325 Ok(())
326 }
327
328 pub fn bind_expr(
329 &mut self,
330 expression: &mut Expr,
331 visible_ctes: &BTreeSet<String>,
332 ) -> Result<(), SQLError> {
333 self.bind_expression_type(expression)?;
334 match expression {
335 Expr::Func {
336 name,
337 binding,
338 args,
339 order_by,
340 filter,
341 ..
342 } => {
343 for argument in args {
344 self.bind_expr(argument, visible_ctes)?;
345 }
346 for order in order_by {
347 self.bind_expr(&mut order.expr, visible_ctes)?;
348 }
349 if let Some(filter) = filter {
350 self.bind_expr(filter, visible_ctes)?;
351 }
352 (self.routine)(name, Some(binding))?;
353 }
354 Expr::Array(items) | Expr::Row(items) | Expr::And(items) | Expr::Or(items) => {
355 for item in items {
356 self.bind_expr(item, visible_ctes)?;
357 }
358 }
359 Expr::Binary { lhs, rhs, .. } => {
360 self.bind_expr(lhs, visible_ctes)?;
361 self.bind_expr(rhs, visible_ctes)?;
362 }
363 Expr::UnaryMinus(inner)
364 | Expr::Not(inner)
365 | Expr::IsNull { expr: inner, .. }
366 | Expr::Cast { expr: inner, .. } => self.bind_expr(inner, visible_ctes)?,
367 Expr::Between { expr, low, high } => {
368 self.bind_expr(expr, visible_ctes)?;
369 self.bind_expr(low, visible_ctes)?;
370 self.bind_expr(high, visible_ctes)?;
371 }
372 Expr::InList { expr, list, .. } => {
373 self.bind_expr(expr, visible_ctes)?;
374 for item in list {
375 self.bind_expr(item, visible_ctes)?;
376 }
377 }
378 Expr::WindowCall { name, args, spec } => {
379 for argument in args {
380 self.bind_expr(argument, visible_ctes)?;
381 }
382 for partition in &mut spec.partition_by {
383 self.bind_expr(partition, visible_ctes)?;
384 }
385 for order in &mut spec.order_by {
386 self.bind_expr(&mut order.expr, visible_ctes)?;
387 }
388 if let Some(frame) = &mut spec.frame {
389 for bound in [&mut frame.start, &mut frame.end] {
390 if let FrameBound::Preceding(inner) | FrameBound::Following(inner) = bound {
391 self.bind_expr(inner, visible_ctes)?;
392 }
393 }
394 }
395 (self.routine)(name, None)?;
396 }
397 Expr::Case {
398 base,
399 when,
400 else_branch,
401 } => {
402 if let Some(base) = base {
403 self.bind_expr(base, visible_ctes)?;
404 }
405 for (condition, result) in when {
406 self.bind_expr(condition, visible_ctes)?;
407 self.bind_expr(result, visible_ctes)?;
408 }
409 if let Some(branch) = else_branch {
410 self.bind_expr(branch, visible_ctes)?;
411 }
412 }
413 Expr::ScalarSubquery(body) | Expr::Exists { body, .. } => {
414 self.bind_select(body, visible_ctes)?;
415 }
416 Expr::InSubquery { expr, body, .. } => {
417 self.bind_expr(expr, visible_ctes)?;
418 self.bind_select(body, visible_ctes)?;
419 }
420 Expr::Star
421 | Expr::QualifiedStar(_)
422 | Expr::Default
423 | Expr::Column(_)
424 | Expr::QualifiedColumn { .. }
425 | Expr::InternalColumn(_)
426 | Expr::Literal(_)
427 | Expr::TypedLiteral { .. }
428 | Expr::Param(_) => {}
429 }
430 Ok(())
431 }
432}