1use std::fmt;
21
22use risingwave_sqlparser::ast::*;
23use strum::EnumDiscriminants;
24
25#[derive(Debug, Clone, PartialEq, Eq)]
28pub enum AstField {
29 Query,
31 Name,
32 Columns,
33
34 Body,
36 With,
37 OrderBy,
38 Limit,
39 Offset,
40
41 Projection,
43 Selection,
44 From,
45 GroupBy,
46 Having,
47 Distinct,
48
49 Left,
51 Right,
52 Operand,
53 ElseResult,
54 Subquery,
55 Inner,
56 Expr,
57 Low,
58 High,
59
60 Relation,
62 Joins,
63
64 JoinOperator,
66
67 Alias,
69
70 Asc,
72 NullsFirst,
73
74 CteTable,
76 Recursive,
77
78 CteInner,
80
81 Lateral,
83}
84
85impl fmt::Display for AstField {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 let s = match self {
88 AstField::Query => "query",
89 AstField::Name => "name",
90 AstField::Columns => "columns",
91 AstField::Body => "body",
92 AstField::With => "with",
93 AstField::OrderBy => "order_by",
94 AstField::Limit => "limit",
95 AstField::Offset => "offset",
96 AstField::Projection => "projection",
97 AstField::Selection => "selection",
98 AstField::From => "from",
99 AstField::GroupBy => "group_by",
100 AstField::Having => "having",
101 AstField::Distinct => "distinct",
102 AstField::Left => "left",
103 AstField::Right => "right",
104 AstField::Operand => "operand",
105 AstField::ElseResult => "else_result",
106 AstField::Subquery => "subquery",
107 AstField::Inner => "inner",
108 AstField::Expr => "expr",
109 AstField::Low => "low",
110 AstField::High => "high",
111 AstField::Relation => "relation",
112 AstField::Joins => "joins",
113 AstField::JoinOperator => "join_operator",
114 AstField::Alias => "alias",
115 AstField::Asc => "asc",
116 AstField::NullsFirst => "nulls_first",
117 AstField::CteTable => "cte_tables",
118 AstField::Recursive => "recursive",
119 AstField::CteInner => "cte_inner",
120 AstField::Lateral => "lateral",
121 };
122 write!(f, "{}", s)
123 }
124}
125
126#[derive(Debug, Clone, PartialEq, Eq)]
130pub enum PathComponent {
131 Field(AstField),
133 Index(usize),
135}
136
137impl PathComponent {
138 pub fn field(field: AstField) -> Self {
140 PathComponent::Field(field)
141 }
142
143 pub fn field_name(&self) -> Option<String> {
145 match self {
146 PathComponent::Field(field) => Some(field.to_string()),
147 PathComponent::Index(_) => None,
148 }
149 }
150
151 pub fn as_ast_field(&self) -> Option<&AstField> {
153 match self {
154 PathComponent::Field(field) => Some(field),
155 PathComponent::Index(_) => None,
156 }
157 }
158
159 pub fn query() -> Self {
161 Self::field(AstField::Query)
162 }
163
164 pub fn body() -> Self {
165 Self::field(AstField::Body)
166 }
167
168 pub fn selection() -> Self {
169 Self::field(AstField::Selection)
170 }
171
172 pub fn projection() -> Self {
173 Self::field(AstField::Projection)
174 }
175
176 pub fn from_clause() -> Self {
177 Self::field(AstField::From)
178 }
179
180 pub fn group_by() -> Self {
181 Self::field(AstField::GroupBy)
182 }
183
184 pub fn having() -> Self {
185 Self::field(AstField::Having)
186 }
187
188 pub fn with_clause() -> Self {
189 Self::field(AstField::With)
190 }
191
192 pub fn order_by() -> Self {
193 Self::field(AstField::OrderBy)
194 }
195
196 pub fn left() -> Self {
197 Self::field(AstField::Left)
198 }
199
200 pub fn right() -> Self {
201 Self::field(AstField::Right)
202 }
203
204 pub fn operand() -> Self {
205 Self::field(AstField::Operand)
206 }
207
208 pub fn else_result() -> Self {
209 Self::field(AstField::ElseResult)
210 }
211
212 pub fn relation() -> Self {
213 Self::field(AstField::Relation)
214 }
215
216 pub fn joins() -> Self {
217 Self::field(AstField::Joins)
218 }
219
220 pub fn subquery() -> Self {
221 Self::field(AstField::Subquery)
222 }
223
224 pub fn cte_tables() -> Self {
225 Self::field(AstField::CteTable)
226 }
227
228 pub fn cte_inner() -> Self {
229 Self::field(AstField::CteInner)
230 }
231}
232
233impl fmt::Display for PathComponent {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235 match self {
236 PathComponent::Field(field) => write!(f, ".{}", field),
237 PathComponent::Index(idx) => write!(f, "[{}]", idx),
238 }
239 }
240}
241
242pub type AstPath = Vec<PathComponent>;
245
246pub fn display_ast_path(path: &AstPath) -> String {
248 path.iter().map(|c| c.to_string()).collect::<String>()
249}
250
251#[derive(Debug, Clone, EnumDiscriminants)]
255#[strum_discriminants(derive(strum::Display))]
256#[strum_discriminants(name(AstNodeType))]
257pub enum AstNode {
258 Statement(Statement),
259 Query(Box<Query>),
260 Select(Box<Select>),
261 Expr(Expr),
262 SelectItem(SelectItem),
263 TableWithJoins(TableWithJoins),
264 Join(Join),
265 TableFactor(TableFactor),
266 OrderByExpr(OrderByExpr),
267 With(With),
268 Cte(Cte),
269 ExprList(Vec<Expr>),
270 SelectItemList(Vec<SelectItem>),
271 TableList(Vec<TableWithJoins>),
272 JoinList(Vec<Join>),
273 OrderByList(Vec<OrderByExpr>),
274 CteList(Vec<Cte>),
275 Option(Option<Box<AstNode>>),
276}
277
278impl AstNode {
279 pub fn get_child(&self, component: &PathComponent) -> Option<AstNode> {
281 match (self, component) {
282 (AstNode::Statement(Statement::Query(query)), PathComponent::Field(field))
284 if *field == AstField::Query =>
285 {
286 Some(AstNode::Query(query.clone()))
287 }
288
289 (
290 AstNode::Statement(Statement::CreateView { query, .. }),
291 PathComponent::Field(field),
292 ) if *field == AstField::Query => Some(AstNode::Query(query.clone())),
293
294 (AstNode::Statement(Statement::CreateView { .. }), PathComponent::Field(field)) => {
296 match field {
297 AstField::Name => None, AstField::Columns => None, _ => None,
300 }
301 }
302
303 (AstNode::Query(query), PathComponent::Field(field)) => match field {
305 AstField::Body => match &query.body {
306 SetExpr::Select(select) => Some(AstNode::Select(select.clone())),
307 SetExpr::Query(subquery) => Some(AstNode::Query(subquery.clone())),
308 SetExpr::SetOperation { left, .. } => {
309 match left.as_ref() {
311 SetExpr::Select(select) => Some(AstNode::Select(select.clone())),
312 SetExpr::Query(subquery) => Some(AstNode::Query(subquery.clone())),
313 _ => None,
314 }
315 }
316 _ => None,
317 },
318 AstField::With => query.with.as_ref().map(|w| AstNode::With(w.clone())),
319 AstField::OrderBy => {
320 if query.order_by.is_empty() {
321 None
322 } else {
323 Some(AstNode::OrderByList(query.order_by.clone()))
324 }
325 }
326 AstField::Limit => query.limit.as_ref().map(|e| AstNode::Expr(e.clone())),
327 AstField::Offset => None, _ => None,
329 },
330
331 (AstNode::Select(select), PathComponent::Field(field)) => match field {
333 AstField::Projection => {
334 if select.projection.is_empty() {
335 None
336 } else {
337 Some(AstNode::SelectItemList(select.projection.clone()))
338 }
339 }
340 AstField::Selection => select.selection.as_ref().map(|e| AstNode::Expr(e.clone())),
341 AstField::From => {
342 if select.from.is_empty() {
343 None
344 } else {
345 Some(AstNode::TableList(select.from.clone()))
346 }
347 }
348 AstField::GroupBy => {
349 if select.group_by.is_empty() {
350 None
351 } else {
352 Some(AstNode::ExprList(select.group_by.clone()))
353 }
354 }
355 AstField::Having => select.having.as_ref().map(|e| AstNode::Expr(e.clone())),
356 AstField::Distinct => None, _ => None,
358 },
359
360 (AstNode::SelectItemList(items), PathComponent::Index(idx)) => items
362 .get(*idx)
363 .map(|item| AstNode::SelectItem(item.clone())),
364 (AstNode::ExprList(exprs), PathComponent::Index(idx)) => {
365 exprs.get(*idx).map(|expr| AstNode::Expr(expr.clone()))
366 }
367 (AstNode::TableList(tables), PathComponent::Index(idx)) => tables
368 .get(*idx)
369 .map(|table| AstNode::TableWithJoins(table.clone())),
370 (AstNode::OrderByList(orders), PathComponent::Index(idx)) => orders
371 .get(*idx)
372 .map(|order| AstNode::OrderByExpr(order.clone())),
373
374 (AstNode::Expr(expr), PathComponent::Field(field)) => match (expr, field) {
376 (Expr::BinaryOp { left, .. }, AstField::Left) => Some(AstNode::Expr(*left.clone())),
377 (Expr::BinaryOp { right, .. }, AstField::Right) => {
378 Some(AstNode::Expr(*right.clone()))
379 }
380 (Expr::Case { operand, .. }, AstField::Operand) => {
381 operand.as_ref().map(|e| AstNode::Expr(*e.clone()))
382 }
383 (Expr::Case { else_result, .. }, AstField::ElseResult) => {
384 else_result.as_ref().map(|e| AstNode::Expr(*e.clone()))
385 }
386 (Expr::Exists(subquery), AstField::Subquery) => {
387 Some(AstNode::Query(subquery.clone()))
388 }
389 (Expr::Subquery(subquery), AstField::Subquery) => {
390 Some(AstNode::Query(subquery.clone()))
391 }
392 (Expr::Function(_func), AstField::Name) => None, (Expr::Nested(inner), AstField::Inner) => Some(AstNode::Expr(*inner.clone())),
394 (Expr::UnaryOp { expr, .. }, AstField::Expr) => Some(AstNode::Expr(*expr.clone())),
395 (Expr::Cast { expr, .. }, AstField::Expr) => Some(AstNode::Expr(*expr.clone())),
396 (Expr::IsNull(expr), AstField::Expr) => Some(AstNode::Expr(*expr.clone())),
397 (Expr::IsNotNull(expr), AstField::Expr) => Some(AstNode::Expr(*expr.clone())),
398 (Expr::Between { expr, .. }, AstField::Expr) => Some(AstNode::Expr(*expr.clone())),
399 (Expr::Between { low, .. }, AstField::Low) => Some(AstNode::Expr(*low.clone())),
400 (Expr::Between { high, .. }, AstField::High) => Some(AstNode::Expr(*high.clone())),
401 _ => None,
402 },
403
404 (AstNode::TableWithJoins(table_with_joins), PathComponent::Field(field)) => match field
406 {
407 AstField::Relation => Some(AstNode::TableFactor(table_with_joins.relation.clone())),
408 AstField::Joins => {
409 if !table_with_joins.joins.is_empty() {
410 Some(AstNode::JoinList(table_with_joins.joins.clone()))
411 } else {
412 None
413 }
414 }
415 _ => None,
416 },
417
418 (AstNode::Join(join), PathComponent::Field(field)) => match field {
420 AstField::Relation => Some(AstNode::TableFactor(join.relation.clone())),
421 AstField::JoinOperator => None, _ => None,
423 },
424
425 (AstNode::TableFactor(table_factor), PathComponent::Field(field)) => {
427 match (table_factor, field) {
428 (TableFactor::Table { .. }, _) => None, (TableFactor::Derived { subquery, .. }, AstField::Subquery) => {
430 Some(AstNode::Query(subquery.clone()))
431 }
432 (TableFactor::TableFunction { .. }, _) => None, _ => None,
434 }
435 }
436
437 (AstNode::JoinList(joins), PathComponent::Index(idx)) => {
439 joins.get(*idx).map(|join| AstNode::Join(join.clone()))
440 }
441
442 (AstNode::SelectItem(select_item), PathComponent::Field(field)) => {
444 match (select_item, field) {
445 (SelectItem::UnnamedExpr(expr), AstField::Expr) => {
446 Some(AstNode::Expr(expr.clone()))
447 }
448 (SelectItem::ExprWithAlias { expr, .. }, AstField::Expr) => {
449 Some(AstNode::Expr(expr.clone()))
450 }
451 (SelectItem::QualifiedWildcard(..), _) => None,
452 (SelectItem::Wildcard(..), _) => None,
453 _ => None,
454 }
455 }
456
457 (AstNode::OrderByExpr(order_by), PathComponent::Field(field)) => match field {
459 AstField::Expr => Some(AstNode::Expr(order_by.expr.clone())),
460 AstField::Asc => None, AstField::NullsFirst => None, _ => None,
463 },
464
465 (AstNode::With(with_clause), PathComponent::Field(field)) => match field {
467 AstField::CteTable => {
468 if with_clause.cte_tables.is_empty() {
469 None
470 } else {
471 Some(AstNode::CteList(with_clause.cte_tables.clone()))
472 }
473 }
474 AstField::Recursive => None, _ => None,
476 },
477
478 (AstNode::CteList(ctes), PathComponent::Index(idx)) => {
480 if *idx < ctes.len() {
481 Some(AstNode::Cte(ctes[*idx].clone()))
482 } else {
483 None
484 }
485 }
486
487 (AstNode::Cte(cte), PathComponent::Field(field)) => match field {
489 AstField::Alias => None, AstField::CteInner => match &cte.cte_inner {
491 CteInner::Query(query) => Some(AstNode::Query(query.clone())),
492 CteInner::ChangeLog(_) => None, },
494 _ => None,
495 },
496
497 _ => {
498 tracing::debug!(
500 "get_child: No match for {:?} with component {:?}",
501 std::mem::discriminant(self),
502 component
503 );
504 None
505 }
506 }
507 }
508
509 pub fn set_child(
512 &self,
513 component: &PathComponent,
514 new_child: Option<AstNode>,
515 ) -> Option<AstNode> {
516 match (self, component) {
517 (AstNode::Statement(Statement::Query(_)), PathComponent::Field(field))
519 if *field == AstField::Query =>
520 {
521 if let Some(AstNode::Query(new_query)) = new_child {
522 Some(AstNode::Statement(Statement::Query(new_query)))
523 } else {
524 None
525 }
526 }
527
528 (
529 AstNode::Statement(Statement::CreateView {
530 name,
531 columns,
532 query: _,
533 or_replace,
534 materialized,
535 if_not_exists,
536 emit_mode,
537 with_options,
538 }),
539 PathComponent::Field(field),
540 ) => match field {
541 AstField::Query => {
542 if let Some(AstNode::Query(new_query)) = new_child {
543 let new_stmt = Statement::CreateView {
544 or_replace: *or_replace,
545 materialized: *materialized,
546 if_not_exists: *if_not_exists,
547 name: name.clone(),
548 columns: columns.clone(),
549 query: new_query,
550 emit_mode: emit_mode.clone(),
551 with_options: with_options.clone(),
552 };
553 Some(AstNode::Statement(new_stmt))
554 } else {
555 None
556 }
557 }
558 _ => None,
559 },
560
561 (AstNode::Query(query), PathComponent::Field(field)) => {
563 let mut new_query = (**query).clone();
564 match field {
565 AstField::Body => {
566 if let Some(AstNode::Select(select)) = new_child {
567 new_query.body = SetExpr::Select(select);
568 Some(AstNode::Query(Box::new(new_query)))
569 } else {
570 None
571 }
572 }
573 AstField::OrderBy => {
574 if let Some(AstNode::OrderByList(orders)) = new_child {
575 new_query.order_by = orders;
576 } else {
577 new_query.order_by = vec![];
578 }
579 Some(AstNode::Query(Box::new(new_query)))
580 }
581 AstField::Limit => {
582 new_query.limit = new_child.and_then(|n| match n {
583 AstNode::Expr(e) => Some(e),
584 _ => None,
585 });
586 Some(AstNode::Query(Box::new(new_query)))
587 }
588 AstField::With => {
589 new_query.with = new_child.and_then(|n| match n {
590 AstNode::With(w) => Some(w),
591 _ => None,
592 });
593 Some(AstNode::Query(Box::new(new_query)))
594 }
595 _ => None,
596 }
597 }
598
599 (AstNode::Select(select), PathComponent::Field(field)) => {
601 let mut new_select = (**select).clone();
602 match field {
603 AstField::Selection => {
604 new_select.selection = new_child.and_then(|n| match n {
605 AstNode::Expr(e) => Some(e),
606 _ => None,
607 });
608 }
609 AstField::Having => {
610 new_select.having = new_child.and_then(|n| match n {
611 AstNode::Expr(e) => Some(e),
612 _ => None,
613 });
614 }
615 AstField::Projection => {
616 if let Some(AstNode::SelectItemList(items)) = new_child {
617 new_select.projection = items;
618 } else {
619 new_select.projection = vec![];
621 }
622 }
623 AstField::From => {
624 if let Some(AstNode::TableList(tables)) = new_child {
625 new_select.from = tables;
626 } else {
627 new_select.from = vec![];
629 }
630 }
631 AstField::GroupBy => {
632 if let Some(AstNode::ExprList(exprs)) = new_child {
633 new_select.group_by = exprs;
634 } else {
635 new_select.group_by = vec![];
637 }
638 }
639 _ => return None,
640 }
641 Some(AstNode::Select(Box::new(new_select)))
642 }
643
644 (AstNode::SelectItemList(items), PathComponent::Index(idx)) => {
646 let mut new_items = items.clone();
647 if *idx < new_items.len() {
648 if let Some(AstNode::SelectItem(item)) = new_child {
649 new_items[*idx] = item;
650 } else {
651 new_items.remove(*idx);
652 }
653 Some(AstNode::SelectItemList(new_items))
654 } else {
655 None
656 }
657 }
658
659 (AstNode::ExprList(exprs), PathComponent::Index(idx)) => {
660 let mut new_exprs = exprs.clone();
661 if *idx < new_exprs.len() {
662 if let Some(AstNode::Expr(expr)) = new_child {
663 new_exprs[*idx] = expr;
664 } else {
665 new_exprs.remove(*idx);
666 }
667 Some(AstNode::ExprList(new_exprs))
668 } else {
669 None
670 }
671 }
672
673 (AstNode::TableList(tables), PathComponent::Index(idx)) => {
674 let mut new_tables = tables.clone();
675 if *idx < new_tables.len() {
676 if let Some(AstNode::TableWithJoins(table)) = new_child {
677 new_tables[*idx] = table;
678 } else {
679 new_tables.remove(*idx);
680 }
681 Some(AstNode::TableList(new_tables))
682 } else {
683 None
684 }
685 }
686
687 (AstNode::TableWithJoins(table_with_joins), PathComponent::Field(field)) => {
689 match field {
690 AstField::Relation => {
691 if let Some(AstNode::TableFactor(new_relation)) = new_child {
692 Some(AstNode::TableWithJoins(TableWithJoins {
693 relation: new_relation,
694 joins: table_with_joins.joins.clone(),
695 }))
696 } else {
697 None
698 }
699 }
700 AstField::Joins => {
701 if let Some(AstNode::JoinList(new_joins)) = new_child {
702 Some(AstNode::TableWithJoins(TableWithJoins {
703 relation: table_with_joins.relation.clone(),
704 joins: new_joins,
705 }))
706 } else {
707 Some(AstNode::TableWithJoins(TableWithJoins {
709 relation: table_with_joins.relation.clone(),
710 joins: vec![],
711 }))
712 }
713 }
714 _ => None,
715 }
716 }
717
718 (AstNode::Join(join), PathComponent::Field(field)) => match field {
720 AstField::Relation => {
721 if let Some(AstNode::TableFactor(new_relation)) = new_child {
722 Some(AstNode::Join(Join {
723 relation: new_relation,
724 join_operator: join.join_operator.clone(),
725 }))
726 } else {
727 None
728 }
729 }
730 _ => None,
731 },
732
733 (AstNode::TableFactor(table_factor), PathComponent::Field(field)) => {
735 match (table_factor, field) {
736 (TableFactor::Derived { lateral, alias, .. }, AstField::Subquery) => {
737 if let Some(AstNode::Query(new_subquery)) = new_child {
738 Some(AstNode::TableFactor(TableFactor::Derived {
739 lateral: *lateral,
740 subquery: new_subquery,
741 alias: alias.clone(),
742 }))
743 } else {
744 None
745 }
746 }
747 _ => None,
748 }
749 }
750
751 (AstNode::JoinList(joins), PathComponent::Index(idx)) => {
753 let mut new_joins = joins.clone();
754 if *idx < new_joins.len() {
755 if let Some(AstNode::Join(new_join)) = new_child {
756 new_joins[*idx] = new_join;
757 } else {
758 new_joins.remove(*idx);
759 }
760 Some(AstNode::JoinList(new_joins))
761 } else {
762 None
763 }
764 }
765
766 (AstNode::OrderByList(orders), PathComponent::Index(idx)) => {
767 let mut new_orders = orders.clone();
768 if *idx < new_orders.len() {
769 if let Some(AstNode::OrderByExpr(order)) = new_child {
770 new_orders[*idx] = order;
771 } else {
772 new_orders.remove(*idx);
773 }
774 Some(AstNode::OrderByList(new_orders))
775 } else {
776 None
777 }
778 }
779
780 (AstNode::Expr(expr), PathComponent::Field(field)) => match (expr, field) {
782 (Expr::BinaryOp { left: _, op, right }, AstField::Left) => {
783 if let Some(AstNode::Expr(new_left)) = new_child {
784 Some(AstNode::Expr(Expr::BinaryOp {
785 left: Box::new(new_left),
786 op: op.clone(),
787 right: right.clone(),
788 }))
789 } else {
790 None
791 }
792 }
793 (Expr::BinaryOp { left, op, right: _ }, AstField::Right) => {
794 if let Some(AstNode::Expr(new_right)) = new_child {
795 Some(AstNode::Expr(Expr::BinaryOp {
796 left: left.clone(),
797 op: op.clone(),
798 right: Box::new(new_right),
799 }))
800 } else {
801 None
802 }
803 }
804 (Expr::Nested(_), AstField::Inner) => {
805 if let Some(AstNode::Expr(new_inner)) = new_child {
806 Some(AstNode::Expr(Expr::Nested(Box::new(new_inner))))
807 } else {
808 None
809 }
810 }
811 _ => None,
812 },
813
814 (AstNode::SelectItem(select_item), PathComponent::Field(field)) => {
816 match (select_item, field) {
817 (SelectItem::UnnamedExpr(_), AstField::Expr) => {
818 if let Some(AstNode::Expr(new_expr)) = new_child {
819 Some(AstNode::SelectItem(SelectItem::UnnamedExpr(new_expr)))
820 } else {
821 None
822 }
823 }
824 (SelectItem::ExprWithAlias { alias, .. }, AstField::Expr) => {
825 if let Some(AstNode::Expr(new_expr)) = new_child {
826 Some(AstNode::SelectItem(SelectItem::ExprWithAlias {
827 expr: new_expr,
828 alias: alias.clone(),
829 }))
830 } else {
831 None
832 }
833 }
834 _ => None,
835 }
836 }
837
838 (AstNode::OrderByExpr(order_by), PathComponent::Field(field)) => match field {
840 AstField::Expr => {
841 if let Some(AstNode::Expr(new_expr)) = new_child {
842 Some(AstNode::OrderByExpr(OrderByExpr {
843 expr: new_expr,
844 asc: order_by.asc,
845 nulls_first: order_by.nulls_first,
846 }))
847 } else {
848 None
849 }
850 }
851 _ => None,
852 },
853
854 (AstNode::With(with_clause), PathComponent::Field(field)) => match field {
856 AstField::CteTable => {
857 if let Some(AstNode::CteList(new_ctes)) = new_child {
858 let mut new_with = with_clause.clone();
859 new_with.cte_tables = new_ctes;
860 Some(AstNode::With(new_with))
861 } else {
862 let mut new_with = with_clause.clone();
864 new_with.cte_tables = vec![];
865 Some(AstNode::With(new_with))
866 }
867 }
868 _ => None,
869 },
870
871 (AstNode::CteList(ctes), PathComponent::Index(idx)) => {
873 if let Some(AstNode::Cte(new_cte)) = new_child {
874 if *idx < ctes.len() {
875 let mut new_ctes = ctes.clone();
876 new_ctes[*idx] = new_cte;
877 Some(AstNode::CteList(new_ctes))
878 } else {
879 None
880 }
881 } else {
882 None
883 }
884 }
885
886 (AstNode::Cte(cte), PathComponent::Field(field)) => match field {
888 AstField::CteInner => {
889 if let Some(AstNode::Query(new_query)) = new_child {
890 let mut new_cte = cte.clone();
891 new_cte.cte_inner = CteInner::Query(new_query);
892 Some(AstNode::Cte(new_cte))
893 } else {
894 None
895 }
896 }
897 _ => None,
898 },
899
900 _ => {
901 tracing::debug!(
903 "set_child: No match for {} ({:?}) with component {:?}",
904 AstNodeType::from(self),
905 std::mem::discriminant(self),
906 component
907 );
908 None
909 }
910 }
911 }
912
913 pub fn to_statement(&self) -> Option<Statement> {
915 match self {
916 AstNode::Statement(stmt) => Some(stmt.clone()),
917 _ => None,
918 }
919 }
920}
921
922pub fn get_node_at_path(root: &AstNode, path: &AstPath) -> Option<AstNode> {
925 let mut current = root.clone();
926 for component in path {
927 current = current.get_child(component)?;
928 }
929 Some(current)
930}
931
932pub fn set_node_at_path(
935 root: &AstNode,
936 path: &AstPath,
937 new_node: Option<AstNode>,
938) -> Option<AstNode> {
939 if path.is_empty() {
940 return new_node;
941 }
942
943 let result = root.clone();
944 let mut current_path = Vec::new();
945
946 for component in &path[..path.len() - 1] {
948 current_path.push(component.clone());
949 }
950
951 let parent = get_node_at_path(&result, ¤t_path)?;
953
954 let modified_parent = parent.set_child(&path[path.len() - 1], new_node)?;
956
957 if current_path.is_empty() {
959 Some(modified_parent)
960 } else {
961 set_node_at_path(&result, ¤t_path, Some(modified_parent))
962 }
963}
964
965fn explore_child_field(
967 node: &AstNode,
968 field: AstField,
969 current_path: &AstPath,
970 paths: &mut Vec<AstPath>,
971) {
972 let field_component = PathComponent::field(field);
973 let child_path = [current_path.clone(), vec![field_component.clone()]].concat();
974 let relative_path = vec![field_component];
975
976 if let Some(child_node) = get_node_at_path(node, &relative_path) {
977 let child_paths = enumerate_reduction_paths(&child_node, child_path);
979 paths.extend(child_paths);
980 }
981}
982
983fn path_depth(path: &AstPath) -> usize {
986 path.len()
987}
988
989pub fn enumerate_reduction_paths(node: &AstNode, current_path: AstPath) -> Vec<AstPath> {
992 let mut paths = vec![current_path.clone()];
993
994 tracing::debug!(
995 "Enumerating paths for node {:?} at path {}",
996 get_node_type_name(node),
997 display_ast_path(¤t_path)
998 );
999
1000 match node {
1001 AstNode::Statement(Statement::Query(_)) => {
1002 explore_child_field(node, AstField::Query, ¤t_path, &mut paths);
1003 }
1004
1005 AstNode::Statement(Statement::CreateView { .. }) => {
1006 explore_child_field(node, AstField::Query, ¤t_path, &mut paths);
1007 }
1008
1009 AstNode::Query(_query) => {
1010 explore_child_field(node, AstField::Body, ¤t_path, &mut paths);
1011 explore_child_field(node, AstField::With, ¤t_path, &mut paths);
1012 explore_child_field(node, AstField::OrderBy, ¤t_path, &mut paths);
1013 }
1014
1015 AstNode::Select(_) => {
1016 explore_child_field(node, AstField::Projection, ¤t_path, &mut paths);
1017 explore_child_field(node, AstField::From, ¤t_path, &mut paths);
1018 explore_child_field(node, AstField::GroupBy, ¤t_path, &mut paths);
1019
1020 let selection_path = [current_path.clone(), vec![PathComponent::selection()]].concat();
1022 if get_node_at_path(node, &vec![PathComponent::selection()]).is_some() {
1023 paths.push(selection_path);
1024 }
1025
1026 let having_path = [current_path.clone(), vec![PathComponent::having()]].concat();
1027 if get_node_at_path(node, &vec![PathComponent::having()]).is_some() {
1028 paths.push(having_path);
1029 }
1030 }
1031
1032 AstNode::SelectItemList(items) => {
1034 for i in 0..items.len() {
1035 let item_path = [current_path.clone(), vec![PathComponent::Index(i)]].concat();
1036 paths.push(item_path);
1037 }
1038 }
1039
1040 AstNode::ExprList(exprs) => {
1041 for i in 0..exprs.len() {
1042 let expr_path = [current_path.clone(), vec![PathComponent::Index(i)]].concat();
1043 paths.push(expr_path.clone());
1044 let relative_path = vec![PathComponent::Index(i)];
1046 if let Some(expr_node) = get_node_at_path(node, &relative_path) {
1047 paths.extend(enumerate_reduction_paths(&expr_node, expr_path));
1048 }
1049 }
1050 }
1051
1052 AstNode::TableList(tables) => {
1053 for i in 0..tables.len() {
1054 let table_path = [current_path.clone(), vec![PathComponent::Index(i)]].concat();
1055 paths.push(table_path.clone());
1056 if let Some(table_node) = node.get_child(&PathComponent::Index(i)) {
1058 paths.extend(enumerate_reduction_paths(&table_node, table_path));
1059 }
1060 }
1061 }
1062
1063 AstNode::TableWithJoins(_) => {
1065 explore_child_field(node, AstField::Relation, ¤t_path, &mut paths);
1066 explore_child_field(node, AstField::Joins, ¤t_path, &mut paths);
1067 }
1068
1069 AstNode::Join(_) => {
1071 explore_child_field(node, AstField::Relation, ¤t_path, &mut paths);
1072 }
1073
1074 AstNode::TableFactor(_) => {
1076 explore_child_field(node, AstField::Subquery, ¤t_path, &mut paths);
1078 }
1079
1080 AstNode::JoinList(joins) => {
1082 for i in 0..joins.len() {
1083 let join_path = [current_path.clone(), vec![PathComponent::Index(i)]].concat();
1084 paths.push(join_path.clone());
1085 if let Some(join_node) = node.get_child(&PathComponent::Index(i)) {
1087 paths.extend(enumerate_reduction_paths(&join_node, join_path));
1088 }
1089 }
1090 }
1091
1092 AstNode::OrderByList(orders) => {
1093 for i in 0..orders.len() {
1094 let order_path = [current_path.clone(), vec![PathComponent::Index(i)]].concat();
1095 paths.push(order_path);
1096 }
1097 }
1098
1099 AstNode::Expr(expr) => match expr {
1101 Expr::BinaryOp { .. } => {
1102 let left_path = [current_path.clone(), vec![PathComponent::left()]].concat();
1103 let right_path = [current_path.clone(), vec![PathComponent::right()]].concat();
1104 paths.push(left_path);
1105 paths.push(right_path);
1106 }
1107 Expr::Case {
1108 operand,
1109 else_result,
1110 ..
1111 } => {
1112 if operand.is_some() {
1113 let operand_path =
1114 [current_path.clone(), vec![PathComponent::operand()]].concat();
1115 paths.push(operand_path);
1116 }
1117 if else_result.is_some() {
1118 let else_path =
1119 [current_path.clone(), vec![PathComponent::else_result()]].concat();
1120 paths.push(else_path);
1121 }
1122 }
1123 Expr::Exists(_) => {
1124 explore_child_field(node, AstField::Subquery, ¤t_path, &mut paths);
1125 }
1126 Expr::Subquery(_) => {
1127 explore_child_field(node, AstField::Subquery, ¤t_path, &mut paths);
1128 }
1129 _ => {}
1130 },
1131
1132 AstNode::With(_) => {
1134 explore_child_field(node, AstField::CteTable, ¤t_path, &mut paths);
1135 }
1136
1137 AstNode::CteList(ctes) => {
1139 for i in 0..ctes.len() {
1140 let cte_path = [current_path.clone(), vec![PathComponent::Index(i)]].concat();
1141 paths.push(cte_path.clone());
1142
1143 if let Some(cte_node) = get_node_at_path(node, &vec![PathComponent::Index(i)]) {
1145 paths.extend(enumerate_reduction_paths(&cte_node, cte_path));
1146 }
1147 }
1148 }
1149
1150 AstNode::Cte(_) => {
1152 explore_child_field(node, AstField::CteInner, ¤t_path, &mut paths);
1153 }
1154
1155 _ => {}
1156 }
1157
1158 paths.sort_by_key(path_depth);
1162
1163 paths
1164}
1165
1166pub fn statement_to_ast_node(stmt: &Statement) -> AstNode {
1168 AstNode::Statement(stmt.clone())
1169}
1170
1171pub fn ast_node_to_statement(node: &AstNode) -> Option<Statement> {
1173 match node {
1174 AstNode::Statement(stmt) => Some(stmt.clone()),
1175 AstNode::Query(query) => Some(Statement::Query(Box::new(query.as_ref().clone()))),
1176 _ => None,
1177 }
1178}
1179
1180pub fn get_node_type_name(node: &AstNode) -> String {
1182 AstNodeType::from(node).to_string()
1183}
1184
1185#[cfg(test)]
1186mod tests {
1187 use risingwave_sqlparser::parser::Parser;
1188
1189 use super::*;
1190
1191 #[test]
1192 fn test_path_enumeration() {
1193 let sql = "SELECT a FROM b;";
1194 let parsed = Parser::parse_sql(sql).expect("Failed to parse SQL");
1195 let stmt = &parsed[0];
1196 let ast_node = statement_to_ast_node(stmt);
1197
1198 let paths = enumerate_reduction_paths(&ast_node, vec![]);
1199
1200 assert!(paths.len() >= 3);
1202 println!("Found {} paths for simple query", paths.len());
1203 }
1204
1205 #[test]
1206 fn test_create_materialized_view() {
1207 let sql = "CREATE MATERIALIZED VIEW stream_query AS SELECT min((tumble_0.c5 + tumble_0.c5)) AS col_0, false AS col_1, TIME '07:30:48' AS col_2, tumble_0.c14 AS col_3 FROM tumble(alltypes1, alltypes1.c11, INTERVAL '10') AS tumble_0 WHERE tumble_0.c1 GROUP BY tumble_0.c10, tumble_0.c9, tumble_0.c13, tumble_0.c1, tumble_0.c16, tumble_0.c14, tumble_0.c5, tumble_0.c8;";
1208 let parsed = Parser::parse_sql(sql).expect("Failed to parse SQL");
1209 let stmt = &parsed[0];
1210 let ast_node = statement_to_ast_node(stmt);
1211
1212 let paths = enumerate_reduction_paths(&ast_node, vec![]);
1213
1214 println!("Found {} paths for CREATE MATERIALIZED VIEW", paths.len());
1215 for (i, path) in paths.iter().enumerate() {
1216 println!("Path {}: {}", i, display_ast_path(path));
1217 }
1218
1219 assert!(!paths.is_empty());
1221
1222 assert!(get_node_at_path(&ast_node, &paths[0]).is_some());
1224 }
1225}