Skip to main content

risingwave_frontend/optimizer/plan_node/
logical_table_function.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 super::utils::impl_distill_by_unit;
16use super::{
17    ColPrunable, ExprRewritable, Logical, LogicalFilter, LogicalPlanRef as PlanRef, LogicalProject,
18    PlanBase, PredicatePushdown, ToBatch, ToStream, generic,
19};
20use crate::error::Result;
21use crate::expr::{ExprRewriter, ExprVisitor, TableFunction};
22use crate::optimizer::optimizer_context::OptimizerContextRef;
23use crate::optimizer::plan_node::expr_visitable::ExprVisitable;
24use crate::optimizer::plan_node::{
25    ColumnPruningContext, PredicatePushdownContext, RewriteStreamContext, ToStreamContext,
26};
27use crate::utils::{ColIndexMapping, Condition};
28
29/// `LogicalTableFunction` is a scalar/table function used as a relation (in the `FROM` clause).
30///
31/// If the function returns a struct, it will be flattened into multiple columns.
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub struct LogicalTableFunction {
34    pub base: PlanBase<Logical>,
35    core: generic::TableFunction,
36}
37
38impl LogicalTableFunction {
39    fn with_core(core: generic::TableFunction) -> Self {
40        let base = PlanBase::new_logical_with_core(&core);
41        Self { base, core }
42    }
43
44    /// Create a [`LogicalTableFunction`] node. Used internally by optimizer.
45    pub fn new(
46        table_function: TableFunction,
47        with_ordinality: bool,
48        ctx: OptimizerContextRef,
49    ) -> Self {
50        Self::with_core(generic::TableFunction::new(
51            table_function,
52            with_ordinality,
53            ctx,
54        ))
55    }
56
57    pub fn table_function(&self) -> &TableFunction {
58        &self.core.table_function
59    }
60
61    pub fn with_ordinality(&self) -> bool {
62        self.core.with_ordinality
63    }
64}
65
66impl_plan_tree_node_for_leaf! { Logical, LogicalTableFunction }
67impl_distill_by_unit!(LogicalTableFunction, core, "LogicalTableFunction");
68
69impl ColPrunable for LogicalTableFunction {
70    fn prune_col(&self, required_cols: &[usize], _ctx: &mut ColumnPruningContext) -> PlanRef {
71        // No pruning.
72        LogicalProject::with_out_col_idx(self.clone().into(), required_cols.iter().copied()).into()
73    }
74}
75
76impl ExprRewritable<Logical> for LogicalTableFunction {
77    fn has_rewritable_expr(&self) -> bool {
78        true
79    }
80
81    fn rewrite_exprs(&self, r: &mut dyn ExprRewriter) -> PlanRef {
82        let mut core = self.core.clone();
83        core.rewrite_exprs(r);
84        Self::with_core(core).into()
85    }
86}
87
88impl ExprVisitable for LogicalTableFunction {
89    fn visit_exprs(&self, v: &mut dyn ExprVisitor) {
90        self.core.visit_exprs(v);
91    }
92}
93
94impl PredicatePushdown for LogicalTableFunction {
95    fn predicate_pushdown(
96        &self,
97        predicate: Condition,
98        _ctx: &mut PredicatePushdownContext,
99    ) -> PlanRef {
100        LogicalFilter::create(self.clone().into(), predicate)
101    }
102}
103
104impl ToBatch for LogicalTableFunction {
105    fn to_batch(&self) -> Result<crate::optimizer::plan_node::BatchPlanRef> {
106        unreachable!("TableFunction should be converted to ProjectSet")
107    }
108}
109
110impl ToStream for LogicalTableFunction {
111    fn to_stream(
112        &self,
113        _ctx: &mut ToStreamContext,
114    ) -> Result<crate::optimizer::plan_node::StreamPlanRef> {
115        unreachable!("TableFunction should be converted to ProjectSet")
116    }
117
118    fn logical_rewrite_for_stream(
119        &self,
120        _ctx: &mut RewriteStreamContext,
121    ) -> Result<(PlanRef, ColIndexMapping)> {
122        unreachable!("TableFunction should be converted to ProjectSet")
123    }
124}