## Coverage Report

#### Created: 2025-11-22 06:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /Users/andrewlamb/Software/datafusion/datafusion/expr-common/src/operator.rs

    Line
    Count
    Source
    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
        ///
    87
        /// Currently only supported to be used with lists:
    88
        /// ```sql
    89
        /// select [1,3] <@ [1,2,3]
    90
        /// ```
    91
        AtArrow,
    92
        /// Arrow at, like `<@`.
    93
        ///
    94
        /// Currently only supported to be used with lists:
    95
        /// ```sql
    96
        /// select [1,2,3] @> [1,3]
    97
        /// ```
    98
        ArrowAt,
    99
        /// Arrow, like `->`.
    100
        ///
    101
        /// Not implemented in DataFusion yet.
    102
        Arrow,
    103
        /// Long arrow, like `->>`
    104
        ///
    105
        /// Not implemented in DataFusion yet.
    106
        LongArrow,
    107
        /// Hash arrow, like `#>`
    108
        ///
    109
        /// Not implemented in DataFusion yet.
    110
        HashArrow,
    111
        /// Hash long arrow, like `#>>`
    112
        ///
    113
        /// Not implemented in DataFusion yet.
    114
        HashLongArrow,
    115
        /// At at, like `@@`
    116
        ///
    117
        /// Not implemented in DataFusion yet.
    118
        AtAt,
    119
        /// Integer division operator, like `DIV` from MySQL or `//` from DuckDB
    120
        ///
    121
        /// Not implemented in DataFusion yet.
    122
        IntegerDivide,
    123
        /// Hash Minis, like `#-`
    124
        ///
    125
        /// Not implemented in DataFusion yet.
    126
        HashMinus,
    127
        /// At question, like `@?`
    128
        ///
    129
        /// Not implemented in DataFusion yet.
    130
        AtQuestion,
    131
        /// Question, like `?`
    132
        ///
    133
        /// Not implemented in DataFusion yet.
    134
        Question,
    135
        /// Question and, like `?&`
    136
        ///
    137
        /// Not implemented in DataFusion yet.
    138
        QuestionAnd,
    139
        /// Question pipe, like `?|`
    140
        ///
    141
        /// Not implemented in DataFusion yet.
    142
        QuestionPipe,
    143
    }
    144
    145
    impl Operator {
    146
        /// If the operator can be negated, return the negated operator
    147
        /// otherwise return None
    148
    0
        pub fn negate(&self) -> Option<Operator> {
    149
    0
            match self {
    150
    0
                Operator::Eq => Some(Operator::NotEq),
    151
    0
                Operator::NotEq => Some(Operator::Eq),
    152
    0
                Operator::Lt => Some(Operator::GtEq),
    153
    0
                Operator::LtEq => Some(Operator::Gt),
    154
    0
                Operator::Gt => Some(Operator::LtEq),
    155
    0
                Operator::GtEq => Some(Operator::Lt),
    156
    0
                Operator::IsDistinctFrom => Some(Operator::IsNotDistinctFrom),
    157
    0
                Operator::IsNotDistinctFrom => Some(Operator::IsDistinctFrom),
    158
    0
                Operator::LikeMatch => Some(Operator::NotLikeMatch),
    159
    0
                Operator::ILikeMatch => Some(Operator::NotILikeMatch),
    160
    0
                Operator::NotLikeMatch => Some(Operator::LikeMatch),
    161
    0
                Operator::NotILikeMatch => Some(Operator::ILikeMatch),
    162
                Operator::Plus
    163
                | Operator::Minus
    164
                | Operator::Multiply
    165
                | Operator::Divide
    166
                | Operator::Modulo
    167
                | Operator::And
    168
                | Operator::Or
    169
                | Operator::RegexMatch
    170
                | Operator::RegexIMatch
    171
                | Operator::RegexNotMatch
    172
                | Operator::RegexNotIMatch
    173
                | Operator::BitwiseAnd
    174
                | Operator::BitwiseOr
    175
                | Operator::BitwiseXor
    176
                | Operator::BitwiseShiftRight
    177
                | Operator::BitwiseShiftLeft
    178
                | Operator::StringConcat
    179
                | Operator::AtArrow
    180
                | Operator::ArrowAt
    181
                | Operator::Arrow
    182
                | Operator::LongArrow
    183
                | Operator::HashArrow
    184
                | Operator::HashLongArrow
    185
                | Operator::AtAt
    186
                | Operator::IntegerDivide
    187
                | Operator::HashMinus
    188
                | Operator::AtQuestion
    189
                | Operator::Question
    190
                | Operator::QuestionAnd
    191
    0
                | Operator::QuestionPipe => None,
    192
            }
    193
    0
        }
    194
    195
        /// Return true if the operator is a numerical operator.
    196
        ///
    197
        /// For example, 'Binary(a, +, b)' would be a numerical expression.
    198
        /// PostgresSQL concept: <https://www.postgresql.org/docs/7.0/operators2198.htm>
    199
    0
        pub fn is_numerical_operators(&self) -> bool {
    200
    0
            matches!(
    201
    0
                self,
    202
                Operator::Plus
    203
                    | Operator::Minus
    204
                    | Operator::Multiply
    205
                    | Operator::Divide
    206
                    | Operator::Modulo
    207
            )
    208
    0
        }
    209
    210
        /// Return true if the comparison operator can be used in interval arithmetic and constraint
    211
        /// propagation
    212
        ///
    213
        /// For example, 'Binary(a, >, b)' expression supports propagation.
    214
    0
        pub fn supports_propagation(&self) -> bool {
    215
    0
            matches!(
    216
    0
                self,
    217
                Operator::Eq
    218
                    | Operator::NotEq
    219
                    | Operator::Lt
    220
                    | Operator::LtEq
    221
                    | Operator::Gt
    222
                    | Operator::GtEq
    223
                    | Operator::IsDistinctFrom
    224
                    | Operator::IsNotDistinctFrom
    225
                    | Operator::RegexMatch
    226
                    | Operator::RegexIMatch
    227
                    | Operator::RegexNotMatch
    228
                    | Operator::RegexNotIMatch
    229
            )
    230
    0
        }
    231
    232
        /// Return true if the operator is a logic operator.
    233
        ///
    234
        /// For example, 'Binary(Binary(a, >, b), AND, Binary(a, <, b + 3))' would
    235
        /// be a logical expression.
    236
    0
        pub fn is_logic_operator(&self) -> bool {
    237
    0
            matches!(self, Operator::And | Operator::Or)
    238
    0
        }
    239
    240
        /// Return the operator where swapping lhs and rhs wouldn't change the result.
    241
        ///
    242
        /// For example `Binary(50, >=, a)` could also be represented as `Binary(a, <=, 50)`.
    243
    0
        pub fn swap(&self) -> Option<Operator> {
    244
    0
            match self {
    245
    0
                Operator::Eq => Some(Operator::Eq),
    246
    0
                Operator::NotEq => Some(Operator::NotEq),
    247
    0
                Operator::Lt => Some(Operator::Gt),
    248
    0
                Operator::LtEq => Some(Operator::GtEq),
    249
    0
                Operator::Gt => Some(Operator::Lt),
    250
    0
                Operator::GtEq => Some(Operator::LtEq),
    251
    0
                Operator::AtArrow => Some(Operator::ArrowAt),
    252
    0
                Operator::ArrowAt => Some(Operator::AtArrow),
    253
                Operator::IsDistinctFrom
    254
                | Operator::IsNotDistinctFrom
    255
                | Operator::Plus
    256
                | Operator::Minus
    257
                | Operator::Multiply
    258
                | Operator::Divide
    259
                | Operator::Modulo
    260
                | Operator::And
    261
                | Operator::Or
    262
                | Operator::RegexMatch
    263
                | Operator::RegexIMatch
    264
                | Operator::RegexNotMatch
    265
                | Operator::RegexNotIMatch
    266
                | Operator::LikeMatch
    267
                | Operator::ILikeMatch
    268
                | Operator::NotLikeMatch
    269
                | Operator::NotILikeMatch
    270
                | Operator::BitwiseAnd
    271
                | Operator::BitwiseOr
    272
                | Operator::BitwiseXor
    273
                | Operator::BitwiseShiftRight
    274
                | Operator::BitwiseShiftLeft
    275
                | Operator::StringConcat
    276
                | Operator::Arrow
    277
                | Operator::LongArrow
    278
                | Operator::HashArrow
    279
                | Operator::HashLongArrow
    280
                | Operator::AtAt
    281
                | Operator::IntegerDivide
    282
                | Operator::HashMinus
    283
                | Operator::AtQuestion
    284
                | Operator::Question
    285
                | Operator::QuestionAnd
    286
    0
                | Operator::QuestionPipe => None,
    287
            }
    288
    0
        }
    289
    290
        /// Get the operator precedence
    291
        /// use <https://www.postgresql.org/docs/7.2/sql-precedence.html> as a reference
    292
    0
        pub fn precedence(&self) -> u8 {
    293
    0
            match self {
    294
    0
                Operator::Or => 5,
    295
    0
                Operator::And => 10,
    296
    0
                Operator::Eq | Operator::NotEq | Operator::LtEq | Operator::GtEq => 15,
    297
    0
                Operator::Lt | Operator::Gt => 20,
    298
                Operator::LikeMatch
    299
                | Operator::NotLikeMatch
    300
                | Operator::ILikeMatch
    301
    0
                | Operator::NotILikeMatch => 25,
    302
                Operator::IsDistinctFrom
    303
                | Operator::IsNotDistinctFrom
    304
                | Operator::RegexMatch
    305
                | Operator::RegexNotMatch
    306
                | Operator::RegexIMatch
    307
                | Operator::RegexNotIMatch
    308
                | Operator::BitwiseAnd
    309
                | Operator::BitwiseOr
    310
                | Operator::BitwiseShiftLeft
    311
                | Operator::BitwiseShiftRight
    312
                | Operator::BitwiseXor
    313
                | Operator::StringConcat
    314
                | Operator::AtArrow
    315
                | Operator::ArrowAt
    316
                | Operator::Arrow
    317
                | Operator::LongArrow
    318
                | Operator::HashArrow
    319
                | Operator::HashLongArrow
    320
                | Operator::AtAt
    321
                | Operator::IntegerDivide
    322
                | Operator::HashMinus
    323
                | Operator::AtQuestion
    324
                | Operator::Question
    325
                | Operator::QuestionAnd
    326
    0
                | Operator::QuestionPipe => 30,
    327
    0
                Operator::Plus | Operator::Minus => 40,
    328
    0
                Operator::Multiply | Operator::Divide | Operator::Modulo => 45,
    329
            }
    330
    0
        }
    331
    332
        /// Returns true if the `Expr::BinaryOperator` with this operator
    333
        /// is guaranteed to return null if either side is null.
    334
    0
        pub fn returns_null_on_null(&self) -> bool {
    335
    0
            match self {
    336
                Operator::Eq
    337
                | Operator::NotEq
    338
                | Operator::Lt
    339
                | Operator::LtEq
    340
                | Operator::Gt
    341
                | Operator::GtEq
    342
                | Operator::Plus
    343
                | Operator::Minus
    344
                | Operator::Multiply
    345
                | Operator::Divide
    346
                | Operator::Modulo
    347
                | Operator::RegexMatch
    348
                | Operator::RegexIMatch
    349
                | Operator::RegexNotMatch
    350
                | Operator::RegexNotIMatch
    351
                | Operator::LikeMatch
    352
                | Operator::ILikeMatch
    353
                | Operator::NotLikeMatch
    354
                | Operator::NotILikeMatch
    355
                | Operator::BitwiseAnd
    356
                | Operator::BitwiseOr
    357
                | Operator::BitwiseXor
    358
                | Operator::BitwiseShiftRight
    359
                | Operator::BitwiseShiftLeft
    360
                | Operator::AtArrow
    361
                | Operator::ArrowAt
    362
                | Operator::Arrow
    363
                | Operator::LongArrow
    364
                | Operator::HashArrow
    365
                | Operator::HashLongArrow
    366
                | Operator::AtAt
    367
                | Operator::IntegerDivide
    368
                | Operator::HashMinus
    369
                | Operator::AtQuestion
    370
                | Operator::Question
    371
                | Operator::QuestionAnd
    372
    0
                | Operator::QuestionPipe => true,
    373
    374
                // E.g. `TRUE OR NULL` is `TRUE`
    375
                Operator::Or
    376
                // E.g. `FALSE AND NULL` is `FALSE`
    377
                | Operator::And
    378
                // IS DISTINCT FROM and IS NOT DISTINCT FROM always return a TRUE/FALSE value, never NULL
    379
                | Operator::IsDistinctFrom
    380
                | Operator::IsNotDistinctFrom
    381
                // DataFusion string concatenation operator treats NULL as an empty string
    382
    0
                | Operator::StringConcat => false,
    383
            }
    384
    0
        }
    385
    }
    386
    387
    impl fmt::Display for Operator {
    388
    0
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    389
    0
            let display = match &self {
    390
    0
                Operator::Eq => "=",
    391
    0
                Operator::NotEq => "!=",
    392
    0
                Operator::Lt => "<",
    393
    0
                Operator::LtEq => "<=",
    394
    0
                Operator::Gt => ">",
    395
    0
                Operator::GtEq => ">=",
    396
    0
                Operator::Plus => "+",
    397
    0
                Operator::Minus => "-",
    398
    0
                Operator::Multiply => "*",
    399
    0
                Operator::Divide => "/",
    400
    0
                Operator::Modulo => "%",
    401
    0
                Operator::And => "AND",
    402
    0
                Operator::Or => "OR",
    403
    0
                Operator::RegexMatch => "~",
    404
    0
                Operator::RegexIMatch => "~*",
    405
    0
                Operator::RegexNotMatch => "!~",
    406
    0
                Operator::RegexNotIMatch => "!~*",
    407
    0
                Operator::LikeMatch => "~~",
    408
    0
                Operator::ILikeMatch => "~~*",
    409
    0
                Operator::NotLikeMatch => "!~~",
    410
    0
                Operator::NotILikeMatch => "!~~*",
    411
    0
                Operator::IsDistinctFrom => "IS DISTINCT FROM",
    412
    0
                Operator::IsNotDistinctFrom => "IS NOT DISTINCT FROM",
    413
    0
                Operator::BitwiseAnd => "&",
    414
    0
                Operator::BitwiseOr => "|",
    415
    0
                Operator::BitwiseXor => "BIT_XOR",
    416
    0
                Operator::BitwiseShiftRight => ">>",
    417
    0
                Operator::BitwiseShiftLeft => "<<",
    418
    0
                Operator::StringConcat => "||",
    419
    0
                Operator::AtArrow => "@>",
    420
    0
                Operator::ArrowAt => "<@",
    421
    0
                Operator::Arrow => "->",
    422
    0
                Operator::LongArrow => "->>",
    423
    0
                Operator::HashArrow => "#>",
    424
    0
                Operator::HashLongArrow => "#>>",
    425
    0
                Operator::AtAt => "@@",
    426
    0
                Operator::IntegerDivide => "DIV",
    427
    0
                Operator::HashMinus => "#-",
    428
    0
                Operator::AtQuestion => "@?",
    429
    0
                Operator::Question => "?",
    430
    0
                Operator::QuestionAnd => "?&",
    431
    0
                Operator::QuestionPipe => "?|",
    432
            };
    433
    0
            write!(f, "{display}")
    434
    0
        }
    435
    }