Skip to main content

Expr

Enum Expr 

Source
pub enum Expr {
Show 27 variants Literal(Literal), Column(ColumnName), NamedArg { name: String, expr: Box<Expr>, }, Variadic(Box<Expr>), Placeholder(u16), Binary { lhs: Box<Expr>, op: BinOp, rhs: Box<Expr>, }, Unary { op: UnOp, expr: Box<Expr>, }, Cast { expr: Box<Expr>, target: CastTarget, }, FieldAccess { base: Box<Expr>, field: String, }, IsNull { expr: Box<Expr>, negated: bool, }, BoolTest { expr: Box<Expr>, value: Option<bool>, negated: bool, }, FunctionCall { name: String, args: Vec<Expr>, }, AggregateOrdered { call: Box<Expr>, order_by: Vec<OrderBy>, distinct: bool, filter: Option<Box<Expr>>, }, Like { expr: Box<Expr>, pattern: Box<Expr>, negated: bool, case_insensitive: bool, }, WindowFunction { name: String, args: Vec<Expr>, partition_by: Vec<Expr>, order_by: Vec<(Expr, bool, Option<bool>)>, frame: Option<WindowFrame>, null_treatment: NullTreatment, filter: Option<Box<Expr>>, }, ScalarSubquery(Box<SelectStatement>), Exists { subquery: Box<SelectStatement>, negated: bool, }, InSubquery { expr: Box<Expr>, subquery: Box<SelectStatement>, negated: bool, }, RowInSubquery { row: Vec<Expr>, subquery: Box<SelectStatement>, negated: bool, }, RowCmpSubquery { row: Vec<Expr>, op: BinOp, subquery: Box<SelectStatement>, }, InList { expr: Box<Expr>, list: Vec<Expr>, negated: bool, }, Extract { field: ExtractField, source: Box<Expr>, }, Array(Vec<Expr>), ArraySubscript { target: Box<Expr>, index: Box<Expr>, }, ArraySlice { target: Box<Expr>, lo: Option<Box<Expr>>, hi: Option<Box<Expr>>, }, AnyAll { expr: Box<Expr>, op: BinOp, array: Box<Expr>, is_any: bool, }, Case { operand: Option<Box<Expr>>, branches: Vec<(Expr, Expr)>, else_branch: Option<Box<Expr>>, },
}

Variants§

§

Literal(Literal)

§

Column(ColumnName)

§

NamedArg

v7.39 (read01 round 77) — a NAMED call argument (f(x := 1), or the older f(x => 1) spelling). Which slot the name fills depends on the callee’s declared parameter names, and a user function’s live in the catalog — which the parser cannot see. So the name rides along in the tree and the evaluator, which has the catalog, does the reordering. Appears only inside a FunctionCall’s argument list.

Fields

§name: String
§expr: Box<Expr>
§

Variadic(Box<Expr>)

v7.39 (read01 round 100) — VARIADIC <array> as the last argument of a variadic function call (concat_ws(',', VARIADIC ARRAY[…])). The inner expression evaluates to an array whose elements the evaluator splices into the call as individual trailing arguments. Appears only inside a FunctionCall’s argument list.

§

Placeholder(u16)

v6.1.1 — $N parameter placeholder for the extended query protocol. The number is 1-based per PostgreSQL convention. Evaluation looks up params[N-1] from the prepared-statement bind buffer; out-of-range indices raise a runtime error (same shape as a column-not-found miss).

§

Binary

Fields

§lhs: Box<Expr>
§rhs: Box<Expr>
§

Unary

Fields

§op: UnOp
§expr: Box<Expr>
§

Cast

PG-style expr::TYPE cast. v1.3 supports VECTOR, INT, BIGINT, FLOAT, TEXT, BOOL targets; engine coerces at evaluation time.

Fields

§expr: Box<Expr>
§target: CastTarget
§

FieldAccess

v7.38 (read01, T9) — composite field access (expr).field. base evaluates to a composite/record value (an explicit ROW(...), a whole-row reference, or a composite-returning function); field names the member (f1..fN positional for an anonymous ROW, or the base column names for a whole-row). Only the parenthesised form reaches here — a bare a.b is parsed as a qualified column reference.

Fields

§base: Box<Expr>
§field: String
§

IsNull

Postfix IS NULL / IS NOT NULL. Returns BOOL.

Fields

§expr: Box<Expr>
§negated: bool
§

BoolTest

v7.39 (round 328, V45) — x IS [NOT] TRUE | FALSE | UNKNOWN, the three-valued boolean tests. value is Some(true) for TRUE, Some(false) for FALSE and None for UNKNOWN.

These used to be lowered to CASE / IS NULL right in the parser. The semantics were right, but the AST then had no way to say what the user wrote, so every renderer printed the lowering: CHECK ((a > 1) IS TRUE) came back as CHECK ((CASE WHEN (a > 1) THEN TRUE ELSE FALSE END)), and a dumped view lost the form too.

Fields

§expr: Box<Expr>
§value: Option<bool>
§negated: bool
§

FunctionCall

Function call name(args...). v1.4 supports a small built-in set (length, upper, lower, abs, coalesce); unknown names error at eval time so the parser stays open for v1.5 aggregates.

Fields

§name: String
§args: Vec<Expr>
§

AggregateOrdered

v7.24 (mailrs round-16 A) — an aggregate call with an internal ordering: array_agg(x ORDER BY y DESC NULLS LAST). Wraps the plain Expr::FunctionCall so every existing FunctionCall consumer stays untouched; only the aggregate executor (and the expression walkers) know the wrapper. Non-aggregate evaluation contexts reject it at eval time.

Fields

§call: Box<Expr>
§order_by: Vec<OrderBy>
§distinct: bool

v7.25 (round-17) — COUNT(DISTINCT x) / string_agg(DISTINCT s, ','). The wrapper carries every aggregate modifier so plain FunctionCall stays untouched.

§filter: Option<Box<Expr>>

v7.32 (mailrs round-29) — agg(args) FILTER (WHERE cond). Only the rows where cond is true contribute to this aggregate (SQL:2003 T612 / PG 9.4). Carried as a first-class modifier — NOT desugared to agg(CASE WHEN cond THEN arg END), which is faithful for NULL-ignoring aggregates but WRONG for array_agg (it would collect a NULL per excluded row). The executor instead skips excluded rows before accumulation, which is correct for every aggregate.

§

Like

SQL LIKE predicate. pattern evaluates to text at runtime; wildcards are % (any run) and _ (one char), backslash escapes the next char (so \% matches a literal %).

Fields

§expr: Box<Expr>
§pattern: Box<Expr>
§negated: bool
§case_insensitive: bool

v7.25 (mailrs round-17) — ILIKE: case-insensitive match. PG folds both operands.

§

WindowFunction

v4.12 window function call: name(args) OVER (PARTITION BY ... ORDER BY ...). Supports ROW_NUMBER / RANK / DENSE_RANK and the partition-aware aggregates SUM / AVG / COUNT / MIN / MAX. The window frame defaults to “entire partition” for unordered windows and “from start of partition through current row” for ordered windows — no explicit ROWS / RANGE clause in v4.12 MVP.

Fields

§name: String
§args: Vec<Expr>
§partition_by: Vec<Expr>
§order_by: Vec<(Expr, bool, Option<bool>)>

v7.24.1 — third slot: explicit NULLS FIRST/LAST (None = PG default, same contract as OrderBy).

§frame: Option<WindowFrame>

v4.20 explicit frame. None means “use the default”: whole-partition when unordered, running aggregate from partition start through current row when ordered.

§null_treatment: NullTreatment

v6.4.2 — IGNORE NULLS / RESPECT NULLS modifier on LAG / LEAD / FIRST_VALUE / LAST_VALUE. Default is Respect (PG / ANSI default — NULLs participate). Other window functions ignore this flag.

§filter: Option<Box<Expr>>

v7.37 D.40 — agg(...) FILTER (WHERE cond) OVER (...). None = no FILTER. Only aggregate window functions honor it; the predicate restricts which peer rows contribute within the frame.

§

ScalarSubquery(Box<SelectStatement>)

v4.10 scalar subquery — (SELECT ...) used in expression position. Must return exactly one row × one column at eval time; the engine errors out otherwise. Uncorrelated only — the inner SELECT cannot reference outer columns.

§

Exists

v4.10 [NOT] EXISTS (SELECT ...). Returns Bool. Inner projection is ignored; only row-count matters.

Fields

§negated: bool
§

InSubquery

v4.10 expr [NOT] IN (SELECT ...). Inner SELECT must project exactly one column; membership is tested by Eq against each row’s value (NULL handling follows ANSI: NULL ∈ list ⇒ NULL ; otherwise present ⇒ true).

Fields

§expr: Box<Expr>
§negated: bool
§

RowInSubquery

(a, b, …) [NOT] IN (SELECT x, y, …) — a row constructor tested against a multi-column subquery. Row comparisons against a list decompose to OR-of-AND at parse time, but the subquery form can’t (its rows are only known at runtime), so this survives as its own node evaluated with PG’s row-comparison three-valued logic.

Fields

§row: Vec<Expr>
§negated: bool
§

RowCmpSubquery

(a, b, …) <op> (SELECT x, y, …) — a row constructor compared to a single-row subquery (=, <>, <, <=, >, >=). Like RowInSubquery, the literal-RHS form decomposes at parse time but the subquery form can’t, so it survives as its own node. The subquery must yield at most one row (zero → NULL, PG scalar-subquery rule).

Fields

§row: Vec<Expr>
§

InList

v7.30.2 (mailrs round-25) — expr [NOT] IN (a, b, …) as a FLAT list. Both the parser’s literal-list path and the engine’s IN-subquery materialisation used to desugar into a left-deep OR-Eq chain, so expression depth scaled with the element count — a 24k-row subquery result overflowed the 2 MiB worker stack (recursive eval AND recursive Box drop) and aborted embedding host processes. The flat node keeps depth constant: eval is an iterative scan with PG three-valued logic, drop is a Vec drop.

Fields

§expr: Box<Expr>
§list: Vec<Expr>
§negated: bool
§

Extract

EXTRACT(<field> FROM <source>) — pull an integer component out of a DATE or TIMESTAMP. Parsed as its own AST node because the FROM keyword is what separates the two halves, not a comma.

Fields

§source: Box<Expr>
§

Array(Vec<Expr>)

v7.10.10 — ARRAY[expr, expr, …] array constructor. Each element is evaluated independently; NULLs are allowed. v7.10 supports only single-dimension TEXT[] semantically; non-text elements coerce at engine evaluation time when the surrounding context (column type / cast) makes the target clear.

§

ArraySubscript

v7.10.10 — array subscript arr[i]. PG 1-based; the engine returns NULL for out-of-range indices.

Fields

§target: Box<Expr>
§index: Box<Expr>
§

ArraySlice

Array slice arr[lo:hi] — PG 1-based, both ends inclusive; a missing bound extends to that end of the array and out-of-range bounds clamp. Returns an array of the same element type.

Fields

§target: Box<Expr>
§

AnyAll

v7.10.12 — expr op ANY(arr) and expr op ALL(arr). The operator is the comparison binary op (Eq / Ne / Lt / …); the engine desugars: ANY returns true if any element satisfies; ALL returns true only if every element does. NULL handling follows PG’s three-valued logic.

Fields

§expr: Box<Expr>
§array: Box<Expr>
§is_any: bool

true = ANY, false = ALL.

§

Case

v7.13.0 — CASE WHEN <cond> THEN <val> ... ELSE <val> END (searched form, operand is None) and CASE <expr> WHEN <val> THEN <val> ... END (simple form, operand is the lead expression compared against each branch’s match). Each (when_expr, then_expr) branch stays as written; engine short-circuits on the first match. else_branch is None when no ELSE; evaluates to NULL. mailrs round-5 G9.

Fields

§operand: Option<Box<Expr>>
§branches: Vec<(Expr, Expr)>
§else_branch: Option<Box<Expr>>

Implementations§

Source§

impl Expr

Source

pub fn for_each_subquery_mut<E>( &mut self, f: &mut impl FnMut(&mut SelectStatement) -> Result<(), E>, ) -> Result<(), E>

v7.39 (round 305, V23) — hand every SelectStatement nested directly inside this expression to f. f receives each nested statement once; descending further (into that statement’s own clauses) is the caller’s job, which keeps this walk finite and lets the caller order the recursion.

The match is deliberately wildcard-free: a new Expr variant does not compile until it says whether it can carry a subquery. The row-count resolution pass is built on this, and a shape it silently failed to visit would leave a LimitExpr::Expr behind — which every row-count reader would take as “no limit”, i.e. the whole table. Compile-time exhaustiveness is what rules that out. Iterative on purpose. Expression trees here get deep (long boolean chains, big IN lists), and this walk is on the path of every statement; recursing would add a frame per node to a stack budget the engine already runs close to — a depth guard that runs on a deliberately small stack caught exactly that. Depth costs heap here instead.

Trait Implementations§

Source§

impl Clone for Expr

Source§

fn clone(&self) -> Expr

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Expr

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for Expr

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for Expr

Source§

fn eq(&self, other: &Expr) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Expr

Auto Trait Implementations§

§

impl Freeze for Expr

§

impl RefUnwindSafe for Expr

§

impl Send for Expr

§

impl Sync for Expr

§

impl Unpin for Expr

§

impl UnsafeUnpin for Expr

§

impl UnwindSafe for Expr

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.