1use crate::expressions::{Expression, Identifier, JoinKind, Literal, TableRef};
9use crate::traversal::ExpressionWalk;
10use serde::{Deserialize, Serialize};
11use std::collections::{HashMap, HashSet, VecDeque};
12#[cfg(feature = "bindings")]
13use ts_rs::TS;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
17#[cfg_attr(feature = "bindings", derive(TS))]
18#[cfg_attr(feature = "bindings", ts(export))]
19pub enum ScopeType {
20 Root,
22 Subquery,
24 DerivedTable,
26 Cte,
28 SetOperation,
30 Udtf,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
36#[serde(rename_all = "snake_case")]
37pub enum SourceKind {
38 Root,
40 Table,
42 DerivedTable,
44 Cte,
46 Virtual,
48 Unknown,
50}
51
52impl Default for SourceKind {
53 fn default() -> Self {
54 Self::Unknown
55 }
56}
57
58pub(crate) fn scope_query(expression: &Expression) -> &Expression {
60 match expression {
61 Expression::Cte(cte) => scope_query(&cte.this),
62 Expression::Subquery(subquery) => scope_query(&subquery.this),
63 Expression::Paren(paren) => scope_query(&paren.this),
64 Expression::Alias(alias) => scope_query(&alias.this),
65 Expression::Prepare(prepare) => scope_query(&prepare.statement),
66 Expression::CreateTable(create) if create.as_select.is_some() => {
67 scope_query(create.as_select.as_ref().unwrap())
68 }
69 _ => expression,
70 }
71}
72
73pub(crate) fn selected_reference_scope(scope: &Scope) -> Scope {
76 let query = scope_query(&scope.expression);
77 let aliases: HashSet<_> = walk_in_scope(query, false)
78 .filter_map(|node| match node {
79 Expression::Table(table) => {
80 Some(table.alias.as_ref().unwrap_or(&table.name).name.clone())
81 }
82 _ => None,
83 })
84 .collect();
85 let mut selected = Scope::new(query.clone());
86 selected.cte_sources = scope.cte_sources.clone();
87 selected.sources = scope
88 .sources
89 .iter()
90 .filter(|(name, source)| {
91 source.kind != SourceKind::Cte || aliases.contains(*name)
94 })
95 .map(|(name, source)| (name.clone(), source.clone()))
96 .collect();
97 selected
98}
99
100#[derive(Debug, Clone)]
102pub struct SourceInfo {
103 pub expression: Expression,
105 pub is_scope: bool,
107 pub kind: SourceKind,
109 pub alias: Option<String>,
111 pub lineage_name: Option<String>,
113}
114
115impl SourceInfo {
116 pub fn new(expression: Expression, is_scope: bool, kind: SourceKind) -> Self {
117 Self {
118 expression,
119 is_scope,
120 kind,
121 alias: None,
122 lineage_name: None,
123 }
124 }
125
126 pub fn with_alias(mut self, alias: impl Into<String>) -> Self {
127 self.alias = Some(alias.into());
128 self
129 }
130
131 pub fn with_lineage_name(mut self, lineage_name: impl Into<String>) -> Self {
132 self.lineage_name = Some(lineage_name.into());
133 self
134 }
135}
136
137#[derive(Debug, Clone, PartialEq, Eq, Hash)]
139pub struct ColumnRef {
140 pub table: Option<String>,
142 pub name: String,
144}
145
146#[derive(Debug, Clone)]
151pub struct Scope {
152 pub expression: Expression,
154
155 pub scope_type: ScopeType,
157
158 pub sources: HashMap<String, SourceInfo>,
160
161 pub lateral_sources: HashMap<String, SourceInfo>,
163
164 pub cte_sources: HashMap<String, SourceInfo>,
166
167 pub outer_columns: Vec<String>,
170
171 pub can_be_correlated: bool,
174
175 pub is_lateral: bool,
177
178 pub subquery_scopes: Vec<Scope>,
180
181 pub derived_table_scopes: Vec<Scope>,
183
184 pub cte_scopes: Vec<Scope>,
186
187 pub udtf_scopes: Vec<Scope>,
189
190 pub table_scopes: Vec<Scope>,
192
193 pub union_scopes: Vec<Scope>,
195
196 columns_cache: Option<Vec<ColumnRef>>,
198
199 external_columns_cache: Option<Vec<ColumnRef>>,
201}
202
203impl Scope {
204 pub fn new(expression: Expression) -> Self {
206 Self {
207 expression,
208 scope_type: ScopeType::Root,
209 sources: HashMap::new(),
210 lateral_sources: HashMap::new(),
211 cte_sources: HashMap::new(),
212 outer_columns: Vec::new(),
213 can_be_correlated: false,
214 is_lateral: false,
215 subquery_scopes: Vec::new(),
216 derived_table_scopes: Vec::new(),
217 cte_scopes: Vec::new(),
218 udtf_scopes: Vec::new(),
219 table_scopes: Vec::new(),
220 union_scopes: Vec::new(),
221 columns_cache: None,
222 external_columns_cache: None,
223 }
224 }
225
226 pub fn branch(&self, expression: Expression, scope_type: ScopeType) -> Self {
228 self.branch_with_options(expression, scope_type, None, None, None)
229 }
230
231 pub fn branch_with_options(
233 &self,
234 expression: Expression,
235 scope_type: ScopeType,
236 sources: Option<HashMap<String, SourceInfo>>,
237 lateral_sources: Option<HashMap<String, SourceInfo>>,
238 outer_columns: Option<Vec<String>>,
239 ) -> Self {
240 let can_be_correlated = self.can_be_correlated
241 || scope_type == ScopeType::Subquery
242 || scope_type == ScopeType::Udtf;
243
244 Self {
245 expression,
246 scope_type,
247 sources: sources.unwrap_or_default(),
248 lateral_sources: lateral_sources.unwrap_or_default(),
249 cte_sources: self.cte_sources.clone(),
250 outer_columns: outer_columns.unwrap_or_default(),
251 can_be_correlated,
252 is_lateral: false,
253 subquery_scopes: Vec::new(),
254 derived_table_scopes: Vec::new(),
255 cte_scopes: Vec::new(),
256 udtf_scopes: Vec::new(),
257 table_scopes: Vec::new(),
258 union_scopes: Vec::new(),
259 columns_cache: None,
260 external_columns_cache: None,
261 }
262 }
263
264 pub fn clear_cache(&mut self) {
266 self.columns_cache = None;
267 self.external_columns_cache = None;
268 }
269
270 pub fn add_source(&mut self, name: String, expression: Expression, is_scope: bool) {
272 let kind = if is_scope {
273 SourceKind::DerivedTable
274 } else {
275 SourceKind::Table
276 };
277 self.add_source_info(name, SourceInfo::new(expression, is_scope, kind));
278 }
279
280 pub fn add_source_info(&mut self, name: String, info: SourceInfo) {
282 self.sources.insert(name, info);
283 self.clear_cache();
284 }
285
286 pub fn add_virtual_source(&mut self, alias: String, expression: Expression) {
288 let lineage_name = self.next_virtual_source_name();
289 let info = SourceInfo::new(expression, false, SourceKind::Virtual)
290 .with_alias(alias.clone())
291 .with_lineage_name(lineage_name);
292 self.add_source_info(alias, info);
293 }
294
295 fn next_virtual_source_name(&self) -> String {
296 let count = self
297 .sources
298 .values()
299 .filter(|source| source.kind == SourceKind::Virtual)
300 .count();
301 format!("_{}", count)
302 }
303
304 pub fn add_lateral_source(&mut self, name: String, expression: Expression, is_scope: bool) {
306 let kind = if is_scope {
307 SourceKind::DerivedTable
308 } else {
309 SourceKind::Table
310 };
311 let info = SourceInfo::new(expression.clone(), is_scope, kind);
312 self.sources.insert(name.clone(), info.clone());
313 self.lateral_sources.insert(name, info);
314 self.clear_cache();
315 }
316
317 pub fn add_cte_source(&mut self, name: String, expression: Expression) {
319 let info = SourceInfo::new(expression, true, SourceKind::Cte);
320 self.cte_sources.insert(name.clone(), info.clone());
321 self.sources.insert(name, info);
322 self.clear_cache();
323 }
324
325 pub fn rename_source(&mut self, old_name: &str, new_name: String) {
327 if let Some(source) = self.sources.remove(old_name) {
328 self.sources.insert(new_name, source);
329 }
330 self.clear_cache();
331 }
332
333 pub fn remove_source(&mut self, name: &str) {
335 self.sources.remove(name);
336 self.clear_cache();
337 }
338
339 pub fn columns(&mut self) -> &[ColumnRef] {
341 if self.columns_cache.is_none() {
342 let mut columns = Vec::new();
343 collect_columns(&self.expression, &mut columns);
344 self.columns_cache = Some(columns);
345 }
346 self.columns_cache.as_ref().unwrap()
347 }
348
349 pub fn output_columns(&self) -> Vec<String> {
354 crate::ast_transforms::get_output_column_names(&self.expression)
355 }
356
357 pub fn source_names(&self) -> HashSet<String> {
359 let mut names: HashSet<String> = self.sources.keys().cloned().collect();
360 names.extend(self.cte_sources.keys().cloned());
361 names
362 }
363
364 pub fn external_columns(&mut self) -> Vec<ColumnRef> {
366 if self.external_columns_cache.is_some() {
367 return self.external_columns_cache.clone().unwrap();
368 }
369
370 let source_names = self.source_names();
371 let columns = self.columns().to_vec();
372
373 let external: Vec<ColumnRef> = columns
374 .into_iter()
375 .filter(|col| {
376 match &col.table {
378 Some(table) => !source_names.contains(table),
379 None => false, }
381 })
382 .collect();
383
384 self.external_columns_cache = Some(external.clone());
385 external
386 }
387
388 pub fn local_columns(&mut self) -> Vec<ColumnRef> {
390 let external_set: HashSet<_> = self.external_columns().into_iter().collect();
391 let columns = self.columns().to_vec();
392
393 columns
394 .into_iter()
395 .filter(|col| !external_set.contains(col))
396 .collect()
397 }
398
399 pub fn unqualified_columns(&mut self) -> Vec<ColumnRef> {
401 self.columns()
402 .iter()
403 .filter(|c| c.table.is_none())
404 .cloned()
405 .collect()
406 }
407
408 pub fn source_columns(&mut self, source_name: &str) -> Vec<ColumnRef> {
410 self.columns()
411 .iter()
412 .filter(|col| col.table.as_deref() == Some(source_name))
413 .cloned()
414 .collect()
415 }
416
417 pub fn is_correlated_subquery(&mut self) -> bool {
423 self.can_be_correlated && !self.external_columns().is_empty()
424 }
425
426 pub fn is_subquery(&self) -> bool {
428 self.scope_type == ScopeType::Subquery
429 }
430
431 pub fn is_derived_table(&self) -> bool {
433 self.scope_type == ScopeType::DerivedTable
434 }
435
436 pub fn is_cte(&self) -> bool {
438 self.scope_type == ScopeType::Cte
439 }
440
441 pub fn is_root(&self) -> bool {
443 self.scope_type == ScopeType::Root
444 }
445
446 pub fn is_udtf(&self) -> bool {
448 self.scope_type == ScopeType::Udtf
449 }
450
451 pub fn is_union(&self) -> bool {
453 self.scope_type == ScopeType::SetOperation
454 }
455
456 pub fn traverse(&self) -> Vec<&Scope> {
458 let mut result = Vec::new();
459 self.traverse_impl(&mut result);
460 result
461 }
462
463 fn traverse_impl<'a>(&'a self, result: &mut Vec<&'a Scope>) {
464 for scope in &self.cte_scopes {
466 scope.traverse_impl(result);
467 }
468 for scope in &self.union_scopes {
469 scope.traverse_impl(result);
470 }
471 for scope in &self.table_scopes {
472 scope.traverse_impl(result);
473 }
474 for scope in &self.subquery_scopes {
475 scope.traverse_impl(result);
476 }
477 result.push(self);
479 }
480
481 pub fn ref_count(&self) -> HashMap<usize, usize> {
483 let mut counts: HashMap<usize, usize> = HashMap::new();
484
485 for scope in self.traverse() {
486 for (_, source_info) in scope.sources.iter() {
487 if source_info.is_scope {
488 let id = &source_info.expression as *const _ as usize;
489 *counts.entry(id).or_insert(0) += 1;
490 }
491 }
492 }
493
494 counts
495 }
496}
497
498fn collect_columns(expr: &Expression, columns: &mut Vec<ColumnRef>) {
500 match expr {
501 Expression::Column(col) => {
502 columns.push(ColumnRef {
503 table: col.table.as_ref().map(|t| t.name.clone()),
504 name: col.name.name.clone(),
505 });
506 }
507 Expression::Select(select) => {
508 for e in &select.expressions {
510 collect_columns(e, columns);
511 }
512 for join in &select.joins {
514 if let Some(on) = &join.on {
515 collect_columns(on, columns);
516 }
517 if let Some(match_condition) = &join.match_condition {
518 collect_columns(match_condition, columns);
519 }
520 }
521 if let Some(where_clause) = &select.where_clause {
523 collect_columns(&where_clause.this, columns);
524 }
525 if let Some(having) = &select.having {
527 collect_columns(&having.this, columns);
528 }
529 if let Some(order_by) = &select.order_by {
531 for ord in &order_by.expressions {
532 collect_columns(&ord.this, columns);
533 }
534 }
535 if let Some(group_by) = &select.group_by {
537 for e in &group_by.expressions {
538 collect_columns(e, columns);
539 }
540 }
541 }
544 Expression::And(bin)
546 | Expression::Or(bin)
547 | Expression::Add(bin)
548 | Expression::Sub(bin)
549 | Expression::Mul(bin)
550 | Expression::Div(bin)
551 | Expression::Mod(bin)
552 | Expression::Eq(bin)
553 | Expression::Neq(bin)
554 | Expression::Lt(bin)
555 | Expression::Lte(bin)
556 | Expression::Gt(bin)
557 | Expression::Gte(bin)
558 | Expression::BitwiseAnd(bin)
559 | Expression::BitwiseOr(bin)
560 | Expression::BitwiseXor(bin)
561 | Expression::Concat(bin) => {
562 collect_columns(&bin.left, columns);
563 collect_columns(&bin.right, columns);
564 }
565 Expression::Like(like) | Expression::ILike(like) => {
567 collect_columns(&like.left, columns);
568 collect_columns(&like.right, columns);
569 if let Some(escape) = &like.escape {
570 collect_columns(escape, columns);
571 }
572 }
573 Expression::Not(un) | Expression::Neg(un) | Expression::BitwiseNot(un) => {
575 collect_columns(&un.this, columns);
576 }
577 Expression::Function(func) => {
578 for arg in &func.args {
579 collect_columns(arg, columns);
580 }
581 }
582 Expression::AggregateFunction(agg) => {
583 for arg in &agg.args {
584 collect_columns(arg, columns);
585 }
586 }
587 Expression::WindowFunction(wf) => {
588 collect_columns(&wf.this, columns);
589 for e in &wf.over.partition_by {
590 collect_columns(e, columns);
591 }
592 for e in &wf.over.order_by {
593 collect_columns(&e.this, columns);
594 }
595 }
596 Expression::Alias(alias) => {
597 collect_columns(&alias.this, columns);
598 }
599 Expression::Case(case) => {
600 if let Some(operand) = &case.operand {
601 collect_columns(operand, columns);
602 }
603 for (when_expr, then_expr) in &case.whens {
604 collect_columns(when_expr, columns);
605 collect_columns(then_expr, columns);
606 }
607 if let Some(else_clause) = &case.else_ {
608 collect_columns(else_clause, columns);
609 }
610 }
611 Expression::Paren(paren) => {
612 collect_columns(&paren.this, columns);
613 }
614 Expression::Ordered(ord) => {
615 collect_columns(&ord.this, columns);
616 }
617 Expression::In(in_expr) => {
618 collect_columns(&in_expr.this, columns);
619 for e in &in_expr.expressions {
620 collect_columns(e, columns);
621 }
622 }
624 Expression::Between(between) => {
625 collect_columns(&between.this, columns);
626 collect_columns(&between.low, columns);
627 collect_columns(&between.high, columns);
628 }
629 Expression::IsNull(is_null) => {
630 collect_columns(&is_null.this, columns);
631 }
632 Expression::Cast(cast) => {
633 collect_columns(&cast.this, columns);
634 }
635 Expression::Extract(extract) => {
636 collect_columns(&extract.this, columns);
637 }
638 Expression::Exists(_) | Expression::Subquery(_) => {
639 }
641 Expression::Prepare(prepare) => {
642 collect_columns(&prepare.statement, columns);
643 }
644 _ => {
645 }
647 }
648}
649
650pub fn build_scope(expression: &Expression) -> Scope {
655 build_scope_with_ctes(expression, &HashMap::new())
656}
657
658pub(crate) fn build_scope_with_ctes(
660 expression: &Expression,
661 ctes: &HashMap<String, SourceInfo>,
662) -> Scope {
663 let mut root = Scope::new(expression.clone());
664 root.cte_sources = ctes.clone();
665 build_scope_impl(expression, &mut root);
666 root
667}
668
669fn build_scope_impl(expression: &Expression, current_scope: &mut Scope) {
670 match expression {
671 Expression::Prepare(prepare) => {
672 build_scope_impl(&prepare.statement, current_scope);
673 }
674 Expression::Select(select) => {
675 if let Some(with) = &select.with {
677 process_ctes(with, current_scope);
678 }
679
680 let mut preceding_sources = HashSet::new();
683 for table in select.from.iter().flat_map(|from| &from.expressions) {
684 add_relation_to_scope(table, current_scope, &mut preceding_sources);
685 }
686 for join in &select.joins {
687 if matches!(join.kind, JoinKind::Array | JoinKind::LeftArray) {
688 add_array_join_to_scope(&join.this, current_scope, &mut preceding_sources);
689 } else {
690 add_relation_to_scope(&join.this, current_scope, &mut preceding_sources);
691 }
692 }
693
694 for lateral_view in &select.lateral_views {
696 add_lateral_view_to_scope(lateral_view, current_scope);
697 }
698
699 collect_subqueries(expression, current_scope);
701 }
702 Expression::JoinedTable(joined) => {
703 let mut preceding_sources = HashSet::new();
704 add_join_group_to_scope(joined, current_scope, &mut preceding_sources);
705 }
706 Expression::Union(union) => {
707 if let Some(with) = &union.with {
708 process_ctes(with, current_scope);
709 }
710
711 let mut left_scope = current_scope.branch(union.left.clone(), ScopeType::SetOperation);
712 build_scope_impl(&union.left, &mut left_scope);
713
714 let mut right_scope =
715 current_scope.branch(union.right.clone(), ScopeType::SetOperation);
716 build_scope_impl(&union.right, &mut right_scope);
717
718 current_scope.union_scopes.push(left_scope);
719 current_scope.union_scopes.push(right_scope);
720 }
721 Expression::Intersect(intersect) => {
722 if let Some(with) = &intersect.with {
723 process_ctes(with, current_scope);
724 }
725
726 let mut left_scope =
727 current_scope.branch(intersect.left.clone(), ScopeType::SetOperation);
728 build_scope_impl(&intersect.left, &mut left_scope);
729
730 let mut right_scope =
731 current_scope.branch(intersect.right.clone(), ScopeType::SetOperation);
732 build_scope_impl(&intersect.right, &mut right_scope);
733
734 current_scope.union_scopes.push(left_scope);
735 current_scope.union_scopes.push(right_scope);
736 }
737 Expression::Except(except) => {
738 if let Some(with) = &except.with {
739 process_ctes(with, current_scope);
740 }
741
742 let mut left_scope = current_scope.branch(except.left.clone(), ScopeType::SetOperation);
743 build_scope_impl(&except.left, &mut left_scope);
744
745 let mut right_scope =
746 current_scope.branch(except.right.clone(), ScopeType::SetOperation);
747 build_scope_impl(&except.right, &mut right_scope);
748
749 current_scope.union_scopes.push(left_scope);
750 current_scope.union_scopes.push(right_scope);
751 }
752 Expression::CreateTable(create) => {
753 if let Some(with) = &create.with_cte {
756 process_ctes(with, current_scope);
757 }
758 if let Some(as_select) = &create.as_select {
760 build_scope_impl(as_select, current_scope);
761 }
762 }
763 Expression::Subquery(subquery) => {
764 build_scope_impl(&subquery.this, current_scope);
765 }
766 Expression::Paren(paren) => {
767 build_scope_impl(&paren.this, current_scope);
768 }
769 Expression::Alias(alias) => {
770 build_scope_impl(&alias.this, current_scope);
771 }
772 _ => {}
773 }
774}
775
776fn process_ctes(with: &crate::expressions::With, current_scope: &mut Scope) {
777 for cte in &with.ctes {
778 let cte_name = cte.alias.name.clone();
779 let cte_expr = Expression::Cte(Box::new(cte.clone()));
780 let mut cte_scope = current_scope.branch(cte_expr.clone(), ScopeType::Cte);
781
782 if with.recursive && cte_body_self_references(cte) {
783 cte_scope.add_cte_source(cte_name.clone(), cte_expr.clone());
784 }
785
786 build_scope_impl(&cte.this, &mut cte_scope);
787 current_scope.add_cte_source(cte_name, cte_expr);
788 current_scope.cte_scopes.push(cte_scope);
789 }
790}
791
792fn cte_body_self_references(cte: &crate::expressions::Cte) -> bool {
793 let cte_name = cte.alias.name.as_str();
794 !cte.this
795 .find_all(|expr| match expr {
796 Expression::Table(table) if table.schema.is_none() && table.catalog.is_none() => {
797 table.name.name.eq_ignore_ascii_case(cte_name)
798 }
799 _ => false,
800 })
801 .is_empty()
802}
803
804fn add_join_group_to_scope(
805 joined: &crate::expressions::JoinedTable,
806 scope: &mut Scope,
807 preceding_sources: &mut HashSet<String>,
808) {
809 add_relation_to_scope(&joined.left, scope, preceding_sources);
810 for join in &joined.joins {
811 add_relation_to_scope(&join.this, scope, preceding_sources);
812 if let Some(condition) = &join.on {
813 collect_subqueries_in_expr(condition, scope);
814 }
815 if let Some(condition) = &join.match_condition {
816 collect_subqueries_in_expr(condition, scope);
817 }
818 }
819 for lateral_view in &joined.lateral_views {
820 add_lateral_view_to_scope(lateral_view, scope);
821 }
822}
823
824fn add_relation_to_scope(
826 expr: &Expression,
827 scope: &mut Scope,
828 preceding_sources: &mut HashSet<String>,
829) {
830 match expr {
831 Expression::JoinedTable(joined) if joined.alias.is_none() => {
832 add_join_group_to_scope(joined, scope, preceding_sources);
833 }
834 Expression::Paren(paren) => add_relation_to_scope(&paren.this, scope, preceding_sources),
835 _ => {
836 if let Some(name) = add_table_to_scope(expr, scope, preceding_sources) {
837 preceding_sources.insert(name);
838 }
839 }
840 }
841}
842
843fn add_table_to_scope(
844 expr: &Expression,
845 scope: &mut Scope,
846 preceding_sources: &HashSet<String>,
847) -> Option<String> {
848 match expr {
849 Expression::Table(table) => {
850 let name = table
851 .alias
852 .as_ref()
853 .map(|a| a.name.clone())
854 .unwrap_or_else(|| table.name.name.clone());
855 let cte_source = if table.schema.is_none() && table.catalog.is_none() {
856 scope.cte_sources.get(&table.name.name).or_else(|| {
857 scope
858 .cte_sources
859 .iter()
860 .find(|(cte_name, _)| cte_name.eq_ignore_ascii_case(&table.name.name))
861 .map(|(_, source)| source)
862 })
863 } else {
864 None
865 };
866
867 if let Some(source) = cte_source {
868 scope.add_source_info(name.clone(), source.clone());
869 } else {
870 let mut source = SourceInfo::new(expr.clone(), false, SourceKind::Table);
871 if let Some(alias) = &table.alias {
872 source = source.with_alias(alias.name.clone());
873 }
874 scope.add_source_info(name.clone(), source);
875 }
876 Some(name)
877 }
878 Expression::Subquery(subquery) => {
879 let name = subquery
880 .alias
881 .as_ref()
882 .map(|a| a.name.clone())
883 .unwrap_or_default();
884
885 let mut derived_scope = scope.branch(subquery.this.clone(), ScopeType::DerivedTable);
886 if subquery.lateral {
887 derived_scope.is_lateral = true;
888 derived_scope.can_be_correlated = true;
889 derived_scope.lateral_sources = preceding_sources
890 .iter()
891 .filter_map(|name| {
892 scope
893 .sources
894 .get(name)
895 .map(|source| (name.clone(), source.clone()))
896 })
897 .collect();
898 }
899 build_scope_impl(&subquery.this, &mut derived_scope);
900
901 scope.add_source(name.clone(), expr.clone(), true);
902 scope.derived_table_scopes.push(derived_scope);
903 Some(name)
904 }
905 Expression::JoinedTable(joined) => {
906 let alias = joined.alias.as_ref()?;
907 let mut derived_scope = scope.branch(expr.clone(), ScopeType::DerivedTable);
908 build_scope_impl(expr, &mut derived_scope);
909 scope.add_source(alias.name.clone(), expr.clone(), true);
910 scope.derived_table_scopes.push(derived_scope);
911 Some(alias.name.clone())
912 }
913 Expression::Unnest(unnest) => {
914 if let Some(alias) = &unnest.alias {
915 scope.add_virtual_source(alias.name.clone(), expr.clone());
916 }
917 unnest.alias.as_ref().map(|alias| alias.name.clone())
918 }
919 Expression::Values(values) => {
920 let name = values
921 .alias
922 .as_ref()
923 .map(|alias| alias.name.clone())
924 .unwrap_or_default();
925 scope.add_virtual_source(name.clone(), expr.clone());
926 Some(name)
927 }
928 Expression::Alias(alias) if matches!(&alias.this, Expression::Unnest(_)) => {
929 scope.add_virtual_source(alias.alias.name.clone(), expr.clone());
930 Some(alias.alias.name.clone())
931 }
932 Expression::Alias(alias)
933 if is_query_like_relation(&alias.this)
934 || matches!(scope_query(&alias.this), Expression::JoinedTable(_)) =>
935 {
936 let outer_columns = alias
937 .column_aliases
938 .iter()
939 .map(|column| column.name.clone())
940 .collect::<Vec<_>>();
941 let mut derived_scope = scope.branch_with_options(
942 alias.this.clone(),
943 ScopeType::DerivedTable,
944 None,
945 None,
946 Some(outer_columns),
947 );
948 build_scope_impl(&alias.this, &mut derived_scope);
949
950 scope.add_source(alias.alias.name.clone(), expr.clone(), true);
951 scope.derived_table_scopes.push(derived_scope);
952 Some(alias.alias.name.clone())
953 }
954 Expression::Lateral(lateral) => {
955 if let Some(alias) = &lateral.alias {
956 scope.add_virtual_source(alias.clone(), expr.clone());
957 }
958 lateral.alias.clone()
959 }
960 Expression::LateralView(lateral_view) => {
961 add_lateral_view_to_scope(lateral_view, scope);
962 lateral_view
963 .table_alias
964 .as_ref()
965 .or_else(|| lateral_view.column_aliases.first())
966 .map(|alias| alias.name.clone())
967 }
968 Expression::Pivot(pivot) => {
969 let name =
970 pivot_source_name(&pivot.this, pivot.alias.as_ref().map(|a| a.name.as_str()));
971 scope.add_source_info(
972 name.clone(),
973 SourceInfo::new(expr.clone(), false, SourceKind::DerivedTable),
974 );
975 add_pivot_inner_scope(&pivot.this, scope);
976 Some(name)
977 }
978 Expression::Unpivot(unpivot) => {
979 let name = pivot_source_name(
980 &unpivot.this,
981 unpivot.alias.as_ref().map(|a| a.name.as_str()),
982 );
983 scope.add_source_info(
984 name.clone(),
985 SourceInfo::new(expr.clone(), false, SourceKind::DerivedTable),
986 );
987 add_pivot_inner_scope(&unpivot.this, scope);
988 Some(name)
989 }
990 Expression::Paren(paren) => add_table_to_scope(&paren.this, scope, preceding_sources),
991 _ => identifier_table(expr).and_then(|table| {
992 add_table_to_scope(
993 &Expression::Table(Box::new(table)),
994 scope,
995 preceding_sources,
996 )
997 }),
998 }
999}
1000
1001fn identifier_table(expr: &Expression) -> Option<TableRef> {
1003 let (function, alias) = match expr {
1004 Expression::Function(function) => (function, None),
1005 Expression::Alias(alias) => match &alias.this {
1006 Expression::Function(function) => (function, Some(alias)),
1007 _ => return None,
1008 },
1009 _ => return None,
1010 };
1011 if !function.name.eq_ignore_ascii_case("IDENTIFIER") {
1012 return None;
1013 }
1014 let [Expression::Literal(literal)] = function.args.as_slice() else {
1015 return None;
1016 };
1017 let Literal::String(name) = literal.as_ref() else {
1018 return None;
1019 };
1020 let mut parts = identifier_table_parts(name)?;
1021 let mut table = TableRef::new("");
1022 table.name = parts.pop().filter(|part| !part.is_empty())?;
1023 table.schema = parts.pop();
1024 table.catalog = parts.pop();
1025 if let Some(alias) = alias {
1026 table.alias = Some(alias.alias.clone());
1027 table.column_aliases = alias.column_aliases.clone();
1028 }
1029 parts.is_empty().then_some(table)
1030}
1031
1032fn identifier_table_parts(name: &str) -> Option<Vec<Identifier>> {
1034 let mut chars = name.chars().peekable();
1035 let mut parts = Vec::new();
1036 loop {
1037 while chars.next_if(|c| c.is_whitespace()).is_some() {}
1038 let quoted = chars.next_if_eq(&'"').is_some();
1039 let mut part = String::new();
1040 if quoted {
1041 loop {
1042 match chars.next()? {
1043 '"' if chars.next_if_eq(&'"').is_some() => part.push('"'),
1044 '"' => break,
1045 ch => part.push(ch),
1046 }
1047 }
1048 } else {
1049 while let Some(ch) =
1050 chars.next_if(|c| c.is_ascii_alphanumeric() || matches!(c, '_' | '$'))
1051 {
1052 part.push(ch);
1053 }
1054 if part.starts_with(|c: char| c.is_ascii_digit() || c == '$') {
1055 return None;
1056 }
1057 }
1058 if part.is_empty() {
1060 if quoted || parts.len() != 1 || chars.peek() != Some(&'.') {
1061 return None;
1062 }
1063 part.push_str("PUBLIC");
1064 }
1065 parts.push(if quoted {
1066 Identifier::quoted(part)
1067 } else {
1068 Identifier::new(part)
1069 });
1070 while chars.next_if(|c| c.is_whitespace()).is_some() {}
1071 match chars.next() {
1072 None => return Some(parts),
1073 Some('.') if parts.len() < 3 => {}
1074 _ => return None,
1075 }
1076 }
1077}
1078
1079fn is_query_like_relation(expr: &Expression) -> bool {
1080 match expr {
1081 Expression::Select(_)
1082 | Expression::Values(_)
1083 | Expression::Subquery(_)
1084 | Expression::Union(_)
1085 | Expression::Intersect(_)
1086 | Expression::Except(_) => true,
1087 Expression::Paren(paren) => is_query_like_relation(&paren.this),
1088 _ => false,
1089 }
1090}
1091
1092fn pivot_source_name(source: &Expression, explicit_alias: Option<&str>) -> String {
1093 if let Some(alias) = explicit_alias {
1094 return alias.to_string();
1095 }
1096
1097 match source {
1098 Expression::Table(table) => table
1099 .alias
1100 .as_ref()
1101 .map(|alias| alias.name.clone())
1102 .unwrap_or_else(|| table.name.name.clone()),
1103 Expression::Subquery(subquery) => subquery
1104 .alias
1105 .as_ref()
1106 .map(|alias| alias.name.clone())
1107 .unwrap_or_else(|| "_0".to_string()),
1108 Expression::Paren(paren) => pivot_source_name(&paren.this, explicit_alias),
1109 _ => "_0".to_string(),
1110 }
1111}
1112
1113fn add_pivot_inner_scope(source: &Expression, scope: &mut Scope) {
1114 match source {
1115 Expression::Subquery(subquery) => {
1116 let mut derived_scope = scope.branch(subquery.this.clone(), ScopeType::DerivedTable);
1117 build_scope_impl(&subquery.this, &mut derived_scope);
1118 scope.derived_table_scopes.push(derived_scope);
1119 }
1120 Expression::Paren(paren) => add_pivot_inner_scope(&paren.this, scope),
1121 _ => {}
1122 }
1123}
1124
1125fn add_lateral_view_to_scope(lateral_view: &crate::expressions::LateralView, scope: &mut Scope) {
1126 let alias = lateral_view
1127 .table_alias
1128 .as_ref()
1129 .or_else(|| lateral_view.column_aliases.first())
1130 .map(|alias| alias.name.clone());
1131
1132 if let Some(alias) = alias {
1133 scope.add_virtual_source(
1134 alias,
1135 Expression::LateralView(Box::new(lateral_view.clone())),
1136 );
1137 }
1138}
1139
1140fn add_array_join_to_scope(
1142 expr: &Expression,
1143 scope: &mut Scope,
1144 preceding_sources: &mut HashSet<String>,
1145) {
1146 let items = match expr {
1147 Expression::Tuple(tuple) => tuple.expressions.as_slice(),
1148 item => std::slice::from_ref(item),
1149 };
1150 for item in items {
1151 if let Expression::Alias(alias) = item {
1152 scope.add_virtual_source(alias.alias.name.clone(), item.clone());
1153 preceding_sources.insert(alias.alias.name.clone());
1154 }
1155 }
1156}
1157
1158fn collect_subqueries(expr: &Expression, parent_scope: &mut Scope) {
1159 if matches!(expr, Expression::Select(_)) {
1160 use crate::ast_children::ChildPathSegment::{Field, Index};
1161
1162 crate::ast_children::for_each_child(expr, |path, child| {
1166 if !matches!(
1167 path,
1168 [Field("from" | "with" | "lateral_views"), ..]
1169 | [Field("joins"), Index(_), Field("this"), ..]
1170 ) {
1171 collect_subqueries_in_expr(child, parent_scope);
1172 }
1173 });
1174 }
1175}
1176
1177fn collect_subqueries_in_expr(expr: &Expression, parent_scope: &mut Scope) {
1178 let mut seen = HashSet::new();
1179 for node in walk_in_scope(expr, false) {
1180 let query = match node {
1181 Expression::Subquery(subquery) if subquery.alias.is_none() => Some(&subquery.this),
1182 Expression::Exists(exists) => Some(&exists.this),
1183 Expression::In(in_expr) => in_expr.query.as_ref(),
1184 Expression::Any(quantified) | Expression::All(quantified) => Some(&quantified.subquery),
1185 _ => None,
1186 };
1187
1188 let Some(query) = query else {
1189 continue;
1190 };
1191
1192 let key = query as *const Expression as usize;
1193 if !seen.insert(key) {
1194 continue;
1195 }
1196
1197 let mut sub_scope = parent_scope.branch(query.clone(), ScopeType::Subquery);
1198 build_scope_impl(query, &mut sub_scope);
1199 parent_scope.subquery_scopes.push(sub_scope);
1200 }
1201}
1202
1203pub fn walk_in_scope<'a>(
1215 expression: &'a Expression,
1216 bfs: bool,
1217) -> impl Iterator<Item = &'a Expression> {
1218 WalkInScopeIter::new(expression, bfs)
1219}
1220
1221struct WalkInScopeIter<'a> {
1223 queue: VecDeque<&'a Expression>,
1224 bfs: bool,
1225}
1226
1227impl<'a> WalkInScopeIter<'a> {
1228 fn new(expression: &'a Expression, bfs: bool) -> Self {
1229 let mut queue = VecDeque::new();
1230 queue.push_back(expression);
1231 Self { queue, bfs }
1232 }
1233
1234 fn should_stop_at(&self, expr: &Expression, is_root: bool) -> bool {
1235 if is_root {
1236 return false;
1237 }
1238
1239 if matches!(expr, Expression::Cte(_)) {
1241 return true;
1242 }
1243
1244 if let Expression::Subquery(subquery) = expr {
1246 if subquery.alias.is_some() {
1247 return true;
1248 }
1249 }
1250
1251 if matches!(
1253 expr,
1254 Expression::Select(_)
1255 | Expression::Union(_)
1256 | Expression::Intersect(_)
1257 | Expression::Except(_)
1258 ) {
1259 return true;
1260 }
1261
1262 false
1263 }
1264
1265 fn get_children(&self, expr: &'a Expression) -> Vec<&'a Expression> {
1266 let mut children = Vec::new();
1267
1268 match expr {
1269 Expression::Prepare(prepare) => {
1270 children.push(&prepare.statement);
1271 }
1272 Expression::Select(select) => {
1273 for e in &select.expressions {
1275 children.push(e);
1276 }
1277 if let Some(from) = &select.from {
1279 for table in &from.expressions {
1280 if !self.should_stop_at(table, false) {
1281 children.push(table);
1282 }
1283 }
1284 }
1285 for join in &select.joins {
1287 if !self.should_stop_at(&join.this, false) {
1288 children.push(&join.this);
1289 }
1290 if let Some(on) = &join.on {
1291 children.push(on);
1292 }
1293 if let Some(condition) = &join.match_condition {
1294 children.push(condition);
1295 }
1296 }
1297 if let Some(where_clause) = &select.where_clause {
1299 children.push(&where_clause.this);
1300 }
1301 if let Some(group_by) = &select.group_by {
1303 for e in &group_by.expressions {
1304 children.push(e);
1305 }
1306 }
1307 if let Some(having) = &select.having {
1309 children.push(&having.this);
1310 }
1311 if let Some(qualify) = &select.qualify {
1312 children.push(&qualify.this);
1313 }
1314 if let Some(order_by) = &select.order_by {
1316 for ord in &order_by.expressions {
1317 children.push(&ord.this);
1318 }
1319 }
1320 if let Some(limit) = &select.limit {
1322 children.push(&limit.this);
1323 }
1324 if let Some(offset) = &select.offset {
1326 children.push(&offset.this);
1327 }
1328 }
1329 Expression::And(bin)
1330 | Expression::Or(bin)
1331 | Expression::Add(bin)
1332 | Expression::Sub(bin)
1333 | Expression::Mul(bin)
1334 | Expression::Div(bin)
1335 | Expression::Mod(bin)
1336 | Expression::Eq(bin)
1337 | Expression::Neq(bin)
1338 | Expression::Lt(bin)
1339 | Expression::Lte(bin)
1340 | Expression::Gt(bin)
1341 | Expression::Gte(bin)
1342 | Expression::BitwiseAnd(bin)
1343 | Expression::BitwiseOr(bin)
1344 | Expression::BitwiseXor(bin)
1345 | Expression::Concat(bin) => {
1346 children.push(&bin.left);
1347 children.push(&bin.right);
1348 }
1349 Expression::Like(like) | Expression::ILike(like) => {
1350 children.push(&like.left);
1351 children.push(&like.right);
1352 if let Some(escape) = &like.escape {
1353 children.push(escape);
1354 }
1355 }
1356 Expression::Not(un) | Expression::Neg(un) | Expression::BitwiseNot(un) => {
1357 children.push(&un.this);
1358 }
1359 Expression::Function(func) => {
1360 for arg in &func.args {
1361 children.push(arg);
1362 }
1363 }
1364 Expression::AggregateFunction(agg) => {
1365 for arg in &agg.args {
1366 children.push(arg);
1367 }
1368 }
1369 Expression::WindowFunction(wf) => {
1370 children.push(&wf.this);
1371 for e in &wf.over.partition_by {
1372 children.push(e);
1373 }
1374 for e in &wf.over.order_by {
1375 children.push(&e.this);
1376 }
1377 }
1378 Expression::Alias(alias) => {
1379 children.push(&alias.this);
1380 }
1381 Expression::Case(case) => {
1382 if let Some(operand) = &case.operand {
1383 children.push(operand);
1384 }
1385 for (when_expr, then_expr) in &case.whens {
1386 children.push(when_expr);
1387 children.push(then_expr);
1388 }
1389 if let Some(else_clause) = &case.else_ {
1390 children.push(else_clause);
1391 }
1392 }
1393 Expression::Paren(paren) => {
1394 children.push(&paren.this);
1395 }
1396 Expression::Ordered(ord) => {
1397 children.push(&ord.this);
1398 }
1399 Expression::In(in_expr) => {
1400 children.push(&in_expr.this);
1401 for e in &in_expr.expressions {
1402 children.push(e);
1403 }
1404 }
1406 Expression::Between(between) => {
1407 children.push(&between.this);
1408 children.push(&between.low);
1409 children.push(&between.high);
1410 }
1411 Expression::IsNull(is_null) => {
1412 children.push(&is_null.this);
1413 }
1414 Expression::Cast(cast) => {
1415 children.push(&cast.this);
1416 }
1417 Expression::Extract(extract) => {
1418 children.push(&extract.this);
1419 }
1420 Expression::Coalesce(coalesce) => {
1421 for e in &coalesce.expressions {
1422 children.push(e);
1423 }
1424 }
1425 Expression::NullIf(nullif) => {
1426 children.push(&nullif.this);
1427 children.push(&nullif.expression);
1428 }
1429 Expression::Table(_table) => {
1430 }
1433 Expression::TryCatch(try_catch) => {
1434 for stmt in &try_catch.try_body {
1435 children.push(stmt);
1436 }
1437 if let Some(catch_body) = &try_catch.catch_body {
1438 for stmt in catch_body {
1439 children.push(stmt);
1440 }
1441 }
1442 }
1443 Expression::Column(_) | Expression::Literal(_) | Expression::Identifier(_) => {
1444 }
1446 Expression::Subquery(_) | Expression::Exists(_) => {}
1448 _ => {
1449 children.extend(expr.children());
1453 }
1454 }
1455
1456 children
1457 }
1458}
1459
1460impl<'a> Iterator for WalkInScopeIter<'a> {
1461 type Item = &'a Expression;
1462
1463 fn next(&mut self) -> Option<Self::Item> {
1464 let expr = if self.bfs {
1465 self.queue.pop_front()?
1466 } else {
1467 self.queue.pop_back()?
1468 };
1469
1470 let children = self.get_children(expr);
1472
1473 if self.bfs {
1474 for child in children {
1475 if !self.should_stop_at(child, false) {
1476 self.queue.push_back(child);
1477 }
1478 }
1479 } else {
1480 for child in children.into_iter().rev() {
1481 if !self.should_stop_at(child, false) {
1482 self.queue.push_back(child);
1483 }
1484 }
1485 }
1486
1487 Some(expr)
1488 }
1489}
1490
1491pub fn find_in_scope<'a, F>(
1503 expression: &'a Expression,
1504 predicate: F,
1505 bfs: bool,
1506) -> Option<&'a Expression>
1507where
1508 F: Fn(&Expression) -> bool,
1509{
1510 walk_in_scope(expression, bfs).find(|e| predicate(e))
1511}
1512
1513pub fn find_all_in_scope<'a, F>(
1525 expression: &'a Expression,
1526 predicate: F,
1527 bfs: bool,
1528) -> Vec<&'a Expression>
1529where
1530 F: Fn(&Expression) -> bool,
1531{
1532 walk_in_scope(expression, bfs)
1533 .filter(|e| predicate(e))
1534 .collect()
1535}
1536
1537pub fn traverse_scope(expression: &Expression) -> Vec<Scope> {
1547 match expression {
1548 Expression::Select(_)
1549 | Expression::Union(_)
1550 | Expression::Intersect(_)
1551 | Expression::Except(_)
1552 | Expression::Prepare(_)
1553 | Expression::CreateTable(_) => {
1554 let root = build_scope(expression);
1555 root.traverse().into_iter().cloned().collect()
1556 }
1557 _ => Vec::new(),
1558 }
1559}
1560
1561#[cfg(test)]
1562mod tests {
1563 use super::*;
1564 use crate::parser::Parser;
1565
1566 fn parse_and_build_scope(sql: &str) -> Scope {
1567 let ast = Parser::parse_sql(sql).expect("Failed to parse SQL");
1568 build_scope(&ast[0])
1569 }
1570
1571 #[test]
1572 fn unaliased_join_members_are_visible_to_following_lateral_relations() {
1573 let scope = parse_and_build_scope(
1574 "SELECT d.id FROM alpha a JOIN (beta b JOIN gamma c ON b.id = c.id) \
1575 ON a.id = b.id CROSS JOIN LATERAL (SELECT c.id) AS d",
1576 );
1577 assert!(scope.sources.contains_key("a"));
1578 assert!(scope.sources.contains_key("b"));
1579 assert!(scope.sources.contains_key("c"));
1580 let lateral = scope.derived_table_scopes.last().expect("lateral scope");
1581 assert!(lateral.is_lateral);
1582 assert_eq!(
1583 lateral
1584 .lateral_sources
1585 .keys()
1586 .map(String::as_str)
1587 .collect::<HashSet<_>>(),
1588 HashSet::from(["a", "b", "c"]),
1589 );
1590 }
1591
1592 #[test]
1593 fn aliased_join_group_hides_member_bindings_from_its_parent() {
1594 let scope = parse_and_build_scope(
1595 "SELECT grouped.id FROM (beta b JOIN gamma c ON b.id = c.id) AS grouped",
1596 );
1597 assert_eq!(scope.sources.len(), 1);
1598 assert!(scope.sources.contains_key("grouped"));
1599 let group = scope
1600 .derived_table_scopes
1601 .first()
1602 .expect("join group scope");
1603 assert!(group.sources.contains_key("b"));
1604 assert!(group.sources.contains_key("c"));
1605 }
1606
1607 #[test]
1608 fn test_simple_select_scope() {
1609 let mut scope = parse_and_build_scope("SELECT a, b FROM t");
1610
1611 assert!(scope.is_root());
1612 assert!(!scope.can_be_correlated);
1613 assert!(scope.sources.contains_key("t"));
1614
1615 let columns = scope.columns();
1616 assert_eq!(columns.len(), 2);
1617 }
1618
1619 #[test]
1620 fn test_derived_table_scope() {
1621 let mut scope = parse_and_build_scope("SELECT x.a FROM (SELECT a FROM t) AS x");
1622
1623 assert!(scope.sources.contains_key("x"));
1624 assert_eq!(scope.derived_table_scopes.len(), 1);
1625
1626 let derived = &mut scope.derived_table_scopes[0];
1627 assert!(derived.is_derived_table());
1628 assert!(derived.sources.contains_key("t"));
1629 }
1630
1631 #[test]
1632 fn test_lateral_preceding_sources_472() {
1633 let scope = parse_and_build_scope(
1634 "WITH c AS (SELECT a FROM t) SELECT n.a FROM t, LATERAL (SELECT t.a) n, c",
1635 );
1636 let lateral = &scope.derived_table_scopes[0];
1637 assert!(lateral.is_lateral);
1638 assert!(lateral.can_be_correlated);
1639 assert_eq!(lateral.lateral_sources.len(), 1);
1640 assert!(lateral.lateral_sources.contains_key("t"));
1641 assert!(!lateral.sources.contains_key("t"));
1642 let scope = parse_and_build_scope("SELECT n.a FROM t, (SELECT t.a) n");
1643 assert!(!scope.derived_table_scopes[0].is_lateral);
1644 assert!(scope.derived_table_scopes[0].lateral_sources.is_empty());
1645 }
1646
1647 #[test]
1648 fn test_clickhouse_array_join_aliases_are_virtual_sources() {
1649 for (sql, aliases) in [
1650 ("SELECT item FROM t ARRAY JOIN arr AS item", &["item"][..]),
1651 (
1652 "SELECT a, b FROM t LEFT ARRAY JOIN arr AS a, t.nested AS b",
1653 &["a", "b"],
1654 ),
1655 ("SELECT arr FROM t ARRAY JOIN arr", &[]),
1656 ] {
1657 let ast = crate::parse_one(sql, crate::dialects::DialectType::ClickHouse).unwrap();
1658 let scope = build_scope(&ast);
1659 let mut virtual_sources: Vec<_> = scope
1660 .sources
1661 .iter()
1662 .filter(|(_, source)| source.kind == SourceKind::Virtual)
1663 .map(|(name, _)| name.as_str())
1664 .collect();
1665 virtual_sources.sort();
1666 assert_eq!(virtual_sources, aliases, "{sql}");
1667 assert_eq!(scope.sources.len(), aliases.len() + 1, "{sql}");
1668 }
1669 }
1670
1671 #[test]
1672 fn test_snowflake_identifier_string_is_a_table_source() {
1673 let ast = crate::parse_one(
1674 "SELECT o.id FROM IDENTIFIER('db.s.orders') AS o, IDENTIFIER('customers'), IDENTIFIER($t)",
1675 crate::dialects::DialectType::Snowflake,
1676 )
1677 .unwrap();
1678 let scope = build_scope(&ast);
1679 assert_eq!(scope.sources.len(), 2);
1680 let Expression::Table(orders) = &scope.sources["o"].expression else {
1681 panic!("expected a table source");
1682 };
1683 assert_eq!(orders.catalog.as_ref().unwrap().name, "db");
1684 assert_eq!(orders.schema.as_ref().unwrap().name, "s");
1685 assert_eq!(orders.name.name, "orders");
1686 assert_eq!(scope.sources["o"].kind, SourceKind::Table);
1687 assert!(scope.sources.contains_key("customers"));
1688 }
1689
1690 #[test]
1691 fn test_subquery_collection_respects_relation_boundaries() {
1692 let scope = parse_and_build_scope(
1693 "SELECT t.a FROM t JOIN (SELECT a FROM s) ON t.a = 1 \
1694 WHERE EXISTS (SELECT 1 FROM u) ORDER BY (SELECT MAX(a) FROM v)",
1695 );
1696 assert_eq!(scope.derived_table_scopes.len(), 1);
1697 assert_eq!(scope.subquery_scopes.len(), 2);
1698 let scope = parse_and_build_scope(
1699 "SELECT t.a FROM t JOIN s ON EXISTS (SELECT 1 FROM u WHERE u.a = t.a)",
1700 );
1701 assert_eq!(scope.subquery_scopes.len(), 1);
1702 assert!(scope.subquery_scopes[0].sources.contains_key("u"));
1703 }
1704
1705 #[test]
1706 fn test_non_correlated_subquery() {
1707 let mut scope = parse_and_build_scope("SELECT * FROM t WHERE EXISTS (SELECT b FROM s)");
1708
1709 assert_eq!(scope.subquery_scopes.len(), 1);
1710
1711 let subquery = &mut scope.subquery_scopes[0];
1712 assert!(subquery.is_subquery());
1713 assert!(subquery.can_be_correlated);
1714
1715 assert!(subquery.sources.contains_key("s"));
1717 assert!(!subquery.is_correlated_subquery());
1718 }
1719
1720 #[test]
1721 fn test_correlated_subquery() {
1722 let mut scope =
1723 parse_and_build_scope("SELECT * FROM t WHERE EXISTS (SELECT b FROM s WHERE s.x = t.y)");
1724
1725 assert_eq!(scope.subquery_scopes.len(), 1);
1726
1727 let subquery = &mut scope.subquery_scopes[0];
1728 assert!(subquery.is_subquery());
1729 assert!(subquery.can_be_correlated);
1730
1731 let external = subquery.external_columns();
1733 assert!(!external.is_empty());
1734 assert!(external.iter().any(|c| c.table.as_deref() == Some("t")));
1735 assert!(subquery.is_correlated_subquery());
1736 }
1737
1738 #[test]
1739 fn test_cte_scope() {
1740 let scope = parse_and_build_scope("WITH cte AS (SELECT a FROM t) SELECT * FROM cte");
1741
1742 assert_eq!(scope.cte_scopes.len(), 1);
1743 assert!(scope.cte_sources.contains_key("cte"));
1744
1745 let cte = &scope.cte_scopes[0];
1746 assert!(cte.is_cte());
1747 }
1748
1749 #[test]
1750 fn test_multiple_sources() {
1751 let scope = parse_and_build_scope("SELECT t.a, s.b FROM t JOIN s ON t.id = s.id");
1752
1753 assert!(scope.sources.contains_key("t"));
1754 assert!(scope.sources.contains_key("s"));
1755 assert_eq!(scope.sources.len(), 2);
1756 }
1757
1758 #[test]
1759 fn test_aliased_table() {
1760 let scope = parse_and_build_scope("SELECT x.a FROM t AS x");
1761
1762 assert!(scope.sources.contains_key("x"));
1764 assert!(!scope.sources.contains_key("t"));
1765 }
1766
1767 #[test]
1768 fn test_local_columns() {
1769 let mut scope = parse_and_build_scope("SELECT t.a, t.b, s.c FROM t JOIN s ON t.id = s.id");
1770
1771 let local = scope.local_columns();
1772 assert_eq!(local.len(), 5);
1775 assert!(local.iter().all(|c| c.table.is_some()));
1776 }
1777
1778 #[test]
1779 fn test_columns_include_join_on_clause_references() {
1780 let mut scope = parse_and_build_scope(
1781 "SELECT o.total FROM orders o JOIN customers c ON c.id = o.customer_id",
1782 );
1783
1784 let cols: Vec<String> = scope
1785 .columns()
1786 .iter()
1787 .map(|c| match &c.table {
1788 Some(t) => format!("{}.{}", t, c.name),
1789 None => c.name.clone(),
1790 })
1791 .collect();
1792
1793 assert!(cols.contains(&"o.total".to_string()));
1794 assert!(cols.contains(&"c.id".to_string()));
1795 assert!(cols.contains(&"o.customer_id".to_string()));
1796 }
1797
1798 #[test]
1799 fn test_unqualified_columns() {
1800 let mut scope = parse_and_build_scope("SELECT a, b, t.c FROM t");
1801
1802 let unqualified = scope.unqualified_columns();
1803 assert_eq!(unqualified.len(), 2);
1805 assert!(unqualified.iter().all(|c| c.table.is_none()));
1806 }
1807
1808 #[test]
1809 fn test_source_columns() {
1810 let mut scope = parse_and_build_scope("SELECT t.a, t.b, s.c FROM t JOIN s ON t.id = s.id");
1811
1812 let t_cols = scope.source_columns("t");
1813 assert!(t_cols.len() >= 2);
1815 assert!(t_cols.iter().all(|c| c.table.as_deref() == Some("t")));
1816
1817 let s_cols = scope.source_columns("s");
1818 assert!(s_cols.len() >= 1);
1820 assert!(s_cols.iter().all(|c| c.table.as_deref() == Some("s")));
1821 }
1822
1823 #[test]
1824 fn test_rename_source() {
1825 let mut scope = parse_and_build_scope("SELECT a FROM t");
1826
1827 assert!(scope.sources.contains_key("t"));
1828 scope.rename_source("t", "new_name".to_string());
1829 assert!(!scope.sources.contains_key("t"));
1830 assert!(scope.sources.contains_key("new_name"));
1831 }
1832
1833 #[test]
1834 fn test_remove_source() {
1835 let mut scope = parse_and_build_scope("SELECT a FROM t");
1836
1837 assert!(scope.sources.contains_key("t"));
1838 scope.remove_source("t");
1839 assert!(!scope.sources.contains_key("t"));
1840 }
1841
1842 #[test]
1843 fn test_walk_in_scope() {
1844 let ast = Parser::parse_sql("SELECT a, b FROM t WHERE a > 1").expect("Failed to parse");
1845 let expr = &ast[0];
1846
1847 let walked: Vec<_> = walk_in_scope(expr, true).collect();
1849 assert!(!walked.is_empty());
1850
1851 assert!(walked.iter().any(|e| matches!(e, Expression::Select(_))));
1853 assert!(walked.iter().any(|e| matches!(e, Expression::Column(_))));
1855 }
1856
1857 #[test]
1858 fn test_find_in_scope() {
1859 let ast = Parser::parse_sql("SELECT a, b FROM t WHERE a > 1").expect("Failed to parse");
1860 let expr = &ast[0];
1861
1862 let found = find_in_scope(expr, |e| matches!(e, Expression::Column(_)), true);
1864 assert!(found.is_some());
1865 assert!(matches!(found.unwrap(), Expression::Column(_)));
1866 }
1867
1868 #[test]
1869 fn test_find_all_in_scope() {
1870 let ast = Parser::parse_sql("SELECT a, b, c FROM t").expect("Failed to parse");
1871 let expr = &ast[0];
1872
1873 let found = find_all_in_scope(expr, |e| matches!(e, Expression::Column(_)), true);
1875 assert_eq!(found.len(), 3);
1876 }
1877
1878 #[test]
1879 fn test_traverse_scope() {
1880 let ast =
1881 Parser::parse_sql("SELECT a FROM (SELECT b FROM t) AS x").expect("Failed to parse");
1882 let expr = &ast[0];
1883
1884 let scopes = traverse_scope(expr);
1885 assert!(!scopes.is_empty());
1888 assert!(scopes.iter().any(|s| s.is_root()));
1890 }
1891
1892 #[test]
1893 fn test_branch_with_options() {
1894 let ast = Parser::parse_sql("SELECT a FROM t").expect("Failed to parse");
1895 let scope = build_scope(&ast[0]);
1896
1897 let child = scope.branch_with_options(
1898 ast[0].clone(),
1899 ScopeType::Subquery, None,
1901 None,
1902 Some(vec!["col1".to_string(), "col2".to_string()]),
1903 );
1904
1905 assert_eq!(child.outer_columns, vec!["col1", "col2"]);
1906 assert!(child.can_be_correlated); }
1908
1909 #[test]
1910 fn test_is_udtf() {
1911 let ast = Parser::parse_sql("SELECT a FROM t").expect("Failed to parse");
1912 let scope = Scope::new(ast[0].clone());
1913 assert!(!scope.is_udtf());
1914
1915 let root = build_scope(&ast[0]);
1916 let udtf_scope = root.branch(ast[0].clone(), ScopeType::Udtf);
1917 assert!(udtf_scope.is_udtf());
1918 }
1919
1920 #[test]
1921 fn test_is_union() {
1922 let scope = parse_and_build_scope("SELECT a FROM t UNION SELECT b FROM s");
1923
1924 assert!(scope.is_root());
1925 assert_eq!(scope.union_scopes.len(), 2);
1926 assert!(scope.union_scopes[0].is_union());
1928 assert!(scope.union_scopes[1].is_union());
1929 }
1930
1931 #[test]
1932 fn test_union_output_columns() {
1933 let scope = parse_and_build_scope(
1934 "SELECT id, name FROM customers UNION ALL SELECT id, name FROM employees",
1935 );
1936 assert_eq!(scope.output_columns(), vec!["id", "name"]);
1937 }
1938
1939 #[test]
1940 fn test_clear_cache() {
1941 let mut scope = parse_and_build_scope("SELECT t.a FROM t");
1942
1943 let _ = scope.columns();
1945 assert!(scope.columns_cache.is_some());
1946
1947 scope.clear_cache();
1949 assert!(scope.columns_cache.is_none());
1950 assert!(scope.external_columns_cache.is_none());
1951 }
1952
1953 #[test]
1954 fn test_scope_traverse() {
1955 let scope = parse_and_build_scope(
1956 "WITH cte AS (SELECT a FROM t) SELECT * FROM cte WHERE EXISTS (SELECT b FROM s)",
1957 );
1958
1959 let traversed = scope.traverse();
1960 assert!(traversed.len() >= 3);
1962 }
1963
1964 #[test]
1965 fn test_create_table_as_select_scope() {
1966 let scope = parse_and_build_scope("CREATE TABLE out_table AS SELECT 1 AS id FROM src");
1968 assert!(
1969 scope.sources.contains_key("src"),
1970 "CTAS scope should contain the FROM table"
1971 );
1972 assert!(
1973 !scope.sources.contains_key("out_table"),
1974 "CTAS target table should not be treated as a source"
1975 );
1976
1977 let scope = parse_and_build_scope(
1979 "CREATE TABLE out_table AS SELECT a.id FROM foo AS a JOIN bar AS b ON a.id = b.id",
1980 );
1981 assert!(scope.sources.contains_key("a"));
1982 assert!(scope.sources.contains_key("b"));
1983 assert!(
1984 !scope.sources.contains_key("out_table"),
1985 "CTAS target table should not be treated as a source"
1986 );
1987
1988 let scope = parse_and_build_scope(
1990 "CREATE TABLE out_table AS WITH cte AS (SELECT 1 AS id FROM src) SELECT * FROM cte",
1991 );
1992 assert!(
1993 scope.sources.contains_key("cte"),
1994 "CTAS with CTE should resolve CTE as source"
1995 );
1996 assert!(
1997 !scope.sources.contains_key("out_table"),
1998 "CTAS target table should not be treated as a source"
1999 );
2000 assert_eq!(scope.cte_scopes.len(), 1);
2001 }
2002
2003 #[test]
2004 fn test_create_table_as_select_traverse() {
2005 let ast = Parser::parse_sql("CREATE TABLE t AS SELECT a FROM src").unwrap();
2006 let scopes = traverse_scope(&ast[0]);
2007 assert!(
2008 !scopes.is_empty(),
2009 "traverse_scope should return scopes for CTAS"
2010 );
2011 }
2012}