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