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(_) => write!(
59                        f,
60                        "'{}'",
61                        v.as_scalar_ref_impl().to_text_with_type(&data_type)
62                    ),
63                    DataType::List { .. } => write!(f, "{}", v.as_list().display_for_explain()),
64                },
65            }?;
66            write!(f, ":{:?}", data_type)
67        }
68    }
69}
70
71impl Literal {
72    pub fn new(data: Datum, data_type: DataType) -> Self {
73        assert!(
74            literal_type_match(&data_type, data.as_ref()),
75            "data_type: {:?}, data: {:?}",
76            data_type,
77            data
78        );
79        Literal {
80            data,
81            data_type: Some(data_type),
82        }
83    }
84
85    pub fn new_untyped(data: Option<String>) -> Self {
86        Literal {
87            data: data.map(Into::into),
88            data_type: None,
89        }
90    }
91
92    pub fn get_data(&self) -> &Datum {
93        &self.data
94    }
95
96    pub fn get_data_type(&self) -> &Option<DataType> {
97        &self.data_type
98    }
99
100    pub fn is_untyped(&self) -> bool {
101        self.data_type.is_none()
102    }
103
104    pub(super) fn from_expr_proto(
105        proto: &risingwave_pb::expr::ExprNode,
106    ) -> crate::error::Result<Self> {
107        let data_type = proto.get_return_type()?;
108        Ok(Self {
109            data: value_encoding_to_literal(&proto.rex_node, &data_type.into())?,
110            data_type: Some(data_type.into()),
111        })
112    }
113}
114
115impl Expr for Literal {
116    fn return_type(&self) -> DataType {
117        self.data_type.clone().unwrap_or(DataType::Varchar)
118    }
119
120    fn to_expr_proto(&self) -> risingwave_pb::expr::ExprNode {
121        use risingwave_pb::expr::*;
122        ExprNode {
123            function_type: ExprType::Unspecified as i32,
124            return_type: Some(self.return_type().to_protobuf()),
125            rex_node: Some(literal_to_value_encoding(self.get_data())),
126        }
127    }
128}
129
130/// Convert a literal value (datum) into protobuf.
131pub fn literal_to_value_encoding(d: &Datum) -> RexNode {
132    RexNode::Constant(d.to_protobuf())
133}
134
135/// Convert protobuf into a literal value (datum).
136fn value_encoding_to_literal(
137    proto: &Option<RexNode>,
138    ty: &DataType,
139) -> crate::error::Result<Datum> {
140    if let Some(rex_node) = proto {
141        if let RexNode::Constant(prost_datum) = rex_node {
142            let datum = Datum::from_protobuf(prost_datum, ty)?;
143            Ok(datum)
144        } else {
145            unreachable!()
146        }
147    } else {
148        Ok(None)
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use risingwave_common::array::{ListValue, StructValue};
155    use risingwave_common::types::{DataType, Datum, ScalarImpl, StructType};
156    use risingwave_common::util::value_encoding::DatumFromProtoExt;
157    use risingwave_pb::expr::expr_node::RexNode;
158
159    use crate::expr::literal::literal_to_value_encoding;
160
161    #[test]
162    fn test_struct_to_value_encoding() {
163        let value = StructValue::new(vec![
164            Some(ScalarImpl::Utf8("".into())),
165            Some(2.into()),
166            Some(3.into()),
167        ]);
168        let data = Some(ScalarImpl::Struct(value.clone()));
169        let node = literal_to_value_encoding(&data);
170        if let RexNode::Constant(prost) = node {
171            let data2 = Datum::from_protobuf(
172                &prost,
173                &StructType::unnamed(vec![DataType::Varchar, DataType::Int32, DataType::Int32])
174                    .into(),
175            )
176            .unwrap()
177            .unwrap();
178            assert_eq!(ScalarImpl::Struct(value), data2);
179        }
180    }
181
182    #[test]
183    fn test_list_to_value_encoding() {
184        let value = ListValue::from_iter(["1", "2", ""]);
185        let data = Some(ScalarImpl::List(value.clone()));
186        let node = literal_to_value_encoding(&data);
187        if let RexNode::Constant(prost) = node {
188            let data2 = Datum::from_protobuf(&prost, &DataType::List(Box::new(DataType::Varchar)))
189                .unwrap()
190                .unwrap();
191            assert_eq!(ScalarImpl::List(value), data2);
192        }
193    }
194}