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