1use crate::expressions::Expression;
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
684 .from
685 .iter()
686 .flat_map(|from| &from.expressions)
687 .chain(select.joins.iter().map(|join| &join.this))
688 {
689 add_relation_to_scope(table, current_scope, &mut preceding_sources);
690 }
691
692 for lateral_view in &select.lateral_views {
694 add_lateral_view_to_scope(lateral_view, current_scope);
695 }
696
697 collect_subqueries(expression, current_scope);
699 }
700 Expression::JoinedTable(joined) => {
701 let mut preceding_sources = HashSet::new();
702 add_join_group_to_scope(joined, current_scope, &mut preceding_sources);
703 }
704 Expression::Union(union) => {
705 if let Some(with) = &union.with {
706 process_ctes(with, current_scope);
707 }
708
709 let mut left_scope = current_scope.branch(union.left.clone(), ScopeType::SetOperation);
710 build_scope_impl(&union.left, &mut left_scope);
711
712 let mut right_scope =
713 current_scope.branch(union.right.clone(), ScopeType::SetOperation);
714 build_scope_impl(&union.right, &mut right_scope);
715
716 current_scope.union_scopes.push(left_scope);
717 current_scope.union_scopes.push(right_scope);
718 }
719 Expression::Intersect(intersect) => {
720 if let Some(with) = &intersect.with {
721 process_ctes(with, current_scope);
722 }
723
724 let mut left_scope =
725 current_scope.branch(intersect.left.clone(), ScopeType::SetOperation);
726 build_scope_impl(&intersect.left, &mut left_scope);
727
728 let mut right_scope =
729 current_scope.branch(intersect.right.clone(), ScopeType::SetOperation);
730 build_scope_impl(&intersect.right, &mut right_scope);
731
732 current_scope.union_scopes.push(left_scope);
733 current_scope.union_scopes.push(right_scope);
734 }
735 Expression::Except(except) => {
736 if let Some(with) = &except.with {
737 process_ctes(with, current_scope);
738 }
739
740 let mut left_scope = current_scope.branch(except.left.clone(), ScopeType::SetOperation);
741 build_scope_impl(&except.left, &mut left_scope);
742
743 let mut right_scope =
744 current_scope.branch(except.right.clone(), ScopeType::SetOperation);
745 build_scope_impl(&except.right, &mut right_scope);
746
747 current_scope.union_scopes.push(left_scope);
748 current_scope.union_scopes.push(right_scope);
749 }
750 Expression::CreateTable(create) => {
751 if let Some(with) = &create.with_cte {
754 process_ctes(with, current_scope);
755 }
756 if let Some(as_select) = &create.as_select {
758 build_scope_impl(as_select, current_scope);
759 }
760 }
761 Expression::Subquery(subquery) => {
762 build_scope_impl(&subquery.this, current_scope);
763 }
764 Expression::Paren(paren) => {
765 build_scope_impl(&paren.this, current_scope);
766 }
767 Expression::Alias(alias) => {
768 build_scope_impl(&alias.this, current_scope);
769 }
770 _ => {}
771 }
772}
773
774fn process_ctes(with: &crate::expressions::With, current_scope: &mut Scope) {
775 for cte in &with.ctes {
776 let cte_name = cte.alias.name.clone();
777 let cte_expr = Expression::Cte(Box::new(cte.clone()));
778 let mut cte_scope = current_scope.branch(cte_expr.clone(), ScopeType::Cte);
779
780 if with.recursive && cte_body_self_references(cte) {
781 cte_scope.add_cte_source(cte_name.clone(), cte_expr.clone());
782 }
783
784 build_scope_impl(&cte.this, &mut cte_scope);
785 current_scope.add_cte_source(cte_name, cte_expr);
786 current_scope.cte_scopes.push(cte_scope);
787 }
788}
789
790fn cte_body_self_references(cte: &crate::expressions::Cte) -> bool {
791 let cte_name = cte.alias.name.as_str();
792 !cte.this
793 .find_all(|expr| match expr {
794 Expression::Table(table) if table.schema.is_none() && table.catalog.is_none() => {
795 table.name.name.eq_ignore_ascii_case(cte_name)
796 }
797 _ => false,
798 })
799 .is_empty()
800}
801
802fn add_join_group_to_scope(
803 joined: &crate::expressions::JoinedTable,
804 scope: &mut Scope,
805 preceding_sources: &mut HashSet<String>,
806) {
807 add_relation_to_scope(&joined.left, scope, preceding_sources);
808 for join in &joined.joins {
809 add_relation_to_scope(&join.this, scope, preceding_sources);
810 if let Some(condition) = &join.on {
811 collect_subqueries_in_expr(condition, scope);
812 }
813 if let Some(condition) = &join.match_condition {
814 collect_subqueries_in_expr(condition, scope);
815 }
816 }
817 for lateral_view in &joined.lateral_views {
818 add_lateral_view_to_scope(lateral_view, scope);
819 }
820}
821
822fn add_relation_to_scope(
824 expr: &Expression,
825 scope: &mut Scope,
826 preceding_sources: &mut HashSet<String>,
827) {
828 match expr {
829 Expression::JoinedTable(joined) if joined.alias.is_none() => {
830 add_join_group_to_scope(joined, scope, preceding_sources);
831 }
832 Expression::Paren(paren) => add_relation_to_scope(&paren.this, scope, preceding_sources),
833 _ => {
834 if let Some(name) = add_table_to_scope(expr, scope, preceding_sources) {
835 preceding_sources.insert(name);
836 }
837 }
838 }
839}
840
841fn add_table_to_scope(
842 expr: &Expression,
843 scope: &mut Scope,
844 preceding_sources: &HashSet<String>,
845) -> Option<String> {
846 match expr {
847 Expression::Table(table) => {
848 let name = table
849 .alias
850 .as_ref()
851 .map(|a| a.name.clone())
852 .unwrap_or_else(|| table.name.name.clone());
853 let cte_source = if table.schema.is_none() && table.catalog.is_none() {
854 scope.cte_sources.get(&table.name.name).or_else(|| {
855 scope
856 .cte_sources
857 .iter()
858 .find(|(cte_name, _)| cte_name.eq_ignore_ascii_case(&table.name.name))
859 .map(|(_, source)| source)
860 })
861 } else {
862 None
863 };
864
865 if let Some(source) = cte_source {
866 scope.add_source_info(name.clone(), source.clone());
867 } else {
868 let mut source = SourceInfo::new(expr.clone(), false, SourceKind::Table);
869 if let Some(alias) = &table.alias {
870 source = source.with_alias(alias.name.clone());
871 }
872 scope.add_source_info(name.clone(), source);
873 }
874 Some(name)
875 }
876 Expression::Subquery(subquery) => {
877 let name = subquery
878 .alias
879 .as_ref()
880 .map(|a| a.name.clone())
881 .unwrap_or_default();
882
883 let mut derived_scope = scope.branch(subquery.this.clone(), ScopeType::DerivedTable);
884 if subquery.lateral {
885 derived_scope.is_lateral = true;
886 derived_scope.can_be_correlated = true;
887 derived_scope.lateral_sources = preceding_sources
888 .iter()
889 .filter_map(|name| {
890 scope
891 .sources
892 .get(name)
893 .map(|source| (name.clone(), source.clone()))
894 })
895 .collect();
896 }
897 build_scope_impl(&subquery.this, &mut derived_scope);
898
899 scope.add_source(name.clone(), expr.clone(), true);
900 scope.derived_table_scopes.push(derived_scope);
901 Some(name)
902 }
903 Expression::JoinedTable(joined) => {
904 let alias = joined.alias.as_ref()?;
905 let mut derived_scope = scope.branch(expr.clone(), ScopeType::DerivedTable);
906 build_scope_impl(expr, &mut derived_scope);
907 scope.add_source(alias.name.clone(), expr.clone(), true);
908 scope.derived_table_scopes.push(derived_scope);
909 Some(alias.name.clone())
910 }
911 Expression::Unnest(unnest) => {
912 if let Some(alias) = &unnest.alias {
913 scope.add_virtual_source(alias.name.clone(), expr.clone());
914 }
915 unnest.alias.as_ref().map(|alias| alias.name.clone())
916 }
917 Expression::Values(values) => {
918 let name = values
919 .alias
920 .as_ref()
921 .map(|alias| alias.name.clone())
922 .unwrap_or_default();
923 scope.add_virtual_source(name.clone(), expr.clone());
924 Some(name)
925 }
926 Expression::Alias(alias) if matches!(&alias.this, Expression::Unnest(_)) => {
927 scope.add_virtual_source(alias.alias.name.clone(), expr.clone());
928 Some(alias.alias.name.clone())
929 }
930 Expression::Alias(alias)
931 if is_query_like_relation(&alias.this)
932 || matches!(scope_query(&alias.this), Expression::JoinedTable(_)) =>
933 {
934 let outer_columns = alias
935 .column_aliases
936 .iter()
937 .map(|column| column.name.clone())
938 .collect::<Vec<_>>();
939 let mut derived_scope = scope.branch_with_options(
940 alias.this.clone(),
941 ScopeType::DerivedTable,
942 None,
943 None,
944 Some(outer_columns),
945 );
946 build_scope_impl(&alias.this, &mut derived_scope);
947
948 scope.add_source(alias.alias.name.clone(), expr.clone(), true);
949 scope.derived_table_scopes.push(derived_scope);
950 Some(alias.alias.name.clone())
951 }
952 Expression::Lateral(lateral) => {
953 if let Some(alias) = &lateral.alias {
954 scope.add_virtual_source(alias.clone(), expr.clone());
955 }
956 lateral.alias.clone()
957 }
958 Expression::LateralView(lateral_view) => {
959 add_lateral_view_to_scope(lateral_view, scope);
960 lateral_view
961 .table_alias
962 .as_ref()
963 .or_else(|| lateral_view.column_aliases.first())
964 .map(|alias| alias.name.clone())
965 }
966 Expression::Pivot(pivot) => {
967 let name =
968 pivot_source_name(&pivot.this, pivot.alias.as_ref().map(|a| a.name.as_str()));
969 scope.add_source_info(
970 name.clone(),
971 SourceInfo::new(expr.clone(), false, SourceKind::DerivedTable),
972 );
973 add_pivot_inner_scope(&pivot.this, scope);
974 Some(name)
975 }
976 Expression::Unpivot(unpivot) => {
977 let name = pivot_source_name(
978 &unpivot.this,
979 unpivot.alias.as_ref().map(|a| a.name.as_str()),
980 );
981 scope.add_source_info(
982 name.clone(),
983 SourceInfo::new(expr.clone(), false, SourceKind::DerivedTable),
984 );
985 add_pivot_inner_scope(&unpivot.this, scope);
986 Some(name)
987 }
988 Expression::Paren(paren) => add_table_to_scope(&paren.this, scope, preceding_sources),
989 _ => None,
990 }
991}
992
993fn is_query_like_relation(expr: &Expression) -> bool {
994 match expr {
995 Expression::Select(_)
996 | Expression::Values(_)
997 | Expression::Subquery(_)
998 | Expression::Union(_)
999 | Expression::Intersect(_)
1000 | Expression::Except(_) => true,
1001 Expression::Paren(paren) => is_query_like_relation(&paren.this),
1002 _ => false,
1003 }
1004}
1005
1006fn pivot_source_name(source: &Expression, explicit_alias: Option<&str>) -> String {
1007 if let Some(alias) = explicit_alias {
1008 return alias.to_string();
1009 }
1010
1011 match source {
1012 Expression::Table(table) => table
1013 .alias
1014 .as_ref()
1015 .map(|alias| alias.name.clone())
1016 .unwrap_or_else(|| table.name.name.clone()),
1017 Expression::Subquery(subquery) => subquery
1018 .alias
1019 .as_ref()
1020 .map(|alias| alias.name.clone())
1021 .unwrap_or_else(|| "_0".to_string()),
1022 Expression::Paren(paren) => pivot_source_name(&paren.this, explicit_alias),
1023 _ => "_0".to_string(),
1024 }
1025}
1026
1027fn add_pivot_inner_scope(source: &Expression, scope: &mut Scope) {
1028 match source {
1029 Expression::Subquery(subquery) => {
1030 let mut derived_scope = scope.branch(subquery.this.clone(), ScopeType::DerivedTable);
1031 build_scope_impl(&subquery.this, &mut derived_scope);
1032 scope.derived_table_scopes.push(derived_scope);
1033 }
1034 Expression::Paren(paren) => add_pivot_inner_scope(&paren.this, scope),
1035 _ => {}
1036 }
1037}
1038
1039fn add_lateral_view_to_scope(lateral_view: &crate::expressions::LateralView, scope: &mut Scope) {
1040 let alias = lateral_view
1041 .table_alias
1042 .as_ref()
1043 .or_else(|| lateral_view.column_aliases.first())
1044 .map(|alias| alias.name.clone());
1045
1046 if let Some(alias) = alias {
1047 scope.add_virtual_source(
1048 alias,
1049 Expression::LateralView(Box::new(lateral_view.clone())),
1050 );
1051 }
1052}
1053
1054fn collect_subqueries(expr: &Expression, parent_scope: &mut Scope) {
1055 if matches!(expr, Expression::Select(_)) {
1056 use crate::ast_children::ChildPathSegment::{Field, Index};
1057
1058 crate::ast_children::for_each_child(expr, |path, child| {
1062 if !matches!(
1063 path,
1064 [Field("from" | "with" | "lateral_views"), ..]
1065 | [Field("joins"), Index(_), Field("this"), ..]
1066 ) {
1067 collect_subqueries_in_expr(child, parent_scope);
1068 }
1069 });
1070 }
1071}
1072
1073fn collect_subqueries_in_expr(expr: &Expression, parent_scope: &mut Scope) {
1074 let mut seen = HashSet::new();
1075 for node in walk_in_scope(expr, false) {
1076 let query = match node {
1077 Expression::Subquery(subquery) if subquery.alias.is_none() => Some(&subquery.this),
1078 Expression::Exists(exists) => Some(&exists.this),
1079 Expression::In(in_expr) => in_expr.query.as_ref(),
1080 Expression::Any(quantified) | Expression::All(quantified) => Some(&quantified.subquery),
1081 _ => None,
1082 };
1083
1084 let Some(query) = query else {
1085 continue;
1086 };
1087
1088 let key = query as *const Expression as usize;
1089 if !seen.insert(key) {
1090 continue;
1091 }
1092
1093 let mut sub_scope = parent_scope.branch(query.clone(), ScopeType::Subquery);
1094 build_scope_impl(query, &mut sub_scope);
1095 parent_scope.subquery_scopes.push(sub_scope);
1096 }
1097}
1098
1099pub fn walk_in_scope<'a>(
1111 expression: &'a Expression,
1112 bfs: bool,
1113) -> impl Iterator<Item = &'a Expression> {
1114 WalkInScopeIter::new(expression, bfs)
1115}
1116
1117struct WalkInScopeIter<'a> {
1119 queue: VecDeque<&'a Expression>,
1120 bfs: bool,
1121}
1122
1123impl<'a> WalkInScopeIter<'a> {
1124 fn new(expression: &'a Expression, bfs: bool) -> Self {
1125 let mut queue = VecDeque::new();
1126 queue.push_back(expression);
1127 Self { queue, bfs }
1128 }
1129
1130 fn should_stop_at(&self, expr: &Expression, is_root: bool) -> bool {
1131 if is_root {
1132 return false;
1133 }
1134
1135 if matches!(expr, Expression::Cte(_)) {
1137 return true;
1138 }
1139
1140 if let Expression::Subquery(subquery) = expr {
1142 if subquery.alias.is_some() {
1143 return true;
1144 }
1145 }
1146
1147 if matches!(
1149 expr,
1150 Expression::Select(_)
1151 | Expression::Union(_)
1152 | Expression::Intersect(_)
1153 | Expression::Except(_)
1154 ) {
1155 return true;
1156 }
1157
1158 false
1159 }
1160
1161 fn get_children(&self, expr: &'a Expression) -> Vec<&'a Expression> {
1162 let mut children = Vec::new();
1163
1164 match expr {
1165 Expression::Prepare(prepare) => {
1166 children.push(&prepare.statement);
1167 }
1168 Expression::Select(select) => {
1169 for e in &select.expressions {
1171 children.push(e);
1172 }
1173 if let Some(from) = &select.from {
1175 for table in &from.expressions {
1176 if !self.should_stop_at(table, false) {
1177 children.push(table);
1178 }
1179 }
1180 }
1181 for join in &select.joins {
1183 if !self.should_stop_at(&join.this, false) {
1184 children.push(&join.this);
1185 }
1186 if let Some(on) = &join.on {
1187 children.push(on);
1188 }
1189 if let Some(condition) = &join.match_condition {
1190 children.push(condition);
1191 }
1192 }
1193 if let Some(where_clause) = &select.where_clause {
1195 children.push(&where_clause.this);
1196 }
1197 if let Some(group_by) = &select.group_by {
1199 for e in &group_by.expressions {
1200 children.push(e);
1201 }
1202 }
1203 if let Some(having) = &select.having {
1205 children.push(&having.this);
1206 }
1207 if let Some(qualify) = &select.qualify {
1208 children.push(&qualify.this);
1209 }
1210 if let Some(order_by) = &select.order_by {
1212 for ord in &order_by.expressions {
1213 children.push(&ord.this);
1214 }
1215 }
1216 if let Some(limit) = &select.limit {
1218 children.push(&limit.this);
1219 }
1220 if let Some(offset) = &select.offset {
1222 children.push(&offset.this);
1223 }
1224 }
1225 Expression::And(bin)
1226 | Expression::Or(bin)
1227 | Expression::Add(bin)
1228 | Expression::Sub(bin)
1229 | Expression::Mul(bin)
1230 | Expression::Div(bin)
1231 | Expression::Mod(bin)
1232 | Expression::Eq(bin)
1233 | Expression::Neq(bin)
1234 | Expression::Lt(bin)
1235 | Expression::Lte(bin)
1236 | Expression::Gt(bin)
1237 | Expression::Gte(bin)
1238 | Expression::BitwiseAnd(bin)
1239 | Expression::BitwiseOr(bin)
1240 | Expression::BitwiseXor(bin)
1241 | Expression::Concat(bin) => {
1242 children.push(&bin.left);
1243 children.push(&bin.right);
1244 }
1245 Expression::Like(like) | Expression::ILike(like) => {
1246 children.push(&like.left);
1247 children.push(&like.right);
1248 if let Some(escape) = &like.escape {
1249 children.push(escape);
1250 }
1251 }
1252 Expression::Not(un) | Expression::Neg(un) | Expression::BitwiseNot(un) => {
1253 children.push(&un.this);
1254 }
1255 Expression::Function(func) => {
1256 for arg in &func.args {
1257 children.push(arg);
1258 }
1259 }
1260 Expression::AggregateFunction(agg) => {
1261 for arg in &agg.args {
1262 children.push(arg);
1263 }
1264 }
1265 Expression::WindowFunction(wf) => {
1266 children.push(&wf.this);
1267 for e in &wf.over.partition_by {
1268 children.push(e);
1269 }
1270 for e in &wf.over.order_by {
1271 children.push(&e.this);
1272 }
1273 }
1274 Expression::Alias(alias) => {
1275 children.push(&alias.this);
1276 }
1277 Expression::Case(case) => {
1278 if let Some(operand) = &case.operand {
1279 children.push(operand);
1280 }
1281 for (when_expr, then_expr) in &case.whens {
1282 children.push(when_expr);
1283 children.push(then_expr);
1284 }
1285 if let Some(else_clause) = &case.else_ {
1286 children.push(else_clause);
1287 }
1288 }
1289 Expression::Paren(paren) => {
1290 children.push(&paren.this);
1291 }
1292 Expression::Ordered(ord) => {
1293 children.push(&ord.this);
1294 }
1295 Expression::In(in_expr) => {
1296 children.push(&in_expr.this);
1297 for e in &in_expr.expressions {
1298 children.push(e);
1299 }
1300 }
1302 Expression::Between(between) => {
1303 children.push(&between.this);
1304 children.push(&between.low);
1305 children.push(&between.high);
1306 }
1307 Expression::IsNull(is_null) => {
1308 children.push(&is_null.this);
1309 }
1310 Expression::Cast(cast) => {
1311 children.push(&cast.this);
1312 }
1313 Expression::Extract(extract) => {
1314 children.push(&extract.this);
1315 }
1316 Expression::Coalesce(coalesce) => {
1317 for e in &coalesce.expressions {
1318 children.push(e);
1319 }
1320 }
1321 Expression::NullIf(nullif) => {
1322 children.push(&nullif.this);
1323 children.push(&nullif.expression);
1324 }
1325 Expression::Table(_table) => {
1326 }
1329 Expression::TryCatch(try_catch) => {
1330 for stmt in &try_catch.try_body {
1331 children.push(stmt);
1332 }
1333 if let Some(catch_body) = &try_catch.catch_body {
1334 for stmt in catch_body {
1335 children.push(stmt);
1336 }
1337 }
1338 }
1339 Expression::Column(_) | Expression::Literal(_) | Expression::Identifier(_) => {
1340 }
1342 Expression::Subquery(_) | Expression::Exists(_) => {}
1344 _ => {
1345 children.extend(expr.children());
1349 }
1350 }
1351
1352 children
1353 }
1354}
1355
1356impl<'a> Iterator for WalkInScopeIter<'a> {
1357 type Item = &'a Expression;
1358
1359 fn next(&mut self) -> Option<Self::Item> {
1360 let expr = if self.bfs {
1361 self.queue.pop_front()?
1362 } else {
1363 self.queue.pop_back()?
1364 };
1365
1366 let children = self.get_children(expr);
1368
1369 if self.bfs {
1370 for child in children {
1371 if !self.should_stop_at(child, false) {
1372 self.queue.push_back(child);
1373 }
1374 }
1375 } else {
1376 for child in children.into_iter().rev() {
1377 if !self.should_stop_at(child, false) {
1378 self.queue.push_back(child);
1379 }
1380 }
1381 }
1382
1383 Some(expr)
1384 }
1385}
1386
1387pub fn find_in_scope<'a, F>(
1399 expression: &'a Expression,
1400 predicate: F,
1401 bfs: bool,
1402) -> Option<&'a Expression>
1403where
1404 F: Fn(&Expression) -> bool,
1405{
1406 walk_in_scope(expression, bfs).find(|e| predicate(e))
1407}
1408
1409pub fn find_all_in_scope<'a, F>(
1421 expression: &'a Expression,
1422 predicate: F,
1423 bfs: bool,
1424) -> Vec<&'a Expression>
1425where
1426 F: Fn(&Expression) -> bool,
1427{
1428 walk_in_scope(expression, bfs)
1429 .filter(|e| predicate(e))
1430 .collect()
1431}
1432
1433pub fn traverse_scope(expression: &Expression) -> Vec<Scope> {
1443 match expression {
1444 Expression::Select(_)
1445 | Expression::Union(_)
1446 | Expression::Intersect(_)
1447 | Expression::Except(_)
1448 | Expression::Prepare(_)
1449 | Expression::CreateTable(_) => {
1450 let root = build_scope(expression);
1451 root.traverse().into_iter().cloned().collect()
1452 }
1453 _ => Vec::new(),
1454 }
1455}
1456
1457#[cfg(test)]
1458mod tests {
1459 use super::*;
1460 use crate::parser::Parser;
1461
1462 fn parse_and_build_scope(sql: &str) -> Scope {
1463 let ast = Parser::parse_sql(sql).expect("Failed to parse SQL");
1464 build_scope(&ast[0])
1465 }
1466
1467 #[test]
1468 fn unaliased_join_members_are_visible_to_following_lateral_relations() {
1469 let scope = parse_and_build_scope(
1470 "SELECT d.id FROM alpha a JOIN (beta b JOIN gamma c ON b.id = c.id) \
1471 ON a.id = b.id CROSS JOIN LATERAL (SELECT c.id) AS d",
1472 );
1473 assert!(scope.sources.contains_key("a"));
1474 assert!(scope.sources.contains_key("b"));
1475 assert!(scope.sources.contains_key("c"));
1476 let lateral = scope.derived_table_scopes.last().expect("lateral scope");
1477 assert!(lateral.is_lateral);
1478 assert_eq!(
1479 lateral
1480 .lateral_sources
1481 .keys()
1482 .map(String::as_str)
1483 .collect::<HashSet<_>>(),
1484 HashSet::from(["a", "b", "c"]),
1485 );
1486 }
1487
1488 #[test]
1489 fn aliased_join_group_hides_member_bindings_from_its_parent() {
1490 let scope = parse_and_build_scope(
1491 "SELECT grouped.id FROM (beta b JOIN gamma c ON b.id = c.id) AS grouped",
1492 );
1493 assert_eq!(scope.sources.len(), 1);
1494 assert!(scope.sources.contains_key("grouped"));
1495 let group = scope
1496 .derived_table_scopes
1497 .first()
1498 .expect("join group scope");
1499 assert!(group.sources.contains_key("b"));
1500 assert!(group.sources.contains_key("c"));
1501 }
1502
1503 #[test]
1504 fn test_simple_select_scope() {
1505 let mut scope = parse_and_build_scope("SELECT a, b FROM t");
1506
1507 assert!(scope.is_root());
1508 assert!(!scope.can_be_correlated);
1509 assert!(scope.sources.contains_key("t"));
1510
1511 let columns = scope.columns();
1512 assert_eq!(columns.len(), 2);
1513 }
1514
1515 #[test]
1516 fn test_derived_table_scope() {
1517 let mut scope = parse_and_build_scope("SELECT x.a FROM (SELECT a FROM t) AS x");
1518
1519 assert!(scope.sources.contains_key("x"));
1520 assert_eq!(scope.derived_table_scopes.len(), 1);
1521
1522 let derived = &mut scope.derived_table_scopes[0];
1523 assert!(derived.is_derived_table());
1524 assert!(derived.sources.contains_key("t"));
1525 }
1526
1527 #[test]
1528 fn test_lateral_preceding_sources_472() {
1529 let scope = parse_and_build_scope(
1530 "WITH c AS (SELECT a FROM t) SELECT n.a FROM t, LATERAL (SELECT t.a) n, c",
1531 );
1532 let lateral = &scope.derived_table_scopes[0];
1533 assert!(lateral.is_lateral);
1534 assert!(lateral.can_be_correlated);
1535 assert_eq!(lateral.lateral_sources.len(), 1);
1536 assert!(lateral.lateral_sources.contains_key("t"));
1537 assert!(!lateral.sources.contains_key("t"));
1538 let scope = parse_and_build_scope("SELECT n.a FROM t, (SELECT t.a) n");
1539 assert!(!scope.derived_table_scopes[0].is_lateral);
1540 assert!(scope.derived_table_scopes[0].lateral_sources.is_empty());
1541 }
1542
1543 #[test]
1544 fn test_subquery_collection_respects_relation_boundaries() {
1545 let scope = parse_and_build_scope(
1546 "SELECT t.a FROM t JOIN (SELECT a FROM s) ON t.a = 1 \
1547 WHERE EXISTS (SELECT 1 FROM u) ORDER BY (SELECT MAX(a) FROM v)",
1548 );
1549 assert_eq!(scope.derived_table_scopes.len(), 1);
1550 assert_eq!(scope.subquery_scopes.len(), 2);
1551 let scope = parse_and_build_scope(
1552 "SELECT t.a FROM t JOIN s ON EXISTS (SELECT 1 FROM u WHERE u.a = t.a)",
1553 );
1554 assert_eq!(scope.subquery_scopes.len(), 1);
1555 assert!(scope.subquery_scopes[0].sources.contains_key("u"));
1556 }
1557
1558 #[test]
1559 fn test_non_correlated_subquery() {
1560 let mut scope = parse_and_build_scope("SELECT * FROM t WHERE EXISTS (SELECT b FROM s)");
1561
1562 assert_eq!(scope.subquery_scopes.len(), 1);
1563
1564 let subquery = &mut scope.subquery_scopes[0];
1565 assert!(subquery.is_subquery());
1566 assert!(subquery.can_be_correlated);
1567
1568 assert!(subquery.sources.contains_key("s"));
1570 assert!(!subquery.is_correlated_subquery());
1571 }
1572
1573 #[test]
1574 fn test_correlated_subquery() {
1575 let mut scope =
1576 parse_and_build_scope("SELECT * FROM t WHERE EXISTS (SELECT b FROM s WHERE s.x = t.y)");
1577
1578 assert_eq!(scope.subquery_scopes.len(), 1);
1579
1580 let subquery = &mut scope.subquery_scopes[0];
1581 assert!(subquery.is_subquery());
1582 assert!(subquery.can_be_correlated);
1583
1584 let external = subquery.external_columns();
1586 assert!(!external.is_empty());
1587 assert!(external.iter().any(|c| c.table.as_deref() == Some("t")));
1588 assert!(subquery.is_correlated_subquery());
1589 }
1590
1591 #[test]
1592 fn test_cte_scope() {
1593 let scope = parse_and_build_scope("WITH cte AS (SELECT a FROM t) SELECT * FROM cte");
1594
1595 assert_eq!(scope.cte_scopes.len(), 1);
1596 assert!(scope.cte_sources.contains_key("cte"));
1597
1598 let cte = &scope.cte_scopes[0];
1599 assert!(cte.is_cte());
1600 }
1601
1602 #[test]
1603 fn test_multiple_sources() {
1604 let scope = parse_and_build_scope("SELECT t.a, s.b FROM t JOIN s ON t.id = s.id");
1605
1606 assert!(scope.sources.contains_key("t"));
1607 assert!(scope.sources.contains_key("s"));
1608 assert_eq!(scope.sources.len(), 2);
1609 }
1610
1611 #[test]
1612 fn test_aliased_table() {
1613 let scope = parse_and_build_scope("SELECT x.a FROM t AS x");
1614
1615 assert!(scope.sources.contains_key("x"));
1617 assert!(!scope.sources.contains_key("t"));
1618 }
1619
1620 #[test]
1621 fn test_local_columns() {
1622 let mut scope = parse_and_build_scope("SELECT t.a, t.b, s.c FROM t JOIN s ON t.id = s.id");
1623
1624 let local = scope.local_columns();
1625 assert_eq!(local.len(), 5);
1628 assert!(local.iter().all(|c| c.table.is_some()));
1629 }
1630
1631 #[test]
1632 fn test_columns_include_join_on_clause_references() {
1633 let mut scope = parse_and_build_scope(
1634 "SELECT o.total FROM orders o JOIN customers c ON c.id = o.customer_id",
1635 );
1636
1637 let cols: Vec<String> = scope
1638 .columns()
1639 .iter()
1640 .map(|c| match &c.table {
1641 Some(t) => format!("{}.{}", t, c.name),
1642 None => c.name.clone(),
1643 })
1644 .collect();
1645
1646 assert!(cols.contains(&"o.total".to_string()));
1647 assert!(cols.contains(&"c.id".to_string()));
1648 assert!(cols.contains(&"o.customer_id".to_string()));
1649 }
1650
1651 #[test]
1652 fn test_unqualified_columns() {
1653 let mut scope = parse_and_build_scope("SELECT a, b, t.c FROM t");
1654
1655 let unqualified = scope.unqualified_columns();
1656 assert_eq!(unqualified.len(), 2);
1658 assert!(unqualified.iter().all(|c| c.table.is_none()));
1659 }
1660
1661 #[test]
1662 fn test_source_columns() {
1663 let mut scope = parse_and_build_scope("SELECT t.a, t.b, s.c FROM t JOIN s ON t.id = s.id");
1664
1665 let t_cols = scope.source_columns("t");
1666 assert!(t_cols.len() >= 2);
1668 assert!(t_cols.iter().all(|c| c.table.as_deref() == Some("t")));
1669
1670 let s_cols = scope.source_columns("s");
1671 assert!(s_cols.len() >= 1);
1673 assert!(s_cols.iter().all(|c| c.table.as_deref() == Some("s")));
1674 }
1675
1676 #[test]
1677 fn test_rename_source() {
1678 let mut scope = parse_and_build_scope("SELECT a FROM t");
1679
1680 assert!(scope.sources.contains_key("t"));
1681 scope.rename_source("t", "new_name".to_string());
1682 assert!(!scope.sources.contains_key("t"));
1683 assert!(scope.sources.contains_key("new_name"));
1684 }
1685
1686 #[test]
1687 fn test_remove_source() {
1688 let mut scope = parse_and_build_scope("SELECT a FROM t");
1689
1690 assert!(scope.sources.contains_key("t"));
1691 scope.remove_source("t");
1692 assert!(!scope.sources.contains_key("t"));
1693 }
1694
1695 #[test]
1696 fn test_walk_in_scope() {
1697 let ast = Parser::parse_sql("SELECT a, b FROM t WHERE a > 1").expect("Failed to parse");
1698 let expr = &ast[0];
1699
1700 let walked: Vec<_> = walk_in_scope(expr, true).collect();
1702 assert!(!walked.is_empty());
1703
1704 assert!(walked.iter().any(|e| matches!(e, Expression::Select(_))));
1706 assert!(walked.iter().any(|e| matches!(e, Expression::Column(_))));
1708 }
1709
1710 #[test]
1711 fn test_find_in_scope() {
1712 let ast = Parser::parse_sql("SELECT a, b FROM t WHERE a > 1").expect("Failed to parse");
1713 let expr = &ast[0];
1714
1715 let found = find_in_scope(expr, |e| matches!(e, Expression::Column(_)), true);
1717 assert!(found.is_some());
1718 assert!(matches!(found.unwrap(), Expression::Column(_)));
1719 }
1720
1721 #[test]
1722 fn test_find_all_in_scope() {
1723 let ast = Parser::parse_sql("SELECT a, b, c FROM t").expect("Failed to parse");
1724 let expr = &ast[0];
1725
1726 let found = find_all_in_scope(expr, |e| matches!(e, Expression::Column(_)), true);
1728 assert_eq!(found.len(), 3);
1729 }
1730
1731 #[test]
1732 fn test_traverse_scope() {
1733 let ast =
1734 Parser::parse_sql("SELECT a FROM (SELECT b FROM t) AS x").expect("Failed to parse");
1735 let expr = &ast[0];
1736
1737 let scopes = traverse_scope(expr);
1738 assert!(!scopes.is_empty());
1741 assert!(scopes.iter().any(|s| s.is_root()));
1743 }
1744
1745 #[test]
1746 fn test_branch_with_options() {
1747 let ast = Parser::parse_sql("SELECT a FROM t").expect("Failed to parse");
1748 let scope = build_scope(&ast[0]);
1749
1750 let child = scope.branch_with_options(
1751 ast[0].clone(),
1752 ScopeType::Subquery, None,
1754 None,
1755 Some(vec!["col1".to_string(), "col2".to_string()]),
1756 );
1757
1758 assert_eq!(child.outer_columns, vec!["col1", "col2"]);
1759 assert!(child.can_be_correlated); }
1761
1762 #[test]
1763 fn test_is_udtf() {
1764 let ast = Parser::parse_sql("SELECT a FROM t").expect("Failed to parse");
1765 let scope = Scope::new(ast[0].clone());
1766 assert!(!scope.is_udtf());
1767
1768 let root = build_scope(&ast[0]);
1769 let udtf_scope = root.branch(ast[0].clone(), ScopeType::Udtf);
1770 assert!(udtf_scope.is_udtf());
1771 }
1772
1773 #[test]
1774 fn test_is_union() {
1775 let scope = parse_and_build_scope("SELECT a FROM t UNION SELECT b FROM s");
1776
1777 assert!(scope.is_root());
1778 assert_eq!(scope.union_scopes.len(), 2);
1779 assert!(scope.union_scopes[0].is_union());
1781 assert!(scope.union_scopes[1].is_union());
1782 }
1783
1784 #[test]
1785 fn test_union_output_columns() {
1786 let scope = parse_and_build_scope(
1787 "SELECT id, name FROM customers UNION ALL SELECT id, name FROM employees",
1788 );
1789 assert_eq!(scope.output_columns(), vec!["id", "name"]);
1790 }
1791
1792 #[test]
1793 fn test_clear_cache() {
1794 let mut scope = parse_and_build_scope("SELECT t.a FROM t");
1795
1796 let _ = scope.columns();
1798 assert!(scope.columns_cache.is_some());
1799
1800 scope.clear_cache();
1802 assert!(scope.columns_cache.is_none());
1803 assert!(scope.external_columns_cache.is_none());
1804 }
1805
1806 #[test]
1807 fn test_scope_traverse() {
1808 let scope = parse_and_build_scope(
1809 "WITH cte AS (SELECT a FROM t) SELECT * FROM cte WHERE EXISTS (SELECT b FROM s)",
1810 );
1811
1812 let traversed = scope.traverse();
1813 assert!(traversed.len() >= 3);
1815 }
1816
1817 #[test]
1818 fn test_create_table_as_select_scope() {
1819 let scope = parse_and_build_scope("CREATE TABLE out_table AS SELECT 1 AS id FROM src");
1821 assert!(
1822 scope.sources.contains_key("src"),
1823 "CTAS scope should contain the FROM table"
1824 );
1825 assert!(
1826 !scope.sources.contains_key("out_table"),
1827 "CTAS target table should not be treated as a source"
1828 );
1829
1830 let scope = parse_and_build_scope(
1832 "CREATE TABLE out_table AS SELECT a.id FROM foo AS a JOIN bar AS b ON a.id = b.id",
1833 );
1834 assert!(scope.sources.contains_key("a"));
1835 assert!(scope.sources.contains_key("b"));
1836 assert!(
1837 !scope.sources.contains_key("out_table"),
1838 "CTAS target table should not be treated as a source"
1839 );
1840
1841 let scope = parse_and_build_scope(
1843 "CREATE TABLE out_table AS WITH cte AS (SELECT 1 AS id FROM src) SELECT * FROM cte",
1844 );
1845 assert!(
1846 scope.sources.contains_key("cte"),
1847 "CTAS with CTE should resolve CTE as source"
1848 );
1849 assert!(
1850 !scope.sources.contains_key("out_table"),
1851 "CTAS target table should not be treated as a source"
1852 );
1853 assert_eq!(scope.cte_scopes.len(), 1);
1854 }
1855
1856 #[test]
1857 fn test_create_table_as_select_traverse() {
1858 let ast = Parser::parse_sql("CREATE TABLE t AS SELECT a FROM src").unwrap();
1859 let scopes = traverse_scope(&ast[0]);
1860 assert!(
1861 !scopes.is_empty(),
1862 "traverse_scope should return scopes for CTAS"
1863 );
1864 }
1865}