Coverage Report

Created: 2024-10-13 08:39

/Users/andrewlamb/Software/datafusion/datafusion/expr-common/src/operator.rs
Line
Count
Source (jump to first uncovered line)
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
18
use std::fmt;
19
20
/// Operators applied to expressions
21
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Hash)]
22
pub 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
91
impl Operator {
92
    /// If the operator can be negated, return the negated operator
93
    /// otherwise return None
94
0
    pub fn negate(&self) -> Option<Operator> {
95
0
        match self {
96
0
            Operator::Eq => Some(Operator::NotEq),
97
0
            Operator::NotEq => Some(Operator::Eq),
98
0
            Operator::Lt => Some(Operator::GtEq),
99
0
            Operator::LtEq => Some(Operator::Gt),
100
0
            Operator::Gt => Some(Operator::LtEq),
101
0
            Operator::GtEq => Some(Operator::Lt),
102
0
            Operator::IsDistinctFrom => Some(Operator::IsNotDistinctFrom),
103
0
            Operator::IsNotDistinctFrom => Some(Operator::IsDistinctFrom),
104
0
            Operator::LikeMatch => Some(Operator::NotLikeMatch),
105
0
            Operator::ILikeMatch => Some(Operator::NotILikeMatch),
106
0
            Operator::NotLikeMatch => Some(Operator::LikeMatch),
107
0
            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
0
            | Operator::ArrowAt => None,
127
        }
128
0
    }
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
0
    pub fn is_numerical_operators(&self) -> bool {
135
0
        matches!(
136
0
            self,
137
            Operator::Plus
138
                | Operator::Minus
139
                | Operator::Multiply
140
                | Operator::Divide
141
                | Operator::Modulo
142
        )
143
0
    }
144
145
    /// Return true if the operator is a comparison operator.
146
    ///
147
    /// For example, 'Binary(a, >, b)' would be a comparison expression.
148
33.6k
    pub fn is_comparison_operator(&self) -> bool {
149
22.1k
        matches!(
150
33.6k
            self,
151
            Operator::Eq
152
                | Operator::NotEq
153
                | Operator::Lt
154
                | Operator::LtEq
155
                | Operator::Gt
156
                | Operator::GtEq
157
                | Operator::IsDistinctFrom
158
                | Operator::IsNotDistinctFrom
159
                | Operator::RegexMatch
160
                | Operator::RegexIMatch
161
                | Operator::RegexNotMatch
162
                | Operator::RegexNotIMatch
163
        )
164
33.6k
    }
165
166
    /// Return true if the operator is a logic operator.
167
    ///
168
    /// For example, 'Binary(Binary(a, >, b), AND, Binary(a, <, b + 3))' would
169
    /// be a logical expression.
170
0
    pub fn is_logic_operator(&self) -> bool {
171
0
        matches!(self, Operator::And | Operator::Or)
172
0
    }
173
174
    /// Return the operator where swapping lhs and rhs wouldn't change the result.
175
    ///
176
    /// For example `Binary(50, >=, a)` could also be represented as `Binary(a, <=, 50)`.
177
0
    pub fn swap(&self) -> Option<Operator> {
178
0
        match self {
179
0
            Operator::Eq => Some(Operator::Eq),
180
0
            Operator::NotEq => Some(Operator::NotEq),
181
0
            Operator::Lt => Some(Operator::Gt),
182
0
            Operator::LtEq => Some(Operator::GtEq),
183
0
            Operator::Gt => Some(Operator::Lt),
184
0
            Operator::GtEq => Some(Operator::LtEq),
185
0
            Operator::AtArrow => Some(Operator::ArrowAt),
186
0
            Operator::ArrowAt => Some(Operator::AtArrow),
187
            Operator::IsDistinctFrom
188
            | Operator::IsNotDistinctFrom
189
            | Operator::Plus
190
            | Operator::Minus
191
            | Operator::Multiply
192
            | Operator::Divide
193
            | Operator::Modulo
194
            | Operator::And
195
            | Operator::Or
196
            | Operator::RegexMatch
197
            | Operator::RegexIMatch
198
            | Operator::RegexNotMatch
199
            | Operator::RegexNotIMatch
200
            | Operator::LikeMatch
201
            | Operator::ILikeMatch
202
            | Operator::NotLikeMatch
203
            | Operator::NotILikeMatch
204
            | Operator::BitwiseAnd
205
            | Operator::BitwiseOr
206
            | Operator::BitwiseXor
207
            | Operator::BitwiseShiftRight
208
            | Operator::BitwiseShiftLeft
209
0
            | Operator::StringConcat => None,
210
        }
211
0
    }
212
213
    /// Get the operator precedence
214
    /// use <https://www.postgresql.org/docs/7.2/sql-precedence.html> as a reference
215
0
    pub fn precedence(&self) -> u8 {
216
0
        match self {
217
0
            Operator::Or => 5,
218
0
            Operator::And => 10,
219
0
            Operator::Eq | Operator::NotEq | Operator::LtEq | Operator::GtEq => 15,
220
0
            Operator::Lt | Operator::Gt => 20,
221
            Operator::LikeMatch
222
            | Operator::NotLikeMatch
223
            | Operator::ILikeMatch
224
0
            | Operator::NotILikeMatch => 25,
225
            Operator::IsDistinctFrom
226
            | Operator::IsNotDistinctFrom
227
            | Operator::RegexMatch
228
            | Operator::RegexNotMatch
229
            | Operator::RegexIMatch
230
            | Operator::RegexNotIMatch
231
            | Operator::BitwiseAnd
232
            | Operator::BitwiseOr
233
            | Operator::BitwiseShiftLeft
234
            | Operator::BitwiseShiftRight
235
            | Operator::BitwiseXor
236
            | Operator::StringConcat
237
            | Operator::AtArrow
238
0
            | Operator::ArrowAt => 30,
239
0
            Operator::Plus | Operator::Minus => 40,
240
0
            Operator::Multiply | Operator::Divide | Operator::Modulo => 45,
241
        }
242
0
    }
243
}
244
245
impl fmt::Display for Operator {
246
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
247
0
        let display = match &self {
248
0
            Operator::Eq => "=",
249
0
            Operator::NotEq => "!=",
250
0
            Operator::Lt => "<",
251
0
            Operator::LtEq => "<=",
252
0
            Operator::Gt => ">",
253
0
            Operator::GtEq => ">=",
254
0
            Operator::Plus => "+",
255
0
            Operator::Minus => "-",
256
0
            Operator::Multiply => "*",
257
0
            Operator::Divide => "/",
258
0
            Operator::Modulo => "%",
259
0
            Operator::And => "AND",
260
0
            Operator::Or => "OR",
261
0
            Operator::RegexMatch => "~",
262
0
            Operator::RegexIMatch => "~*",
263
0
            Operator::RegexNotMatch => "!~",
264
0
            Operator::RegexNotIMatch => "!~*",
265
0
            Operator::LikeMatch => "~~",
266
0
            Operator::ILikeMatch => "~~*",
267
0
            Operator::NotLikeMatch => "!~~",
268
0
            Operator::NotILikeMatch => "!~~*",
269
0
            Operator::IsDistinctFrom => "IS DISTINCT FROM",
270
0
            Operator::IsNotDistinctFrom => "IS NOT DISTINCT FROM",
271
0
            Operator::BitwiseAnd => "&",
272
0
            Operator::BitwiseOr => "|",
273
0
            Operator::BitwiseXor => "BIT_XOR",
274
0
            Operator::BitwiseShiftRight => ">>",
275
0
            Operator::BitwiseShiftLeft => "<<",
276
0
            Operator::StringConcat => "||",
277
0
            Operator::AtArrow => "@>",
278
0
            Operator::ArrowAt => "<@",
279
        };
280
0
        write!(f, "{display}")
281
0
    }
282
}