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