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) => Some(
80 table
81 .alias
82 .as_ref()
83 .unwrap_or(&table.name)
84 .name
85 .to_lowercase(),
86 ),
87 _ => None,
88 })
89 .collect();
90 let mut selected = Scope::new(query.clone());
91 selected.cte_sources = scope.cte_sources.clone();
92 selected.sources = scope
93 .sources
94 .iter()
95 .filter(|(name, source)| {
96 source.kind != SourceKind::Cte || aliases.contains(&name.to_lowercase())
97 })
98 .map(|(name, source)| (name.clone(), source.clone()))
99 .collect();
100 selected
101}
102
103#[derive(Debug, Clone)]
105pub struct SourceInfo {
106 pub expression: Expression,
108 pub is_scope: bool,
110 pub kind: SourceKind,
112 pub alias: Option<String>,
114 pub lineage_name: Option<String>,
116}
117
118impl SourceInfo {
119 pub fn new(expression: Expression, is_scope: bool, kind: SourceKind) -> Self {
120 Self {
121 expression,
122 is_scope,
123 kind,
124 alias: None,
125 lineage_name: None,
126 }
127 }
128
129 pub fn with_alias(mut self, alias: impl Into<String>) -> Self {
130 self.alias = Some(alias.into());
131 self
132 }
133
134 pub fn with_lineage_name(mut self, lineage_name: impl Into<String>) -> Self {
135 self.lineage_name = Some(lineage_name.into());
136 self
137 }
138}
139
140#[derive(Debug, Clone, PartialEq, Eq, Hash)]
142pub struct ColumnRef {
143 pub table: Option<String>,
145 pub name: String,
147}
148
149#[derive(Debug, Clone)]
154pub struct Scope {
155 pub expression: Expression,
157
158 pub scope_type: ScopeType,
160
161 pub sources: HashMap<String, SourceInfo>,
163
164 pub lateral_sources: HashMap<String, SourceInfo>,
166
167 pub cte_sources: HashMap<String, SourceInfo>,
169
170 pub outer_columns: Vec<String>,
173
174 pub can_be_correlated: 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 subquery_scopes: Vec::new(),
215 derived_table_scopes: Vec::new(),
216 cte_scopes: Vec::new(),
217 udtf_scopes: Vec::new(),
218 table_scopes: Vec::new(),
219 union_scopes: Vec::new(),
220 columns_cache: None,
221 external_columns_cache: None,
222 }
223 }
224
225 pub fn branch(&self, expression: Expression, scope_type: ScopeType) -> Self {
227 self.branch_with_options(expression, scope_type, None, None, None)
228 }
229
230 pub fn branch_with_options(
232 &self,
233 expression: Expression,
234 scope_type: ScopeType,
235 sources: Option<HashMap<String, SourceInfo>>,
236 lateral_sources: Option<HashMap<String, SourceInfo>>,
237 outer_columns: Option<Vec<String>>,
238 ) -> Self {
239 let can_be_correlated = self.can_be_correlated
240 || scope_type == ScopeType::Subquery
241 || scope_type == ScopeType::Udtf;
242
243 Self {
244 expression,
245 scope_type,
246 sources: sources.unwrap_or_default(),
247 lateral_sources: lateral_sources.unwrap_or_default(),
248 cte_sources: self.cte_sources.clone(),
249 outer_columns: outer_columns.unwrap_or_default(),
250 can_be_correlated,
251 subquery_scopes: Vec::new(),
252 derived_table_scopes: Vec::new(),
253 cte_scopes: Vec::new(),
254 udtf_scopes: Vec::new(),
255 table_scopes: Vec::new(),
256 union_scopes: Vec::new(),
257 columns_cache: None,
258 external_columns_cache: None,
259 }
260 }
261
262 pub fn clear_cache(&mut self) {
264 self.columns_cache = None;
265 self.external_columns_cache = None;
266 }
267
268 pub fn add_source(&mut self, name: String, expression: Expression, is_scope: bool) {
270 let kind = if is_scope {
271 SourceKind::DerivedTable
272 } else {
273 SourceKind::Table
274 };
275 self.add_source_info(name, SourceInfo::new(expression, is_scope, kind));
276 }
277
278 pub fn add_source_info(&mut self, name: String, info: SourceInfo) {
280 self.sources.insert(name, info);
281 self.clear_cache();
282 }
283
284 pub fn add_virtual_source(&mut self, alias: String, expression: Expression) {
286 let lineage_name = self.next_virtual_source_name();
287 let info = SourceInfo::new(expression, false, SourceKind::Virtual)
288 .with_alias(alias.clone())
289 .with_lineage_name(lineage_name);
290 self.add_source_info(alias, info);
291 }
292
293 fn next_virtual_source_name(&self) -> String {
294 let count = self
295 .sources
296 .values()
297 .filter(|source| source.kind == SourceKind::Virtual)
298 .count();
299 format!("_{}", count)
300 }
301
302 pub fn add_lateral_source(&mut self, name: String, expression: Expression, is_scope: bool) {
304 let kind = if is_scope {
305 SourceKind::DerivedTable
306 } else {
307 SourceKind::Table
308 };
309 let info = SourceInfo::new(expression.clone(), is_scope, kind);
310 self.sources.insert(name.clone(), info.clone());
311 self.lateral_sources.insert(name, info);
312 self.clear_cache();
313 }
314
315 pub fn add_cte_source(&mut self, name: String, expression: Expression) {
317 let info = SourceInfo::new(expression, true, SourceKind::Cte);
318 self.cte_sources.insert(name.clone(), info.clone());
319 self.sources.insert(name, info);
320 self.clear_cache();
321 }
322
323 pub fn rename_source(&mut self, old_name: &str, new_name: String) {
325 if let Some(source) = self.sources.remove(old_name) {
326 self.sources.insert(new_name, source);
327 }
328 self.clear_cache();
329 }
330
331 pub fn remove_source(&mut self, name: &str) {
333 self.sources.remove(name);
334 self.clear_cache();
335 }
336
337 pub fn columns(&mut self) -> &[ColumnRef] {
339 if self.columns_cache.is_none() {
340 let mut columns = Vec::new();
341 collect_columns(&self.expression, &mut columns);
342 self.columns_cache = Some(columns);
343 }
344 self.columns_cache.as_ref().unwrap()
345 }
346
347 pub fn output_columns(&self) -> Vec<String> {
352 crate::ast_transforms::get_output_column_names(&self.expression)
353 }
354
355 pub fn source_names(&self) -> HashSet<String> {
357 let mut names: HashSet<String> = self.sources.keys().cloned().collect();
358 names.extend(self.cte_sources.keys().cloned());
359 names
360 }
361
362 pub fn external_columns(&mut self) -> Vec<ColumnRef> {
364 if self.external_columns_cache.is_some() {
365 return self.external_columns_cache.clone().unwrap();
366 }
367
368 let source_names = self.source_names();
369 let columns = self.columns().to_vec();
370
371 let external: Vec<ColumnRef> = columns
372 .into_iter()
373 .filter(|col| {
374 match &col.table {
376 Some(table) => !source_names.contains(table),
377 None => false, }
379 })
380 .collect();
381
382 self.external_columns_cache = Some(external.clone());
383 external
384 }
385
386 pub fn local_columns(&mut self) -> Vec<ColumnRef> {
388 let external_set: HashSet<_> = self.external_columns().into_iter().collect();
389 let columns = self.columns().to_vec();
390
391 columns
392 .into_iter()
393 .filter(|col| !external_set.contains(col))
394 .collect()
395 }
396
397 pub fn unqualified_columns(&mut self) -> Vec<ColumnRef> {
399 self.columns()
400 .iter()
401 .filter(|c| c.table.is_none())
402 .cloned()
403 .collect()
404 }
405
406 pub fn source_columns(&mut self, source_name: &str) -> Vec<ColumnRef> {
408 self.columns()
409 .iter()
410 .filter(|col| col.table.as_deref() == Some(source_name))
411 .cloned()
412 .collect()
413 }
414
415 pub fn is_correlated_subquery(&mut self) -> bool {
421 self.can_be_correlated && !self.external_columns().is_empty()
422 }
423
424 pub fn is_subquery(&self) -> bool {
426 self.scope_type == ScopeType::Subquery
427 }
428
429 pub fn is_derived_table(&self) -> bool {
431 self.scope_type == ScopeType::DerivedTable
432 }
433
434 pub fn is_cte(&self) -> bool {
436 self.scope_type == ScopeType::Cte
437 }
438
439 pub fn is_root(&self) -> bool {
441 self.scope_type == ScopeType::Root
442 }
443
444 pub fn is_udtf(&self) -> bool {
446 self.scope_type == ScopeType::Udtf
447 }
448
449 pub fn is_union(&self) -> bool {
451 self.scope_type == ScopeType::SetOperation
452 }
453
454 pub fn traverse(&self) -> Vec<&Scope> {
456 let mut result = Vec::new();
457 self.traverse_impl(&mut result);
458 result
459 }
460
461 fn traverse_impl<'a>(&'a self, result: &mut Vec<&'a Scope>) {
462 for scope in &self.cte_scopes {
464 scope.traverse_impl(result);
465 }
466 for scope in &self.union_scopes {
467 scope.traverse_impl(result);
468 }
469 for scope in &self.table_scopes {
470 scope.traverse_impl(result);
471 }
472 for scope in &self.subquery_scopes {
473 scope.traverse_impl(result);
474 }
475 result.push(self);
477 }
478
479 pub fn ref_count(&self) -> HashMap<usize, usize> {
481 let mut counts: HashMap<usize, usize> = HashMap::new();
482
483 for scope in self.traverse() {
484 for (_, source_info) in scope.sources.iter() {
485 if source_info.is_scope {
486 let id = &source_info.expression as *const _ as usize;
487 *counts.entry(id).or_insert(0) += 1;
488 }
489 }
490 }
491
492 counts
493 }
494}
495
496fn collect_columns(expr: &Expression, columns: &mut Vec<ColumnRef>) {
498 match expr {
499 Expression::Column(col) => {
500 columns.push(ColumnRef {
501 table: col.table.as_ref().map(|t| t.name.clone()),
502 name: col.name.name.clone(),
503 });
504 }
505 Expression::Select(select) => {
506 for e in &select.expressions {
508 collect_columns(e, columns);
509 }
510 for join in &select.joins {
512 if let Some(on) = &join.on {
513 collect_columns(on, columns);
514 }
515 if let Some(match_condition) = &join.match_condition {
516 collect_columns(match_condition, columns);
517 }
518 }
519 if let Some(where_clause) = &select.where_clause {
521 collect_columns(&where_clause.this, columns);
522 }
523 if let Some(having) = &select.having {
525 collect_columns(&having.this, columns);
526 }
527 if let Some(order_by) = &select.order_by {
529 for ord in &order_by.expressions {
530 collect_columns(&ord.this, columns);
531 }
532 }
533 if let Some(group_by) = &select.group_by {
535 for e in &group_by.expressions {
536 collect_columns(e, columns);
537 }
538 }
539 }
542 Expression::And(bin)
544 | Expression::Or(bin)
545 | Expression::Add(bin)
546 | Expression::Sub(bin)
547 | Expression::Mul(bin)
548 | Expression::Div(bin)
549 | Expression::Mod(bin)
550 | Expression::Eq(bin)
551 | Expression::Neq(bin)
552 | Expression::Lt(bin)
553 | Expression::Lte(bin)
554 | Expression::Gt(bin)
555 | Expression::Gte(bin)
556 | Expression::BitwiseAnd(bin)
557 | Expression::BitwiseOr(bin)
558 | Expression::BitwiseXor(bin)
559 | Expression::Concat(bin) => {
560 collect_columns(&bin.left, columns);
561 collect_columns(&bin.right, columns);
562 }
563 Expression::Like(like) | Expression::ILike(like) => {
565 collect_columns(&like.left, columns);
566 collect_columns(&like.right, columns);
567 if let Some(escape) = &like.escape {
568 collect_columns(escape, columns);
569 }
570 }
571 Expression::Not(un) | Expression::Neg(un) | Expression::BitwiseNot(un) => {
573 collect_columns(&un.this, columns);
574 }
575 Expression::Function(func) => {
576 for arg in &func.args {
577 collect_columns(arg, columns);
578 }
579 }
580 Expression::AggregateFunction(agg) => {
581 for arg in &agg.args {
582 collect_columns(arg, columns);
583 }
584 }
585 Expression::WindowFunction(wf) => {
586 collect_columns(&wf.this, columns);
587 for e in &wf.over.partition_by {
588 collect_columns(e, columns);
589 }
590 for e in &wf.over.order_by {
591 collect_columns(&e.this, columns);
592 }
593 }
594 Expression::Alias(alias) => {
595 collect_columns(&alias.this, columns);
596 }
597 Expression::Case(case) => {
598 if let Some(operand) = &case.operand {
599 collect_columns(operand, columns);
600 }
601 for (when_expr, then_expr) in &case.whens {
602 collect_columns(when_expr, columns);
603 collect_columns(then_expr, columns);
604 }
605 if let Some(else_clause) = &case.else_ {
606 collect_columns(else_clause, columns);
607 }
608 }
609 Expression::Paren(paren) => {
610 collect_columns(&paren.this, columns);
611 }
612 Expression::Ordered(ord) => {
613 collect_columns(&ord.this, columns);
614 }
615 Expression::In(in_expr) => {
616 collect_columns(&in_expr.this, columns);
617 for e in &in_expr.expressions {
618 collect_columns(e, columns);
619 }
620 }
622 Expression::Between(between) => {
623 collect_columns(&between.this, columns);
624 collect_columns(&between.low, columns);
625 collect_columns(&between.high, columns);
626 }
627 Expression::IsNull(is_null) => {
628 collect_columns(&is_null.this, columns);
629 }
630 Expression::Cast(cast) => {
631 collect_columns(&cast.this, columns);
632 }
633 Expression::Extract(extract) => {
634 collect_columns(&extract.this, columns);
635 }
636 Expression::Exists(_) | Expression::Subquery(_) => {
637 }
639 Expression::Prepare(prepare) => {
640 collect_columns(&prepare.statement, columns);
641 }
642 _ => {
643 }
645 }
646}
647
648pub fn build_scope(expression: &Expression) -> Scope {
653 build_scope_with_ctes(expression, &HashMap::new())
654}
655
656pub(crate) fn build_scope_with_ctes(
658 expression: &Expression,
659 ctes: &HashMap<String, SourceInfo>,
660) -> Scope {
661 let mut root = Scope::new(expression.clone());
662 root.cte_sources = ctes.clone();
663 build_scope_impl(expression, &mut root);
664 root
665}
666
667fn build_scope_impl(expression: &Expression, current_scope: &mut Scope) {
668 match expression {
669 Expression::Prepare(prepare) => {
670 build_scope_impl(&prepare.statement, current_scope);
671 }
672 Expression::Select(select) => {
673 if let Some(with) = &select.with {
675 process_ctes(with, current_scope);
676 }
677
678 if let Some(from) = &select.from {
680 for table in &from.expressions {
681 add_table_to_scope(table, current_scope);
682 }
683 }
684
685 for join in &select.joins {
687 add_table_to_scope(&join.this, current_scope);
688 }
689
690 for lateral_view in &select.lateral_views {
692 add_lateral_view_to_scope(lateral_view, current_scope);
693 }
694
695 collect_subqueries(expression, current_scope);
697 }
698 Expression::Union(union) => {
699 if let Some(with) = &union.with {
700 process_ctes(with, current_scope);
701 }
702
703 let mut left_scope = current_scope.branch(union.left.clone(), ScopeType::SetOperation);
704 build_scope_impl(&union.left, &mut left_scope);
705
706 let mut right_scope =
707 current_scope.branch(union.right.clone(), ScopeType::SetOperation);
708 build_scope_impl(&union.right, &mut right_scope);
709
710 current_scope.union_scopes.push(left_scope);
711 current_scope.union_scopes.push(right_scope);
712 }
713 Expression::Intersect(intersect) => {
714 if let Some(with) = &intersect.with {
715 process_ctes(with, current_scope);
716 }
717
718 let mut left_scope =
719 current_scope.branch(intersect.left.clone(), ScopeType::SetOperation);
720 build_scope_impl(&intersect.left, &mut left_scope);
721
722 let mut right_scope =
723 current_scope.branch(intersect.right.clone(), ScopeType::SetOperation);
724 build_scope_impl(&intersect.right, &mut right_scope);
725
726 current_scope.union_scopes.push(left_scope);
727 current_scope.union_scopes.push(right_scope);
728 }
729 Expression::Except(except) => {
730 if let Some(with) = &except.with {
731 process_ctes(with, current_scope);
732 }
733
734 let mut left_scope = current_scope.branch(except.left.clone(), ScopeType::SetOperation);
735 build_scope_impl(&except.left, &mut left_scope);
736
737 let mut right_scope =
738 current_scope.branch(except.right.clone(), ScopeType::SetOperation);
739 build_scope_impl(&except.right, &mut right_scope);
740
741 current_scope.union_scopes.push(left_scope);
742 current_scope.union_scopes.push(right_scope);
743 }
744 Expression::CreateTable(create) => {
745 if let Some(with) = &create.with_cte {
748 process_ctes(with, current_scope);
749 }
750 if let Some(as_select) = &create.as_select {
752 build_scope_impl(as_select, current_scope);
753 }
754 }
755 Expression::Subquery(subquery) => {
756 build_scope_impl(&subquery.this, current_scope);
757 }
758 Expression::Paren(paren) => {
759 build_scope_impl(&paren.this, current_scope);
760 }
761 _ => {}
762 }
763}
764
765fn process_ctes(with: &crate::expressions::With, current_scope: &mut Scope) {
766 for cte in &with.ctes {
767 let cte_name = cte.alias.name.clone();
768 let cte_expr = Expression::Cte(Box::new(cte.clone()));
769 let mut cte_scope = current_scope.branch(cte_expr.clone(), ScopeType::Cte);
770
771 if with.recursive && cte_body_self_references(cte) {
772 cte_scope.add_cte_source(cte_name.clone(), cte_expr.clone());
773 }
774
775 build_scope_impl(&cte.this, &mut cte_scope);
776 current_scope.add_cte_source(cte_name, cte_expr);
777 current_scope.cte_scopes.push(cte_scope);
778 }
779}
780
781fn cte_body_self_references(cte: &crate::expressions::Cte) -> bool {
782 let cte_name = cte.alias.name.as_str();
783 !cte.this
784 .find_all(|expr| match expr {
785 Expression::Table(table) if table.schema.is_none() && table.catalog.is_none() => {
786 table.name.name.eq_ignore_ascii_case(cte_name)
787 }
788 _ => false,
789 })
790 .is_empty()
791}
792
793fn add_table_to_scope(expr: &Expression, scope: &mut Scope) {
794 match expr {
795 Expression::Table(table) => {
796 let name = table
797 .alias
798 .as_ref()
799 .map(|a| a.name.clone())
800 .unwrap_or_else(|| table.name.name.clone());
801 let cte_source = if table.schema.is_none() && table.catalog.is_none() {
802 scope.cte_sources.get(&table.name.name).or_else(|| {
803 scope
804 .cte_sources
805 .iter()
806 .find(|(cte_name, _)| cte_name.eq_ignore_ascii_case(&table.name.name))
807 .map(|(_, source)| source)
808 })
809 } else {
810 None
811 };
812
813 if let Some(source) = cte_source {
814 scope.add_source_info(name, source.clone());
815 } else {
816 let mut source = SourceInfo::new(expr.clone(), false, SourceKind::Table);
817 if let Some(alias) = &table.alias {
818 source = source.with_alias(alias.name.clone());
819 }
820 scope.add_source_info(name, source);
821 }
822 }
823 Expression::Subquery(subquery) => {
824 let name = subquery
825 .alias
826 .as_ref()
827 .map(|a| a.name.clone())
828 .unwrap_or_default();
829
830 let mut derived_scope = scope.branch(subquery.this.clone(), ScopeType::DerivedTable);
831 build_scope_impl(&subquery.this, &mut derived_scope);
832
833 scope.add_source(name.clone(), expr.clone(), true);
834 scope.derived_table_scopes.push(derived_scope);
835 }
836 Expression::Unnest(unnest) => {
837 if let Some(alias) = &unnest.alias {
838 scope.add_virtual_source(alias.name.clone(), expr.clone());
839 }
840 }
841 Expression::Alias(alias) if matches!(&alias.this, Expression::Unnest(_)) => {
842 scope.add_virtual_source(alias.alias.name.clone(), expr.clone());
843 }
844 Expression::Alias(alias) if is_query_like_relation(&alias.this) => {
845 let outer_columns = alias
846 .column_aliases
847 .iter()
848 .map(|column| column.name.clone())
849 .collect::<Vec<_>>();
850 let mut derived_scope = scope.branch_with_options(
851 alias.this.clone(),
852 ScopeType::DerivedTable,
853 None,
854 None,
855 Some(outer_columns),
856 );
857 build_scope_impl(&alias.this, &mut derived_scope);
858
859 scope.add_source(alias.alias.name.clone(), expr.clone(), true);
860 scope.derived_table_scopes.push(derived_scope);
861 }
862 Expression::Lateral(lateral) => {
863 if let Some(alias) = &lateral.alias {
864 scope.add_virtual_source(alias.clone(), expr.clone());
865 }
866 }
867 Expression::LateralView(lateral_view) => {
868 add_lateral_view_to_scope(lateral_view, scope);
869 }
870 Expression::Pivot(pivot) => {
871 let name =
872 pivot_source_name(&pivot.this, pivot.alias.as_ref().map(|a| a.name.as_str()));
873 scope.add_source_info(
874 name,
875 SourceInfo::new(expr.clone(), false, SourceKind::DerivedTable),
876 );
877 add_pivot_inner_scope(&pivot.this, scope);
878 }
879 Expression::Unpivot(unpivot) => {
880 let name = pivot_source_name(
881 &unpivot.this,
882 unpivot.alias.as_ref().map(|a| a.name.as_str()),
883 );
884 scope.add_source_info(
885 name,
886 SourceInfo::new(expr.clone(), false, SourceKind::DerivedTable),
887 );
888 add_pivot_inner_scope(&unpivot.this, scope);
889 }
890 Expression::Paren(paren) => {
891 add_table_to_scope(&paren.this, scope);
892 }
893 _ => {}
894 }
895}
896
897fn is_query_like_relation(expr: &Expression) -> bool {
898 match expr {
899 Expression::Select(_)
900 | Expression::Subquery(_)
901 | Expression::Union(_)
902 | Expression::Intersect(_)
903 | Expression::Except(_) => true,
904 Expression::Paren(paren) => is_query_like_relation(&paren.this),
905 _ => false,
906 }
907}
908
909fn pivot_source_name(source: &Expression, explicit_alias: Option<&str>) -> String {
910 if let Some(alias) = explicit_alias {
911 return alias.to_string();
912 }
913
914 match source {
915 Expression::Table(table) => table
916 .alias
917 .as_ref()
918 .map(|alias| alias.name.clone())
919 .unwrap_or_else(|| table.name.name.clone()),
920 Expression::Subquery(subquery) => subquery
921 .alias
922 .as_ref()
923 .map(|alias| alias.name.clone())
924 .unwrap_or_else(|| "_0".to_string()),
925 Expression::Paren(paren) => pivot_source_name(&paren.this, explicit_alias),
926 _ => "_0".to_string(),
927 }
928}
929
930fn add_pivot_inner_scope(source: &Expression, scope: &mut Scope) {
931 match source {
932 Expression::Subquery(subquery) => {
933 let mut derived_scope = scope.branch(subquery.this.clone(), ScopeType::DerivedTable);
934 build_scope_impl(&subquery.this, &mut derived_scope);
935 scope.derived_table_scopes.push(derived_scope);
936 }
937 Expression::Paren(paren) => add_pivot_inner_scope(&paren.this, scope),
938 _ => {}
939 }
940}
941
942fn add_lateral_view_to_scope(lateral_view: &crate::expressions::LateralView, scope: &mut Scope) {
943 let alias = lateral_view
944 .table_alias
945 .as_ref()
946 .or_else(|| lateral_view.column_aliases.first())
947 .map(|alias| alias.name.clone());
948
949 if let Some(alias) = alias {
950 scope.add_virtual_source(
951 alias,
952 Expression::LateralView(Box::new(lateral_view.clone())),
953 );
954 }
955}
956
957fn collect_subqueries(expr: &Expression, parent_scope: &mut Scope) {
958 if matches!(expr, Expression::Select(_)) {
959 use crate::ast_children::ChildPathSegment::{Field, Index};
960
961 crate::ast_children::for_each_child(expr, |path, child| {
965 if !matches!(
966 path,
967 [Field("from" | "with" | "lateral_views"), ..]
968 | [Field("joins"), Index(_), Field("this"), ..]
969 ) {
970 collect_subqueries_in_expr(child, parent_scope);
971 }
972 });
973 }
974}
975
976fn collect_subqueries_in_expr(expr: &Expression, parent_scope: &mut Scope) {
977 let mut seen = HashSet::new();
978 for node in walk_in_scope(expr, false) {
979 let query = match node {
980 Expression::Subquery(subquery) if subquery.alias.is_none() => Some(&subquery.this),
981 Expression::Exists(exists) => Some(&exists.this),
982 Expression::In(in_expr) => in_expr.query.as_ref(),
983 Expression::Any(quantified) | Expression::All(quantified) => Some(&quantified.subquery),
984 _ => None,
985 };
986
987 let Some(query) = query else {
988 continue;
989 };
990
991 let key = query as *const Expression as usize;
992 if !seen.insert(key) {
993 continue;
994 }
995
996 let mut sub_scope = parent_scope.branch(query.clone(), ScopeType::Subquery);
997 build_scope_impl(query, &mut sub_scope);
998 parent_scope.subquery_scopes.push(sub_scope);
999 }
1000}
1001
1002pub fn walk_in_scope<'a>(
1014 expression: &'a Expression,
1015 bfs: bool,
1016) -> impl Iterator<Item = &'a Expression> {
1017 WalkInScopeIter::new(expression, bfs)
1018}
1019
1020struct WalkInScopeIter<'a> {
1022 queue: VecDeque<&'a Expression>,
1023 bfs: bool,
1024}
1025
1026impl<'a> WalkInScopeIter<'a> {
1027 fn new(expression: &'a Expression, bfs: bool) -> Self {
1028 let mut queue = VecDeque::new();
1029 queue.push_back(expression);
1030 Self { queue, bfs }
1031 }
1032
1033 fn should_stop_at(&self, expr: &Expression, is_root: bool) -> bool {
1034 if is_root {
1035 return false;
1036 }
1037
1038 if matches!(expr, Expression::Cte(_)) {
1040 return true;
1041 }
1042
1043 if let Expression::Subquery(subquery) = expr {
1045 if subquery.alias.is_some() {
1046 return true;
1047 }
1048 }
1049
1050 if matches!(
1052 expr,
1053 Expression::Select(_)
1054 | Expression::Union(_)
1055 | Expression::Intersect(_)
1056 | Expression::Except(_)
1057 ) {
1058 return true;
1059 }
1060
1061 false
1062 }
1063
1064 fn get_children(&self, expr: &'a Expression) -> Vec<&'a Expression> {
1065 let mut children = Vec::new();
1066
1067 match expr {
1068 Expression::Prepare(prepare) => {
1069 children.push(&prepare.statement);
1070 }
1071 Expression::Select(select) => {
1072 for e in &select.expressions {
1074 children.push(e);
1075 }
1076 if let Some(from) = &select.from {
1078 for table in &from.expressions {
1079 if !self.should_stop_at(table, false) {
1080 children.push(table);
1081 }
1082 }
1083 }
1084 for join in &select.joins {
1086 if !self.should_stop_at(&join.this, false) {
1087 children.push(&join.this);
1088 }
1089 if let Some(on) = &join.on {
1090 children.push(on);
1091 }
1092 if let Some(condition) = &join.match_condition {
1093 children.push(condition);
1094 }
1095 }
1096 if let Some(where_clause) = &select.where_clause {
1098 children.push(&where_clause.this);
1099 }
1100 if let Some(group_by) = &select.group_by {
1102 for e in &group_by.expressions {
1103 children.push(e);
1104 }
1105 }
1106 if let Some(having) = &select.having {
1108 children.push(&having.this);
1109 }
1110 if let Some(qualify) = &select.qualify {
1111 children.push(&qualify.this);
1112 }
1113 if let Some(order_by) = &select.order_by {
1115 for ord in &order_by.expressions {
1116 children.push(&ord.this);
1117 }
1118 }
1119 if let Some(limit) = &select.limit {
1121 children.push(&limit.this);
1122 }
1123 if let Some(offset) = &select.offset {
1125 children.push(&offset.this);
1126 }
1127 }
1128 Expression::And(bin)
1129 | Expression::Or(bin)
1130 | Expression::Add(bin)
1131 | Expression::Sub(bin)
1132 | Expression::Mul(bin)
1133 | Expression::Div(bin)
1134 | Expression::Mod(bin)
1135 | Expression::Eq(bin)
1136 | Expression::Neq(bin)
1137 | Expression::Lt(bin)
1138 | Expression::Lte(bin)
1139 | Expression::Gt(bin)
1140 | Expression::Gte(bin)
1141 | Expression::BitwiseAnd(bin)
1142 | Expression::BitwiseOr(bin)
1143 | Expression::BitwiseXor(bin)
1144 | Expression::Concat(bin) => {
1145 children.push(&bin.left);
1146 children.push(&bin.right);
1147 }
1148 Expression::Like(like) | Expression::ILike(like) => {
1149 children.push(&like.left);
1150 children.push(&like.right);
1151 if let Some(escape) = &like.escape {
1152 children.push(escape);
1153 }
1154 }
1155 Expression::Not(un) | Expression::Neg(un) | Expression::BitwiseNot(un) => {
1156 children.push(&un.this);
1157 }
1158 Expression::Function(func) => {
1159 for arg in &func.args {
1160 children.push(arg);
1161 }
1162 }
1163 Expression::AggregateFunction(agg) => {
1164 for arg in &agg.args {
1165 children.push(arg);
1166 }
1167 }
1168 Expression::WindowFunction(wf) => {
1169 children.push(&wf.this);
1170 for e in &wf.over.partition_by {
1171 children.push(e);
1172 }
1173 for e in &wf.over.order_by {
1174 children.push(&e.this);
1175 }
1176 }
1177 Expression::Alias(alias) => {
1178 children.push(&alias.this);
1179 }
1180 Expression::Case(case) => {
1181 if let Some(operand) = &case.operand {
1182 children.push(operand);
1183 }
1184 for (when_expr, then_expr) in &case.whens {
1185 children.push(when_expr);
1186 children.push(then_expr);
1187 }
1188 if let Some(else_clause) = &case.else_ {
1189 children.push(else_clause);
1190 }
1191 }
1192 Expression::Paren(paren) => {
1193 children.push(&paren.this);
1194 }
1195 Expression::Ordered(ord) => {
1196 children.push(&ord.this);
1197 }
1198 Expression::In(in_expr) => {
1199 children.push(&in_expr.this);
1200 for e in &in_expr.expressions {
1201 children.push(e);
1202 }
1203 }
1205 Expression::Between(between) => {
1206 children.push(&between.this);
1207 children.push(&between.low);
1208 children.push(&between.high);
1209 }
1210 Expression::IsNull(is_null) => {
1211 children.push(&is_null.this);
1212 }
1213 Expression::Cast(cast) => {
1214 children.push(&cast.this);
1215 }
1216 Expression::Extract(extract) => {
1217 children.push(&extract.this);
1218 }
1219 Expression::Coalesce(coalesce) => {
1220 for e in &coalesce.expressions {
1221 children.push(e);
1222 }
1223 }
1224 Expression::NullIf(nullif) => {
1225 children.push(&nullif.this);
1226 children.push(&nullif.expression);
1227 }
1228 Expression::Table(_table) => {
1229 }
1232 Expression::TryCatch(try_catch) => {
1233 for stmt in &try_catch.try_body {
1234 children.push(stmt);
1235 }
1236 if let Some(catch_body) = &try_catch.catch_body {
1237 for stmt in catch_body {
1238 children.push(stmt);
1239 }
1240 }
1241 }
1242 Expression::Column(_) | Expression::Literal(_) | Expression::Identifier(_) => {
1243 }
1245 Expression::Subquery(_) | Expression::Exists(_) => {}
1247 _ => {
1248 children.extend(expr.children());
1252 }
1253 }
1254
1255 children
1256 }
1257}
1258
1259impl<'a> Iterator for WalkInScopeIter<'a> {
1260 type Item = &'a Expression;
1261
1262 fn next(&mut self) -> Option<Self::Item> {
1263 let expr = if self.bfs {
1264 self.queue.pop_front()?
1265 } else {
1266 self.queue.pop_back()?
1267 };
1268
1269 let children = self.get_children(expr);
1271
1272 if self.bfs {
1273 for child in children {
1274 if !self.should_stop_at(child, false) {
1275 self.queue.push_back(child);
1276 }
1277 }
1278 } else {
1279 for child in children.into_iter().rev() {
1280 if !self.should_stop_at(child, false) {
1281 self.queue.push_back(child);
1282 }
1283 }
1284 }
1285
1286 Some(expr)
1287 }
1288}
1289
1290pub fn find_in_scope<'a, F>(
1302 expression: &'a Expression,
1303 predicate: F,
1304 bfs: bool,
1305) -> Option<&'a Expression>
1306where
1307 F: Fn(&Expression) -> bool,
1308{
1309 walk_in_scope(expression, bfs).find(|e| predicate(e))
1310}
1311
1312pub fn find_all_in_scope<'a, F>(
1324 expression: &'a Expression,
1325 predicate: F,
1326 bfs: bool,
1327) -> Vec<&'a Expression>
1328where
1329 F: Fn(&Expression) -> bool,
1330{
1331 walk_in_scope(expression, bfs)
1332 .filter(|e| predicate(e))
1333 .collect()
1334}
1335
1336pub fn traverse_scope(expression: &Expression) -> Vec<Scope> {
1346 match expression {
1347 Expression::Select(_)
1348 | Expression::Union(_)
1349 | Expression::Intersect(_)
1350 | Expression::Except(_)
1351 | Expression::Prepare(_)
1352 | Expression::CreateTable(_) => {
1353 let root = build_scope(expression);
1354 root.traverse().into_iter().cloned().collect()
1355 }
1356 _ => Vec::new(),
1357 }
1358}
1359
1360#[cfg(test)]
1361mod tests {
1362 use super::*;
1363 use crate::parser::Parser;
1364
1365 fn parse_and_build_scope(sql: &str) -> Scope {
1366 let ast = Parser::parse_sql(sql).expect("Failed to parse SQL");
1367 build_scope(&ast[0])
1368 }
1369
1370 #[test]
1371 fn test_simple_select_scope() {
1372 let mut scope = parse_and_build_scope("SELECT a, b FROM t");
1373
1374 assert!(scope.is_root());
1375 assert!(!scope.can_be_correlated);
1376 assert!(scope.sources.contains_key("t"));
1377
1378 let columns = scope.columns();
1379 assert_eq!(columns.len(), 2);
1380 }
1381
1382 #[test]
1383 fn test_derived_table_scope() {
1384 let mut scope = parse_and_build_scope("SELECT x.a FROM (SELECT a FROM t) AS x");
1385
1386 assert!(scope.sources.contains_key("x"));
1387 assert_eq!(scope.derived_table_scopes.len(), 1);
1388
1389 let derived = &mut scope.derived_table_scopes[0];
1390 assert!(derived.is_derived_table());
1391 assert!(derived.sources.contains_key("t"));
1392 }
1393
1394 #[test]
1395 fn test_subquery_collection_respects_relation_boundaries() {
1396 let scope = parse_and_build_scope(
1397 "SELECT t.a FROM t JOIN (SELECT a FROM s) ON t.a = 1 \
1398 WHERE EXISTS (SELECT 1 FROM u) ORDER BY (SELECT MAX(a) FROM v)",
1399 );
1400 assert_eq!(scope.derived_table_scopes.len(), 1);
1401 assert_eq!(scope.subquery_scopes.len(), 2);
1402 let scope = parse_and_build_scope(
1403 "SELECT t.a FROM t JOIN s ON EXISTS (SELECT 1 FROM u WHERE u.a = t.a)",
1404 );
1405 assert_eq!(scope.subquery_scopes.len(), 1);
1406 assert!(scope.subquery_scopes[0].sources.contains_key("u"));
1407 }
1408
1409 #[test]
1410 fn test_non_correlated_subquery() {
1411 let mut scope = parse_and_build_scope("SELECT * FROM t WHERE EXISTS (SELECT b FROM s)");
1412
1413 assert_eq!(scope.subquery_scopes.len(), 1);
1414
1415 let subquery = &mut scope.subquery_scopes[0];
1416 assert!(subquery.is_subquery());
1417 assert!(subquery.can_be_correlated);
1418
1419 assert!(subquery.sources.contains_key("s"));
1421 assert!(!subquery.is_correlated_subquery());
1422 }
1423
1424 #[test]
1425 fn test_correlated_subquery() {
1426 let mut scope =
1427 parse_and_build_scope("SELECT * FROM t WHERE EXISTS (SELECT b FROM s WHERE s.x = t.y)");
1428
1429 assert_eq!(scope.subquery_scopes.len(), 1);
1430
1431 let subquery = &mut scope.subquery_scopes[0];
1432 assert!(subquery.is_subquery());
1433 assert!(subquery.can_be_correlated);
1434
1435 let external = subquery.external_columns();
1437 assert!(!external.is_empty());
1438 assert!(external.iter().any(|c| c.table.as_deref() == Some("t")));
1439 assert!(subquery.is_correlated_subquery());
1440 }
1441
1442 #[test]
1443 fn test_cte_scope() {
1444 let scope = parse_and_build_scope("WITH cte AS (SELECT a FROM t) SELECT * FROM cte");
1445
1446 assert_eq!(scope.cte_scopes.len(), 1);
1447 assert!(scope.cte_sources.contains_key("cte"));
1448
1449 let cte = &scope.cte_scopes[0];
1450 assert!(cte.is_cte());
1451 }
1452
1453 #[test]
1454 fn test_multiple_sources() {
1455 let scope = parse_and_build_scope("SELECT t.a, s.b FROM t JOIN s ON t.id = s.id");
1456
1457 assert!(scope.sources.contains_key("t"));
1458 assert!(scope.sources.contains_key("s"));
1459 assert_eq!(scope.sources.len(), 2);
1460 }
1461
1462 #[test]
1463 fn test_aliased_table() {
1464 let scope = parse_and_build_scope("SELECT x.a FROM t AS x");
1465
1466 assert!(scope.sources.contains_key("x"));
1468 assert!(!scope.sources.contains_key("t"));
1469 }
1470
1471 #[test]
1472 fn test_local_columns() {
1473 let mut scope = parse_and_build_scope("SELECT t.a, t.b, s.c FROM t JOIN s ON t.id = s.id");
1474
1475 let local = scope.local_columns();
1476 assert_eq!(local.len(), 5);
1479 assert!(local.iter().all(|c| c.table.is_some()));
1480 }
1481
1482 #[test]
1483 fn test_columns_include_join_on_clause_references() {
1484 let mut scope = parse_and_build_scope(
1485 "SELECT o.total FROM orders o JOIN customers c ON c.id = o.customer_id",
1486 );
1487
1488 let cols: Vec<String> = scope
1489 .columns()
1490 .iter()
1491 .map(|c| match &c.table {
1492 Some(t) => format!("{}.{}", t, c.name),
1493 None => c.name.clone(),
1494 })
1495 .collect();
1496
1497 assert!(cols.contains(&"o.total".to_string()));
1498 assert!(cols.contains(&"c.id".to_string()));
1499 assert!(cols.contains(&"o.customer_id".to_string()));
1500 }
1501
1502 #[test]
1503 fn test_unqualified_columns() {
1504 let mut scope = parse_and_build_scope("SELECT a, b, t.c FROM t");
1505
1506 let unqualified = scope.unqualified_columns();
1507 assert_eq!(unqualified.len(), 2);
1509 assert!(unqualified.iter().all(|c| c.table.is_none()));
1510 }
1511
1512 #[test]
1513 fn test_source_columns() {
1514 let mut scope = parse_and_build_scope("SELECT t.a, t.b, s.c FROM t JOIN s ON t.id = s.id");
1515
1516 let t_cols = scope.source_columns("t");
1517 assert!(t_cols.len() >= 2);
1519 assert!(t_cols.iter().all(|c| c.table.as_deref() == Some("t")));
1520
1521 let s_cols = scope.source_columns("s");
1522 assert!(s_cols.len() >= 1);
1524 assert!(s_cols.iter().all(|c| c.table.as_deref() == Some("s")));
1525 }
1526
1527 #[test]
1528 fn test_rename_source() {
1529 let mut scope = parse_and_build_scope("SELECT a FROM t");
1530
1531 assert!(scope.sources.contains_key("t"));
1532 scope.rename_source("t", "new_name".to_string());
1533 assert!(!scope.sources.contains_key("t"));
1534 assert!(scope.sources.contains_key("new_name"));
1535 }
1536
1537 #[test]
1538 fn test_remove_source() {
1539 let mut scope = parse_and_build_scope("SELECT a FROM t");
1540
1541 assert!(scope.sources.contains_key("t"));
1542 scope.remove_source("t");
1543 assert!(!scope.sources.contains_key("t"));
1544 }
1545
1546 #[test]
1547 fn test_walk_in_scope() {
1548 let ast = Parser::parse_sql("SELECT a, b FROM t WHERE a > 1").expect("Failed to parse");
1549 let expr = &ast[0];
1550
1551 let walked: Vec<_> = walk_in_scope(expr, true).collect();
1553 assert!(!walked.is_empty());
1554
1555 assert!(walked.iter().any(|e| matches!(e, Expression::Select(_))));
1557 assert!(walked.iter().any(|e| matches!(e, Expression::Column(_))));
1559 }
1560
1561 #[test]
1562 fn test_find_in_scope() {
1563 let ast = Parser::parse_sql("SELECT a, b FROM t WHERE a > 1").expect("Failed to parse");
1564 let expr = &ast[0];
1565
1566 let found = find_in_scope(expr, |e| matches!(e, Expression::Column(_)), true);
1568 assert!(found.is_some());
1569 assert!(matches!(found.unwrap(), Expression::Column(_)));
1570 }
1571
1572 #[test]
1573 fn test_find_all_in_scope() {
1574 let ast = Parser::parse_sql("SELECT a, b, c FROM t").expect("Failed to parse");
1575 let expr = &ast[0];
1576
1577 let found = find_all_in_scope(expr, |e| matches!(e, Expression::Column(_)), true);
1579 assert_eq!(found.len(), 3);
1580 }
1581
1582 #[test]
1583 fn test_traverse_scope() {
1584 let ast =
1585 Parser::parse_sql("SELECT a FROM (SELECT b FROM t) AS x").expect("Failed to parse");
1586 let expr = &ast[0];
1587
1588 let scopes = traverse_scope(expr);
1589 assert!(!scopes.is_empty());
1592 assert!(scopes.iter().any(|s| s.is_root()));
1594 }
1595
1596 #[test]
1597 fn test_branch_with_options() {
1598 let ast = Parser::parse_sql("SELECT a FROM t").expect("Failed to parse");
1599 let scope = build_scope(&ast[0]);
1600
1601 let child = scope.branch_with_options(
1602 ast[0].clone(),
1603 ScopeType::Subquery, None,
1605 None,
1606 Some(vec!["col1".to_string(), "col2".to_string()]),
1607 );
1608
1609 assert_eq!(child.outer_columns, vec!["col1", "col2"]);
1610 assert!(child.can_be_correlated); }
1612
1613 #[test]
1614 fn test_is_udtf() {
1615 let ast = Parser::parse_sql("SELECT a FROM t").expect("Failed to parse");
1616 let scope = Scope::new(ast[0].clone());
1617 assert!(!scope.is_udtf());
1618
1619 let root = build_scope(&ast[0]);
1620 let udtf_scope = root.branch(ast[0].clone(), ScopeType::Udtf);
1621 assert!(udtf_scope.is_udtf());
1622 }
1623
1624 #[test]
1625 fn test_is_union() {
1626 let scope = parse_and_build_scope("SELECT a FROM t UNION SELECT b FROM s");
1627
1628 assert!(scope.is_root());
1629 assert_eq!(scope.union_scopes.len(), 2);
1630 assert!(scope.union_scopes[0].is_union());
1632 assert!(scope.union_scopes[1].is_union());
1633 }
1634
1635 #[test]
1636 fn test_union_output_columns() {
1637 let scope = parse_and_build_scope(
1638 "SELECT id, name FROM customers UNION ALL SELECT id, name FROM employees",
1639 );
1640 assert_eq!(scope.output_columns(), vec!["id", "name"]);
1641 }
1642
1643 #[test]
1644 fn test_clear_cache() {
1645 let mut scope = parse_and_build_scope("SELECT t.a FROM t");
1646
1647 let _ = scope.columns();
1649 assert!(scope.columns_cache.is_some());
1650
1651 scope.clear_cache();
1653 assert!(scope.columns_cache.is_none());
1654 assert!(scope.external_columns_cache.is_none());
1655 }
1656
1657 #[test]
1658 fn test_scope_traverse() {
1659 let scope = parse_and_build_scope(
1660 "WITH cte AS (SELECT a FROM t) SELECT * FROM cte WHERE EXISTS (SELECT b FROM s)",
1661 );
1662
1663 let traversed = scope.traverse();
1664 assert!(traversed.len() >= 3);
1666 }
1667
1668 #[test]
1669 fn test_create_table_as_select_scope() {
1670 let scope = parse_and_build_scope("CREATE TABLE out_table AS SELECT 1 AS id FROM src");
1672 assert!(
1673 scope.sources.contains_key("src"),
1674 "CTAS scope should contain the FROM table"
1675 );
1676 assert!(
1677 !scope.sources.contains_key("out_table"),
1678 "CTAS target table should not be treated as a source"
1679 );
1680
1681 let scope = parse_and_build_scope(
1683 "CREATE TABLE out_table AS SELECT a.id FROM foo AS a JOIN bar AS b ON a.id = b.id",
1684 );
1685 assert!(scope.sources.contains_key("a"));
1686 assert!(scope.sources.contains_key("b"));
1687 assert!(
1688 !scope.sources.contains_key("out_table"),
1689 "CTAS target table should not be treated as a source"
1690 );
1691
1692 let scope = parse_and_build_scope(
1694 "CREATE TABLE out_table AS WITH cte AS (SELECT 1 AS id FROM src) SELECT * FROM cte",
1695 );
1696 assert!(
1697 scope.sources.contains_key("cte"),
1698 "CTAS with CTE should resolve CTE as source"
1699 );
1700 assert!(
1701 !scope.sources.contains_key("out_table"),
1702 "CTAS target table should not be treated as a source"
1703 );
1704 assert_eq!(scope.cte_scopes.len(), 1);
1705 }
1706
1707 #[test]
1708 fn test_create_table_as_select_traverse() {
1709 let ast = Parser::parse_sql("CREATE TABLE t AS SELECT a FROM src").unwrap();
1710 let scopes = traverse_scope(&ast[0]);
1711 assert!(
1712 !scopes.is_empty(),
1713 "traverse_scope should return scopes for CTAS"
1714 );
1715 }
1716}