1#![cfg_attr(
40 not(any(feature = "ast-tools", feature = "generate", feature = "semantic")),
41 allow(dead_code)
42)]
43
44use crate::expressions::{Expression, TableRef};
45use std::collections::{HashMap, VecDeque};
46
47pub type NodeId = usize;
49
50#[derive(Debug, Clone)]
52pub struct ParentInfo {
53 pub parent_id: Option<NodeId>,
55 pub arg_key: String,
57 pub index: Option<usize>,
59}
60
61#[derive(Debug, Default)]
75pub struct TreeContext {
76 nodes: HashMap<NodeId, ParentInfo>,
78 next_id: NodeId,
80 path: Vec<(NodeId, String, Option<usize>)>,
82}
83
84impl TreeContext {
85 pub fn new() -> Self {
87 Self::default()
88 }
89
90 pub fn build(root: &Expression) -> Self {
92 let mut ctx = Self::new();
93 ctx.visit_expr(root);
94 ctx
95 }
96
97 fn visit_expr(&mut self, expr: &Expression) -> NodeId {
99 let id = self.next_id;
100 self.next_id += 1;
101
102 let parent_info = if let Some((parent_id, arg_key, index)) = self.path.last() {
104 ParentInfo {
105 parent_id: Some(*parent_id),
106 arg_key: arg_key.clone(),
107 index: *index,
108 }
109 } else {
110 ParentInfo {
111 parent_id: None,
112 arg_key: String::new(),
113 index: None,
114 }
115 };
116 self.nodes.insert(id, parent_info);
117
118 crate::ast_children::for_each_child(expr, |child_path, child| {
119 let (key, index) = child_location(child_path);
120 self.path.push((id, key, index));
121 self.visit_expr(child);
122 self.path.pop();
123 });
124
125 id
126 }
127
128 pub fn get(&self, id: NodeId) -> Option<&ParentInfo> {
130 self.nodes.get(&id)
131 }
132
133 pub fn depth_of(&self, id: NodeId) -> usize {
135 let mut depth = 0;
136 let mut current = id;
137 while let Some(info) = self.nodes.get(¤t) {
138 if let Some(parent_id) = info.parent_id {
139 depth += 1;
140 current = parent_id;
141 } else {
142 break;
143 }
144 }
145 depth
146 }
147
148 pub fn ancestors_of(&self, id: NodeId) -> Vec<NodeId> {
150 let mut ancestors = Vec::new();
151 let mut current = id;
152 while let Some(info) = self.nodes.get(¤t) {
153 if let Some(parent_id) = info.parent_id {
154 ancestors.push(parent_id);
155 current = parent_id;
156 } else {
157 break;
158 }
159 }
160 ancestors
161 }
162}
163
164fn child_location(path: &[crate::ast_children::ChildPathSegment]) -> (String, Option<usize>) {
165 use crate::ast_children::ChildPathSegment;
166
167 let mut key = String::new();
168 let mut index = None;
169 for (position, segment) in path.iter().enumerate() {
170 match segment {
171 ChildPathSegment::Field(field) => {
172 if !key.is_empty() {
173 key.push('.');
174 }
175 key.push_str(field);
176 }
177 ChildPathSegment::Index(value) if position + 1 == path.len() => {
178 index = Some(*value);
179 }
180 ChildPathSegment::Index(value) => {
181 key.push('[');
182 key.push_str(&value.to_string());
183 key.push(']');
184 }
185 }
186 }
187 (key, index)
188}
189
190pub struct DfsIter<'a> {
199 stack: Vec<&'a Expression>,
200}
201
202impl<'a> DfsIter<'a> {
203 pub fn new(root: &'a Expression) -> Self {
205 Self { stack: vec![root] }
206 }
207}
208
209impl<'a> Iterator for DfsIter<'a> {
210 type Item = &'a Expression;
211
212 fn next(&mut self) -> Option<Self::Item> {
213 let expr = self.stack.pop()?;
214
215 let child_start = self.stack.len();
216 crate::ast_children::for_each_child_untracked(expr, |child| self.stack.push(child));
217 self.stack[child_start..].reverse();
218
219 Some(expr)
220 }
221}
222
223pub struct BfsIter<'a> {
231 queue: VecDeque<&'a Expression>,
232}
233
234impl<'a> BfsIter<'a> {
235 pub fn new(root: &'a Expression) -> Self {
237 let mut queue = VecDeque::new();
238 queue.push_back(root);
239 Self { queue }
240 }
241}
242
243impl<'a> Iterator for BfsIter<'a> {
244 type Item = &'a Expression;
245
246 fn next(&mut self) -> Option<Self::Item> {
247 let expr = self.queue.pop_front()?;
248
249 crate::ast_children::for_each_child_untracked(expr, |child| self.queue.push_back(child));
250
251 Some(expr)
252 }
253}
254
255pub trait ExpressionWalk {
261 fn dfs(&self) -> DfsIter<'_>;
266
267 fn bfs(&self) -> BfsIter<'_>;
271
272 fn find<F>(&self, predicate: F) -> Option<&Expression>
276 where
277 F: Fn(&Expression) -> bool;
278
279 fn find_all<F>(&self, predicate: F) -> Vec<&Expression>
283 where
284 F: Fn(&Expression) -> bool;
285
286 fn contains<F>(&self, predicate: F) -> bool
288 where
289 F: Fn(&Expression) -> bool;
290
291 fn count<F>(&self, predicate: F) -> usize
293 where
294 F: Fn(&Expression) -> bool;
295
296 fn children(&self) -> Vec<&Expression>;
301
302 fn tree_depth(&self) -> usize;
306
307 #[cfg(any(
314 feature = "transpile",
315 feature = "ast-tools",
316 feature = "generate",
317 feature = "semantic"
318 ))]
319 fn transform_owned<F>(self, fun: F) -> crate::Result<Expression>
320 where
321 F: Fn(Expression) -> crate::Result<Option<Expression>>,
322 Self: Sized;
323}
324
325impl ExpressionWalk for Expression {
326 fn dfs(&self) -> DfsIter<'_> {
327 DfsIter::new(self)
328 }
329
330 fn bfs(&self) -> BfsIter<'_> {
331 BfsIter::new(self)
332 }
333
334 fn find<F>(&self, predicate: F) -> Option<&Expression>
335 where
336 F: Fn(&Expression) -> bool,
337 {
338 self.dfs().find(|e| predicate(e))
339 }
340
341 fn find_all<F>(&self, predicate: F) -> Vec<&Expression>
342 where
343 F: Fn(&Expression) -> bool,
344 {
345 self.dfs().filter(|e| predicate(e)).collect()
346 }
347
348 fn contains<F>(&self, predicate: F) -> bool
349 where
350 F: Fn(&Expression) -> bool,
351 {
352 self.dfs().any(|e| predicate(e))
353 }
354
355 fn count<F>(&self, predicate: F) -> usize
356 where
357 F: Fn(&Expression) -> bool,
358 {
359 self.dfs().filter(|e| predicate(e)).count()
360 }
361
362 fn children(&self) -> Vec<&Expression> {
363 let mut result: Vec<&Expression> = Vec::new();
364 crate::ast_children::for_each_child(self, |_, child| result.push(child));
365 result
366 }
367
368 fn tree_depth(&self) -> usize {
369 let mut max_depth = 0usize;
370 let mut stack = vec![(self, 0usize)];
371 while let Some((node, depth)) = stack.pop() {
372 max_depth = max_depth.max(depth);
373 crate::ast_children::for_each_child(node, |_, child| {
374 stack.push((child, depth + 1));
375 });
376 }
377 max_depth
378 }
379
380 #[cfg(any(
381 feature = "transpile",
382 feature = "ast-tools",
383 feature = "generate",
384 feature = "semantic"
385 ))]
386 fn transform_owned<F>(self, fun: F) -> crate::Result<Expression>
387 where
388 F: Fn(Expression) -> crate::Result<Option<Expression>>,
389 {
390 transform(self, &fun)
391 }
392}
393
394#[cfg(any(
417 feature = "transpile",
418 feature = "ast-tools",
419 feature = "generate",
420 feature = "semantic"
421))]
422pub fn transform<F>(expr: Expression, fun: &F) -> crate::Result<Expression>
423where
424 F: Fn(Expression) -> crate::Result<Option<Expression>>,
425{
426 crate::dialects::transform_recursive(expr, &|e| match fun(e)? {
427 Some(transformed) => Ok(transformed),
428 None => Ok(Expression::Null(crate::expressions::Null)),
429 })
430}
431
432#[cfg(any(
456 feature = "transpile",
457 feature = "ast-tools",
458 feature = "generate",
459 feature = "semantic"
460))]
461pub fn transform_map<F>(expr: Expression, fun: &F) -> crate::Result<Expression>
462where
463 F: Fn(Expression) -> crate::Result<Expression>,
464{
465 crate::dialects::transform_recursive(expr, fun)
466}
467
468#[cfg(any(
483 feature = "transpile",
484 feature = "ast-tools",
485 feature = "generate",
486 feature = "semantic"
487))]
488pub fn transform_all<F>(expr: Expression, fun: &F) -> crate::Result<Expression>
489where
490 F: Fn(Expression) -> crate::Result<Expression>,
491{
492 transform_with_dispatch(expr, fun, &|_| true, &|node, fun| fun(node))
493}
494
495#[cfg(any(
498 feature = "transpile",
499 feature = "ast-tools",
500 feature = "generate",
501 feature = "semantic"
502))]
503pub(crate) fn transform_with_dispatch<F, P, G>(
504 expr: Expression,
505 transform_fn: &F,
506 uses_generated_dispatch: &P,
507 fallback: &G,
508) -> crate::Result<Expression>
509where
510 F: Fn(Expression) -> crate::Result<Expression>,
511 P: Fn(&Expression) -> bool,
512 G: Fn(Expression, &F) -> crate::Result<Expression>,
513{
514 enum Task {
515 Visit(Expression),
516 Finish {
517 shell: Expression,
518 child_count: usize,
519 },
520 }
521
522 let mut tasks = vec![Task::Visit(expr)];
523 let mut results = Vec::new();
524
525 while let Some(task) = tasks.pop() {
526 match task {
527 Task::Visit(mut expression) => {
528 if !uses_generated_dispatch(&expression) {
529 results.push(fallback(expression, transform_fn)?);
530 continue;
531 }
532
533 let mut children = Vec::new();
534 crate::ast_children::for_each_child_mut(&mut expression, |child| {
535 children.push(std::mem::replace(
536 child,
537 Expression::Null(crate::expressions::Null),
538 ));
539 });
540 let child_count = children.len();
541 tasks.push(Task::Finish {
542 shell: expression,
543 child_count,
544 });
545 for child in children.into_iter().rev() {
546 tasks.push(Task::Visit(child));
547 }
548 }
549 Task::Finish {
550 mut shell,
551 child_count,
552 } => {
553 if results.len() < child_count {
554 return Err(crate::error::Error::Internal(
555 "transform result stack underflow".to_string(),
556 ));
557 }
558 let transformed_children = results.split_off(results.len() - child_count);
559 let mut transformed_children = transformed_children.into_iter();
560 crate::ast_children::for_each_child_mut(&mut shell, |child| {
561 *child = transformed_children
562 .next()
563 .expect("validated transform child count");
564 });
565 if transformed_children.next().is_some() {
566 return Err(crate::error::Error::Internal(
567 "transform child restoration mismatch".to_string(),
568 ));
569 }
570 results.push(transform_fn(shell)?);
571 }
572 }
573 }
574
575 match results.len() {
576 1 => Ok(results.pop().expect("single transform result")),
577 _ => Err(crate::error::Error::Internal(
578 "unexpected transform result stack size".to_string(),
579 )),
580 }
581}
582
583pub fn is_column(expr: &Expression) -> bool {
591 matches!(expr, Expression::Column(_))
592}
593
594pub fn is_literal(expr: &Expression) -> bool {
596 matches!(
597 expr,
598 Expression::Literal(_) | Expression::Boolean(_) | Expression::Null(_)
599 )
600}
601
602pub fn is_function(expr: &Expression) -> bool {
604 matches!(
605 expr,
606 Expression::Function(_) | Expression::AggregateFunction(_) | Expression::Hierarchy(_)
607 )
608}
609
610pub fn is_subquery(expr: &Expression) -> bool {
612 matches!(expr, Expression::Subquery(_))
613}
614
615pub fn is_select(expr: &Expression) -> bool {
617 matches!(expr, Expression::Select(_))
618}
619
620pub fn is_aggregate(expr: &Expression) -> bool {
626 matches!(
627 expr,
628 Expression::AggregateFunction(_)
629 | Expression::Count(_)
630 | Expression::Sum(_)
631 | Expression::Avg(_)
632 | Expression::Min(_)
633 | Expression::Max(_)
634 | Expression::GroupConcat(_)
635 | Expression::StringAgg(_)
636 | Expression::ListAgg(_)
637 | Expression::ArrayAgg(_)
638 | Expression::CountIf(_)
639 | Expression::SumIf(_)
640 | Expression::Stddev(_)
641 | Expression::StddevPop(_)
642 | Expression::StddevSamp(_)
643 | Expression::Variance(_)
644 | Expression::VarPop(_)
645 | Expression::VarSamp(_)
646 | Expression::Median(_)
647 | Expression::Mode(_)
648 | Expression::First(_)
649 | Expression::Last(_)
650 | Expression::AnyValue(_)
651 | Expression::ApproxDistinct(_)
652 | Expression::ApproxCountDistinct(_)
653 | Expression::ApproxPercentile(_)
654 | Expression::Percentile(_)
655 | Expression::PercentileCont(_)
656 | Expression::PercentileDisc(_)
657 | Expression::LogicalAnd(_)
658 | Expression::LogicalOr(_)
659 | Expression::Skewness(_)
660 | Expression::ArrayConcatAgg(_)
661 | Expression::ArrayUniqueAgg(_)
662 | Expression::BoolXorAgg(_)
663 | Expression::BitwiseAndAgg(_)
664 | Expression::BitwiseOrAgg(_)
665 | Expression::BitwiseXorAgg(_)
666 | Expression::JsonArrayAgg(_)
667 | Expression::JsonObjectAgg(_)
668 | Expression::JSONArrayAgg(_)
669 | Expression::JSONObjectAgg(_)
670 | Expression::JSONBObjectAgg(_)
671 | Expression::ParameterizedAgg(_)
672 | Expression::ArgMax(_)
673 | Expression::ArgMin(_)
674 | Expression::ApproxTopK(_)
675 | Expression::ApproxTopKAccumulate(_)
676 | Expression::ApproxTopKCombine(_)
677 | Expression::ApproxTopSum(_)
678 | Expression::ApproxQuantiles(_)
679 | Expression::Grouping(_)
680 | Expression::GroupingId(_)
681 | Expression::AnonymousAggFunc(_)
682 | Expression::CombinedAggFunc(_)
683 | Expression::CombinedParameterizedAgg(_)
684 | Expression::HashAgg(_)
685 | Expression::Hll(_)
686 | Expression::Minhash(_)
687 | Expression::ObjectAgg(_)
688 | Expression::AIAgg(_)
689 | Expression::Quantile(_)
690 | Expression::ApproxQuantile(_)
691 | Expression::Corr(_)
692 | Expression::CovarPop(_)
693 | Expression::CovarSamp(_)
694 | Expression::RegrValx(_)
695 | Expression::RegrValy(_)
696 | Expression::RegrAvgx(_)
697 | Expression::RegrAvgy(_)
698 | Expression::RegrCount(_)
699 | Expression::RegrIntercept(_)
700 | Expression::RegrR2(_)
701 | Expression::RegrSxx(_)
702 | Expression::RegrSxy(_)
703 | Expression::RegrSyy(_)
704 | Expression::RegrSlope(_)
705 )
706}
707
708pub fn is_window_function(expr: &Expression) -> bool {
710 matches!(expr, Expression::WindowFunction(_))
711}
712
713pub fn get_columns(expr: &Expression) -> Vec<&Expression> {
717 expr.find_all(is_column)
718}
719
720pub fn get_tables(expr: &Expression) -> Vec<&Expression> {
728 expr.find_all(|e| matches!(e, Expression::Table(_)))
729}
730
731pub fn get_all_tables(expr: &Expression) -> Vec<Expression> {
739 use std::collections::HashSet;
740
741 let mut seen = HashSet::new();
742 let mut result = Vec::new();
743
744 for node in expr.dfs() {
746 if let Expression::Table(t) = node {
747 let qname = table_ref_qualified_name(t);
748 if seen.insert(qname) {
749 result.push(node.clone());
750 }
751 }
752
753 let refs: Vec<&TableRef> = match node {
755 Expression::Insert(ins) => vec![&ins.table],
756 Expression::Update(upd) => {
757 let mut v = vec![&upd.table];
758 v.extend(upd.extra_tables.iter());
759 v
760 }
761 Expression::Delete(del) => {
762 let mut v = vec![&del.table];
763 v.extend(del.using.iter());
764 v
765 }
766 _ => continue,
767 };
768 for tref in refs {
769 if tref.name.name.is_empty() {
770 continue;
771 }
772 let qname = table_ref_qualified_name(tref);
773 if seen.insert(qname) {
774 result.push(Expression::Table(Box::new(tref.clone())));
775 }
776 }
777 }
778
779 result
780}
781
782fn table_ref_qualified_name(t: &TableRef) -> String {
784 let mut name = String::new();
785 if let Some(ref cat) = t.catalog {
786 name.push_str(&cat.name);
787 name.push('.');
788 }
789 if let Some(ref schema) = t.schema {
790 name.push_str(&schema.name);
791 name.push('.');
792 }
793 name.push_str(&t.name.name);
794 name
795}
796
797fn unwrap_merge_table(expr: &Expression) -> Option<&Expression> {
801 match expr {
802 Expression::Table(_) => Some(expr),
803 Expression::Alias(alias) => match &alias.this {
804 Expression::Table(_) => Some(&alias.this),
805 _ => None,
806 },
807 _ => None,
808 }
809}
810
811pub fn get_merge_target(expr: &Expression) -> Option<&Expression> {
816 match expr {
817 Expression::Merge(m) => unwrap_merge_table(&m.this),
818 _ => None,
819 }
820}
821
822pub fn get_merge_source(expr: &Expression) -> Option<&Expression> {
828 match expr {
829 Expression::Merge(m) => unwrap_merge_table(&m.using),
830 _ => None,
831 }
832}
833
834pub fn contains_aggregate(expr: &Expression) -> bool {
836 expr.contains(is_aggregate)
837}
838
839pub fn contains_window_function(expr: &Expression) -> bool {
841 expr.contains(is_window_function)
842}
843
844pub fn contains_subquery(expr: &Expression) -> bool {
846 expr.contains(is_subquery)
847}
848
849macro_rules! is_type {
855 ($name:ident, $($variant:pat),+ $(,)?) => {
856 pub fn $name(expr: &Expression) -> bool {
858 matches!(expr, $($variant)|+)
859 }
860 };
861}
862
863is_type!(is_insert, Expression::Insert(_));
865is_type!(is_update, Expression::Update(_));
866is_type!(is_delete, Expression::Delete(_));
867is_type!(is_merge, Expression::Merge(_));
868is_type!(is_union, Expression::Union(_));
869is_type!(is_intersect, Expression::Intersect(_));
870is_type!(is_except, Expression::Except(_));
871
872is_type!(is_boolean, Expression::Boolean(_));
874is_type!(is_null_literal, Expression::Null(_));
875is_type!(is_star, Expression::Star(_));
876is_type!(is_identifier, Expression::Identifier(_));
877is_type!(is_table, Expression::Table(_));
878
879is_type!(is_eq, Expression::Eq(_));
881is_type!(is_neq, Expression::Neq(_));
882is_type!(is_lt, Expression::Lt(_));
883is_type!(is_lte, Expression::Lte(_));
884is_type!(is_gt, Expression::Gt(_));
885is_type!(is_gte, Expression::Gte(_));
886is_type!(is_like, Expression::Like(_));
887is_type!(is_ilike, Expression::ILike(_));
888
889is_type!(is_add, Expression::Add(_));
891is_type!(is_sub, Expression::Sub(_));
892is_type!(is_mul, Expression::Mul(_));
893is_type!(is_div, Expression::Div(_));
894is_type!(is_mod, Expression::Mod(_));
895is_type!(is_concat, Expression::Concat(_));
896
897is_type!(is_and, Expression::And(_));
899is_type!(is_or, Expression::Or(_));
900is_type!(is_not, Expression::Not(_));
901
902is_type!(is_in, Expression::In(_));
904is_type!(is_between, Expression::Between(_));
905is_type!(is_is_null, Expression::IsNull(_));
906is_type!(is_exists, Expression::Exists(_));
907
908is_type!(is_count, Expression::Count(_));
910is_type!(is_sum, Expression::Sum(_));
911is_type!(is_avg, Expression::Avg(_));
912is_type!(is_min_func, Expression::Min(_));
913is_type!(is_max_func, Expression::Max(_));
914is_type!(is_coalesce, Expression::Coalesce(_));
915is_type!(is_null_if, Expression::NullIf(_));
916is_type!(is_cast, Expression::Cast(_));
917is_type!(is_try_cast, Expression::TryCast(_));
918is_type!(is_safe_cast, Expression::SafeCast(_));
919is_type!(is_case, Expression::Case(_));
920
921is_type!(is_from, Expression::From(_));
923is_type!(is_join, Expression::Join(_));
924is_type!(is_where, Expression::Where(_));
925is_type!(is_group_by, Expression::GroupBy(_));
926is_type!(is_having, Expression::Having(_));
927is_type!(is_order_by, Expression::OrderBy(_));
928is_type!(is_limit, Expression::Limit(_));
929is_type!(is_offset, Expression::Offset(_));
930is_type!(is_with, Expression::With(_));
931is_type!(is_cte, Expression::Cte(_));
932is_type!(is_alias, Expression::Alias(_));
933is_type!(is_paren, Expression::Paren(_));
934is_type!(is_ordered, Expression::Ordered(_));
935
936is_type!(is_create_table, Expression::CreateTable(_));
938is_type!(is_drop_table, Expression::DropTable(_));
939is_type!(is_alter_table, Expression::AlterTable(_));
940is_type!(is_create_index, Expression::CreateIndex(_));
941is_type!(is_drop_index, Expression::DropIndex(_));
942is_type!(is_create_view, Expression::CreateView(_));
943is_type!(is_drop_view, Expression::DropView(_));
944
945pub fn is_query(expr: &Expression) -> bool {
951 matches!(
952 expr,
953 Expression::Select(_)
954 | Expression::Insert(_)
955 | Expression::Update(_)
956 | Expression::Delete(_)
957 | Expression::Merge(_)
958 )
959}
960
961pub fn is_set_operation(expr: &Expression) -> bool {
963 matches!(
964 expr,
965 Expression::Union(_) | Expression::Intersect(_) | Expression::Except(_)
966 )
967}
968
969pub fn is_comparison(expr: &Expression) -> bool {
971 matches!(
972 expr,
973 Expression::Eq(_)
974 | Expression::Neq(_)
975 | Expression::Lt(_)
976 | Expression::Lte(_)
977 | Expression::Gt(_)
978 | Expression::Gte(_)
979 | Expression::Like(_)
980 | Expression::ILike(_)
981 )
982}
983
984pub fn is_arithmetic(expr: &Expression) -> bool {
986 matches!(
987 expr,
988 Expression::Add(_)
989 | Expression::Sub(_)
990 | Expression::Mul(_)
991 | Expression::Div(_)
992 | Expression::Mod(_)
993 )
994}
995
996pub fn is_logical(expr: &Expression) -> bool {
998 matches!(
999 expr,
1000 Expression::And(_) | Expression::Or(_) | Expression::Not(_)
1001 )
1002}
1003
1004pub fn is_ddl(expr: &Expression) -> bool {
1006 matches!(
1007 expr,
1008 Expression::CreateTable(_)
1009 | Expression::DropTable(_)
1010 | Expression::Undrop(_)
1011 | Expression::AlterTable(_)
1012 | Expression::CreateIndex(_)
1013 | Expression::DropIndex(_)
1014 | Expression::CreateView(_)
1015 | Expression::DropView(_)
1016 | Expression::AlterView(_)
1017 | Expression::CreateSchema(_)
1018 | Expression::DropSchema(_)
1019 | Expression::CreateDatabase(_)
1020 | Expression::DropDatabase(_)
1021 | Expression::CreateFunction(_)
1022 | Expression::DropFunction(_)
1023 | Expression::CreateProcedure(_)
1024 | Expression::DropProcedure(_)
1025 | Expression::CreateSequence(_)
1026 | Expression::CreateSynonym(_)
1027 | Expression::DropSequence(_)
1028 | Expression::AlterSequence(_)
1029 | Expression::CreateTrigger(_)
1030 | Expression::DropTrigger(_)
1031 | Expression::CreateType(_)
1032 | Expression::DropType(_)
1033 )
1034}
1035
1036pub fn find_parent<'a>(root: &'a Expression, target: &Expression) -> Option<&'a Expression> {
1043 fn search<'a>(node: &'a Expression, target: *const Expression) -> Option<&'a Expression> {
1044 let mut result = None;
1045 crate::ast_children::for_each_child(node, |_, child| {
1046 if result.is_none() {
1047 if std::ptr::eq(child, target) {
1048 result = Some(node);
1049 } else {
1050 result = search(child, target);
1051 }
1052 }
1053 });
1054 result
1055 }
1056
1057 search(root, target as *const Expression)
1058}
1059
1060pub fn find_ancestor<'a, F>(
1066 root: &'a Expression,
1067 target: &Expression,
1068 predicate: F,
1069) -> Option<&'a Expression>
1070where
1071 F: Fn(&Expression) -> bool,
1072{
1073 fn build_path<'a>(
1075 node: &'a Expression,
1076 target: *const Expression,
1077 path: &mut Vec<&'a Expression>,
1078 ) -> bool {
1079 if std::ptr::eq(node, target) {
1080 return true;
1081 }
1082 path.push(node);
1083 let mut found = false;
1084 crate::ast_children::for_each_child(node, |_, child| {
1085 if !found {
1086 found = build_path(child, target, path);
1087 }
1088 });
1089 if found {
1090 return true;
1091 }
1092 path.pop();
1093 false
1094 }
1095
1096 let mut path = Vec::new();
1097 if !build_path(root, target as *const Expression, &mut path) {
1098 return None;
1099 }
1100
1101 for ancestor in path.iter().rev() {
1103 if predicate(ancestor) {
1104 return Some(ancestor);
1105 }
1106 }
1107 None
1108}
1109
1110#[cfg(test)]
1111mod tests {
1112 use super::*;
1113 use crate::expressions::{BinaryOp, Column, Identifier, LikeOp, Literal, TableRef};
1114
1115 fn make_column(name: &str) -> Expression {
1116 Expression::boxed_column(Column {
1117 name: Identifier {
1118 name: name.to_string(),
1119 quoted: false,
1120 trailing_comments: vec![],
1121 span: None,
1122 },
1123 table: None,
1124 join_mark: false,
1125 trailing_comments: vec![],
1126 span: None,
1127 inferred_type: None,
1128 })
1129 }
1130
1131 fn make_literal(value: i64) -> Expression {
1132 Expression::Literal(Box::new(Literal::Number(value.to_string())))
1133 }
1134
1135 #[test]
1136 fn test_dfs_simple() {
1137 let left = make_column("a");
1138 let right = make_literal(1);
1139 let expr = Expression::Eq(Box::new(BinaryOp {
1140 left,
1141 right,
1142 left_comments: vec![],
1143 operator_comments: vec![],
1144 trailing_comments: vec![],
1145 inferred_type: None,
1146 }));
1147
1148 let nodes: Vec<_> = expr.dfs().collect();
1149 assert_eq!(nodes.len(), 3); assert!(matches!(nodes[0], Expression::Eq(_)));
1151 assert!(matches!(nodes[1], Expression::Column(_)));
1152 assert!(matches!(nodes[2], Expression::Literal(_)));
1153 }
1154
1155 #[test]
1156 fn test_find() {
1157 let left = make_column("a");
1158 let right = make_literal(1);
1159 let expr = Expression::Eq(Box::new(BinaryOp {
1160 left,
1161 right,
1162 left_comments: vec![],
1163 operator_comments: vec![],
1164 trailing_comments: vec![],
1165 inferred_type: None,
1166 }));
1167
1168 let column = expr.find(is_column);
1169 assert!(column.is_some());
1170 assert!(matches!(column.unwrap(), Expression::Column(_)));
1171
1172 let literal = expr.find(is_literal);
1173 assert!(literal.is_some());
1174 assert!(matches!(literal.unwrap(), Expression::Literal(_)));
1175 }
1176
1177 #[test]
1178 fn test_find_all() {
1179 let col1 = make_column("a");
1180 let col2 = make_column("b");
1181 let expr = Expression::And(Box::new(BinaryOp {
1182 left: col1,
1183 right: col2,
1184 left_comments: vec![],
1185 operator_comments: vec![],
1186 trailing_comments: vec![],
1187 inferred_type: None,
1188 }));
1189
1190 let columns = expr.find_all(is_column);
1191 assert_eq!(columns.len(), 2);
1192 }
1193
1194 #[test]
1195 fn test_contains() {
1196 let col = make_column("a");
1197 let lit = make_literal(1);
1198 let expr = Expression::Eq(Box::new(BinaryOp {
1199 left: col,
1200 right: lit,
1201 left_comments: vec![],
1202 operator_comments: vec![],
1203 trailing_comments: vec![],
1204 inferred_type: None,
1205 }));
1206
1207 assert!(expr.contains(is_column));
1208 assert!(expr.contains(is_literal));
1209 assert!(!expr.contains(is_subquery));
1210 }
1211
1212 #[test]
1213 fn test_count() {
1214 let col1 = make_column("a");
1215 let col2 = make_column("b");
1216 let lit = make_literal(1);
1217
1218 let inner = Expression::Add(Box::new(BinaryOp {
1219 left: col2,
1220 right: lit,
1221 left_comments: vec![],
1222 operator_comments: vec![],
1223 trailing_comments: vec![],
1224 inferred_type: None,
1225 }));
1226
1227 let expr = Expression::Eq(Box::new(BinaryOp {
1228 left: col1,
1229 right: inner,
1230 left_comments: vec![],
1231 operator_comments: vec![],
1232 trailing_comments: vec![],
1233 inferred_type: None,
1234 }));
1235
1236 assert_eq!(expr.count(is_column), 2);
1237 assert_eq!(expr.count(is_literal), 1);
1238 }
1239
1240 #[test]
1241 fn test_tree_depth() {
1242 let lit = make_literal(1);
1244 assert_eq!(lit.tree_depth(), 0);
1245
1246 let col = make_column("a");
1248 let expr = Expression::Eq(Box::new(BinaryOp {
1249 left: col,
1250 right: lit.clone(),
1251 left_comments: vec![],
1252 operator_comments: vec![],
1253 trailing_comments: vec![],
1254 inferred_type: None,
1255 }));
1256 assert_eq!(expr.tree_depth(), 1);
1257
1258 let inner = Expression::Add(Box::new(BinaryOp {
1260 left: make_column("b"),
1261 right: lit,
1262 left_comments: vec![],
1263 operator_comments: vec![],
1264 trailing_comments: vec![],
1265 inferred_type: None,
1266 }));
1267 let outer = Expression::Eq(Box::new(BinaryOp {
1268 left: make_column("a"),
1269 right: inner,
1270 left_comments: vec![],
1271 operator_comments: vec![],
1272 trailing_comments: vec![],
1273 inferred_type: None,
1274 }));
1275 assert_eq!(outer.tree_depth(), 2);
1276 }
1277
1278 #[test]
1279 fn test_tree_context() {
1280 let col = make_column("a");
1281 let lit = make_literal(1);
1282 let expr = Expression::Eq(Box::new(BinaryOp {
1283 left: col,
1284 right: lit,
1285 left_comments: vec![],
1286 operator_comments: vec![],
1287 trailing_comments: vec![],
1288 inferred_type: None,
1289 }));
1290
1291 let ctx = TreeContext::build(&expr);
1292
1293 let root_info = ctx.get(0).unwrap();
1295 assert!(root_info.parent_id.is_none());
1296
1297 let left_info = ctx.get(1).unwrap();
1299 assert_eq!(left_info.parent_id, Some(0));
1300 assert_eq!(left_info.arg_key, "left");
1301
1302 let right_info = ctx.get(2).unwrap();
1303 assert_eq!(right_info.parent_id, Some(0));
1304 assert_eq!(right_info.arg_key, "right");
1305 }
1306
1307 #[test]
1310 fn test_transform_rename_columns() {
1311 let ast = crate::parser::Parser::parse_sql("SELECT a, b FROM t").unwrap();
1312 let expr = ast[0].clone();
1313 let result = super::transform_map(expr, &|e| {
1314 if let Expression::Column(ref c) = e {
1315 if c.name.name == "a" {
1316 return Ok(Expression::boxed_column(Column {
1317 name: Identifier::new("alpha"),
1318 table: c.table.clone(),
1319 join_mark: false,
1320 trailing_comments: vec![],
1321 span: None,
1322 inferred_type: None,
1323 }));
1324 }
1325 }
1326 Ok(e)
1327 })
1328 .unwrap();
1329 let sql = crate::generator::Generator::sql(&result).unwrap();
1330 assert!(sql.contains("alpha"), "Expected 'alpha' in: {}", sql);
1331 assert!(sql.contains("b"), "Expected 'b' in: {}", sql);
1332 }
1333
1334 #[test]
1335 fn test_transform_noop() {
1336 let ast = crate::parser::Parser::parse_sql("SELECT 1 + 2").unwrap();
1337 let expr = ast[0].clone();
1338 let result = super::transform_map(expr.clone(), &|e| Ok(e)).unwrap();
1339 let sql1 = crate::generator::Generator::sql(&expr).unwrap();
1340 let sql2 = crate::generator::Generator::sql(&result).unwrap();
1341 assert_eq!(sql1, sql2);
1342 }
1343
1344 #[test]
1345 fn test_transform_nested() {
1346 let ast = crate::parser::Parser::parse_sql("SELECT a + b FROM t").unwrap();
1347 let expr = ast[0].clone();
1348 let result = super::transform_map(expr, &|e| {
1349 if let Expression::Column(ref c) = e {
1350 return Ok(Expression::Literal(Box::new(Literal::Number(
1351 if c.name.name == "a" { "1" } else { "2" }.to_string(),
1352 ))));
1353 }
1354 Ok(e)
1355 })
1356 .unwrap();
1357 let sql = crate::generator::Generator::sql(&result).unwrap();
1358 assert_eq!(sql, "SELECT 1 + 2 FROM t");
1359 }
1360
1361 #[test]
1362 fn test_transform_error() {
1363 let ast = crate::parser::Parser::parse_sql("SELECT a FROM t").unwrap();
1364 let expr = ast[0].clone();
1365 let result = super::transform_map(expr, &|e| {
1366 if let Expression::Column(ref c) = e {
1367 if c.name.name == "a" {
1368 return Err(crate::error::Error::parse("test error", 0, 0, 0, 0));
1369 }
1370 }
1371 Ok(e)
1372 });
1373 assert!(result.is_err());
1374 }
1375
1376 #[test]
1377 fn test_transform_owned_trait() {
1378 let ast = crate::parser::Parser::parse_sql("SELECT x FROM t").unwrap();
1379 let expr = ast[0].clone();
1380 let result = expr.transform_owned(|e| Ok(Some(e))).unwrap();
1381 let sql = crate::generator::Generator::sql(&result).unwrap();
1382 assert_eq!(sql, "SELECT x FROM t");
1383 }
1384
1385 #[test]
1388 fn test_children_leaf() {
1389 let lit = make_literal(1);
1390 assert_eq!(lit.children().len(), 0);
1391 }
1392
1393 #[test]
1394 fn test_children_binary_op() {
1395 let left = make_column("a");
1396 let right = make_literal(1);
1397 let expr = Expression::Eq(Box::new(BinaryOp {
1398 left,
1399 right,
1400 left_comments: vec![],
1401 operator_comments: vec![],
1402 trailing_comments: vec![],
1403 inferred_type: None,
1404 }));
1405 let children = expr.children();
1406 assert_eq!(children.len(), 2);
1407 assert!(matches!(children[0], Expression::Column(_)));
1408 assert!(matches!(children[1], Expression::Literal(_)));
1409 }
1410
1411 #[test]
1412 fn test_children_select() {
1413 let ast = crate::parser::Parser::parse_sql("SELECT a, b FROM t").unwrap();
1414 let expr = &ast[0];
1415 let children = expr.children();
1416 assert!(children.len() >= 2);
1418 }
1419
1420 #[test]
1421 fn test_children_follow_ast_field_order() {
1422 let ast = crate::parser::Parser::parse_sql("SELECT a, b FROM t").unwrap();
1423 let children = ast[0].children();
1424
1425 assert!(matches!(children[0], Expression::Column(column) if column.name.name == "a"));
1426 assert!(matches!(children[1], Expression::Column(column) if column.name.name == "b"));
1427 assert!(matches!(children[2], Expression::Table(table) if table.name.name == "t"));
1428 }
1429
1430 #[test]
1431 fn test_traversal_covers_previously_omitted_expression_fields() {
1432 let like = Expression::Like(Box::new(LikeOp {
1433 left: make_column("name"),
1434 right: Expression::Literal(Box::new(Literal::String("x%".to_string()))),
1435 escape: Some(Expression::Literal(Box::new(Literal::String(
1436 "!".to_string(),
1437 )))),
1438 quantifier: None,
1439 inferred_type: None,
1440 }));
1441 let nodes: Vec<_> = like.dfs().collect();
1442 assert_eq!(nodes.len(), 4);
1443 assert!(matches!(
1444 nodes[3],
1445 Expression::Literal(literal)
1446 if matches!(literal.as_ref(), Literal::String(value) if value == "!")
1447 ));
1448
1449 let mut table = TableRef::new("events");
1450 table.hints.push(make_column("table_hint"));
1451 table.identifier_func = Some(Box::new(Expression::identifier("dynamic_table")));
1452 let table = Expression::Table(Box::new(table));
1453 let children = table.children();
1454 assert_eq!(children.len(), 2);
1455 assert!(
1456 matches!(children[0], Expression::Column(column) if column.name.name == "table_hint")
1457 );
1458 assert!(
1459 matches!(children[1], Expression::Identifier(identifier) if identifier.name == "dynamic_table")
1460 );
1461 }
1462
1463 #[test]
1464 fn test_children_select_includes_from_and_join_sources() {
1465 let ast = crate::parser::Parser::parse_sql(
1466 "SELECT u.id FROM users u JOIN orders o ON u.id = o.user_id",
1467 )
1468 .unwrap();
1469 let expr = &ast[0];
1470 let children = expr.children();
1471
1472 let table_names: Vec<&str> = children
1473 .iter()
1474 .filter_map(|e| match e {
1475 Expression::Table(t) => Some(t.name.name.as_str()),
1476 _ => None,
1477 })
1478 .collect();
1479
1480 assert!(table_names.contains(&"users"));
1481 assert!(table_names.contains(&"orders"));
1482 }
1483
1484 #[test]
1485 fn test_get_tables_includes_insert_query_sources() {
1486 let ast = crate::parser::Parser::parse_sql(
1487 "INSERT INTO dst (id) SELECT s.id FROM src s JOIN dim d ON s.id = d.id",
1488 )
1489 .unwrap();
1490 let expr = &ast[0];
1491 let tables = get_tables(expr);
1492 let names: Vec<&str> = tables
1493 .iter()
1494 .filter_map(|e| match e {
1495 Expression::Table(t) => Some(t.name.name.as_str()),
1496 _ => None,
1497 })
1498 .collect();
1499
1500 assert!(names.contains(&"src"));
1501 assert!(names.contains(&"dim"));
1502 }
1503
1504 #[test]
1507 fn test_find_parent_binary() {
1508 let left = make_column("a");
1509 let right = make_literal(1);
1510 let expr = Expression::Eq(Box::new(BinaryOp {
1511 left,
1512 right,
1513 left_comments: vec![],
1514 operator_comments: vec![],
1515 trailing_comments: vec![],
1516 inferred_type: None,
1517 }));
1518
1519 let col = expr.find(is_column).unwrap();
1521 let parent = super::find_parent(&expr, col);
1522 assert!(parent.is_some());
1523 assert!(matches!(parent.unwrap(), Expression::Eq(_)));
1524 }
1525
1526 #[test]
1527 fn test_find_parent_root_has_none() {
1528 let lit = make_literal(1);
1529 let parent = super::find_parent(&lit, &lit);
1530 assert!(parent.is_none());
1531 }
1532
1533 #[test]
1536 fn test_find_ancestor_select() {
1537 let ast = crate::parser::Parser::parse_sql("SELECT a FROM t WHERE a > 1").unwrap();
1538 let expr = &ast[0];
1539
1540 let where_col = expr.dfs().find(|e| {
1542 if let Expression::Column(c) = e {
1543 c.name.name == "a"
1544 } else {
1545 false
1546 }
1547 });
1548 assert!(where_col.is_some());
1549
1550 let ancestor = super::find_ancestor(expr, where_col.unwrap(), is_select);
1552 assert!(ancestor.is_some());
1553 assert!(matches!(ancestor.unwrap(), Expression::Select(_)));
1554 }
1555
1556 #[test]
1557 fn test_find_ancestor_no_match() {
1558 let left = make_column("a");
1559 let right = make_literal(1);
1560 let expr = Expression::Eq(Box::new(BinaryOp {
1561 left,
1562 right,
1563 left_comments: vec![],
1564 operator_comments: vec![],
1565 trailing_comments: vec![],
1566 inferred_type: None,
1567 }));
1568
1569 let col = expr.find(is_column).unwrap();
1570 let ancestor = super::find_ancestor(&expr, col, is_select);
1571 assert!(ancestor.is_none());
1572 }
1573
1574 #[test]
1575 fn test_ancestors() {
1576 let col = make_column("a");
1577 let lit = make_literal(1);
1578 let inner = Expression::Add(Box::new(BinaryOp {
1579 left: col,
1580 right: lit,
1581 left_comments: vec![],
1582 operator_comments: vec![],
1583 trailing_comments: vec![],
1584 inferred_type: None,
1585 }));
1586 let outer = Expression::Eq(Box::new(BinaryOp {
1587 left: make_column("b"),
1588 right: inner,
1589 left_comments: vec![],
1590 operator_comments: vec![],
1591 trailing_comments: vec![],
1592 inferred_type: None,
1593 }));
1594
1595 let ctx = TreeContext::build(&outer);
1596
1597 let ancestors = ctx.ancestors_of(3);
1605 assert_eq!(ancestors, vec![2, 0]); }
1607
1608 #[test]
1609 fn test_get_merge_target_and_source() {
1610 let dialect = crate::Dialect::get(crate::dialects::DialectType::Generic);
1611
1612 let sql = "MERGE INTO orders o USING customers c ON o.customer_id = c.id WHEN MATCHED THEN UPDATE SET amount = amount + 100";
1614 let exprs = dialect.parse(sql).unwrap();
1615 let expr = &exprs[0];
1616
1617 assert!(is_merge(expr));
1618 assert!(is_query(expr));
1619
1620 let target = get_merge_target(expr).expect("should find target table");
1621 assert!(matches!(target, Expression::Table(_)));
1622 if let Expression::Table(t) = target {
1623 assert_eq!(t.name.name, "orders");
1624 }
1625
1626 let source = get_merge_source(expr).expect("should find source table");
1627 assert!(matches!(source, Expression::Table(_)));
1628 if let Expression::Table(t) = source {
1629 assert_eq!(t.name.name, "customers");
1630 }
1631 }
1632
1633 #[test]
1634 fn test_get_merge_source_subquery_returns_none() {
1635 let dialect = crate::Dialect::get(crate::dialects::DialectType::Generic);
1636
1637 let sql = "MERGE INTO orders o USING (SELECT * FROM customers) c ON o.customer_id = c.id WHEN MATCHED THEN DELETE";
1639 let exprs = dialect.parse(sql).unwrap();
1640 let expr = &exprs[0];
1641
1642 assert!(get_merge_target(expr).is_some());
1643 assert!(get_merge_source(expr).is_none());
1644 }
1645
1646 #[test]
1647 fn test_get_merge_on_non_merge_returns_none() {
1648 let dialect = crate::Dialect::get(crate::dialects::DialectType::Generic);
1649 let exprs = dialect.parse("SELECT 1").unwrap();
1650 assert!(get_merge_target(&exprs[0]).is_none());
1651 assert!(get_merge_source(&exprs[0]).is_none());
1652 }
1653
1654 #[test]
1655 fn test_get_tables_finds_tables_inside_in_subquery() {
1656 let dialect = crate::Dialect::get(crate::dialects::DialectType::Generic);
1657 let sql = "SELECT id, name FROM customers WHERE id IN (SELECT customer_id FROM orders WHERE amount > 1000)";
1658 let exprs = dialect.parse(sql).unwrap();
1659 let tables = get_tables(&exprs[0]);
1660 let names: Vec<&str> = tables
1661 .iter()
1662 .filter_map(|e| {
1663 if let Expression::Table(t) = e {
1664 Some(t.name.name.as_str())
1665 } else {
1666 None
1667 }
1668 })
1669 .collect();
1670 assert!(names.contains(&"customers"), "should find outer table");
1671 assert!(names.contains(&"orders"), "should find subquery table");
1672 }
1673
1674 #[test]
1675 fn test_get_tables_finds_tables_inside_exists_subquery() {
1676 let dialect = crate::Dialect::get(crate::dialects::DialectType::Generic);
1677 let sql = "SELECT * FROM customers c WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id)";
1678 let exprs = dialect.parse(sql).unwrap();
1679 let tables = get_tables(&exprs[0]);
1680 let names: Vec<&str> = tables
1681 .iter()
1682 .filter_map(|e| {
1683 if let Expression::Table(t) = e {
1684 Some(t.name.name.as_str())
1685 } else {
1686 None
1687 }
1688 })
1689 .collect();
1690 assert!(names.contains(&"customers"), "should find outer table");
1691 assert!(
1692 names.contains(&"orders"),
1693 "should find EXISTS subquery table"
1694 );
1695 }
1696
1697 #[test]
1698 fn test_get_tables_finds_tables_in_correlated_subquery() {
1699 let dialect = crate::Dialect::get(crate::dialects::DialectType::TSQL);
1700 let sql = "SELECT id, name FROM customers WHERE id IN (SELECT customer_id FROM orders WHERE amount > 1000)";
1701 let exprs = dialect.parse(sql).unwrap();
1702 let tables = get_tables(&exprs[0]);
1703 let names: Vec<&str> = tables
1704 .iter()
1705 .filter_map(|e| {
1706 if let Expression::Table(t) = e {
1707 Some(t.name.name.as_str())
1708 } else {
1709 None
1710 }
1711 })
1712 .collect();
1713 assert!(
1714 names.contains(&"customers"),
1715 "TSQL: should find outer table"
1716 );
1717 assert!(
1718 names.contains(&"orders"),
1719 "TSQL: should find subquery table"
1720 );
1721 }
1722}