risingwave_frontend/binder/expr/
binary_op.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::bail_not_implemented;
16use risingwave_common::types::{DataType, JsonbVal};
17use risingwave_sqlparser::ast::{BinaryOperator, Expr};
18
19use crate::binder::Binder;
20use crate::error::{ErrorCode, Result};
21use crate::expr::{Expr as _, ExprImpl, ExprType, FunctionCall};
22
23impl Binder {
24    pub(super) fn bind_binary_op(
25        &mut self,
26        left: &Expr,
27        op: &BinaryOperator,
28        mut right: &Expr,
29    ) -> Result<ExprImpl> {
30        let bound_left = self.bind_expr_inner(left)?;
31
32        let mut func_types = vec![];
33
34        right = match right {
35            Expr::SomeOp(expr) => {
36                func_types.push(ExprType::Some);
37                expr
38            }
39            Expr::AllOp(expr) => {
40                func_types.push(ExprType::All);
41                expr
42            }
43            right => right,
44        };
45
46        let bound_right = self.bind_expr_inner(right)?;
47
48        if let BinaryOperator::Custom(name) = &op
49            && matches!(name.as_str(), "@?" | "@@")
50        {
51            // jsonb @? jsonpath => jsonb_path_exists(jsonb, jsonpath, '{}', silent => true)
52            // jsonb @@ jsonpath => jsonb_path_match(jsonb, jsonpath, '{}', silent => true)
53            return Ok(FunctionCall::new_unchecked(
54                match name.as_str() {
55                    "@?" => ExprType::JsonbPathExists,
56                    "@@" => ExprType::JsonbPathMatch,
57                    _ => unreachable!(),
58                },
59                vec![
60                    bound_left,
61                    bound_right,
62                    ExprImpl::literal_jsonb(JsonbVal::empty_object()), // vars
63                    ExprImpl::literal_bool(true),                      // silent
64                ],
65                DataType::Boolean,
66            )
67            .into());
68        }
69
70        func_types.extend(Self::resolve_binary_operator(
71            op,
72            &bound_left,
73            &bound_right,
74        )?);
75
76        FunctionCall::new_binary_op_func(func_types, vec![bound_left, bound_right])
77    }
78
79    fn resolve_binary_operator(
80        op: &BinaryOperator,
81        bound_left: &ExprImpl,
82        bound_right: &ExprImpl,
83    ) -> Result<Vec<ExprType>> {
84        let mut func_types = vec![];
85        let final_type = match op {
86            BinaryOperator::Plus => ExprType::Add,
87            BinaryOperator::Minus => ExprType::Subtract,
88            BinaryOperator::Multiply => ExprType::Multiply,
89            BinaryOperator::Divide => ExprType::Divide,
90            BinaryOperator::Modulo => ExprType::Modulus,
91            BinaryOperator::NotEq => ExprType::NotEqual,
92            BinaryOperator::Eq => ExprType::Equal,
93            BinaryOperator::Lt => ExprType::LessThan,
94            BinaryOperator::LtEq => ExprType::LessThanOrEqual,
95            BinaryOperator::Gt => ExprType::GreaterThan,
96            BinaryOperator::GtEq => ExprType::GreaterThanOrEqual,
97            BinaryOperator::And => ExprType::And,
98            BinaryOperator::Or => ExprType::Or,
99            BinaryOperator::Pow => ExprType::Pow,
100            BinaryOperator::Custom(name) if name == "@>" => {
101                let left_type = (!bound_left.is_untyped()).then(|| bound_left.return_type());
102                let right_type = (!bound_right.is_untyped()).then(|| bound_right.return_type());
103                match (left_type, right_type) {
104                    (Some(DataType::List { .. }), Some(DataType::List { .. }))
105                    | (Some(DataType::List { .. }), None)
106                    | (None, Some(DataType::List { .. })) => ExprType::ArrayContains,
107                    (Some(DataType::Jsonb), Some(DataType::Jsonb))
108                    | (Some(DataType::Jsonb), None)
109                    | (None, Some(DataType::Jsonb)) => ExprType::JsonbContains,
110                    (left, right) => {
111                        return Err(ErrorCode::BindError(format!(
112                            "operator does not exist: {} @> {}",
113                            left.map_or_else(|| String::from("unknown"), |x| x.to_string()),
114                            right.map_or_else(|| String::from("unknown"), |x| x.to_string()),
115                        ))
116                        .into());
117                    }
118                }
119            }
120            BinaryOperator::Custom(name) if name == "<@" => {
121                let left_type = (!bound_left.is_untyped()).then(|| bound_left.return_type());
122                let right_type = (!bound_right.is_untyped()).then(|| bound_right.return_type());
123                match (left_type, right_type) {
124                    (Some(DataType::List { .. }), Some(DataType::List { .. }))
125                    | (Some(DataType::List { .. }), None)
126                    | (None, Some(DataType::List { .. })) => ExprType::ArrayContained,
127                    (Some(DataType::Jsonb), Some(DataType::Jsonb))
128                    | (Some(DataType::Jsonb), None)
129                    | (None, Some(DataType::Jsonb)) => ExprType::JsonbContained,
130                    (left, right) => {
131                        return Err(ErrorCode::BindError(format!(
132                            "operator does not exist: {} <@ {}",
133                            left.map_or_else(|| String::from("unknown"), |x| x.to_string()),
134                            right.map_or_else(|| String::from("unknown"), |x| x.to_string()),
135                        ))
136                        .into());
137                    }
138                }
139            }
140            BinaryOperator::Custom(name) if name == "&&" => {
141                let left_type = (!bound_left.is_untyped()).then(|| bound_left.return_type());
142                let right_type = (!bound_right.is_untyped()).then(|| bound_right.return_type());
143                match (left_type, right_type) {
144                    (Some(DataType::List { .. }), Some(DataType::List { .. }))
145                    | (Some(DataType::List { .. }), None)
146                    | (None, Some(DataType::List { .. })) => ExprType::ArrayOverlaps,
147                    (left, right) => {
148                        return Err(ErrorCode::BindError(format!(
149                            "operator does not exist: {} && {}",
150                            left.map_or_else(|| String::from("unknown"), |x| x.to_string()),
151                            right.map_or_else(|| String::from("unknown"), |x| x.to_string()),
152                        ))
153                        .into());
154                    }
155                }
156            }
157            BinaryOperator::Custom(name) if name == "||" => {
158                let left_type = (!bound_left.is_untyped()).then(|| bound_left.return_type());
159                let right_type = (!bound_right.is_untyped()).then(|| bound_right.return_type());
160                // Dispatching order following PostgreSQL:
161                // 1. array
162                // 2. explicitly string
163                // 3. `T || T` for any T with its own `||` operator
164                // 4. implicitly string (i.e. unknown)
165                // 5. invalid
166                match (left_type, right_type) {
167                    // array concatenation
168                    (Some(DataType::List { .. }), Some(DataType::List { .. }))
169                    | (Some(DataType::List { .. }), None)
170                    | (None, Some(DataType::List { .. })) => ExprType::ArrayCat,
171                    (Some(DataType::List { .. }), Some(_)) => ExprType::ArrayAppend,
172                    (Some(_), Some(DataType::List { .. })) => ExprType::ArrayPrepend,
173
174                    // string concatenation
175                    (Some(DataType::Varchar), _) | (_, Some(DataType::Varchar)) => {
176                        ExprType::ConcatOp
177                    }
178
179                    // jsonb concatenation
180                    (Some(DataType::Jsonb), Some(DataType::Jsonb))
181                    | (Some(DataType::Jsonb), None)
182                    | (None, Some(DataType::Jsonb)) => ExprType::JsonbConcat,
183
184                    // bytea concatenation
185                    (Some(DataType::Bytea), Some(DataType::Bytea))
186                    | (Some(DataType::Bytea), None)
187                    | (None, Some(DataType::Bytea)) => ExprType::ByteaConcatOp,
188
189                    // vector/halfvec concatenation
190                    (Some(DataType::Vector(_)), Some(DataType::Vector(_)))
191                    | (Some(DataType::Vector(_)), None)
192                    | (None, Some(DataType::Vector(_))) => ExprType::VecConcat,
193
194                    // TODO: varbit, tsvector, tsquery
195                    // Once these types are supported, they shall go before the unknown-as-string case below.
196
197                    // string concatenation
198                    (None, _) | (_, None) => ExprType::ConcatOp,
199
200                    // invalid
201                    (Some(left_type), Some(right_type)) => {
202                        return Err(ErrorCode::BindError(format!(
203                            "operator does not exist: {} || {}",
204                            left_type, right_type
205                        ))
206                        .into());
207                    }
208                }
209            }
210            BinaryOperator::Custom(name) => match name.as_str() {
211                // number
212                "&" => ExprType::BitwiseAnd,
213                "|" => ExprType::BitwiseOr,
214                "#" => ExprType::BitwiseXor,
215                "<<" => ExprType::BitwiseShiftLeft,
216                ">>" => ExprType::BitwiseShiftRight,
217                // string
218                "^@" => ExprType::StartsWith,
219                "~" => ExprType::RegexpEq,
220                "~~" => ExprType::Like,
221                "~~*" => ExprType::ILike,
222                "!~" => {
223                    func_types.push(ExprType::Not);
224                    ExprType::RegexpEq
225                }
226                "!~~" => {
227                    func_types.push(ExprType::Not);
228                    ExprType::Like
229                }
230                "!~~*" => {
231                    func_types.push(ExprType::Not);
232                    ExprType::ILike
233                }
234                // jsonb
235                "->" => ExprType::JsonbAccess,
236                "->>" => ExprType::JsonbAccessStr,
237                "#-" => ExprType::JsonbDeletePath,
238                "#>" => ExprType::JsonbExtractPathVariadic,
239                "#>>" => ExprType::JsonbExtractPathTextVariadic,
240                "?" => ExprType::JsonbExists,
241                "?|" => ExprType::JsonbExistsAny,
242                "?&" => ExprType::JsonbExistsAll,
243                // vector
244                "<->" => ExprType::L2Distance,
245                "<=>" => ExprType::CosineDistance,
246                "<+>" => ExprType::L1Distance,
247                "<#>" => {
248                    func_types.push(ExprType::Neg);
249                    ExprType::InnerProduct
250                }
251                _ => bail_not_implemented!(issue = 112, "binary op: {:?}", name),
252            },
253            BinaryOperator::Xor | BinaryOperator::PGQualified(_) => {
254                bail_not_implemented!(issue = 112, "binary op: {:?}", op)
255            }
256        };
257        func_types.push(final_type);
258        Ok(func_types)
259    }
260}