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 =
293 RelationIdentity::parse_reference(name)
294 .ok()
295 .is_some_and(|(schema, relation)| {
296 schema.is_none() && visible_ctes.contains(&relation)
297 });
298 if is_cte {
299 return Ok(());
300 }
301 }
302 if let Some(visit) = self.source.as_mut() {
303 visit(source)?;
304 }
305 match source {
306 FromClause::Table { name, .. } => {
307 (self.relation)(name)?;
308 }
309 FromClause::Join {
310 left, right, on, ..
311 } => {
312 self.bind_from(left, visible_ctes)?;
313 self.bind_from(right, visible_ctes)?;
314 if let Some(expression) = on {
315 self.bind_expr(expression, visible_ctes)?;
316 }
317 }
318 FromClause::Values { rows, .. } => {
319 for expression in rows.iter_mut().flatten() {
320 self.bind_expr(expression, visible_ctes)?;
321 }
322 }
323 FromClause::Function {
324 name,
325 binding,
326 relations,
327 args,
328 ..
329 } => {
330 (self.routine)(name, Some(binding))?;
331 if let Some(relations) = relations {
332 (self.relation)(&mut relations.left)?;
333 (self.relation)(&mut relations.right)?;
334 }
335 for expression in args {
336 self.bind_expr(expression, visible_ctes)?;
337 }
338 }
339 FromClause::FunctionGroup { functions, .. } => {
340 for function in functions {
341 (self.routine)(&mut function.name, Some(&mut function.binding))?;
342 if let Some(relations) = &mut function.relations {
343 (self.relation)(&mut relations.left)?;
344 (self.relation)(&mut relations.right)?;
345 }
346 for expression in &mut function.args {
347 self.bind_expr(expression, visible_ctes)?;
348 }
349 }
350 }
351 FromClause::Subquery { body, .. } => self.bind_select(body, visible_ctes)?,
352 }
353 Ok(())
354 }
355
356 fn bind_expression_type(&mut self, expression: &mut Expr) -> Result<(), SQLError> {
357 if let Some(visit) = self.expression.as_mut() {
358 visit(expression)?;
359 }
360 if let (
361 Some(visit),
362 Expr::Cast { ty, .. }
363 | Expr::TypedLiteral { ty, .. }
364 | Expr::CompositeRow {
365 binding: crate::ast::CompositeRowBinding { ty, .. },
366 ..
367 },
368 ) = (self.ty.as_mut(), expression)
369 {
370 visit(ty);
371 }
372 Ok(())
373 }
374
375 fn bind_window_call(
377 &mut self,
378 args: &mut [Expr],
379 filter: Option<&mut Expr>,
380 spec: &mut crate::ast::WindowSpec,
381 visible_ctes: &BTreeSet<String>,
382 ) -> Result<(), SQLError> {
383 for argument in args {
384 self.bind_expr(argument, visible_ctes)?;
385 }
386 if let Some(filter) = filter {
387 self.bind_expr(filter, visible_ctes)?;
388 }
389 for partition in &mut spec.partition_by {
390 self.bind_expr(partition, visible_ctes)?;
391 }
392 for order in &mut spec.order_by {
393 self.bind_expr(&mut order.expr, visible_ctes)?;
394 }
395 if let Some(frame) = &mut spec.frame {
396 for bound in [&mut frame.start, &mut frame.end] {
397 if let FrameBound::Preceding(inner) | FrameBound::Following(inner) = bound {
398 self.bind_expr(inner, visible_ctes)?;
399 }
400 }
401 }
402 Ok(())
403 }
404
405 fn bind_projection(
406 &mut self,
407 projection: &mut crate::ast::Projection,
408 visible_ctes: &BTreeSet<String>,
409 ) -> Result<(), SQLError> {
410 if let Some(visit) = self.projection.as_mut() {
411 visit(projection)?;
412 }
413 self.bind_expr(&mut projection.expr, visible_ctes)
414 }
415
416 pub fn bind_expr(
417 &mut self,
418 expression: &mut Expr,
419 visible_ctes: &BTreeSet<String>,
420 ) -> Result<(), SQLError> {
421 self.bind_expression_type(expression)?;
422 match expression {
423 Expr::Func {
424 name,
425 binding,
426 args,
427 order_by,
428 filter,
429 ..
430 } => {
431 for argument in args {
432 self.bind_expr(argument, visible_ctes)?;
433 }
434 for order in order_by {
435 self.bind_expr(&mut order.expr, visible_ctes)?;
436 }
437 if let Some(filter) = filter {
438 self.bind_expr(filter, visible_ctes)?;
439 }
440 (self.routine)(name, Some(binding))?;
441 }
442 Expr::Array(items)
443 | Expr::Row(items)
444 | Expr::CompositeRow { items, .. }
445 | Expr::And(items)
446 | Expr::Or(items) => {
447 for item in items {
448 self.bind_expr(item, visible_ctes)?;
449 }
450 }
451 Expr::Binary { lhs, rhs, .. } => {
452 self.bind_expr(lhs, visible_ctes)?;
453 self.bind_expr(rhs, visible_ctes)?;
454 }
455 Expr::UnaryMinus(inner)
456 | Expr::Not(inner)
457 | Expr::IsNull { expr: inner, .. }
458 | Expr::Cast { expr: inner, .. } => self.bind_expr(inner, visible_ctes)?,
459 Expr::Between { expr, low, high } => {
460 self.bind_expr(expr, visible_ctes)?;
461 self.bind_expr(low, visible_ctes)?;
462 self.bind_expr(high, visible_ctes)?;
463 }
464 Expr::InList { expr, list, .. } => {
465 self.bind_expr(expr, visible_ctes)?;
466 for item in list {
467 self.bind_expr(item, visible_ctes)?;
468 }
469 }
470 Expr::WindowCall {
471 name,
472 args,
473 spec,
474 filter,
475 ..
476 } => {
477 self.bind_window_call(args, filter.as_deref_mut(), spec, visible_ctes)?;
478 (self.routine)(name, None)?;
479 }
480 Expr::Case {
481 base,
482 when,
483 else_branch,
484 } => {
485 if let Some(base) = base {
486 self.bind_expr(base, visible_ctes)?;
487 }
488 for (condition, result) in when {
489 self.bind_expr(condition, visible_ctes)?;
490 self.bind_expr(result, visible_ctes)?;
491 }
492 if let Some(branch) = else_branch {
493 self.bind_expr(branch, visible_ctes)?;
494 }
495 }
496 Expr::ScalarSubquery(body) | Expr::Exists { body, .. } => {
497 self.bind_select(body, visible_ctes)?;
498 }
499 Expr::InSubquery { expr, body, .. } => {
500 self.bind_expr(expr, visible_ctes)?;
501 self.bind_select(body, visible_ctes)?;
502 }
503 Expr::Star
504 | Expr::QualifiedStar(_)
505 | Expr::Default
506 | Expr::Column(_)
507 | Expr::QualifiedColumn { .. }
508 | Expr::InternalColumn(_)
509 | Expr::Literal(_)
510 | Expr::TypedLiteral { .. }
511 | Expr::Param(_) => {}
512 }
513 Ok(())
514 }
515}