risingwave_frontend/expr/
expr_visitor.rs

1// Copyright 2022 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use risingwave_common::util::recursive::{Recurse, tracker};
16
17use super::{
18    AggCall, CorrelatedInputRef, EXPR_DEPTH_THRESHOLD, EXPR_TOO_DEEP_NOTICE, ExprImpl,
19    FunctionCall, FunctionCallWithLambda, InputRef, Literal, Now, Parameter, SecretRef, Subquery,
20    TableFunction, UserDefinedFunction, WindowFunction,
21};
22use crate::session::current::notice_to_user;
23
24/// The default implementation of [`ExprVisitor::visit_expr`] that simply dispatches to other
25/// methods based on the type of the expression.
26///
27/// You can use this function as a helper to reduce boilerplate code when implementing the trait.
28// TODO: This is essentially a mimic of `super` pattern from OO languages. Ideally, we should
29// adopt the style proposed in https://github.com/risingwavelabs/risingwave/issues/13477.
30pub fn default_visit_expr<V: ExprVisitor + ?Sized>(visitor: &mut V, expr: &ExprImpl) {
31    // TODO: Implementors may choose to not use this function at all, in which case we will fail
32    // to track the recursion and grow the stack as necessary. The current approach is only a
33    // best-effort attempt to prevent stack overflow.
34    tracker!().recurse(|t| {
35        if t.depth_reaches(EXPR_DEPTH_THRESHOLD) {
36            notice_to_user(EXPR_TOO_DEEP_NOTICE);
37        }
38
39        match expr {
40            ExprImpl::InputRef(inner) => visitor.visit_input_ref(inner),
41            ExprImpl::Literal(inner) => visitor.visit_literal(inner),
42            ExprImpl::FunctionCall(inner) => visitor.visit_function_call(inner),
43            ExprImpl::FunctionCallWithLambda(inner) => {
44                visitor.visit_function_call_with_lambda(inner)
45            }
46            ExprImpl::AggCall(inner) => visitor.visit_agg_call(inner),
47            ExprImpl::Subquery(inner) => visitor.visit_subquery(inner),
48            ExprImpl::CorrelatedInputRef(inner) => visitor.visit_correlated_input_ref(inner),
49            ExprImpl::TableFunction(inner) => visitor.visit_table_function(inner),
50            ExprImpl::WindowFunction(inner) => visitor.visit_window_function(inner),
51            ExprImpl::UserDefinedFunction(inner) => visitor.visit_user_defined_function(inner),
52            ExprImpl::Parameter(inner) => visitor.visit_parameter(inner),
53            ExprImpl::Now(inner) => visitor.visit_now(inner),
54            ExprImpl::SecretRef(inner) => visitor.visit_secret_ref(inner),
55        }
56    })
57}
58
59/// Traverse an expression tree.
60///
61/// Each method of the trait is a hook that can be overridden to customize the behavior when
62/// traversing the corresponding type of node. By default, every method recursively visits the
63/// subtree.
64///
65/// Note: The default implementation for `visit_subquery` is a no-op, i.e., expressions inside
66/// subqueries are not traversed.
67pub trait ExprVisitor {
68    fn visit_expr(&mut self, expr: &ExprImpl) {
69        default_visit_expr(self, expr)
70    }
71    fn visit_function_call(&mut self, func_call: &FunctionCall) {
72        func_call
73            .inputs()
74            .iter()
75            .for_each(|expr| self.visit_expr(expr));
76    }
77    fn visit_function_call_with_lambda(&mut self, func_call: &FunctionCallWithLambda) {
78        self.visit_function_call(func_call.base())
79    }
80    fn visit_agg_call(&mut self, agg_call: &AggCall) {
81        agg_call
82            .args()
83            .iter()
84            .for_each(|expr| self.visit_expr(expr));
85        agg_call.order_by().visit_expr(self);
86        agg_call.filter().visit_expr(self);
87    }
88    fn visit_parameter(&mut self, _: &Parameter) {}
89    fn visit_literal(&mut self, _: &Literal) {}
90    fn visit_input_ref(&mut self, _: &InputRef) {}
91    fn visit_subquery(&mut self, _: &Subquery) {}
92    fn visit_correlated_input_ref(&mut self, _: &CorrelatedInputRef) {}
93
94    fn visit_table_function(&mut self, func_call: &TableFunction) {
95        func_call.args.iter().for_each(|expr| self.visit_expr(expr));
96    }
97    fn visit_window_function(&mut self, func_call: &WindowFunction) {
98        func_call.args.iter().for_each(|expr| self.visit_expr(expr));
99    }
100    fn visit_user_defined_function(&mut self, func_call: &UserDefinedFunction) {
101        func_call.args.iter().for_each(|expr| self.visit_expr(expr));
102    }
103    fn visit_now(&mut self, _: &Now) {}
104    fn visit_secret_ref(&mut self, _: &SecretRef) {}
105}