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())
367 .collect();
368 }
369 }
370 self.bind_target_names(&mut insert.columns, &target);
371 let mut conflict_scope = target.clone();
372 conflict_scope.insert_qualifier("excluded", &target.output);
373 let mut target_scopes = vec![conflict_scope];
374 target_scopes.extend_from_slice(outer);
375 if let Some(conflict) = &mut insert.on_conflict {
376 self.bind_target_names(&mut conflict.conflict_columns, &target);
377 for expression in &mut conflict.expressions {
378 self.bind_expr(expression, &target_scopes, &context)?;
379 }
380 if let Some(predicate) = conflict.predicate.as_deref_mut() {
381 self.bind_expr(predicate, &target_scopes, &context)?;
382 }
383 if let OnConflictAction::Update {
384 assignments,
385 r#where,
386 } = &mut conflict.action
387 {
388 for (column, expression) in assignments {
389 self.bind_target_name(column, &target);
390 self.bind_expr(expression, &target_scopes, &context)?;
391 }
392 if let Some(expression) = r#where {
393 self.bind_expr(expression, &target_scopes, &context)?;
394 }
395 }
396 }
397 let returning = action_returning_scope(
398 &target,
399 &target,
400 crate::ast::RuleEvent::Insert,
401 &insert.returning_aliases,
402 );
403 let mut returning_scopes = vec![returning.clone()];
404 returning_scopes.extend_from_slice(outer);
405 self.bind_projections(
406 &mut insert.returning,
407 Some(&returning),
408 &returning_scopes,
409 &context,
410 )
411 }
412
413 fn bind_update(
414 &mut self,
415 update: &mut UpdateStmt,
416 outer: &[ColumnScope],
417 context: &ColumnBindingContext,
418 ) -> Result<(), SQLError> {
419 let context = self.bind_ctes(&mut update.with, outer, context)?;
420 let target = self.table_scope(
421 &update.table,
422 &update.target_qualifier,
423 Some(&update.target_qualifier),
424 &[],
425 None,
426 &ColumnBindingContext::default(),
427 )?;
428 let (local, scopes) =
429 self.bind_dml_source(update.from.as_mut(), &target, outer, &context)?;
430 for (column, expression) in &mut update.assignments {
431 self.bind_target_name(column, &target);
432 self.bind_expr(expression, &scopes, &context)?;
433 }
434 if let Some(expression) = &mut update.r#where {
435 self.bind_expr(expression, &scopes, &context)?;
436 }
437 let returning = action_returning_scope(
438 &local,
439 &target,
440 crate::ast::RuleEvent::Update,
441 &update.returning_aliases,
442 );
443 let mut returning_scopes = vec![returning.clone()];
444 returning_scopes.extend_from_slice(outer);
445 self.bind_projections(
446 &mut update.returning,
447 Some(&returning),
448 &returning_scopes,
449 &context,
450 )
451 }
452
453 fn bind_delete(
454 &mut self,
455 delete: &mut DeleteStmt,
456 outer: &[ColumnScope],
457 context: &ColumnBindingContext,
458 ) -> Result<(), SQLError> {
459 let context = self.bind_ctes(&mut delete.with, outer, context)?;
460 let target = self.table_scope(
461 &delete.table,
462 &delete.target_qualifier,
463 Some(&delete.target_qualifier),
464 &[],
465 None,
466 &ColumnBindingContext::default(),
467 )?;
468 let (local, scopes) =
469 self.bind_dml_source(delete.using.as_mut(), &target, outer, &context)?;
470 if let Some(expression) = &mut delete.r#where {
471 self.bind_expr(expression, &scopes, &context)?;
472 }
473 let returning = action_returning_scope(
474 &local,
475 &target,
476 crate::ast::RuleEvent::Delete,
477 &delete.returning_aliases,
478 );
479 let mut returning_scopes = vec![returning.clone()];
480 returning_scopes.extend_from_slice(outer);
481 self.bind_projections(
482 &mut delete.returning,
483 Some(&returning),
484 &returning_scopes,
485 &context,
486 )
487 }
488
489 fn bind_dml_source(
490 &mut self,
491 source: Option<&mut FromClause>,
492 target: &ColumnScope,
493 outer: &[ColumnScope],
494 context: &ColumnBindingContext,
495 ) -> Result<(ColumnScope, Vec<ColumnScope>), SQLError> {
496 let mut source_outer = vec![target.clone()];
497 source_outer.extend_from_slice(outer);
498 let source = source
499 .map(|source| self.bind_from(source, &source_outer, context))
500 .transpose()?;
501 let local = source.as_ref().map_or_else(
502 || target.clone(),
503 |source| ColumnScope::combined(target, source),
504 );
505 let mut scopes = vec![local.clone()];
506 scopes.extend_from_slice(outer);
507 Ok((local, scopes))
508 }
509
510 fn bind_target_names(&mut self, names: &mut [String], target: &ColumnScope) {
511 for name in names {
512 self.bind_target_name(name, target);
513 }
514 }
515
516 fn bind_target_name(&mut self, name: &mut String, target: &ColumnScope) {
517 let Some(column) = target
518 .output
519 .iter()
520 .find(|column| same_identifier(&column.name, name))
521 else {
522 return;
523 };
524 self.dependencies
525 .extend(column.dependencies.iter().cloned());
526 name.clone_from(&column.current_name);
527 }
528
529 fn bind_ctes(
530 &mut self,
531 ctes: &mut [CTE],
532 outer: &[ColumnScope],
533 context: &ColumnBindingContext,
534 ) -> Result<ColumnBindingContext, SQLError> {
535 let mut visible = context.clone();
536 let recursive_names = ctes
537 .iter()
538 .filter(|cte| cte.recursive)
539 .map(|cte| {
540 let columns = if cte.columns.is_empty() {
541 cte_output_names(&cte.body)
542 } else {
543 cte.columns.clone()
544 };
545 (cte.name.to_ascii_lowercase(), columns)
546 })
547 .collect::<Vec<_>>();
548 for (name, columns) in recursive_names {
549 visible.ctes.entry(name).or_insert(columns);
550 }
551 for cte in ctes {
552 let mut statement = cte.body.clone().into_statement();
553 self.bind_statement(&mut statement, outer, &visible)?;
554 cte.body = statement.try_into()?;
555 if let Some(cycle) = &mut cte.cycle {
556 self.bind_expr(&mut cycle.mark_value, outer, &visible)?;
557 self.bind_expr(&mut cycle.mark_default, outer, &visible)?;
558 }
559 let mut columns = cte_output_names(&cte.body);
560 apply_positional_aliases(&mut columns, &cte.columns);
561 if let Some(search) = &cte.search {
562 columns.push(search.sequence_column.clone());
563 }
564 if let Some(cycle) = &cte.cycle {
565 columns.push(cycle.mark_column.clone());
566 columns.push(cycle.path_column.clone());
567 }
568 visible.ctes.insert(cte.name.to_ascii_lowercase(), columns);
569 }
570 Ok(visible)
571 }
572
573 fn bind_select(
574 &mut self,
575 select: &mut SelectStmt,
576 outer: &[ColumnScope],
577 context: &ColumnBindingContext,
578 ) -> Result<(), SQLError> {
579 let context = self.bind_ctes(&mut select.with, outer, context)?;
580 let local = select
581 .from
582 .as_mut()
583 .map(|source| self.bind_from(source, outer, &context))
584 .transpose()?;
585 let mut scopes = local.iter().cloned().collect::<Vec<_>>();
586 scopes.extend_from_slice(outer);
587 self.bind_projections(&mut select.projections, local.as_ref(), &scopes, &context)?;
588 for expression in select.values.iter_mut().flatten() {
589 self.bind_expr(expression, &scopes, &context)?;
590 }
591 if let Some(expression) = &mut select.r#where {
592 self.bind_expr(expression, &scopes, &context)?;
593 }
594 for expression in &mut select.group_by {
595 self.bind_expr(expression, &scopes, &context)?;
596 }
597 for expression in select.grouping_sets.iter_mut().flatten() {
598 self.bind_expr(expression, &scopes, &context)?;
599 }
600 if let Some(expression) = &mut select.having {
601 self.bind_expr(expression, &scopes, &context)?;
602 }
603 let output_names = select_output_names(select);
604 for order in &mut select.order_by {
605 if !is_output_alias(&order.expr, &output_names) {
606 self.bind_expr(&mut order.expr, &scopes, &context)?;
607 }
608 }
609 if let Some(expression) = &mut select.limit {
610 self.bind_expr(expression, &scopes, &context)?;
611 }
612 if let Some(expression) = &mut select.offset {
613 self.bind_expr(expression, &scopes, &context)?;
614 }
615 for expression in &mut select.distinct_on {
616 self.bind_expr(expression, &scopes, &context)?;
617 }
618 if let Some(set) = &mut select.set_op {
619 if let Some(left) = &mut set.left {
620 self.bind_select(left, outer, &context)?;
621 }
622 self.bind_select(&mut set.right, outer, &context)?;
623 let set_output = set
624 .left
625 .as_deref()
626 .map_or_else(|| output_names.clone(), select_output_names);
627 for order in &mut set.combined_order_by {
628 if !is_output_alias(&order.expr, &set_output) {
629 self.bind_expr(&mut order.expr, outer, &context)?;
630 }
631 }
632 if let Some(expression) = &mut set.combined_limit {
633 self.bind_expr(expression, outer, &context)?;
634 }
635 if let Some(expression) = &mut set.combined_offset {
636 self.bind_expr(expression, outer, &context)?;
637 }
638 }
639 Ok(())
640 }
641
642 fn bind_from(
643 &mut self,
644 source: &mut FromClause,
645 outer: &[ColumnScope],
646 context: &ColumnBindingContext,
647 ) -> Result<ColumnScope, SQLError> {
648 match source {
649 source @ FromClause::Table { .. } => self.bind_table_source(source, context),
650 source @ FromClause::Join { .. } => self.bind_join(source, outer, context),
651 FromClause::Values {
652 rows,
653 alias,
654 column_aliases,
655 ..
656 } => {
657 for expression in rows.iter_mut().flatten() {
658 self.bind_expr(expression, outer, context)?;
659 }
660 let mut columns = if column_aliases.is_empty() {
661 (1..=rows.first().map_or(0, Vec::len))
662 .map(|position| format!("column{position}"))
663 .collect::<Vec<_>>()
664 } else {
665 column_aliases.clone()
666 };
667 apply_positional_aliases(&mut columns, column_aliases);
668 Ok(opaque_scope(&columns, alias.as_deref()))
669 }
670 FromClause::Function {
671 output_name,
672 args,
673 alias,
674 column_aliases,
675 ordinality,
676 ..
677 } => {
678 for expression in args {
679 self.bind_expr(expression, outer, context)?;
680 }
681 let mut columns = vec![output_name.clone()];
682 apply_positional_aliases(&mut columns, column_aliases);
683 if *ordinality {
684 columns.push("ordinality".into());
685 }
686 Ok(opaque_scope(
687 &columns,
688 Some(alias.as_deref().unwrap_or(output_name)),
689 ))
690 }
691 FromClause::FunctionGroup {
692 functions,
693 alias,
694 column_aliases,
695 ordinality,
696 } => {
697 for function in functions.iter_mut() {
698 for expression in &mut function.args {
699 self.bind_expr(expression, outer, context)?;
700 }
701 }
702 let mut columns = functions
703 .iter()
704 .flat_map(|function| {
705 if function.column_aliases.is_empty() {
706 vec![function.output_name.clone()]
707 } else {
708 function.column_aliases.clone()
709 }
710 })
711 .collect::<Vec<_>>();
712 apply_positional_aliases(&mut columns, column_aliases);
713 if *ordinality {
714 columns.push("ordinality".into());
715 }
716 Ok(opaque_scope(&columns, alias.as_deref()))
717 }
718 FromClause::Subquery {
719 body,
720 alias,
721 column_aliases,
722 } => {
723 self.bind_select(body, outer, context)?;
724 let mut columns = select_output_names(body);
725 apply_positional_aliases(&mut columns, column_aliases);
726 Ok(opaque_scope(&columns, alias.as_deref()))
727 }
728 }
729 }
730
731 fn bind_join(
732 &mut self,
733 source: &mut FromClause,
734 outer: &[ColumnScope],
735 context: &ColumnBindingContext,
736 ) -> Result<ColumnScope, SQLError> {
737 let FromClause::Join {
738 left,
739 right,
740 on,
741 using,
742 natural,
743 alias,
744 column_aliases,
745 lateral,
746 ..
747 } = source
748 else {
749 unreachable!("join column binding requires a join source")
750 };
751 if let ColumnBindingMode::Rename { relation, from, to } = self.mode {
752 if *natural
753 || using.as_ref().is_some_and(|using| {
754 using
755 .columns
756 .iter()
757 .any(|column| same_identifier(column, from))
758 })
759 {
760 preserve_table_column_name(self.catalog, left, relation, from, to)?;
761 preserve_table_column_name(self.catalog, right, relation, from, to)?;
762 }
763 }
764 let left_scope = self.bind_from(left, outer, context)?;
765 let mut right_outer = Vec::new();
766 if *lateral {
767 right_outer.push(left_scope.clone());
768 }
769 right_outer.extend_from_slice(outer);
770 let right_scope = self.bind_from(right, &right_outer, context)?;
771 let input_scope = ColumnScope::combined(&left_scope, &right_scope);
772 let mut on_scopes = vec![input_scope];
773 on_scopes.extend_from_slice(outer);
774 if let Some(expression) = on {
775 self.bind_expr(expression, &on_scopes, context)?;
776 }
777 if *natural {
778 let columns = left_scope
779 .output
780 .iter()
781 .filter(|left| {
782 right_scope
783 .output
784 .iter()
785 .any(|right| same_identifier(&left.name, &right.name))
786 })
787 .map(|column| column.name.clone())
788 .collect();
789 *using = Some(crate::ast::JoinUsing {
790 columns,
791 alias: None,
792 });
793 *natural = false;
794 }
795 let scope = self.join_scope(
796 left_scope,
797 right_scope,
798 using.as_mut(),
799 alias.as_deref(),
800 column_aliases,
801 )?;
802 self.remove_dropped_column_aliases(column_aliases, &scope);
803 Ok(scope)
804 }
805
806 fn join_scope(
807 &mut self,
808 left: ColumnScope,
809 right: ColumnScope,
810 using: Option<&mut crate::ast::JoinUsing>,
811 alias: Option<&str>,
812 column_aliases: &[String],
813 ) -> Result<ColumnScope, SQLError> {
814 let using_alias = using.as_ref().and_then(|using| using.alias.clone());
815 let mut merged = Vec::new();
816 if let Some(using) = using {
817 for name in &mut using.columns {
818 let left_matches = left.unqualified(name);
819 let right_matches = right.unqualified(name);
820 for column in left_matches.iter().chain(&right_matches) {
821 self.dependencies
822 .extend(column.dependencies.iter().cloned());
823 }
824 let left_current = unique_current_name(&left_matches);
825 let right_current = unique_current_name(&right_matches);
826 if left_current.is_some()
827 && right_current.is_some()
828 && left_current != right_current
829 {
830 return Err(SQLError::Internal(format!(
831 "rule JOIN USING column \"{name}\" resolved to different visible names after column rebinding"
832 )));
833 }
834 let current_name = left_current
835 .or(right_current)
836 .unwrap_or_else(|| name.clone());
837 let mut dependencies = BTreeSet::new();
838 for column in left_matches.iter().chain(&right_matches) {
839 dependencies.extend(column.dependencies.iter().cloned());
840 }
841 let stored_name = name.clone();
842 name.clone_from(¤t_name);
843 merged.push(ScopeColumn {
844 name: stored_name,
845 current_name: current_name.clone(),
846 reference: Expr::Column(current_name),
847 dependencies,
848 });
849 }
850 }
851 let merged_names = merged
852 .iter()
853 .map(|column| column.name.clone())
854 .collect::<Vec<_>>();
855 let mut output = merged;
856 output.extend(
857 left.output
858 .iter()
859 .chain(&right.output)
860 .filter(|column| {
861 !merged_names
862 .iter()
863 .any(|name| same_identifier(name, &column.name))
864 })
865 .cloned(),
866 );
867 if let Some(alias) = alias {
868 for (position, column) in output.iter_mut().enumerate() {
869 if let Some(name) = column_aliases.get(position) {
870 column.name.clone_from(name);
871 column.current_name.clone_from(name);
872 }
873 column.reference = Expr::qualified_column(alias, &column.current_name);
874 }
875 let mut scope = ColumnScope {
876 output: output.clone(),
877 ..ColumnScope::default()
878 };
879 scope.insert_qualifier(alias, &output);
880 return Ok(scope);
881 }
882 let mut qualifiers = left.qualifiers;
883 qualifiers.extend(right.qualifiers);
884 let mut scope = ColumnScope { output, qualifiers };
885 if let Some(using_alias) = using_alias.as_deref() {
886 let merged = scope
887 .output
888 .iter()
889 .filter(|column| {
890 merged_names
891 .iter()
892 .any(|name| same_identifier(name, &column.name))
893 })
894 .cloned()
895 .collect::<Vec<_>>();
896 scope.insert_qualifier(using_alias, &merged);
897 }
898 Ok(scope)
899 }
900
901 fn bind_projections(
902 &mut self,
903 projections: &mut Vec<Projection>,
904 local: Option<&ColumnScope>,
905 scopes: &[ColumnScope],
906 context: &ColumnBindingContext,
907 ) -> Result<(), SQLError> {
908 let mut bound = Vec::with_capacity(projections.len());
909 for mut projection in projections.drain(..) {
910 let expanded = match &projection.expr {
911 Expr::Star => local.map(|scope| scope.output.as_slice()),
912 Expr::QualifiedStar(qualifier) => {
913 scopes.iter().find_map(|scope| scope.qualified(qualifier))
914 }
915 _ => None,
916 };
917 if let Some(columns) = expanded {
918 for column in columns {
919 self.dependencies
920 .extend(column.dependencies.iter().cloned());
921 bound.push(Projection {
922 expr: column.reference.clone(),
923 alias: Some(column.name.clone()),
924 });
925 }
926 continue;
927 }
928 let implicit_name = match &projection.expr {
929 Expr::Column(name) | Expr::QualifiedColumn { column: name, .. } => {
930 Some(name.clone())
931 }
932 _ => None,
933 };
934 self.bind_expr(&mut projection.expr, scopes, context)?;
935 if projection.alias.is_none() && self.mode.is_rename() {
936 let current_name = match &projection.expr {
937 Expr::Column(name) | Expr::QualifiedColumn { column: name, .. } => Some(name),
938 _ => None,
939 };
940 if implicit_name
941 .as_ref()
942 .zip(current_name)
943 .is_some_and(|(stored, current)| !same_identifier(stored, current))
944 {
945 projection.alias = implicit_name;
946 }
947 }
948 bound.push(projection);
949 }
950 *projections = bound;
951 Ok(())
952 }
953}