datafusion_expr_common/
operator.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::fmt;
19
20/// Operators applied to expressions
21#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Hash)]
22pub enum Operator {
23    /// Expressions are equal
24    Eq,
25    /// Expressions are not equal
26    NotEq,
27    /// Left side is smaller than right side
28    Lt,
29    /// Left side is smaller or equal to right side
30    LtEq,
31    /// Left side is greater than right side
32    Gt,
33    /// Left side is greater or equal to right side
34    GtEq,
35    /// Addition
36    Plus,
37    /// Subtraction
38    Minus,
39    /// Multiplication operator, like `*`
40    Multiply,
41    /// Division operator, like `/`
42    Divide,
43    /// Remainder operator, like `%`
44    Modulo,
45    /// Logical AND, like `&&`
46    And,
47    /// Logical OR, like `||`
48    Or,
49    /// `IS DISTINCT FROM` (see [`distinct`])
50    ///
51    /// [`distinct`]: arrow::compute::kernels::cmp::distinct
52    IsDistinctFrom,
53    /// `IS NOT DISTINCT FROM` (see [`not_distinct`])
54    ///
55    /// [`not_distinct`]: arrow::compute::kernels::cmp::not_distinct
56    IsNotDistinctFrom,
57    /// Case sensitive regex match
58    RegexMatch,
59    /// Case insensitive regex match
60    RegexIMatch,
61    /// Case sensitive regex not match
62    RegexNotMatch,
63    /// Case insensitive regex not match
64    RegexNotIMatch,
65    /// Case sensitive pattern match
66    LikeMatch,
67    /// Case insensitive pattern match
68    ILikeMatch,
69    /// Case sensitive pattern not match
70    NotLikeMatch,
71    /// Case insensitive pattern not match
72    NotILikeMatch,
73    /// Bitwise and, like `&`
74    BitwiseAnd,
75    /// Bitwise or, like `|`
76    BitwiseOr,
77    /// Bitwise xor, such as `^` in MySQL or `#` in PostgreSQL
78    BitwiseXor,
79    /// Bitwise right, like `>>`
80    BitwiseShiftRight,
81    /// Bitwise left, like `<<`
82    BitwiseShiftLeft,
83    /// String concat
84    StringConcat,
85    /// At arrow, like `@>`
86    AtArrow,
87    /// Arrow at, like `<@`
88    ArrowAt,
89}
90
91impl Operator {
92    /// If the operator can be negated, return the negated operator
93    /// otherwise return None
94    pub fn negate(&self) -> Option<Operator> {
95        match self {
96            Operator::Eq => Some(Operator::NotEq),
97            Operator::NotEq => Some(Operator::Eq),
98            Operator::Lt => Some(Operator::GtEq),
99            Operator::LtEq => Some(Operator::Gt),
100            Operator::Gt => Some(Operator::LtEq),
101            Operator::GtEq => Some(Operator::Lt),
102            Operator::IsDistinctFrom => Some(Operator::IsNotDistinctFrom),
103            Operator::IsNotDistinctFrom => Some(Operator::IsDistinctFrom),
104            Operator::LikeMatch => Some(Operator::NotLikeMatch),
105            Operator::ILikeMatch => Some(Operator::NotILikeMatch),
106            Operator::NotLikeMatch => Some(Operator::LikeMatch),
107            Operator::NotILikeMatch => Some(Operator::ILikeMatch),
108            Operator::Plus
109            | Operator::Minus
110            | Operator::Multiply
111            | Operator::Divide
112            | Operator::Modulo
113            | Operator::And
114            | Operator::Or
115            | Operator::RegexMatch
116            | Operator::RegexIMatch
117            | Operator::RegexNotMatch
118            | Operator::RegexNotIMatch
119            | Operator::BitwiseAnd
120            | Operator::BitwiseOr
121            | Operator::BitwiseXor
122            | Operator::BitwiseShiftRight
123            | Operator::BitwiseShiftLeft
124            | Operator::StringConcat
125            | Operator::AtArrow
126            | Operator::ArrowAt => None,
127        }
128    }
129
130    /// Return true if the operator is a numerical operator.
131    ///
132    /// For example, 'Binary(a, +, b)' would be a numerical expression.
133    /// PostgresSQL concept: <https://www.postgresql.org/docs/7.0/operators2198.htm>
134    pub fn is_numerical_operators(&self) -> bool {
135        matches!(
136            self,
137            Operator::Plus
138                | Operator::Minus
139                | Operator::Multiply
140                | Operator::Divide
141                | Operator::Modulo
142        )
143    }
144
145    /// Return true if the comparison operator can be used in interval arithmetic and constraint
146    /// propagation
147    ///
148    /// For example, 'Binary(a, >, b)' expression supports propagation.
149    pub fn supports_propagation(&self) -> bool {
150        matches!(
151            self,
152            Operator::Eq
153                | Operator::NotEq
154                | Operator::Lt
155                | Operator::LtEq
156                | Operator::Gt
157                | Operator::GtEq
158                | Operator::IsDistinctFrom
159                | Operator::IsNotDistinctFrom
160                | Operator::RegexMatch
161                | Operator::RegexIMatch
162                | Operator::RegexNotMatch
163                | Operator::RegexNotIMatch
164        )
165    }
166
167    /// Return true if the comparison operator can be used in interval arithmetic and constraint
168    /// propagation
169    ///
170    /// For example, 'Binary(a, >, b)' expression supports propagation.
171    #[deprecated(since = "43.0.0", note = "please use `supports_propagation` instead")]
172    pub fn is_comparison_operator(&self) -> bool {
173        self.supports_propagation()
174    }
175
176    /// Return true if the operator is a logic operator.
177    ///
178    /// For example, 'Binary(Binary(a, >, b), AND, Binary(a, <, b + 3))' would
179    /// be a logical expression.
180    pub fn is_logic_operator(&self) -> bool {
181        matches!(self, Operator::And | Operator::Or)
182    }
183
184    /// Return the operator where swapping lhs and rhs wouldn't change the result.
185    ///
186    /// For example `Binary(50, >=, a)` could also be represented as `Binary(a, <=, 50)`.
187    pub fn swap(&self) -> Option<Operator> {
188        match self {
189            Operator::Eq => Some(Operator::Eq),
190            Operator::NotEq => Some(Operator::NotEq),
191            Operator::Lt => Some(Operator::Gt),
192            Operator::LtEq => Some(Operator::GtEq),
193            Operator::Gt => Some(Operator::Lt),
194            Operator::GtEq => Some(Operator::LtEq),
195            Operator::AtArrow => Some(Operator::ArrowAt),
196            Operator::ArrowAt => Some(Operator::AtArrow),
197            Operator::IsDistinctFrom
198            | Operator::IsNotDistinctFrom
199            | Operator::Plus
200            | Operator::Minus
201            | Operator::Multiply
202            | Operator::Divide
203            | Operator::Modulo
204            | Operator::And
205            | Operator::Or
206            | Operator::RegexMatch
207            | Operator::RegexIMatch
208            | Operator::RegexNotMatch
209            | Operator::RegexNotIMatch
210            | Operator::LikeMatch
211            | Operator::ILikeMatch
212            | Operator::NotLikeMatch
213            | Operator::NotILikeMatch
214            | Operator::BitwiseAnd
215            | Operator::BitwiseOr
216            | Operator::BitwiseXor
217            | Operator::BitwiseShiftRight
218            | Operator::BitwiseShiftLeft
219            | Operator::StringConcat => None,
220        }
221    }
222
223    /// Get the operator precedence
224    /// use <https://www.postgresql.org/docs/7.2/sql-precedence.html> as a reference
225    pub fn precedence(&self) -> u8 {
226        match self {
227            Operator::Or => 5,
228            Operator::And => 10,
229            Operator::Eq | Operator::NotEq | Operator::LtEq | Operator::GtEq => 15,
230            Operator::Lt | Operator::Gt => 20,
231            Operator::LikeMatch
232            | Operator::NotLikeMatch
233            | Operator::ILikeMatch
234            | Operator::NotILikeMatch => 25,
235            Operator::IsDistinctFrom
236            | Operator::IsNotDistinctFrom
237            | Operator::RegexMatch
238            | Operator::RegexNotMatch
239            | Operator::RegexIMatch
240            | Operator::RegexNotIMatch
241            | Operator::BitwiseAnd
242            | Operator::BitwiseOr
243            | Operator::BitwiseShiftLeft
244            | Operator::BitwiseShiftRight
245            | Operator::BitwiseXor
246            | Operator::StringConcat
247            | Operator::AtArrow
248            | Operator::ArrowAt => 30,
249            Operator::Plus | Operator::Minus => 40,
250            Operator::Multiply | Operator::Divide | Operator::Modulo => 45,
251        }
252    }
253}
254
255impl fmt::Display for Operator {
256    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
257        let display = match &self {
258            Operator::Eq => "=",
259            Operator::NotEq => "!=",
260            Operator::Lt => "<",
261            Operator::LtEq => "<=",
262            Operator::Gt => ">",
263            Operator::GtEq => ">=",
264            Operator::Plus => "+",
265            Operator::Minus => "-",
266            Operator::Multiply => "*",
267            Operator::Divide => "/",
268            Operator::Modulo => "%",
269            Operator::And => "AND",
270            Operator::Or => "OR",
271            Operator::RegexMatch => "~",
272            Operator::RegexIMatch => "~*",
273            Operator::RegexNotMatch => "!~",
274            Operator::RegexNotIMatch => "!~*",
275            Operator::LikeMatch => "~~",
276            Operator::ILikeMatch => "~~*",
277            Operator::NotLikeMatch => "!~~",
278            Operator::NotILikeMatch => "!~~*",
279            Operator::IsDistinctFrom => "IS DISTINCT FROM",
280            Operator::IsNotDistinctFrom => "IS NOT DISTINCT FROM",
281            Operator::BitwiseAnd => "&",
282            Operator::BitwiseOr => "|",
283            Operator::BitwiseXor => "BIT_XOR",
284            Operator::BitwiseShiftRight => ">>",
285            Operator::BitwiseShiftLeft => "<<",
286            Operator::StringConcat => "||",
287            Operator::AtArrow => "@>",
288            Operator::ArrowAt => "<@",
289        };
290        write!(f, "{display}")
291    }
292}