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