1mod expressions;
10mod helpers;
11mod lifecycle;
12mod sources;
13mod statements;
14
15pub use lifecycle::{
16 bind_rule_action_column_dependencies, bind_rule_condition_column_dependencies,
17 bind_stored_statement_source_columns, remove_rule_source_column_aliases,
18 remove_stored_statement_source_column_aliases, rewrite_rule_column_references,
19 stored_statement_column_dependencies,
20};
21pub use statements::rewrite_stored_statement_column;
22
23pub trait StoredColumnCatalog {
25 fn stored_relation_column_names(&self, name: &str) -> Result<Option<Vec<String>>, SQLError>;
26}
27
28pub struct StoredSourceColumns {
30 pub catalog: crate::catalog::analysis::CatalogReadView,
31 pub resolution: crate::catalog::resolution::RelationNameResolution,
32}
33pub trait StoredSourceCatalog {
34 fn stored_source_columns(&self) -> StoredSourceColumns;
35}
36impl StoredSourceColumns {
37 pub fn bind_statement(&self, statement: &mut Statement) -> Result<bool, SQLError> {
38 bind_stored_statement_source_columns(statement, |name| {
39 Ok(
40 if let Some(table) = self.catalog.table_resolved(&self.resolution, name)? {
41 Some(
42 table
43 .columns
44 .iter()
45 .map(|column| column.name.clone())
46 .collect(),
47 )
48 } else {
49 self.catalog
50 .foreign_table_resolved(&self.resolution, name)?
51 .map(|table| {
52 table
53 .columns
54 .iter()
55 .map(|column| column.name.clone())
56 .collect()
57 })
58 },
59 )
60 })
61 }
62}
63
64#[derive(Clone, Copy)]
65pub struct StoredColumnBindingContext<'a> {
66 pub sources: &'a dyn StoredColumnCatalog,
67 pub merge: &'a dyn crate::routines::merge_columns::StoredMergeColumnCatalog,
68}
69
70use std::collections::{BTreeMap, BTreeSet};
71
72use crate::ast::{
73 DeleteStmt, Expr, FromClause, InsertStmt, OnConflictAction, Projection, SelectStmt, Statement,
74 UpdateStmt, CTE,
75};
76use crate::SQLError;
77
78use uqa_core::RelationIdentity;
79
80use crate::catalog::events::RuleColumnDependency;
81use helpers::{
82 action_returning_scope, apply_positional_aliases, is_default_values_insert, is_output_alias,
83 opaque_scope, preserve_table_column_name, same_identifier, select_output_names,
84 table_alias_count_error, unique_current_name,
85};
86
87fn cte_output_names(body: &crate::ast::CteBody) -> Vec<String> {
88 if let Some(query) = body.query() {
89 return select_output_names(query);
90 }
91 helpers::projection_output_names(body.returning().unwrap_or_default())
92}
93
94#[derive(Clone, Copy)]
95enum ColumnBindingMode<'a> {
96 Bind,
97 Rename {
98 relation: &'a RelationIdentity,
99 from: &'a str,
100 to: &'a str,
101 },
102 Drop {
103 dependencies: &'a BTreeSet<RuleColumnDependency>,
104 },
105}
106
107impl<'a> ColumnBindingMode<'a> {
108 fn column_names(self, relation: &RelationIdentity, current: &str) -> (String, String) {
109 match self {
110 Self::Rename {
111 relation: target,
112 from,
113 to,
114 } if relation == target && current == to => (from.to_string(), to.to_string()),
115 Self::Bind | Self::Rename { .. } | Self::Drop { .. } => {
116 (current.to_string(), current.to_string())
117 }
118 }
119 }
120
121 const fn is_rename(self) -> bool {
122 matches!(self, Self::Rename { .. })
123 }
124
125 const fn dropped_dependencies(self) -> Option<&'a BTreeSet<RuleColumnDependency>> {
126 match self {
127 Self::Drop { dependencies } => Some(dependencies),
128 Self::Bind | Self::Rename { .. } => None,
129 }
130 }
131}
132
133#[derive(Clone)]
134struct ScopeColumn {
135 name: String,
137 current_name: String,
139 reference: Expr,
141 dependencies: BTreeSet<RuleColumnDependency>,
142}
143
144#[derive(Clone, Default)]
145struct ColumnScope {
146 output: Vec<ScopeColumn>,
147 qualifiers: BTreeMap<String, Vec<ScopeColumn>>,
148}
149
150impl ColumnScope {
151 fn insert_qualifier(&mut self, qualifier: &str, columns: &[ScopeColumn]) {
152 self.qualifiers
153 .insert(qualifier.to_ascii_lowercase(), columns.to_vec());
154 }
155
156 fn qualified(&self, qualifier: &str) -> Option<&[ScopeColumn]> {
157 self.qualifiers
158 .get(&qualifier.to_ascii_lowercase())
159 .map(Vec::as_slice)
160 }
161
162 fn unqualified(&self, name: &str) -> Vec<&ScopeColumn> {
163 self.output
164 .iter()
165 .filter(|column| same_identifier(&column.name, name))
166 .collect()
167 }
168
169 fn combined(left: &Self, right: &Self) -> Self {
170 let mut output = left.output.clone();
171 output.extend(right.output.iter().cloned());
172 let mut qualifiers = left.qualifiers.clone();
173 qualifiers.extend(right.qualifiers.clone());
174 Self { output, qualifiers }
175 }
176}
177
178#[derive(Clone, Default)]
179struct ColumnBindingContext {
180 ctes: BTreeMap<String, Vec<String>>,
181}
182
183struct StoredColumnBinder<'a> {
184 catalog: StoredColumnBindingContext<'a>,
185 mode: ColumnBindingMode<'a>,
186 dependencies: BTreeSet<RuleColumnDependency>,
187 alias_shape_changed: bool,
188}
189
190impl<'a> StoredColumnBinder<'a> {
191 fn new(catalog: StoredColumnBindingContext<'a>, mode: ColumnBindingMode<'a>) -> Self {
192 Self {
193 catalog,
194 mode,
195 dependencies: BTreeSet::new(),
196 alias_shape_changed: false,
197 }
198 }
199
200 fn finish(self) -> BTreeSet<RuleColumnDependency> {
201 self.dependencies
202 }
203
204 const fn alias_shape_changed(&self) -> bool {
205 self.alias_shape_changed
206 }
207
208 fn remove_dropped_column_aliases(
209 &mut self,
210 column_aliases: &mut Vec<String>,
211 scope: &ColumnScope,
212 ) {
213 let Some(dependencies) = self.mode.dropped_dependencies() else {
214 return;
215 };
216 let positions = scope
217 .output
218 .iter()
219 .enumerate()
220 .filter_map(|(position, column)| {
221 (!column.dependencies.is_disjoint(dependencies)).then_some(position)
222 })
223 .collect::<Vec<_>>();
224 for position in positions.into_iter().rev() {
225 if position < column_aliases.len() {
226 column_aliases.remove(position);
227 self.alias_shape_changed = true;
228 }
229 }
230 }
231
232 fn table_scope(
233 &self,
234 name: &str,
235 qualifier: &str,
236 alias: Option<&str>,
237 column_aliases: &[String],
238 bound_columns: Option<&[String]>,
239 context: &ColumnBindingContext,
240 ) -> Result<ColumnScope, SQLError> {
241 if let Some(columns) = context.ctes.get(&name.to_ascii_lowercase()) {
242 if column_aliases.len() > columns.len() {
243 return Err(table_alias_count_error(
244 alias.unwrap_or(qualifier),
245 columns.len(),
246 column_aliases.len(),
247 ));
248 }
249 let mut columns = columns.clone();
250 apply_positional_aliases(&mut columns, column_aliases);
251 return Ok(opaque_scope(&columns, Some(alias.unwrap_or(qualifier))));
252 }
253 let columns = match bound_columns {
254 Some(columns) => columns.to_vec(),
255 None => self
256 .catalog
257 .sources
258 .stored_relation_column_names(name)?
259 .ok_or_else(|| SQLError::UnknownTable(name.to_string()))?,
260 };
261 if column_aliases.len() > columns.len() {
262 return Err(table_alias_count_error(
263 alias.unwrap_or(qualifier),
264 columns.len(),
265 column_aliases.len(),
266 ));
267 }
268 let relation = RelationIdentity::from_legacy_name(name).map_err(|error| {
269 SQLError::Internal(format!("decode bound rule relation `{name}`: {error}"))
270 })?;
271 let visible_qualifier = alias.unwrap_or(qualifier);
272 let output = columns
273 .into_iter()
274 .enumerate()
275 .map(|(position, column)| {
276 let (stored_physical, current_physical) =
277 self.mode.column_names(&relation, &column);
278 let name = column_aliases
279 .get(position)
280 .cloned()
281 .unwrap_or_else(|| stored_physical.clone());
282 let current_name = column_aliases
283 .get(position)
284 .cloned()
285 .unwrap_or(current_physical);
286 ScopeColumn {
287 reference: Expr::qualified_column(visible_qualifier, ¤t_name),
288 dependencies: BTreeSet::from([RuleColumnDependency {
289 relation: relation.clone(),
290 column: stored_physical,
291 }]),
292 name,
293 current_name,
294 }
295 })
296 .collect::<Vec<_>>();
297 let mut scope = ColumnScope {
298 output: output.clone(),
299 ..ColumnScope::default()
300 };
301 if let Some(alias) = alias {
302 scope.insert_qualifier(alias, &output);
303 } else {
304 scope.insert_qualifier(qualifier, &output);
305 scope.insert_qualifier(name, &output);
306 if let Some((_, local)) = name.rsplit_once('.') {
307 scope.insert_qualifier(local.trim_matches('"'), &output);
308 }
309 }
310 Ok(scope)
311 }
312
313 fn bind_statement(
314 &mut self,
315 statement: &mut Statement,
316 outer: &[ColumnScope],
317 context: &ColumnBindingContext,
318 ) -> Result<(), SQLError> {
319 match statement {
320 Statement::Select(select) => self.bind_select(select, outer, context),
321 Statement::Insert(insert) => self.bind_insert(insert, outer, context),
322 Statement::Update(update) => self.bind_update(update, outer, context),
323 Statement::Delete(delete) => self.bind_delete(delete, outer, context),
324 Statement::Merge(merge) => self.bind_merge(merge, outer, context),
325 Statement::Notify { .. } => Ok(()),
326 _ => Err(SQLError::Internal(
327 "validated rewrite-rule action has an unsupported statement kind".into(),
328 )),
329 }
330 }
331
332 fn bind_insert(
333 &mut self,
334 insert: &mut InsertStmt,
335 outer: &[ColumnScope],
336 context: &ColumnBindingContext,
337 ) -> Result<(), SQLError> {
338 let context = self.bind_ctes(&mut insert.with, outer, context)?;
339 for expression in insert.rows.iter_mut().flatten() {
340 self.bind_expr(expression, outer, &context)?;
341 }
342 if let Some(select) = insert.select_source.as_deref_mut() {
343 self.bind_select(select, outer, &context)?;
344 }
345 let target = self.table_scope(
346 &insert.table,
347 &insert.target_qualifier,
348 Some(&insert.target_qualifier),
349 &[],
350 None,
351 &ColumnBindingContext::default(),
352 )?;
353 if insert.columns.is_empty() && !is_default_values_insert(&insert.rows) {
354 let width = insert.rows.first().map(Vec::len).or_else(|| {
355 insert
356 .select_source
357 .as_deref()
358 .map(select_output_names)
359 .map(|columns| columns.len())
360 });
361 if let Some(width) = width {
362 insert.columns = target
363 .output
364 .iter()
365 .take(width)
366 .map(|column| column.current_name.clone().into())
367 .collect();
368 }
369 }
370 for assignment in &mut insert.columns {
371 self.bind_target_name(&mut assignment.column, &target);
372 for expression in assignment.expressions_mut() {
373 self.bind_expr(expression, outer, &context)?;
374 }
375 }
376 let mut conflict_scope = target.clone();
377 conflict_scope.insert_qualifier("excluded", &target.output);
378 let mut target_scopes = vec![conflict_scope];
379 target_scopes.extend_from_slice(outer);
380 if let Some(conflict) = &mut insert.on_conflict {
381 self.bind_target_names(&mut conflict.conflict_columns, &target);
382 for expression in &mut conflict.expressions {
383 self.bind_expr(expression, &target_scopes, &context)?;
384 }
385 if let Some(predicate) = conflict.predicate.as_deref_mut() {
386 self.bind_expr(predicate, &target_scopes, &context)?;
387 }
388 if let OnConflictAction::Update {
389 assignments,
390 r#where,
391 } = &mut conflict.action
392 {
393 for (column, expression) in assignments {
394 self.bind_target_name(&mut column.column, &target);
395 for expression in column.expressions_mut() {
396 self.bind_expr(expression, &target_scopes, &context)?;
397 }
398 self.bind_expr(expression, &target_scopes, &context)?;
399 }
400 if let Some(expression) = r#where {
401 self.bind_expr(expression, &target_scopes, &context)?;
402 }
403 }
404 }
405 let returning = action_returning_scope(
406 &target,
407 &target,
408 crate::ast::RuleEvent::Insert,
409 &insert.returning_aliases,
410 );
411 let mut returning_scopes = vec![returning.clone()];
412 returning_scopes.extend_from_slice(outer);
413 self.bind_projections(
414 &mut insert.returning,
415 Some(&returning),
416 &returning_scopes,
417 &context,
418 )
419 }
420
421 fn bind_update(
422 &mut self,
423 update: &mut UpdateStmt,
424 outer: &[ColumnScope],
425 context: &ColumnBindingContext,
426 ) -> Result<(), SQLError> {
427 let context = self.bind_ctes(&mut update.with, outer, context)?;
428 let target = self.table_scope(
429 &update.table,
430 &update.target_qualifier,
431 Some(&update.target_qualifier),
432 &[],
433 None,
434 &ColumnBindingContext::default(),
435 )?;
436 let (local, scopes) =
437 self.bind_dml_source(update.from.as_mut(), &target, outer, &context)?;
438 for (column, expression) in &mut update.assignments {
439 self.bind_target_name(&mut column.column, &target);
440 for expression in column.expressions_mut() {
441 self.bind_expr(expression, &scopes, &context)?;
442 }
443 self.bind_expr(expression, &scopes, &context)?;
444 }
445 if let Some(expression) = &mut update.r#where {
446 self.bind_expr(expression, &scopes, &context)?;
447 }
448 let returning = action_returning_scope(
449 &local,
450 &target,
451 crate::ast::RuleEvent::Update,
452 &update.returning_aliases,
453 );
454 let mut returning_scopes = vec![returning.clone()];
455 returning_scopes.extend_from_slice(outer);
456 self.bind_projections(
457 &mut update.returning,
458 Some(&returning),
459 &returning_scopes,
460 &context,
461 )
462 }
463
464 fn bind_delete(
465 &mut self,
466 delete: &mut DeleteStmt,
467 outer: &[ColumnScope],
468 context: &ColumnBindingContext,
469 ) -> Result<(), SQLError> {
470 let context = self.bind_ctes(&mut delete.with, outer, context)?;
471 let target = self.table_scope(
472 &delete.table,
473 &delete.target_qualifier,
474 Some(&delete.target_qualifier),
475 &[],
476 None,
477 &ColumnBindingContext::default(),
478 )?;
479 let (local, scopes) =
480 self.bind_dml_source(delete.using.as_mut(), &target, outer, &context)?;
481 if let Some(expression) = &mut delete.r#where {
482 self.bind_expr(expression, &scopes, &context)?;
483 }
484 let returning = action_returning_scope(
485 &local,
486 &target,
487 crate::ast::RuleEvent::Delete,
488 &delete.returning_aliases,
489 );
490 let mut returning_scopes = vec![returning.clone()];
491 returning_scopes.extend_from_slice(outer);
492 self.bind_projections(
493 &mut delete.returning,
494 Some(&returning),
495 &returning_scopes,
496 &context,
497 )
498 }
499
500 fn bind_dml_source(
501 &mut self,
502 source: Option<&mut FromClause>,
503 target: &ColumnScope,
504 outer: &[ColumnScope],
505 context: &ColumnBindingContext,
506 ) -> Result<(ColumnScope, Vec<ColumnScope>), SQLError> {
507 let mut source_outer = vec![target.clone()];
508 source_outer.extend_from_slice(outer);
509 let source = source
510 .map(|source| self.bind_from(source, &source_outer, context))
511 .transpose()?;
512 let local = source.as_ref().map_or_else(
513 || target.clone(),
514 |source| ColumnScope::combined(target, source),
515 );
516 let mut scopes = vec![local.clone()];
517 scopes.extend_from_slice(outer);
518 Ok((local, scopes))
519 }
520
521 fn bind_target_names(&mut self, names: &mut [String], target: &ColumnScope) {
522 for name in names {
523 self.bind_target_name(name, target);
524 }
525 }
526
527 fn bind_target_name(&mut self, name: &mut String, target: &ColumnScope) {
528 let Some(column) = target
529 .output
530 .iter()
531 .find(|column| same_identifier(&column.name, name))
532 else {
533 return;
534 };
535 self.dependencies
536 .extend(column.dependencies.iter().cloned());
537 name.clone_from(&column.current_name);
538 }
539
540 fn bind_ctes(
541 &mut self,
542 ctes: &mut [CTE],
543 outer: &[ColumnScope],
544 context: &ColumnBindingContext,
545 ) -> Result<ColumnBindingContext, SQLError> {
546 let mut visible = context.clone();
547 let recursive_names = ctes
548 .iter()
549 .filter(|cte| cte.recursive)
550 .map(|cte| {
551 let columns = if cte.columns.is_empty() {
552 cte_output_names(&cte.body)
553 } else {
554 cte.columns.clone()
555 };
556 (cte.name.to_ascii_lowercase(), columns)
557 })
558 .collect::<Vec<_>>();
559 for (name, columns) in recursive_names {
560 visible.ctes.entry(name).or_insert(columns);
561 }
562 for cte in ctes {
563 let mut statement = cte.body.clone().into_statement();
564 self.bind_statement(&mut statement, outer, &visible)?;
565 cte.body = statement.try_into()?;
566 if let Some(cycle) = &mut cte.cycle {
567 self.bind_expr(&mut cycle.mark_value, outer, &visible)?;
568 self.bind_expr(&mut cycle.mark_default, outer, &visible)?;
569 }
570 let mut columns = cte_output_names(&cte.body);
571 apply_positional_aliases(&mut columns, &cte.columns);
572 if let Some(search) = &cte.search {
573 columns.push(search.sequence_column.clone());
574 }
575 if let Some(cycle) = &cte.cycle {
576 columns.push(cycle.mark_column.clone());
577 columns.push(cycle.path_column.clone());
578 }
579 visible.ctes.insert(cte.name.to_ascii_lowercase(), columns);
580 }
581 Ok(visible)
582 }
583
584 fn bind_select(
585 &mut self,
586 select: &mut SelectStmt,
587 outer: &[ColumnScope],
588 context: &ColumnBindingContext,
589 ) -> Result<(), SQLError> {
590 let context = self.bind_ctes(&mut select.with, outer, context)?;
591 let local = select
592 .from
593 .as_mut()
594 .map(|source| self.bind_from(source, outer, &context))
595 .transpose()?;
596 let mut scopes = local.iter().cloned().collect::<Vec<_>>();
597 scopes.extend_from_slice(outer);
598 self.bind_projections(&mut select.projections, local.as_ref(), &scopes, &context)?;
599 for expression in select.values.iter_mut().flatten() {
600 self.bind_expr(expression, &scopes, &context)?;
601 }
602 if let Some(expression) = &mut select.r#where {
603 self.bind_expr(expression, &scopes, &context)?;
604 }
605 for expression in &mut select.group_by {
606 self.bind_expr(expression, &scopes, &context)?;
607 }
608 for expression in select.grouping_sets.iter_mut().flatten() {
609 self.bind_expr(expression, &scopes, &context)?;
610 }
611 if let Some(expression) = &mut select.having {
612 self.bind_expr(expression, &scopes, &context)?;
613 }
614 let output_names = select_output_names(select);
615 for order in &mut select.order_by {
616 if !is_output_alias(&order.expr, &output_names) {
617 self.bind_expr(&mut order.expr, &scopes, &context)?;
618 }
619 }
620 if let Some(expression) = &mut select.limit {
621 self.bind_expr(expression, &scopes, &context)?;
622 }
623 if let Some(expression) = &mut select.offset {
624 self.bind_expr(expression, &scopes, &context)?;
625 }
626 for expression in &mut select.distinct_on {
627 self.bind_expr(expression, &scopes, &context)?;
628 }
629 if let Some(set) = &mut select.set_op {
630 if let Some(left) = &mut set.left {
631 self.bind_select(left, outer, &context)?;
632 }
633 self.bind_select(&mut set.right, outer, &context)?;
634 let set_output = set
635 .left
636 .as_deref()
637 .map_or_else(|| output_names.clone(), select_output_names);
638 for order in &mut set.combined_order_by {
639 if !is_output_alias(&order.expr, &set_output) {
640 self.bind_expr(&mut order.expr, outer, &context)?;
641 }
642 }
643 if let Some(expression) = &mut set.combined_limit {
644 self.bind_expr(expression, outer, &context)?;
645 }
646 if let Some(expression) = &mut set.combined_offset {
647 self.bind_expr(expression, outer, &context)?;
648 }
649 }
650 Ok(())
651 }
652
653 fn bind_from(
654 &mut self,
655 source: &mut FromClause,
656 outer: &[ColumnScope],
657 context: &ColumnBindingContext,
658 ) -> Result<ColumnScope, SQLError> {
659 match source {
660 source @ FromClause::Table { .. } => self.bind_table_source(source, context),
661 source @ FromClause::Join { .. } => self.bind_join(source, outer, context),
662 FromClause::Values {
663 rows,
664 alias,
665 column_aliases,
666 ..
667 } => {
668 for expression in rows.iter_mut().flatten() {
669 self.bind_expr(expression, outer, context)?;
670 }
671 let mut columns = if column_aliases.is_empty() {
672 (1..=rows.first().map_or(0, Vec::len))
673 .map(|position| format!("column{position}"))
674 .collect::<Vec<_>>()
675 } else {
676 column_aliases.clone()
677 };
678 apply_positional_aliases(&mut columns, column_aliases);
679 Ok(opaque_scope(&columns, alias.as_deref()))
680 }
681 FromClause::Function {
682 output_name,
683 args,
684 alias,
685 column_aliases,
686 ordinality,
687 ..
688 } => {
689 for expression in args {
690 self.bind_expr(expression, outer, context)?;
691 }
692 let mut columns = vec![output_name.clone()];
693 apply_positional_aliases(&mut columns, column_aliases);
694 if *ordinality {
695 columns.push("ordinality".into());
696 }
697 Ok(opaque_scope(
698 &columns,
699 Some(alias.as_deref().unwrap_or(output_name)),
700 ))
701 }
702 FromClause::FunctionGroup {
703 functions,
704 alias,
705 column_aliases,
706 ordinality,
707 } => {
708 for function in functions.iter_mut() {
709 for expression in &mut function.args {
710 self.bind_expr(expression, outer, context)?;
711 }
712 }
713 let mut columns = functions
714 .iter()
715 .flat_map(|function| {
716 if function.column_aliases.is_empty() {
717 vec![function.output_name.clone()]
718 } else {
719 function.column_aliases.clone()
720 }
721 })
722 .collect::<Vec<_>>();
723 apply_positional_aliases(&mut columns, column_aliases);
724 if *ordinality {
725 columns.push("ordinality".into());
726 }
727 Ok(opaque_scope(&columns, alias.as_deref()))
728 }
729 FromClause::Subquery {
730 body,
731 alias,
732 column_aliases,
733 } => {
734 self.bind_select(body, outer, context)?;
735 let mut columns = select_output_names(body);
736 apply_positional_aliases(&mut columns, column_aliases);
737 Ok(opaque_scope(&columns, alias.as_deref()))
738 }
739 }
740 }
741
742 fn bind_join(
743 &mut self,
744 source: &mut FromClause,
745 outer: &[ColumnScope],
746 context: &ColumnBindingContext,
747 ) -> Result<ColumnScope, SQLError> {
748 let FromClause::Join {
749 left,
750 right,
751 on,
752 using,
753 natural,
754 alias,
755 column_aliases,
756 lateral,
757 ..
758 } = source
759 else {
760 unreachable!("join column binding requires a join source")
761 };
762 if let ColumnBindingMode::Rename { relation, from, to } = self.mode {
763 if *natural
764 || using.as_ref().is_some_and(|using| {
765 using
766 .columns
767 .iter()
768 .any(|column| same_identifier(column, from))
769 })
770 {
771 preserve_table_column_name(self.catalog, left, relation, from, to)?;
772 preserve_table_column_name(self.catalog, right, relation, from, to)?;
773 }
774 }
775 let left_scope = self.bind_from(left, outer, context)?;
776 let mut right_outer = Vec::new();
777 if *lateral {
778 right_outer.push(left_scope.clone());
779 }
780 right_outer.extend_from_slice(outer);
781 let right_scope = self.bind_from(right, &right_outer, context)?;
782 let input_scope = ColumnScope::combined(&left_scope, &right_scope);
783 let mut on_scopes = vec![input_scope];
784 on_scopes.extend_from_slice(outer);
785 if let Some(expression) = on {
786 self.bind_expr(expression, &on_scopes, context)?;
787 }
788 if *natural {
789 let columns = left_scope
790 .output
791 .iter()
792 .filter(|left| {
793 right_scope
794 .output
795 .iter()
796 .any(|right| same_identifier(&left.name, &right.name))
797 })
798 .map(|column| column.name.clone())
799 .collect();
800 *using = Some(crate::ast::JoinUsing {
801 columns,
802 alias: None,
803 });
804 *natural = false;
805 }
806 let scope = self.join_scope(
807 left_scope,
808 right_scope,
809 using.as_mut(),
810 alias.as_deref(),
811 column_aliases,
812 )?;
813 self.remove_dropped_column_aliases(column_aliases, &scope);
814 Ok(scope)
815 }
816
817 fn join_scope(
818 &mut self,
819 left: ColumnScope,
820 right: ColumnScope,
821 using: Option<&mut crate::ast::JoinUsing>,
822 alias: Option<&str>,
823 column_aliases: &[String],
824 ) -> Result<ColumnScope, SQLError> {
825 let using_alias = using.as_ref().and_then(|using| using.alias.clone());
826 let mut merged = Vec::new();
827 if let Some(using) = using {
828 for name in &mut using.columns {
829 let left_matches = left.unqualified(name);
830 let right_matches = right.unqualified(name);
831 for column in left_matches.iter().chain(&right_matches) {
832 self.dependencies
833 .extend(column.dependencies.iter().cloned());
834 }
835 let left_current = unique_current_name(&left_matches);
836 let right_current = unique_current_name(&right_matches);
837 if left_current.is_some()
838 && right_current.is_some()
839 && left_current != right_current
840 {
841 return Err(SQLError::Internal(format!(
842 "rule JOIN USING column \"{name}\" resolved to different visible names after column rebinding"
843 )));
844 }
845 let current_name = left_current
846 .or(right_current)
847 .unwrap_or_else(|| name.clone());
848 let mut dependencies = BTreeSet::new();
849 for column in left_matches.iter().chain(&right_matches) {
850 dependencies.extend(column.dependencies.iter().cloned());
851 }
852 let stored_name = name.clone();
853 name.clone_from(¤t_name);
854 merged.push(ScopeColumn {
855 name: stored_name,
856 current_name: current_name.clone(),
857 reference: Expr::Column(current_name),
858 dependencies,
859 });
860 }
861 }
862 let merged_names = merged
863 .iter()
864 .map(|column| column.name.clone())
865 .collect::<Vec<_>>();
866 let mut output = merged;
867 output.extend(
868 left.output
869 .iter()
870 .chain(&right.output)
871 .filter(|column| {
872 !merged_names
873 .iter()
874 .any(|name| same_identifier(name, &column.name))
875 })
876 .cloned(),
877 );
878 if let Some(alias) = alias {
879 for (position, column) in output.iter_mut().enumerate() {
880 if let Some(name) = column_aliases.get(position) {
881 column.name.clone_from(name);
882 column.current_name.clone_from(name);
883 }
884 column.reference = Expr::qualified_column(alias, &column.current_name);
885 }
886 let mut scope = ColumnScope {
887 output: output.clone(),
888 ..ColumnScope::default()
889 };
890 scope.insert_qualifier(alias, &output);
891 return Ok(scope);
892 }
893 let mut qualifiers = left.qualifiers;
894 qualifiers.extend(right.qualifiers);
895 let mut scope = ColumnScope { output, qualifiers };
896 if let Some(using_alias) = using_alias.as_deref() {
897 let merged = scope
898 .output
899 .iter()
900 .filter(|column| {
901 merged_names
902 .iter()
903 .any(|name| same_identifier(name, &column.name))
904 })
905 .cloned()
906 .collect::<Vec<_>>();
907 scope.insert_qualifier(using_alias, &merged);
908 }
909 Ok(scope)
910 }
911
912 fn bind_projections(
913 &mut self,
914 projections: &mut Vec<Projection>,
915 local: Option<&ColumnScope>,
916 scopes: &[ColumnScope],
917 context: &ColumnBindingContext,
918 ) -> Result<(), SQLError> {
919 let mut bound = Vec::with_capacity(projections.len());
920 for mut projection in projections.drain(..) {
921 let expanded = match &projection.expr {
922 Expr::Star => local.map(|scope| scope.output.as_slice()),
923 Expr::QualifiedStar(qualifier) => {
924 scopes.iter().find_map(|scope| scope.qualified(qualifier))
925 }
926 _ => None,
927 };
928 if let Some(columns) = expanded {
929 for column in columns {
930 self.dependencies
931 .extend(column.dependencies.iter().cloned());
932 bound.push(Projection {
933 expr: column.reference.clone(),
934 alias: Some(column.name.clone()),
935 });
936 }
937 continue;
938 }
939 let implicit_name = match &projection.expr {
940 Expr::Column(name) | Expr::QualifiedColumn { column: name, .. } => {
941 Some(name.clone())
942 }
943 _ => None,
944 };
945 self.bind_expr(&mut projection.expr, scopes, context)?;
946 if projection.alias.is_none() && self.mode.is_rename() {
947 let current_name = match &projection.expr {
948 Expr::Column(name) | Expr::QualifiedColumn { column: name, .. } => Some(name),
949 _ => None,
950 };
951 if implicit_name
952 .as_ref()
953 .zip(current_name)
954 .is_some_and(|(stored, current)| !same_identifier(stored, current))
955 {
956 projection.alias = implicit_name;
957 }
958 }
959 bound.push(projection);
960 }
961 *projections = bound;
962 Ok(())
963 }
964}