blob: 33512b0c354d6a10f06181d465625faac6d572c0 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use std::fmt;
/// Operators applied to expressions
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Hash)]
pub enum Operator {
/// Expressions are equal
Eq,
/// Expressions are not equal
NotEq,
/// Left side is smaller than right side
Lt,
/// Left side is smaller or equal to right side
LtEq,
/// Left side is greater than right side
Gt,
/// Left side is greater or equal to right side
GtEq,
/// Addition
Plus,
/// Subtraction
Minus,
/// Multiplication operator, like `*`
Multiply,
/// Division operator, like `/`
Divide,
/// Remainder operator, like `%`
Modulo,
/// Logical AND, like `&&`
And,
/// Logical OR, like `||`
Or,
/// `IS DISTINCT FROM` (see [`distinct`])
///
/// [`distinct`]: arrow::compute::kernels::cmp::distinct
IsDistinctFrom,
/// `IS NOT DISTINCT FROM` (see [`not_distinct`])
///
/// [`not_distinct`]: arrow::compute::kernels::cmp::not_distinct
IsNotDistinctFrom,
/// Case sensitive regex match
RegexMatch,
/// Case insensitive regex match
RegexIMatch,
/// Case sensitive regex not match
RegexNotMatch,
/// Case insensitive regex not match
RegexNotIMatch,
/// Case sensitive pattern match
LikeMatch,
/// Case insensitive pattern match
ILikeMatch,
/// Case sensitive pattern not match
NotLikeMatch,
/// Case insensitive pattern not match
NotILikeMatch,
/// Bitwise and, like `&`
BitwiseAnd,
/// Bitwise or, like `|`
BitwiseOr,
/// Bitwise xor, such as `^` in MySQL or `#` in PostgreSQL
BitwiseXor,
/// Bitwise right, like `>>`
BitwiseShiftRight,
/// Bitwise left, like `<<`
BitwiseShiftLeft,
/// String concat
StringConcat,
/// At arrow, like `@>`.
///
/// Currently only supported to be used with lists:
/// ```sql
/// select [1,3] <@ [1,2,3]
/// ```
AtArrow,
/// Arrow at, like `<@`.
///
/// Currently only supported to be used with lists:
/// ```sql
/// select [1,2,3] @> [1,3]
/// ```
ArrowAt,
/// Arrow, like `->`.
///
/// Not implemented in DataFusion yet.
Arrow,
/// Long arrow, like `->>`
///
/// Not implemented in DataFusion yet.
LongArrow,
/// Hash arrow, like `#>`
///
/// Not implemented in DataFusion yet.
HashArrow,
/// Hash long arrow, like `#>>`
///
/// Not implemented in DataFusion yet.
HashLongArrow,
/// At at, like `@@`
///
/// Not implemented in DataFusion yet.
AtAt,
/// Integer division operator, like `DIV` from MySQL or `//` from DuckDB
///
/// Not implemented in DataFusion yet.
IntegerDivide,
/// Hash Minis, like `#-`
///
/// Not implemented in DataFusion yet.
HashMinus,
/// At question, like `@?`
///
/// Not implemented in DataFusion yet.
AtQuestion,
/// Question, like `?`
///
/// Not implemented in DataFusion yet.
Question,
/// Question and, like `?&`
///
/// Not implemented in DataFusion yet.
QuestionAnd,
/// Question pipe, like `?|`
///
/// Not implemented in DataFusion yet.
QuestionPipe,
}
impl Operator {
/// If the operator can be negated, return the negated operator
/// otherwise return None
pub fn negate(&self) -> Option<Operator> {
match self {
Operator::Eq => Some(Operator::NotEq),
Operator::NotEq => Some(Operator::Eq),
Operator::Lt => Some(Operator::GtEq),
Operator::LtEq => Some(Operator::Gt),
Operator::Gt => Some(Operator::LtEq),
Operator::GtEq => Some(Operator::Lt),
Operator::IsDistinctFrom => Some(Operator::IsNotDistinctFrom),
Operator::IsNotDistinctFrom => Some(Operator::IsDistinctFrom),
Operator::LikeMatch => Some(Operator::NotLikeMatch),
Operator::ILikeMatch => Some(Operator::NotILikeMatch),
Operator::NotLikeMatch => Some(Operator::LikeMatch),
Operator::NotILikeMatch => Some(Operator::ILikeMatch),
Operator::Plus
| Operator::Minus
| Operator::Multiply
| Operator::Divide
| Operator::Modulo
| Operator::And
| Operator::Or
| Operator::RegexMatch
| Operator::RegexIMatch
| Operator::RegexNotMatch
| Operator::RegexNotIMatch
| Operator::BitwiseAnd
| Operator::BitwiseOr
| Operator::BitwiseXor
| Operator::BitwiseShiftRight
| Operator::BitwiseShiftLeft
| Operator::StringConcat
| Operator::AtArrow
| Operator::ArrowAt
| Operator::Arrow
| Operator::LongArrow
| Operator::HashArrow
| Operator::HashLongArrow
| Operator::AtAt
| Operator::IntegerDivide
| Operator::HashMinus
| Operator::AtQuestion
| Operator::Question
| Operator::QuestionAnd
| Operator::QuestionPipe => None,
}
}
/// Return true if the operator is a numerical operator.
///
/// For example, 'Binary(a, +, b)' would be a numerical expression.
/// PostgresSQL concept: <https://www.postgresql.org/docs/7.0/operators2198.htm>
pub fn is_numerical_operators(&self) -> bool {
matches!(
self,
Operator::Plus
| Operator::Minus
| Operator::Multiply
| Operator::Divide
| Operator::Modulo
)
}
/// Return true if the comparison operator can be used in interval arithmetic and constraint
/// propagation
///
/// For example, 'Binary(a, >, b)' expression supports propagation.
pub fn supports_propagation(&self) -> bool {
matches!(
self,
Operator::Eq
| Operator::NotEq
| Operator::Lt
| Operator::LtEq
| Operator::Gt
| Operator::GtEq
| Operator::IsDistinctFrom
| Operator::IsNotDistinctFrom
| Operator::RegexMatch
| Operator::RegexIMatch
| Operator::RegexNotMatch
| Operator::RegexNotIMatch
)
}
/// Return true if the operator is a logic operator.
///
/// For example, 'Binary(Binary(a, >, b), AND, Binary(a, <, b + 3))' would
/// be a logical expression.
pub fn is_logic_operator(&self) -> bool {
matches!(self, Operator::And | Operator::Or)
}
/// Return the operator where swapping lhs and rhs wouldn't change the result.
///
/// For example `Binary(50, >=, a)` could also be represented as `Binary(a, <=, 50)`.
pub fn swap(&self) -> Option<Operator> {
match self {
Operator::Eq => Some(Operator::Eq),
Operator::NotEq => Some(Operator::NotEq),
Operator::Lt => Some(Operator::Gt),
Operator::LtEq => Some(Operator::GtEq),
Operator::Gt => Some(Operator::Lt),
Operator::GtEq => Some(Operator::LtEq),
Operator::AtArrow => Some(Operator::ArrowAt),
Operator::ArrowAt => Some(Operator::AtArrow),
Operator::IsDistinctFrom
| Operator::IsNotDistinctFrom
| Operator::Plus
| Operator::Minus
| Operator::Multiply
| Operator::Divide
| Operator::Modulo
| Operator::And
| Operator::Or
| Operator::RegexMatch
| Operator::RegexIMatch
| Operator::RegexNotMatch
| Operator::RegexNotIMatch
| Operator::LikeMatch
| Operator::ILikeMatch
| Operator::NotLikeMatch
| Operator::NotILikeMatch
| Operator::BitwiseAnd
| Operator::BitwiseOr
| Operator::BitwiseXor
| Operator::BitwiseShiftRight
| Operator::BitwiseShiftLeft
| Operator::StringConcat
| Operator::Arrow
| Operator::LongArrow
| Operator::HashArrow
| Operator::HashLongArrow
| Operator::AtAt
| Operator::IntegerDivide
| Operator::HashMinus
| Operator::AtQuestion
| Operator::Question
| Operator::QuestionAnd
| Operator::QuestionPipe => None,
}
}
/// Get the operator precedence
/// use <https://www.postgresql.org/docs/7.2/sql-precedence.html> as a reference
pub fn precedence(&self) -> u8 {
match self {
Operator::Or => 5,
Operator::And => 10,
Operator::Eq | Operator::NotEq | Operator::LtEq | Operator::GtEq => 15,
Operator::Lt | Operator::Gt => 20,
Operator::LikeMatch
| Operator::NotLikeMatch
| Operator::ILikeMatch
| Operator::NotILikeMatch => 25,
Operator::IsDistinctFrom
| Operator::IsNotDistinctFrom
| Operator::RegexMatch
| Operator::RegexNotMatch
| Operator::RegexIMatch
| Operator::RegexNotIMatch
| Operator::BitwiseAnd
| Operator::BitwiseOr
| Operator::BitwiseShiftLeft
| Operator::BitwiseShiftRight
| Operator::BitwiseXor
| Operator::StringConcat
| Operator::AtArrow
| Operator::ArrowAt
| Operator::Arrow
| Operator::LongArrow
| Operator::HashArrow
| Operator::HashLongArrow
| Operator::AtAt
| Operator::IntegerDivide
| Operator::HashMinus
| Operator::AtQuestion
| Operator::Question
| Operator::QuestionAnd
| Operator::QuestionPipe => 30,
Operator::Plus | Operator::Minus => 40,
Operator::Multiply | Operator::Divide | Operator::Modulo => 45,
}
}
/// Returns true if the `Expr::BinaryOperator` with this operator
/// is guaranteed to return null if either side is null.
pub fn returns_null_on_null(&self) -> bool {
match self {
Operator::Eq
| Operator::NotEq
| Operator::Lt
| Operator::LtEq
| Operator::Gt
| Operator::GtEq
| Operator::Plus
| Operator::Minus
| Operator::Multiply
| Operator::Divide
| Operator::Modulo
| Operator::RegexMatch
| Operator::RegexIMatch
| Operator::RegexNotMatch
| Operator::RegexNotIMatch
| Operator::LikeMatch
| Operator::ILikeMatch
| Operator::NotLikeMatch
| Operator::NotILikeMatch
| Operator::BitwiseAnd
| Operator::BitwiseOr
| Operator::BitwiseXor
| Operator::BitwiseShiftRight
| Operator::BitwiseShiftLeft
| Operator::AtArrow
| Operator::ArrowAt
| Operator::Arrow
| Operator::LongArrow
| Operator::HashArrow
| Operator::HashLongArrow
| Operator::AtAt
| Operator::IntegerDivide
| Operator::HashMinus
| Operator::AtQuestion
| Operator::Question
| Operator::QuestionAnd
| Operator::QuestionPipe => true,
// E.g. `TRUE OR NULL` is `TRUE`
Operator::Or
// E.g. `FALSE AND NULL` is `FALSE`
| Operator::And
// IS DISTINCT FROM and IS NOT DISTINCT FROM always return a TRUE/FALSE value, never NULL
| Operator::IsDistinctFrom
| Operator::IsNotDistinctFrom
// DataFusion string concatenation operator treats NULL as an empty string
| Operator::StringConcat => false,
}
}
}
impl fmt::Display for Operator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let display = match &self {
Operator::Eq => "=",
Operator::NotEq => "!=",
Operator::Lt => "<",
Operator::LtEq => "<=",
Operator::Gt => ">",
Operator::GtEq => ">=",
Operator::Plus => "+",
Operator::Minus => "-",
Operator::Multiply => "*",
Operator::Divide => "/",
Operator::Modulo => "%",
Operator::And => "AND",
Operator::Or => "OR",
Operator::RegexMatch => "~",
Operator::RegexIMatch => "~*",
Operator::RegexNotMatch => "!~",
Operator::RegexNotIMatch => "!~*",
Operator::LikeMatch => "~~",
Operator::ILikeMatch => "~~*",
Operator::NotLikeMatch => "!~~",
Operator::NotILikeMatch => "!~~*",
Operator::IsDistinctFrom => "IS DISTINCT FROM",
Operator::IsNotDistinctFrom => "IS NOT DISTINCT FROM",
Operator::BitwiseAnd => "&",
Operator::BitwiseOr => "|",
Operator::BitwiseXor => "BIT_XOR",
Operator::BitwiseShiftRight => ">>",
Operator::BitwiseShiftLeft => "<<",
Operator::StringConcat => "||",
Operator::AtArrow => "@>",
Operator::ArrowAt => "<@",
Operator::Arrow => "->",
Operator::LongArrow => "->>",
Operator::HashArrow => "#>",
Operator::HashLongArrow => "#>>",
Operator::AtAt => "@@",
Operator::IntegerDivide => "DIV",
Operator::HashMinus => "#-",
Operator::AtQuestion => "@?",
Operator::Question => "?",
Operator::QuestionAnd => "?&",
Operator::QuestionPipe => "?|",
};
write!(f, "{display}")
}
}