Skip to main content

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