Skip to main content

risingwave_frontend/optimizer/plan_node/generic/
values.rs

1// Copyright 2026 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 std::sync::Arc;
16
17use educe::Educe;
18use pretty_xmlish::{Pretty, Str, XmlNode};
19use risingwave_common::catalog::Schema;
20
21use super::{DistillUnit, GenericPlanNode};
22use crate::expr::{Expr, ExprImpl, ExprRewriter, ExprVisitor};
23use crate::optimizer::optimizer_context::OptimizerContextRef;
24use crate::optimizer::plan_node::utils::childless_record;
25use crate::optimizer::property::FunctionalDependencySet;
26
27/// The convention-independent core of a values plan node.
28#[derive(Debug, Clone, Educe)]
29#[educe(PartialEq, Eq, Hash)]
30pub struct Values {
31    pub rows: Arc<[Vec<ExprImpl>]>,
32    pub schema: Schema,
33    pub stream_key: Option<Vec<usize>>,
34
35    #[educe(PartialEq(ignore))]
36    #[educe(Hash(ignore))]
37    pub ctx: OptimizerContextRef,
38}
39
40impl Values {
41    pub fn new(rows: Vec<Vec<ExprImpl>>, schema: Schema, ctx: OptimizerContextRef) -> Self {
42        Self::new_inner(rows, schema, ctx, None)
43    }
44
45    pub fn new_with_stream_key(
46        rows: Vec<Vec<ExprImpl>>,
47        schema: Schema,
48        ctx: OptimizerContextRef,
49        stream_key: Vec<usize>,
50    ) -> Self {
51        Self::new_inner(rows, schema, ctx, Some(stream_key))
52    }
53
54    fn new_inner(
55        rows: Vec<Vec<ExprImpl>>,
56        schema: Schema,
57        ctx: OptimizerContextRef,
58        stream_key: Option<Vec<usize>>,
59    ) -> Self {
60        for exprs in &rows {
61            for (i, expr) in exprs.iter().enumerate() {
62                assert_eq!(schema.fields()[i].data_type(), expr.return_type());
63            }
64        }
65
66        Self {
67            rows: rows.into(),
68            schema,
69            stream_key,
70            ctx,
71        }
72    }
73
74    pub fn rows(&self) -> &[Vec<ExprImpl>] {
75        self.rows.as_ref()
76    }
77
78    pub fn rewrite_exprs(&mut self, r: &mut dyn ExprRewriter) {
79        self.rows = self
80            .rows
81            .iter()
82            .map(|exprs| {
83                exprs
84                    .iter()
85                    .map(|e| r.rewrite_expr(e.clone()))
86                    .collect::<Vec<_>>()
87            })
88            .collect::<Vec<_>>()
89            .into();
90    }
91
92    pub fn visit_exprs(&self, v: &mut dyn ExprVisitor) {
93        self.rows.iter().flatten().for_each(|e| v.visit_expr(e));
94    }
95
96    pub fn rows_pretty<'a>(&self) -> Pretty<'a> {
97        let data = self
98            .rows()
99            .iter()
100            .map(|row| {
101                let collect = row.iter().map(Pretty::debug).collect();
102                Pretty::Array(collect)
103            })
104            .collect();
105        Pretty::Array(data)
106    }
107}
108
109impl GenericPlanNode for Values {
110    fn schema(&self) -> Schema {
111        self.schema.clone()
112    }
113
114    fn stream_key(&self) -> Option<Vec<usize>> {
115        self.stream_key.clone()
116    }
117
118    fn ctx(&self) -> OptimizerContextRef {
119        self.ctx.clone()
120    }
121
122    fn functional_dependency(&self) -> FunctionalDependencySet {
123        FunctionalDependencySet::new(self.schema.len())
124    }
125}
126
127impl DistillUnit for Values {
128    fn distill_with_name<'a>(&self, name: impl Into<Str<'a>>) -> XmlNode<'a> {
129        childless_record(
130            name,
131            vec![
132                ("rows", self.rows_pretty()),
133                ("schema", Pretty::debug(&self.schema)),
134            ],
135        )
136    }
137}