Skip to main content

BoundExpr

Enum BoundExpr 

Source
pub enum BoundExpr {
Show 33 variants Null, Integer(i64), Real(f64), Text(Vec<u8>), Blob(Vec<u8>), Parameter(u32), Raise { action: RaiseAction, message: Option<Vec<u8>>, computed: Option<Box<BoundExpr>>, foreign_key: bool, }, Column { source: usize, column: u16, slot: u16, affinity: Affinity, collation: Collation, }, Rowid { source: usize, }, External { name: Vec<u8>, arguments: Vec<BoundExpr>, }, VirtualFunction { source: usize, name: Vec<u8>, arguments: Vec<BoundExpr>, }, Unary { op: UnaryOp, operand: Box<BoundExpr>, }, Arithmetic { op: BinaryOp, left: Box<BoundExpr>, right: Box<BoundExpr>, }, Compare { op: BinaryOp, left: Box<BoundExpr>, right: Box<BoundExpr>, affinity: Option<Affinity>, collation: Collation, }, And(Box<BoundExpr>, Box<BoundExpr>), Or(Box<BoundExpr>, Box<BoundExpr>), Not(Box<BoundExpr>), IsNull { negated: bool, operand: Box<BoundExpr>, }, Is { negated: bool, left: Box<BoundExpr>, right: Box<BoundExpr>, affinity: Option<Affinity>, collation: Collation, }, Between { negated: bool, operand: Box<BoundExpr>, low: Box<BoundExpr>, high: Box<BoundExpr>, low_affinity: Option<Affinity>, low_collation: Collation, high_affinity: Option<Affinity>, high_collation: Collation, }, InList { negated: bool, operand: Box<BoundExpr>, list: Vec<BoundExpr>, affinity: Option<Affinity>, collation: Collation, }, Case { operand: Option<Box<BoundExpr>>, branches: Vec<(BoundExpr, BoundExpr)>, otherwise: Option<Box<BoundExpr>>, comparisons: Vec<(Option<Affinity>, Collation)>, }, Cast { operand: Box<BoundExpr>, affinity: Affinity, }, Pattern { negated: bool, op: PatternOp, operand: Box<BoundExpr>, pattern: Box<BoundExpr>, escape: Option<Box<BoundExpr>>, }, Time { func: TimeFunc, arguments: Vec<BoundExpr>, }, Math { func: MathFunc, arguments: Vec<BoundExpr>, }, Json { func: JsonFunc, arguments: Vec<BoundExpr>, }, Function { func: ScalarFunc, arguments: Vec<BoundExpr>, collation: Collation, }, WindowRef { slot: usize, collation: Option<Collation>, }, Aggregate { slot: usize, collation: Option<Collation>, }, SorterColumn { column: u16, }, Subquery { id: usize, kind: SubqueryKind, negated: bool, operand: Option<Box<BoundExpr>>, block: Box<BoundSelect>, affinity: Option<Affinity>, collation: Collation, }, Collate { operand: Box<BoundExpr>, collation: Collation, },
}
Expand description

A bound expression, with every name resolved and every rule decided.

Variants§

§

Null

A NULL literal.

§

Integer(i64)

An integer literal.

§

Real(f64)

A real literal.

§

Text(Vec<u8>)

A text literal.

§

Blob(Vec<u8>)

A blob literal.

§

Parameter(u32)

A bound parameter.

§

Raise

RAISE(...) inside a trigger body.

It is an expression in the grammar and it never produces a value: every action either stops the statement or abandons the row. It is bound as one anyway because that is where it is written - SELECT RAISE(ABORT, 'no') WHERE new.x < 0 puts it in a result column, guarded by a WHERE - and a statement form would not reach that position.

Fields

§action: RaiseAction

Which action.

§message: Option<Vec<u8>>

The message, when the action takes one and it is a string literal.

§computed: Option<Box<BoundExpr>>

The message, when it is any other expression.

Evaluated when the RAISE fires, and read as text: NULL is an empty message and a number is its text, which is what SQLite reports. A literal stays in message, so the bodies the binder synthesises for foreign keys compile as they always have.

§foreign_key: bool

Whether the abort is a foreign key’s rather than a trigger’s.

The two are the same expression and report different codes, and nothing in the SQL says which: the foreign-key bodies the binder synthesises set it, and RAISE as anybody writes it does not.

§

Column

A column of a FROM term.

Fields

§source: usize

Which FROM term, by position.

§column: u16

Which column of it, by declared position.

§slot: u16

Which slot of the row’s record holds it.

Not the same number as the declared position once the table has a VIRTUAL generated column: that column takes no slot, so every column after it sits one place earlier in the record. Carrying both is what keeps an index key - which names declared positions - and a record read - which names slots - from being confused for each other.

§affinity: Affinity

The column’s affinity.

§collation: Collation

The column’s declared collation.

§

Rowid

The rowid of a FROM term.

Fields

§source: usize

Which FROM term.

§

External

A call to a function an application registered.

It carries the name and nothing else: the binder resolved that such a function exists and takes this many arguments, and the machine looks up what it does when it runs. A closure in a bound tree would make the tree depend on who was holding it.

Fields

§name: Vec<u8>

The folded name.

§arguments: Vec<BoundExpr>

The arguments, already bound.

§

VirtualFunction

One of a module’s auxiliary functions, written f(table, ...).

It reads the module’s cursor rather than a column, which is why it names a FROM term instead of taking the table as an argument: bm25 wants to know which phrase matched where in the row the cursor is on, and no column carries that.

Fields

§source: usize

Which FROM term - the virtual table the call is about.

§name: Vec<u8>

The function’s folded name, for the module to recognise.

§arguments: Vec<BoundExpr>

The arguments after the table.

§

Unary

A unary operator.

Fields

§op: UnaryOp

Which operator.

§operand: Box<BoundExpr>

The operand.

§

Arithmetic

An arithmetic, bitwise or concatenation operator.

Fields

§op: BinaryOp

Which operator.

§left: Box<BoundExpr>

The left operand.

§right: Box<BoundExpr>

The right operand.

§

Compare

A comparison, with the affinity and collation it applies.

Fields

§op: BinaryOp

Which comparison.

§left: Box<BoundExpr>

The left operand.

§right: Box<BoundExpr>

The right operand.

§affinity: Option<Affinity>

The affinity applied to both sides before comparing.

§collation: Collation

The collation the comparison uses.

§

And(Box<BoundExpr>, Box<BoundExpr>)

AND, with three-valued semantics.

§

Or(Box<BoundExpr>, Box<BoundExpr>)

OR, with three-valued semantics.

§

Not(Box<BoundExpr>)

NOT.

§

IsNull

IS NULL or NOT NULL.

Fields

§negated: bool

Whether the test is for not-null.

§operand: Box<BoundExpr>

The operand.

§

Is

IS / IS NOT, which never yields NULL.

Fields

§negated: bool

Whether NOT was written.

§left: Box<BoundExpr>

The left operand.

§right: Box<BoundExpr>

The right operand.

§affinity: Option<Affinity>

The affinity applied before comparing.

§collation: Collation

The collation the comparison uses.

§

Between

BETWEEN, kept as one node so its operand is evaluated once.

Each bound has its own affinity and collation (task-2088). SQLite codes x BETWEEN lo AND hi as x >= lo AND x <= hi, and each of those comparisons takes its rules from its own two operands. One pair of rules taken from x and lo ignored hi entirely: measured against 3.53.4, s BETWEEN 'a' AND 'B' COLLATE NOCASE returned no rows where SQLite returns a and b, and '5' BETWEEN 1 AND CAST('9' AS INTEGER) answered 0 where SQLite applies the upper bound’s INTEGER affinity and answers 1.

Fields

§negated: bool

Whether NOT was written.

§operand: Box<BoundExpr>

The value being tested.

§low: Box<BoundExpr>

The lower bound.

§high: Box<BoundExpr>

The upper bound.

§low_affinity: Option<Affinity>

The affinity operand >= low applies.

§low_collation: Collation

The collation operand >= low uses.

§high_affinity: Option<Affinity>

The affinity operand <= high applies.

§high_collation: Collation

The collation operand <= high uses.

§

InList

IN over a value list.

Fields

§negated: bool

Whether NOT was written.

§operand: Box<BoundExpr>

The value being tested.

§list: Vec<BoundExpr>

The list.

§affinity: Option<Affinity>

The affinity applied before comparing.

§collation: Collation

The collation the comparison uses.

§

Case

CASE.

Fields

§operand: Option<Box<BoundExpr>>

The base operand, when the form has one.

§branches: Vec<(BoundExpr, BoundExpr)>

The WHEN/THEN pairs.

§otherwise: Option<Box<BoundExpr>>

The ELSE arm.

§comparisons: Vec<(Option<Affinity>, Collation)>

The affinity and collation each WHEN comparison uses in the base form, one per branch, and empty in the searched form.

SQLite codes CASE x WHEN y as x = y for each branch, so each comparison takes its rules from x and its own y through comparison_rules. One collation taken from x for every branch made CASE 'a' WHEN 'A' COLLATE NOCASE answer 0 where 3.53.4 answers 1, and no affinity made CASE id WHEN '1' answer 0 on an INTEGER column where 3.53.4 answers 1 (task-2094).

§

Cast

CAST.

Fields

§operand: Box<BoundExpr>

The operand.

§affinity: Affinity

The affinity the declared type maps to.

§

Pattern

LIKE, GLOB, REGEXP or MATCH.

Fields

§negated: bool

Whether NOT was written.

§op: PatternOp

Which operator.

§operand: Box<BoundExpr>

The value being matched.

§pattern: Box<BoundExpr>

The pattern.

§escape: Option<Box<BoundExpr>>

The ESCAPE argument.

§

Time

A date or time function call.

Fields

§func: TimeFunc

Which function.

§arguments: Vec<BoundExpr>

The arguments.

§

Math

A math function call.

It is its own variant rather than a Function with a different tag because a math function has no collation to carry: none of them compares anything.

Fields

§func: MathFunc

Which function.

§arguments: Vec<BoundExpr>

The arguments.

§

Json

A JSON function call.

Its own variant for the reason JsonFunc is its own enum: every one of these can fail, and every one of them reads the JSON mark its arguments carry. A Function node promises neither.

Fields

§func: JsonFunc

Which function.

§arguments: Vec<BoundExpr>

The arguments.

§

Function

A scalar function call.

Fields

§func: ScalarFunc

Which function.

§arguments: Vec<BoundExpr>

The arguments.

§collation: Collation

The collation the function’s comparisons use.

§

WindowRef

A reference to a window value computed for this row.

Fields

§slot: usize

Which window call, by position in the block’s list.

§collation: Option<Collation>

The explicit collation the call’s arguments carry, if one does.

The arguments live in the block’s window list, out of reach of BoundExpr::explicit_collation, so the binder copies the answer here (task-2094). The PARTITION BY and the ORDER BY of the window do not count: 3.53.4 answers max(s) OVER (PARTITION BY s COLLATE NOCASE) = 'C' with 0.

§

Aggregate

A reference to an aggregate accumulator computed for this row group.

Fields

§slot: usize

Which accumulator, by position.

§collation: Option<Collation>

The explicit collation the call’s arguments carry, if one does.

SQLite marks the aggregate call EP_Collate from its arguments, so max(s COLLATE NOCASE) = 'C' compares with NOCASE. The arguments live in the binder’s aggregate list, out of reach of BoundExpr::explicit_collation, so the binder copies the answer here (task-2094). An argument’s ORDER BY and a FILTER do not count: 3.53.4 answers group_concat(s ORDER BY s COLLATE NOCASE) = 'A,A,B,B,C,C' with 0.

§

SorterColumn

A column of the current sorter row, used after an ORDER BY sort.

Fields

§column: u16

Which column of the sorted record.

§

Subquery

A nested query used as a value: EXISTS, a scalar, or the right side of an IN.

The three are one variant because they differ only in what they do with the block’s rows, and the machinery underneath - a store, filled once or once per outer row depending on correlation - is identical. Splitting them would mean three copies of the correlation rule, which is the part that is easy to get wrong.

Fields

§id: usize

The statement-wide number of this subquery, so the compiler can build it once even when the expression is compiled twice.

§kind: SubqueryKind

What the rows are used for.

§negated: bool

Whether NOT was written.

§operand: Option<Box<BoundExpr>>

The left side of an IN.

§block: Box<BoundSelect>

The block.

§affinity: Option<Affinity>

The affinity an IN applies to both sides before comparing.

§collation: Collation

The collation an IN compares with.

§

Collate

An explicit COLLATE on an expression that is not a column.

The node exists so the collation survives to the comparison that uses it. Attaching it only to columns loses x = 'BLUE' COLLATE BINARY, where the operand carrying the collation is a literal - and losing it means the column’s own collation wins and the comparison quietly answers a different question.

Fields

§operand: Box<BoundExpr>

The operand, which evaluates unchanged.

§collation: Collation

The collation the operand forces on a comparison.

Implementations§

Source§

impl BoundExpr

Source

pub fn collation(&self) -> Option<Collation>

Returns the collation this expression carries, if it has one.

SQLite’s sqlite3ExprCollSeq, in its order: a column has its declared collation, a CAST and a unary + have their operand’s, and any other expression has the explicit collation of an operand, if one has one. So CAST(n AS TEXT) = 'A' on a NOCASE column n compares with NOCASE, and n || '' = 'A' compares with BINARY. Measured against 3.53.4 (task-2089): CAST(n AS TEXT) = 'A' and +n = 'A' answered 0 here where SQLite answers 1.

Source

pub fn explicit_collation(&self) -> Option<Collation>

Returns the collation an explicit COLLATE forced on this expression.

This is not the same question as BoundExpr::collation. A column declared COLLATE NOCASE has an implicit collation; x COLLATE BINARY has an explicit one, and an explicit collation on either side of a comparison beats an implicit one on the other side.

An explicit collation reaches up through every operator and function argument (task-2089). SQLite marks a node EP_Collate when any operand has the mark, and reads the collation from the first operand that has it, left first. This used to look only at the top node, so ('a' COLLATE NOCASE || 'x') = 'AX' compared with BINARY and answered 0 where 3.53.4 answers 1, and 'a' COLLATE BINARY || 'b' COLLATE NOCASE has to answer BINARY because the left operand is asked first. BoundExpr::children lists operands in SQLite’s order for every node whose value is text. A scalar subquery has no children here, and SQLite does not carry a COLLATE out of one either. An aggregate or window call has no children here either, because its arguments live in the block’s lists, so its reference carries the answer for them: see [explicit_argument_collation].

Source§

impl BoundExpr

Source

pub fn affinity(&self) -> Option<Affinity>

Returns the affinity this expression has as an operand.

SQLite’s rule: a column has its own affinity, a cast has the cast’s, a parenthesised expression has its operand’s, and everything else has none. “None” is a real answer here, not a missing one.

Source

pub fn is_constant(&self) -> bool

Returns whether the expression reads any column or aggregate.

Source

pub fn columns_used(&self, into: &mut Vec<u16>)

Returns which declared column positions the expression reads.

The declared position rather than the record slot, because the callers that ask - a generated column’s dependency order, and the index-key matcher - both think in declared positions.

Source

pub fn children(&self) -> Vec<&BoundExpr>

Returns every sub-expression one expression holds, in no order.

The match is exhaustive on purpose: there is no _ arm, so a variant added later is a compilation error here rather than a silently unvisited subtree. That matters because the covering-index decision is built on this walk, and a missed subtree there would be a column read from an index that does not hold it.

A subquery’s block is deliberately not a child. It is a query of its own with its own FROM terms, and the only thing about it that concerns an enclosing term is which of that term’s columns it correlates to - which the block records separately and which the caller reads.

Source

pub fn children_mut(&mut self) -> Vec<&mut BoundExpr>

Returns every sub-expression one expression holds, mutably.

The mirror of BoundExpr::children, and exhaustive for the same reason: a variant added later is a compilation error here rather than a subtree some rewrite silently skips. crate::rewrite is the only caller and the trigger firing point is why it exists - a body’s OLD and NEW reads are replaced by the values the row actually holds, and one missed subtree there is a trigger that reads a NULL where a value was.

A subquery’s block is not a child here either, for the reason it is not one there: it is a query of its own. crate::rewrite descends into it separately, because a correlated block is exactly where a foreign key’s NOT EXISTS (SELECT 1 FROM parent WHERE p.k = NEW.c) keeps its NEW.

Source

pub fn block_mut(&mut self) -> Option<&mut BoundSelect>

Returns the block a subquery expression holds, when it is one.

Separate from BoundExpr::children_mut because a block is not a sub-expression: it is a query, with its own FROM terms and its own scope. A rewrite that treats it as one would run over the wrong tree.

Source

pub fn columns_read(&self, source: usize, into: &mut ColumnUse)

Records which of one FROM term’s columns this expression reads.

A correlated subquery makes the answer unknowable from here - the block is a query of its own and could read any column of the term it correlates to - so it is recorded as opaque rather than guessed at. @param source - the FROM term to look for @param into - what has been found so far

Source§

impl BoundExpr

Source

pub fn sources_used(&self, into: &mut Vec<usize>)

Returns which FROM terms the expression reads.

Trait Implementations§

Source§

impl Clone for BoundExpr

Source§

fn clone(&self) -> Self

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 BoundExpr

Source§

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

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

impl PartialEq for BoundExpr

Source§

fn eq(&self, other: &Self) -> 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 BoundExpr

Auto Trait Implementations§

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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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.