1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
mod display;
use super::*;
/// An SQL expression of any type.
///
/// The parser does not distinguish between expressions of different types
/// (e.g. boolean vs string), so the caller must handle expressions of
/// inappropriate type, like `WHERE 1` or `SELECT 1=1`, as necessary.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Expr {
/// Identifier e.g. table name or column name
Identifier(Ident),
/// Unqualified wildcard (`*`). SQL allows this in limited contexts, such as:
/// - right after `SELECT` (which is represented as a [SelectItem::Wildcard] instead)
/// - or as part of an aggregate function, e.g. `COUNT(*)`,
///
/// ...but we currently also accept it in contexts where it doesn't make
/// sense, such as `* + *`
Wildcard,
/// Qualified wildcard, e.g. `alias.*` or `schema.table.*`.
/// (Same caveats apply to `QualifiedWildcard` as to `Wildcard`.)
QualifiedWildcard(Vec<Ident>),
/// Multi-part identifier, e.g. `table_alias.column` or `schema.table.col`
CompoundIdentifier(Vec<Ident>),
/// `IS NULL` expression
IsNull(Box<Expr>),
/// `IS NOT NULL` expression
IsNotNull(Box<Expr>),
/// `[ NOT ] IN (val1, val2, ...)`
InList(InList),
/// `[ NOT ] IN (SELECT ...)`
InSubquery(InSubquery),
/// `<expr> [ NOT ] BETWEEN <low> AND <high>`
Between(Between),
/// Binary operation e.g. `1 + 1` or `foo > bar`
BinaryOp(BinaryOp),
/// Unary operation e.g. `NOT foo`
UnaryOp(UnaryOp),
/// CAST an expression to a different data type e.g. `CAST(foo AS VARCHAR(123))`
Cast(Cast),
/// TRY_CAST an expression to a different data type e.g. `TRY_CAST(foo AS VARCHAR(123))`
// this differs from CAST in the choice of how to implement invalid conversions
TryCast(TryCast),
/// EXTRACT(DateTimeField FROM <expr>)
Extract(Extract),
/// SUBSTRING(<expr> [FROM <expr>] [FOR <expr>])
Substring(Substring),
/// TRIM([BOTH | LEADING | TRAILING] <expr> [FROM <expr>])\
/// Or\
/// TRIM(<expr>)
Trim(Trim),
/// `expr COLLATE collation`
Collate(Collate),
/// Nested expression e.g. `(foo > bar)` or `(1)`
Nested(Box<Expr>),
/// A literal value, such as string, number, date or NULL
Value(Value),
/// A constant of form `<data_type> 'value'`.
/// This can represent ANSI SQL `DATE`, `TIME`, and `TIMESTAMP` literals (such as `DATE '2020-01-01'`),
/// as well as constants of other types (a non-standard PostgreSQL extension).
TypedString(TypedString),
MapAccess(MapAccess),
/// Scalar function call e.g. `LEFT(foo, 5)`
Function(Function),
/// `CASE [<operand>] WHEN <condition> THEN <result> ... [ELSE <result>] END`
///
/// Note we only recognize a complete single expression as `<condition>`,
/// not `< 0` nor `1, 2, 3` as allowed in a `<simple when clause>` per
/// <https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#simple-when-clause>
Case(Case),
/// An exists expression `EXISTS(SELECT ...)`, used in expressions like
/// `WHERE EXISTS (SELECT ...)`.
Exists(Box<Query>),
/// A parenthesized subquery `(SELECT ...)`, used in expression like
/// `SELECT (subquery) AS x` or `WHERE (subquery) = x`
Subquery(Box<Query>),
/// The `LISTAGG` function `SELECT LISTAGG(...) WITHIN GROUP (ORDER BY ...)`
ListAgg(ListAgg),
}
/// `CASE [<operand>] WHEN <condition> THEN <result> ... [ELSE <result>] END`
///
/// Note we only recognize a complete single expression as `<condition>`,
/// not `< 0` nor `1, 2, 3` as allowed in a `<simple when clause>` per
/// <https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#simple-when-clause>
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Case {
pub operand: Option<Box<Expr>>,
pub conditions: Vec<Expr>,
pub results: Vec<Expr>,
pub else_result: Option<Box<Expr>>,
}
/// `[ NOT ] IN (val1, val2, ...)`
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct InList {
pub expr: Box<Expr>,
pub list: Vec<Expr>,
pub negated: bool,
}
/// `[ NOT ] IN (SELECT ...)`
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct InSubquery {
pub expr: Box<Expr>,
pub subquery: Box<Query>,
pub negated: bool,
}
/// `<expr> [ NOT ] BETWEEN <low> AND <high>`
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Between {
pub expr: Box<Expr>,
pub negated: bool,
pub low: Box<Expr>,
pub high: Box<Expr>,
}
/// Binary operation e.g. `1 + 1` or `foo > bar`
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct BinaryOp {
pub left: Box<Expr>,
pub op: BinaryOperator,
pub right: Box<Expr>,
}
/// Unary operation e.g. `NOT foo`
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct UnaryOp {
pub op: UnaryOperator,
pub expr: Box<Expr>,
}
/// CAST an expression to a different data type e.g. `CAST(foo AS VARCHAR(123))`
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Cast {
pub expr: Box<Expr>,
pub data_type: DataType,
}
/// TRY_CAST an expression to a different data type e.g. `TRY_CAST(foo AS VARCHAR(123))`
// this differs from CAST in the choice of how to implement invalid conversions
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct TryCast {
pub expr: Box<Expr>,
pub data_type: DataType,
}
/// EXTRACT(DateTimeField FROM <expr>)
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Extract {
pub field: DateTimeField,
pub expr: Box<Expr>,
}
/// SUBSTRING(<expr> [FROM <expr>] [FOR <expr>])
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Substring {
pub expr: Box<Expr>,
pub substring_from: Option<Box<Expr>>,
pub substring_for: Option<Box<Expr>>,
}
/// TRIM([BOTH | LEADING | TRAILING] <expr> [FROM <expr>])\
/// Or\
/// TRIM(<expr>)
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Trim {
pub expr: Box<Expr>,
// ([BOTH | LEADING | TRAILING], <expr>)
pub trim_where: Option<(TrimWhereField, Box<Expr>)>,
}
/// `expr COLLATE collation`
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Collate {
pub expr: Box<Expr>,
pub collation: ObjectName,
}
/// A constant of form `<data_type> 'value'`.
/// This can represent ANSI SQL `DATE`, `TIME`, and `TIMESTAMP` literals (such as `DATE '2020-01-01'`),
/// as well as constants of other types (a non-standard PostgreSQL extension).
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct TypedString {
pub data_type: DataType,
pub value: String,
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct MapAccess {
pub column: Box<Expr>,
pub key: String,
}