1use std::collections::{BTreeMap, BTreeSet};
10
11use crate::ast::{
12 Expr, FrameBound, FromClause, OrderBy, Projection, RuleEvent, SelectStmt, Statement,
13 UpdateStmt, CTE,
14};
15use crate::plpgsql::{bind_statement, ResolvedVariable, VariableResolver};
16use crate::SQLError;
17
18mod insert;
19use insert::bind_insert;
20mod namespace;
21mod references;
22mod returning;
23mod row_expansion;
24mod scope;
25pub use references::{
26 first_rule_row_reference_in_expr, first_rule_row_reference_in_select,
27 first_rule_row_reference_in_statement, rule_action_has_set_operation,
28 rule_condition_plan_references_whole_row, rule_condition_plan_row_columns,
29 rule_expr_references_row, rule_expr_references_whole_row, rule_expr_row_columns,
30 rule_new_row_columns, rule_statement_references_row, rule_statement_references_whole_row,
31 rule_statement_row_columns,
32};
33pub use returning::expand_rule_action_returning_stars;
34pub use row_expansion::expand_rule_action_row_stars;
35use scope::{
36 apply_positional_aliases, collect_visible_scope, cte_output_columns, RuleBindingScope,
37};
38
39pub fn action_target_qualifier_referenced(
40 catalog: &dyn RuleSourceCatalog,
41 action: &Statement,
42 qualifier: &str,
43) -> bool {
44 namespace::action_target_qualifier_referenced(catalog, action, qualifier)
45}
46
47mod context;
48use context::RuleBindingContext;
49pub use context::{rule_action_target_columns, rule_action_target_row_type, RuleSourceCatalog};
50
51pub fn bind_rule_action(
54 catalog: &dyn RuleSourceCatalog,
55 action: &Statement,
56 action_columns: &BTreeSet<String>,
57 resolver: &mut dyn VariableResolver,
58) -> Result<Statement, SQLError> {
59 let context = RuleBindingContext::with_catalog(catalog, true);
60 let (returning, action_event) = match action {
61 Statement::Insert(statement) => (&statement.returning, RuleEvent::Insert),
62 Statement::Update(statement) => (&statement.returning, RuleEvent::Update),
63 Statement::Delete(statement) => (&statement.returning, RuleEvent::Delete),
64 _ => {
65 return bind_rule_statement_body(
66 action,
67 resolver,
68 &RuleBindingScope::default(),
69 &context,
70 )
71 }
72 };
73 let mut body = action.clone();
74 let aliases = match &mut body {
75 Statement::Insert(statement) => {
76 statement.returning.clear();
77 statement.returning_aliases.clone()
78 }
79 Statement::Update(statement) => {
80 statement.returning.clear();
81 statement.returning_aliases.clone()
82 }
83 Statement::Delete(statement) => {
84 statement.returning.clear();
85 statement.returning_aliases.clone()
86 }
87 _ => unreachable!("DML rule action changed statement kind"),
88 };
89 let mut bound = {
90 let mut body_resolver = RuleActionBodyResolver {
91 action_columns,
92 action_event,
93 event_resolver: resolver,
94 };
95 bind_rule_statement_body(
96 &body,
97 &mut body_resolver,
98 &RuleBindingScope::default(),
99 &context,
100 )?
101 };
102 if returning.is_empty() {
103 return Ok(bound);
104 }
105 let returning = returning::bind_rule_action_returning(
106 returning,
107 action_columns,
108 &aliases,
109 action_event,
110 resolver,
111 &context,
112 )?;
113 match &mut bound {
114 Statement::Insert(statement) => statement.returning = returning,
115 Statement::Update(statement) => statement.returning = returning,
116 Statement::Delete(statement) => statement.returning = returning,
117 _ => unreachable!("bound DML rule action changed statement kind"),
118 }
119 Ok(bound)
120}
121
122struct RuleActionBodyResolver<'a, 'resolver> {
123 action_columns: &'a BTreeSet<String>,
124 action_event: RuleEvent,
125 event_resolver: &'resolver mut dyn VariableResolver,
126}
127
128impl RuleActionBodyResolver<'_, '_> {
129 fn is_action_column(&self, name: &str) -> bool {
130 matches!(self.action_event, RuleEvent::Update | RuleEvent::Delete)
131 && self
132 .action_columns
133 .iter()
134 .any(|column| column.eq_ignore_ascii_case(name))
135 }
136}
137
138impl VariableResolver for RuleActionBodyResolver<'_, '_> {
139 fn resolve_name(&mut self, name: &str) -> Result<Option<ResolvedVariable>, SQLError> {
140 if self.is_action_column(name) {
141 Ok(None)
142 } else {
143 self.event_resolver.resolve_name(name)
144 }
145 }
146
147 fn resolve_qualified(
148 &mut self,
149 qualifier: &str,
150 column: &str,
151 ) -> Result<Option<ResolvedVariable>, SQLError> {
152 self.event_resolver.resolve_qualified(qualifier, column)
153 }
154
155 fn resolve_param(&mut self, index: usize) -> Result<Option<ResolvedVariable>, SQLError> {
156 self.event_resolver.resolve_param(index)
157 }
158
159 fn rewrite_name(&mut self, name: &str) -> Result<Option<Expr>, SQLError> {
160 if self.is_action_column(name) {
161 Ok(None)
162 } else {
163 self.event_resolver.rewrite_name(name)
164 }
165 }
166
167 fn rewrite_qualified(
168 &mut self,
169 qualifier: &str,
170 column: &str,
171 ) -> Result<Option<Expr>, SQLError> {
172 self.event_resolver.rewrite_qualified(qualifier, column)
173 }
174
175 fn rewrite_qualified_star(&mut self, qualifier: &str) -> Result<Option<Vec<Expr>>, SQLError> {
176 self.event_resolver.rewrite_qualified_star(qualifier)
177 }
178
179 fn rewrite_qualified_whole_row(&mut self, qualifier: &str) -> Result<Option<Expr>, SQLError> {
180 self.event_resolver.rewrite_qualified_whole_row(qualifier)
181 }
182
183 fn rewrite_param(&mut self, index: usize) -> Result<Option<Expr>, SQLError> {
184 self.event_resolver.rewrite_param(index)
185 }
186
187 fn rewrite_internal(
188 &mut self,
189 column: crate::ast::InternalColumnRef,
190 ) -> Result<Option<Expr>, SQLError> {
191 self.event_resolver.rewrite_internal(column)
192 }
193}
194
195pub fn bind_rule_expr_scoped(
197 expr: &Expr,
198 resolver: &mut dyn VariableResolver,
199 shadowed: &BTreeSet<String>,
200) -> Result<Expr, SQLError> {
201 bind_rule_expr_with_scope(
202 expr,
203 resolver,
204 &RuleBindingScope::from_qualifiers(shadowed),
205 &RuleBindingContext::default(),
206 )
207}
208
209fn bind_rule_expr_with_scope(
210 expr: &Expr,
211 resolver: &mut dyn VariableResolver,
212 scope: &RuleBindingScope,
213 context: &RuleBindingContext<'_>,
214) -> Result<Expr, SQLError> {
215 Ok(match expr {
216 Expr::Column(name) => {
217 if scope.qualifier_is_shadowed(name) || scope.column_is_shadowed(name) {
218 expr.clone()
219 } else {
220 resolver.rewrite_name(name)?.unwrap_or_else(|| expr.clone())
221 }
222 }
223 Expr::QualifiedColumn { qualifier, column } => {
224 if scope.qualifier_is_shadowed(qualifier) {
225 expr.clone()
226 } else {
227 resolver
228 .rewrite_qualified(qualifier, column)?
229 .unwrap_or_else(|| expr.clone())
230 }
231 }
232 Expr::Param(index) => resolver
233 .rewrite_param(*index)?
234 .unwrap_or_else(|| expr.clone()),
235 Expr::InternalColumn(column) => resolver
236 .rewrite_internal(*column)?
237 .unwrap_or_else(|| expr.clone()),
238 Expr::QualifiedStar(qualifier) => {
239 if scope.qualifier_is_shadowed(qualifier) {
240 expr.clone()
241 } else {
242 resolver
243 .rewrite_qualified_whole_row(qualifier)?
244 .unwrap_or_else(|| expr.clone())
245 }
246 }
247 Expr::Default | Expr::Literal(_) | Expr::TypedLiteral { .. } | Expr::Star => expr.clone(),
248 Expr::Func { .. } => bind_rule_function_expression(expr, resolver, scope, context)?,
249 Expr::Array(items) => Expr::Array(bind_exprs(items, resolver, scope, context)?),
250 Expr::Row(items) => Expr::Row(bind_expanding_exprs(items, resolver, scope, context)?),
251 Expr::Binary { op, lhs, rhs } => Expr::Binary {
252 op: *op,
253 lhs: Box::new(bind_rule_expr_with_scope(lhs, resolver, scope, context)?),
254 rhs: Box::new(bind_rule_expr_with_scope(rhs, resolver, scope, context)?),
255 },
256 Expr::UnaryMinus(inner) => Expr::UnaryMinus(Box::new(bind_rule_expr_with_scope(
257 inner, resolver, scope, context,
258 )?)),
259 Expr::Not(inner) => Expr::Not(Box::new(bind_rule_expr_with_scope(
260 inner, resolver, scope, context,
261 )?)),
262 Expr::And(items) => Expr::And(bind_exprs(items, resolver, scope, context)?),
263 Expr::Or(items) => Expr::Or(bind_exprs(items, resolver, scope, context)?),
264 Expr::IsNull { expr, negated } => Expr::IsNull {
265 expr: Box::new(bind_rule_expr_with_scope(expr, resolver, scope, context)?),
266 negated: *negated,
267 },
268 Expr::Between { expr, low, high } => Expr::Between {
269 expr: Box::new(bind_rule_expr_with_scope(expr, resolver, scope, context)?),
270 low: Box::new(bind_rule_expr_with_scope(low, resolver, scope, context)?),
271 high: Box::new(bind_rule_expr_with_scope(high, resolver, scope, context)?),
272 },
273 Expr::InList {
274 expr,
275 list,
276 negated,
277 } => Expr::InList {
278 expr: Box::new(bind_rule_expr_with_scope(expr, resolver, scope, context)?),
279 list: bind_exprs(list, resolver, scope, context)?,
280 negated: *negated,
281 },
282 Expr::WindowCall { .. } => bind_rule_window_expression(expr, resolver, scope, context)?,
283 Expr::Case { .. } => bind_rule_case_expression(expr, resolver, scope, context)?,
284 Expr::Cast { expr, ty } => Expr::Cast {
285 expr: Box::new(bind_rule_expr_with_scope(expr, resolver, scope, context)?),
286 ty: ty.clone(),
287 },
288 Expr::ScalarSubquery(body) => Expr::ScalarSubquery(Box::new(bind_select_with_scope(
289 body, resolver, scope, context,
290 )?)),
291 Expr::Exists { body, negated } => Expr::Exists {
292 body: Box::new(bind_select_with_scope(body, resolver, scope, context)?),
293 negated: *negated,
294 },
295 Expr::InSubquery {
296 expr,
297 body,
298 negated,
299 } => Expr::InSubquery {
300 expr: Box::new(bind_rule_expr_with_scope(expr, resolver, scope, context)?),
301 body: Box::new(bind_select_with_scope(body, resolver, scope, context)?),
302 negated: *negated,
303 },
304 })
305}
306
307fn bind_rule_function_expression(
308 expr: &Expr,
309 resolver: &mut dyn VariableResolver,
310 scope: &RuleBindingScope,
311 context: &RuleBindingContext<'_>,
312) -> Result<Expr, SQLError> {
313 let Expr::Func {
314 name,
315 binding,
316 args,
317 distinct,
318 order_by,
319 filter,
320 } = expr
321 else {
322 unreachable!("function binder received a non-function expression")
323 };
324 Ok(Expr::Func {
325 name: name.clone(),
326 binding: binding.clone(),
327 args: bind_exprs(args, resolver, scope, context)?,
328 distinct: *distinct,
329 order_by: bind_orders(order_by, resolver, scope, context)?,
330 filter: filter
331 .as_deref()
332 .map(|expr| bind_rule_expr_with_scope(expr, resolver, scope, context).map(Box::new))
333 .transpose()?,
334 })
335}
336
337fn bind_rule_window_expression(
338 expr: &Expr,
339 resolver: &mut dyn VariableResolver,
340 scope: &RuleBindingScope,
341 context: &RuleBindingContext<'_>,
342) -> Result<Expr, SQLError> {
343 let Expr::WindowCall { name, args, spec } = expr else {
344 unreachable!("window binder received a non-window expression")
345 };
346 Ok(Expr::WindowCall {
347 name: name.clone(),
348 args: bind_exprs(args, resolver, scope, context)?,
349 spec: crate::ast::WindowSpec {
350 reference: spec.reference.clone(),
351 partition_by: bind_exprs(&spec.partition_by, resolver, scope, context)?,
352 order_by: bind_orders(&spec.order_by, resolver, scope, context)?,
353 frame: spec
354 .frame
355 .as_ref()
356 .map(|frame| -> Result<crate::ast::WindowFrame, SQLError> {
357 Ok(crate::ast::WindowFrame {
358 mode: frame.mode,
359 start: bind_frame_bound(&frame.start, resolver, scope, context)?,
360 end: bind_frame_bound(&frame.end, resolver, scope, context)?,
361 })
362 })
363 .transpose()?,
364 },
365 })
366}
367
368fn bind_rule_case_expression(
369 expr: &Expr,
370 resolver: &mut dyn VariableResolver,
371 scope: &RuleBindingScope,
372 context: &RuleBindingContext<'_>,
373) -> Result<Expr, SQLError> {
374 let Expr::Case {
375 base,
376 when,
377 else_branch,
378 } = expr
379 else {
380 unreachable!("CASE binder received a non-CASE expression")
381 };
382 Ok(Expr::Case {
383 base: base
384 .as_deref()
385 .map(|expr| bind_rule_expr_with_scope(expr, resolver, scope, context).map(Box::new))
386 .transpose()?,
387 when: when
388 .iter()
389 .map(|(condition, result)| {
390 Ok((
391 bind_rule_expr_with_scope(condition, resolver, scope, context)?,
392 bind_rule_expr_with_scope(result, resolver, scope, context)?,
393 ))
394 })
395 .collect::<Result<Vec<_>, SQLError>>()?,
396 else_branch: else_branch
397 .as_deref()
398 .map(|expr| bind_rule_expr_with_scope(expr, resolver, scope, context).map(Box::new))
399 .transpose()?,
400 })
401}
402
403fn bind_rule_select_scoped(
404 catalog: &dyn RuleSourceCatalog,
405 select: &SelectStmt,
406 resolver: &mut dyn VariableResolver,
407) -> Result<SelectStmt, SQLError> {
408 bind_select_with_scope(
409 select,
410 resolver,
411 &RuleBindingScope::default(),
412 &RuleBindingContext::with_catalog(catalog, false),
413 )
414}
415
416fn bind_rule_statement_body(
417 statement: &Statement,
418 resolver: &mut dyn VariableResolver,
419 inherited: &RuleBindingScope,
420 context: &RuleBindingContext<'_>,
421) -> Result<Statement, SQLError> {
422 Ok(match statement {
423 Statement::Select(select) => Statement::Select(Box::new(bind_select_with_scope(
424 select, resolver, inherited, context,
425 )?)),
426 Statement::Insert(insert) => {
427 Statement::Insert(bind_insert(insert, resolver, inherited, context)?)
428 }
429 Statement::Update(update) => {
430 Statement::Update(bind_update(update, resolver, inherited, context)?)
431 }
432 Statement::Delete(delete) => {
433 let mut output = delete.clone();
434 output.with = bind_ctes(&delete.with, resolver, inherited, context)?;
435 let context = context.with_ctes(&delete.with)?;
436 let mut target_scope = inherited.clone();
437 target_scope.insert_qualifier(&delete.target_qualifier);
438 output.using = delete
439 .using
440 .as_ref()
441 .map(|source| bind_from(source, resolver, &target_scope, &context))
442 .transpose()?;
443 let mut expression_scope = target_scope;
444 if let Some(source) = &delete.using {
445 collect_visible_scope(source, &context, &mut expression_scope)?;
446 }
447 output.r#where = bind_optional_expr(
448 delete.r#where.as_ref(),
449 resolver,
450 &expression_scope,
451 &context,
452 )?;
453 output.returning.clear();
454 Statement::Delete(output)
455 }
456 _ => return bind_statement(statement, resolver),
457 })
458}
459
460fn bind_update(
461 update: &UpdateStmt,
462 resolver: &mut dyn VariableResolver,
463 inherited: &RuleBindingScope,
464 context: &RuleBindingContext<'_>,
465) -> Result<UpdateStmt, SQLError> {
466 let mut output = update.clone();
467 output.with = bind_ctes(&update.with, resolver, inherited, context)?;
468 let context = context.with_ctes(&update.with)?;
469 let mut target_scope = inherited.clone();
470 target_scope.insert_qualifier(&update.target_qualifier);
471 output.from = update
472 .from
473 .as_ref()
474 .map(|source| bind_from(source, resolver, &target_scope, &context))
475 .transpose()?;
476 let mut expression_scope = target_scope;
477 if let Some(source) = &update.from {
478 collect_visible_scope(source, &context, &mut expression_scope)?;
479 }
480 output.assignments = update
481 .assignments
482 .iter()
483 .map(|(column, expr)| {
484 Ok((
485 column.clone(),
486 bind_rule_expr_with_scope(expr, resolver, &expression_scope, &context)?,
487 ))
488 })
489 .collect::<Result<Vec<_>, SQLError>>()?;
490 output.r#where = bind_optional_expr(
491 update.r#where.as_ref(),
492 resolver,
493 &expression_scope,
494 &context,
495 )?;
496 output.returning.clear();
497 Ok(output)
498}
499
500fn bind_select_with_scope(
501 select: &SelectStmt,
502 resolver: &mut dyn VariableResolver,
503 inherited: &RuleBindingScope,
504 context: &RuleBindingContext<'_>,
505) -> Result<SelectStmt, SQLError> {
506 let local_context = context.with_ctes(&select.with)?;
507 let mut scope = inherited.clone();
508 if let Some(source) = &select.from {
509 collect_visible_scope(source, &local_context, &mut scope)?;
510 }
511 Ok(SelectStmt {
512 projections: bind_projections(&select.projections, resolver, &scope, &local_context)?,
513 values: select
514 .values
515 .iter()
516 .map(|row| bind_expanding_exprs(row, resolver, &scope, &local_context))
517 .collect::<Result<Vec<_>, SQLError>>()?,
518 from: select
519 .from
520 .as_ref()
521 .map(|source| bind_from(source, resolver, inherited, &local_context))
522 .transpose()?,
523 r#where: bind_optional_expr(select.r#where.as_ref(), resolver, &scope, &local_context)?,
524 group_by: bind_exprs(&select.group_by, resolver, &scope, &local_context)?,
525 grouping_sets: select
526 .grouping_sets
527 .iter()
528 .map(|set| bind_exprs(set, resolver, &scope, &local_context))
529 .collect::<Result<Vec<_>, SQLError>>()?,
530 group_distinct: select.group_distinct,
531 having: bind_optional_expr(select.having.as_ref(), resolver, &scope, &local_context)?,
532 order_by: bind_orders(&select.order_by, resolver, &scope, &local_context)?,
533 limit: bind_optional_expr(select.limit.as_ref(), resolver, &scope, &local_context)?,
534 with_ties: select.with_ties,
535 offset: bind_optional_expr(select.offset.as_ref(), resolver, &scope, &local_context)?,
536 with: bind_ctes(&select.with, resolver, inherited, context)?,
537 set_op: select
538 .set_op
539 .as_ref()
540 .map(|operation| -> Result<Box<crate::ast::SetOp>, SQLError> {
541 Ok(Box::new(crate::ast::SetOp {
542 kind: operation.kind,
543 all: operation.all,
544 left: operation
545 .left
546 .as_deref()
547 .map(|left| {
548 bind_select_with_scope(left, resolver, inherited, &local_context)
549 .map(Box::new)
550 })
551 .transpose()?,
552 right: bind_select_with_scope(
553 &operation.right,
554 resolver,
555 inherited,
556 &local_context,
557 )?,
558 combined_order_by: bind_orders(
559 &operation.combined_order_by,
560 resolver,
561 inherited,
562 &local_context,
563 )?,
564 combined_limit: bind_optional_expr(
565 operation.combined_limit.as_ref(),
566 resolver,
567 inherited,
568 &local_context,
569 )?,
570 combined_with_ties: operation.combined_with_ties,
571 combined_offset: bind_optional_expr(
572 operation.combined_offset.as_ref(),
573 resolver,
574 inherited,
575 &local_context,
576 )?,
577 }))
578 })
579 .transpose()?,
580 distinct: select.distinct,
581 distinct_on: bind_exprs(&select.distinct_on, resolver, &scope, &local_context)?,
582 locking: select.locking.clone(),
583 })
584}
585
586fn bind_from(
587 from: &FromClause,
588 resolver: &mut dyn VariableResolver,
589 inherited: &RuleBindingScope,
590 context: &RuleBindingContext<'_>,
591) -> Result<FromClause, SQLError> {
592 Ok(match from {
593 FromClause::Table { .. } => from.clone(),
594 FromClause::Join { .. } => bind_join_from(from, resolver, inherited, context)?,
595 FromClause::Values {
596 rows,
597 alias,
598 column_aliases,
599 internal_relation,
600 internal_column_types,
601 } => FromClause::Values {
602 rows: rows
603 .iter()
604 .map(|row| bind_exprs(row, resolver, inherited, context))
605 .collect::<Result<Vec<_>, SQLError>>()?,
606 alias: alias.clone(),
607 column_aliases: column_aliases.clone(),
608 internal_relation: *internal_relation,
609 internal_column_types: internal_column_types.clone(),
610 },
611 FromClause::Function {
612 name,
613 binding,
614 output_name,
615 relations,
616 args,
617 alias,
618 column_aliases,
619 ordinality,
620 column_types,
621 } => FromClause::Function {
622 name: name.clone(),
623 binding: binding.clone(),
624 output_name: output_name.clone(),
625 relations: relations.clone(),
626 args: bind_exprs(args, resolver, inherited, context)?,
627 alias: alias.clone(),
628 column_aliases: column_aliases.clone(),
629 ordinality: *ordinality,
630 column_types: column_types.clone(),
631 },
632 FromClause::FunctionGroup {
633 functions,
634 alias,
635 column_aliases,
636 ordinality,
637 } => FromClause::FunctionGroup {
638 functions: functions
639 .iter()
640 .map(|function| {
641 Ok(crate::ast::TableFunction {
642 name: function.name.clone(),
643 binding: function.binding.clone(),
644 output_name: function.output_name.clone(),
645 relations: function.relations.clone(),
646 args: bind_exprs(&function.args, resolver, inherited, context)?,
647 column_aliases: function.column_aliases.clone(),
648 column_types: function.column_types.clone(),
649 })
650 })
651 .collect::<Result<Vec<_>, SQLError>>()?,
652 alias: alias.clone(),
653 column_aliases: column_aliases.clone(),
654 ordinality: *ordinality,
655 },
656 FromClause::Subquery {
657 body,
658 alias,
659 column_aliases,
660 } => FromClause::Subquery {
661 body: Box::new(bind_select_with_scope(body, resolver, inherited, context)?),
662 alias: alias.clone(),
663 column_aliases: column_aliases.clone(),
664 },
665 })
666}
667
668fn bind_join_from(
669 from: &FromClause,
670 resolver: &mut dyn VariableResolver,
671 inherited: &RuleBindingScope,
672 context: &RuleBindingContext<'_>,
673) -> Result<FromClause, SQLError> {
674 let FromClause::Join {
675 left,
676 right,
677 kind,
678 on,
679 using,
680 natural,
681 alias,
682 column_aliases,
683 lateral,
684 } = from
685 else {
686 unreachable!("join binder received a non-join source")
687 };
688 let bound_left = bind_from(left, resolver, inherited, context)?;
689 let mut right_scope = inherited.clone();
690 if *lateral {
691 collect_visible_scope(left, context, &mut right_scope)?;
692 }
693 let bound_right = bind_from(right, resolver, &right_scope, context)?;
694 let mut on_scope = inherited.clone();
695 collect_visible_scope(left, context, &mut on_scope)?;
696 collect_visible_scope(right, context, &mut on_scope)?;
697 Ok(FromClause::Join {
698 left: Box::new(bound_left),
699 right: Box::new(bound_right),
700 kind: *kind,
701 on: bind_optional_expr(on.as_ref(), resolver, &on_scope, context)?,
702 using: using.clone(),
703 natural: *natural,
704 alias: alias.clone(),
705 column_aliases: column_aliases.clone(),
706 lateral: *lateral,
707 })
708}
709
710fn bind_ctes(
711 ctes: &[CTE],
712 resolver: &mut dyn VariableResolver,
713 inherited: &RuleBindingScope,
714 context: &RuleBindingContext<'_>,
715) -> Result<Vec<CTE>, SQLError> {
716 let mut visible = context.clone();
717 let mut bound = Vec::with_capacity(ctes.len());
718 for cte in ctes {
719 if cte.recursive {
720 visible
721 .ctes
722 .entry(cte.name.to_ascii_lowercase())
723 .or_default();
724 let mut columns = cte_output_columns(&cte.body, &visible)?;
725 apply_positional_aliases(&mut columns, &cte.columns);
726 visible.ctes.insert(cte.name.to_ascii_lowercase(), columns);
727 }
728 bound.push(CTE {
729 name: cte.name.clone(),
730 columns: cte.columns.clone(),
731 recursive: cte.recursive,
732 materialization: cte.materialization,
733 search: cte.search.clone(),
734 cycle: cte
735 .cycle
736 .as_ref()
737 .map(|cycle| -> Result<crate::ast::CteCycleClause, SQLError> {
738 Ok(crate::ast::CteCycleClause {
739 columns: cycle.columns.clone(),
740 mark_column: cycle.mark_column.clone(),
741 mark_value: bind_rule_expr_with_scope(
742 &cycle.mark_value,
743 resolver,
744 inherited,
745 &visible,
746 )?,
747 mark_default: bind_rule_expr_with_scope(
748 &cycle.mark_default,
749 resolver,
750 inherited,
751 &visible,
752 )?,
753 path_column: cycle.path_column.clone(),
754 })
755 })
756 .transpose()?,
757 body: match &cte.body {
758 crate::ast::CteBody::Query(query) => crate::ast::CteBody::Query(Box::new(
759 bind_select_with_scope(query, resolver, inherited, &visible)?,
760 )),
761 body => body.clone(),
763 },
764 });
765 let mut columns = cte_output_columns(&cte.body, &visible)?;
766 apply_positional_aliases(&mut columns, &cte.columns);
767 if let Some(search) = &cte.search {
768 columns.push(search.sequence_column.clone());
769 }
770 if let Some(cycle) = &cte.cycle {
771 columns.push(cycle.mark_column.clone());
772 columns.push(cycle.path_column.clone());
773 }
774 visible.ctes.insert(cte.name.to_ascii_lowercase(), columns);
775 }
776 Ok(bound)
777}
778
779fn bind_frame_bound(
780 bound: &FrameBound,
781 resolver: &mut dyn VariableResolver,
782 scope: &RuleBindingScope,
783 context: &RuleBindingContext<'_>,
784) -> Result<FrameBound, SQLError> {
785 Ok(match bound {
786 FrameBound::Preceding(expr) => FrameBound::Preceding(Box::new(bind_rule_expr_with_scope(
787 expr, resolver, scope, context,
788 )?)),
789 FrameBound::Following(expr) => FrameBound::Following(Box::new(bind_rule_expr_with_scope(
790 expr, resolver, scope, context,
791 )?)),
792 _ => bound.clone(),
793 })
794}
795
796fn bind_projections(
797 projections: &[Projection],
798 resolver: &mut dyn VariableResolver,
799 scope: &RuleBindingScope,
800 context: &RuleBindingContext<'_>,
801) -> Result<Vec<Projection>, SQLError> {
802 let mut bound = Vec::with_capacity(projections.len());
803 for projection in projections {
804 if let Some(expressions) = expand_qualified_star(&projection.expr, resolver, scope)? {
805 bound.extend(expressions.into_iter().map(|expr| Projection {
806 expr,
807 alias: projection.alias.clone(),
808 }));
809 } else {
810 bound.push(Projection {
811 expr: bind_rule_expr_with_scope(&projection.expr, resolver, scope, context)?,
812 alias: projection.alias.clone(),
813 });
814 }
815 }
816 Ok(bound)
817}
818
819fn bind_expanding_exprs(
820 expressions: &[Expr],
821 resolver: &mut dyn VariableResolver,
822 scope: &RuleBindingScope,
823 context: &RuleBindingContext<'_>,
824) -> Result<Vec<Expr>, SQLError> {
825 let mut bound = Vec::with_capacity(expressions.len());
826 for expression in expressions {
827 if let Some(expressions) = expand_qualified_star(expression, resolver, scope)? {
828 bound.extend(expressions);
829 } else {
830 bound.push(bind_rule_expr_with_scope(
831 expression, resolver, scope, context,
832 )?);
833 }
834 }
835 Ok(bound)
836}
837
838fn expand_qualified_star(
839 expression: &Expr,
840 resolver: &mut dyn VariableResolver,
841 scope: &RuleBindingScope,
842) -> Result<Option<Vec<Expr>>, SQLError> {
843 let Expr::QualifiedStar(qualifier) = expression else {
844 return Ok(None);
845 };
846 if scope.qualifier_is_shadowed(qualifier) {
847 return Ok(None);
848 }
849 resolver.rewrite_qualified_star(qualifier)
850}
851
852fn bind_exprs(
853 expressions: &[Expr],
854 resolver: &mut dyn VariableResolver,
855 scope: &RuleBindingScope,
856 context: &RuleBindingContext<'_>,
857) -> Result<Vec<Expr>, SQLError> {
858 expressions
859 .iter()
860 .map(|expr| bind_rule_expr_with_scope(expr, resolver, scope, context))
861 .collect()
862}
863
864fn bind_optional_expr(
865 expression: Option<&Expr>,
866 resolver: &mut dyn VariableResolver,
867 scope: &RuleBindingScope,
868 context: &RuleBindingContext<'_>,
869) -> Result<Option<Expr>, SQLError> {
870 expression
871 .map(|expr| bind_rule_expr_with_scope(expr, resolver, scope, context))
872 .transpose()
873}
874
875fn bind_orders(
876 orders: &[OrderBy],
877 resolver: &mut dyn VariableResolver,
878 scope: &RuleBindingScope,
879 context: &RuleBindingContext<'_>,
880) -> Result<Vec<OrderBy>, SQLError> {
881 orders
882 .iter()
883 .map(|order| {
884 Ok(OrderBy {
885 expr: bind_rule_expr_with_scope(&order.expr, resolver, scope, context)?,
886 descending: order.descending,
887 nulls: order.nulls,
888 })
889 })
890 .collect()
891}
892
893pub fn invalid_rule_action_reference(qualifier: &str) -> SQLError {
894 SQLError::Routine {
895 sqlstate: "42P01".into(),
896 message: format!(
897 "invalid reference to FROM-clause entry for table \"{qualifier}\"\nDETAIL: There is an entry for table \"{qualifier}\", but it cannot be referenced from this part of the query."
898 ),
899 }
900}