risingwave_frontend/expr/
literal.rs

1// Copyright 2025 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::types::{DataType, Datum, ToText, literal_type_match};
16use risingwave_common::util::value_encoding::{DatumFromProtoExt, DatumToProtoExt};
17use risingwave_pb::expr::expr_node::RexNode;
18
19use super::Expr;
20use crate::expr::ExprType;
21#[derive(Clone, Eq, PartialEq, Hash)]
22pub struct Literal {
23    data: Datum,
24    // `null` or `'foo'` is of `unknown` type until used in a typed context (e.g. func arg)
25    data_type: Option<DataType>,
26}
27
28impl std::fmt::Debug for Literal {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        if f.alternate() {
31            f.debug_struct("Literal")
32                .field("data", &self.data)
33                .field("data_type", &self.data_type)
34                .finish()
35        } else {
36            let data_type = self.return_type();
37            match &self.data {
38                None => write!(f, "null"),
39                Some(v) => match data_type {
40                    DataType::Boolean => write!(f, "{}", v.as_bool()),
41                    DataType::Int16
42                    | DataType::Int32
43                    | DataType::Int64
44                    | DataType::Serial
45                    | DataType::Decimal
46                    | DataType::Float32
47                    | DataType::Float64 => write!(f, "{}", v.as_scalar_ref_impl().to_text()),
48                    DataType::Varchar
49                    | DataType::Bytea
50                    | DataType::Date
51                    | DataType::Timestamp
52                    | DataType::Timestamptz
53                    | DataType::Time
54                    | DataType::Interval
55                    | DataType::Jsonb
56                    | DataType::Int256
57                    | DataType::Struct(_)
58                    | DataType::Map(_)
59                    | DataType::Vector(_) => write!(
60                        f,
61                        "'{}'",
62                        v.as_scalar_ref_impl().to_text_with_type(&data_type)
63                    ),
64                    DataType::List { .. } => write!(f, "{}", v.as_list().display_for_explain()),
65                },
66            }?;
67            write!(f, ":{:?}", data_type)
68        }
69    }
70}
71
72impl Literal {
73    pub fn new(data: Datum, data_type: DataType) -> Self {
74        assert!(
75            literal_type_match(&data_type, data.as_ref()),
76            "data_type: {:?}, data: {:?}",
77            data_type,
78            data
79        );
80        Literal {
81            data,
82            data_type: Some(data_type),
83        }
84    }
85
86    pub fn new_untyped(data: Option<String>) -> Self {
87        Literal {
88            data: data.map(Into::into),
89            data_type: None,
90        }
91    }
92
93    pub fn get_data(&self) -> &Datum {
94        &self.data
95    }
96
97    pub fn get_data_type(&self) -> &Option<DataType> {
98        &self.data_type
99    }
100
101    pub fn is_untyped(&self) -> bool {
102        self.data_type.is_none()
103    }
104
105    pub(super) fn from_expr_proto(
106        proto: &risingwave_pb::expr::ExprNode,
107    ) -> crate::error::Result<Self> {
108        let data_type = proto.get_return_type()?;
109        Ok(Self {
110            data: value_encoding_to_literal(&proto.rex_node, &data_type.into())?,
111            data_type: Some(data_type.into()),
112        })
113    }
114}
115
116impl Expr for Literal {
117    fn return_type(&self) -> DataType {
118        self.data_type.clone().unwrap_or(DataType::Varchar)
119    }
120
121    fn try_to_expr_proto(&self) -> Result<risingwave_pb::expr::ExprNode, String> {
122        use risingwave_pb::expr::*;
123
124        Ok(ExprNode {
125            function_type: ExprType::Unspecified as i32,
126            return_type: Some(self.return_type().to_protobuf()),
127            rex_node: Some(literal_to_value_encoding(self.get_data())),
128        })
129    }
130}
131
132/// Convert a literal value (datum) into protobuf.
133pub fn literal_to_value_encoding(d: &Datum) -> RexNode {
134    RexNode::Constant(d.to_protobuf())
135}
136
137/// Convert protobuf into a literal value (datum).
138fn value_encoding_to_literal(
139    proto: &Option<RexNode>,
140    ty: &DataType,
141) -> crate::error::Result<Datum> {
142    if let Some(rex_node) = proto {
143        if let RexNode::Constant(prost_datum) = rex_node {
144            let datum = Datum::from_protobuf(prost_datum, ty)?;
145            Ok(datum)
146        } else {
147            unreachable!()
148        }
149    } else {
150        Ok(None)
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    use risingwave_common::array::{ListValue, StructValue};
157    use risingwave_common::types::{DataType, Datum, ScalarImpl, StructType};
158    use risingwave_common::util::value_encoding::DatumFromProtoExt;
159    use risingwave_pb::expr::expr_node::RexNode;
160
161    use crate::expr::literal::literal_to_value_encoding;
162
163    #[test]
164    fn test_struct_to_value_encoding() {
165        let value = StructValue::new(vec![
166            Some(ScalarImpl::Utf8("".into())),
167            Some(2.into()),
168            Some(3.into()),
169        ]);
170        let data = Some(ScalarImpl::Struct(value.clone()));
171        let node = literal_to_value_encoding(&data);
172        if let RexNode::Constant(prost) = node {
173            let data2 = Datum::from_protobuf(
174                &prost,
175                &StructType::unnamed(vec![DataType::Varchar, DataType::Int32, DataType::Int32])
176                    .into(),
177            )
178            .unwrap()
179            .unwrap();
180            assert_eq!(ScalarImpl::Struct(value), data2);
181        }
182    }
183
184    #[test]
185    fn test_list_to_value_encoding() {
186        let value = ListValue::from_iter(["1", "2", ""]);
187        let data = Some(ScalarImpl::List(value.clone()));
188        let node = literal_to_value_encoding(&data);
189        if let RexNode::Constant(prost) = node {
190            let data2 = Datum::from_protobuf(&prost, &DataType::List(Box::new(DataType::Varchar)))
191                .unwrap()
192                .unwrap();
193            assert_eq!(ScalarImpl::List(value), data2);
194        }
195    }
196}