Skip to main content

ExpressionSyntax

Struct ExpressionSyntax 

Source
pub struct ExpressionSyntax {
Show 19 fields pub typecast_operator: bool, pub subscript: bool, pub slice_step: bool, pub collate: bool, pub at_time_zone: bool, pub semi_structured_access: bool, pub array_constructor: bool, pub multidim_array_literals: bool, pub collection_literals: bool, pub row_constructor: bool, pub struct_constructor: bool, pub field_selection: bool, pub field_wildcard: bool, pub typed_string_literals: bool, pub typed_interval_literal: bool, pub relaxed_interval_syntax: bool, pub mysql_interval_operator: bool, pub positional_column: bool, pub lambda_keyword: bool,
}
Expand description

Dialect-owned expression postfix and constructor syntax accepted by the parser.

The postfix operators that navigate a value and the constructor / typed-literal forms that build one, each gated by dialect data: a flag decides whether the parser admits the form, and when off the leading punctuation/keyword surfaces as a clean parse error. The infix/prefix operator spellings and the function-call-tail forms split out into OperatorSyntax and CallSyntax once this struct crossed its documented 16-field line; this half keeps only the shapes that build or navigate a single expression value. Most gates are over lexemes that always tokenize (a lone : and :: are structural punctuation); a flag whose form needs a dialect-gated lexeme says “also gates the tokenizer” in its first paragraph.

Fields§

§typecast_operator: bool

Accept the expr::type typecast operator.

§subscript: bool

Accept base[index] element access and base[lower:upper] slicing.

§slice_step: bool

Accept DuckDB’s three-bound slice base[lower:upper:step] on top of the two-bound slice subscript admits. A pure parser gate (the : separators and the - placeholder always tokenize): reachable only once subscript has opened the brackets (the dependency is FeatureDependencyViolation::SliceStepWithoutSubscript), it admits the second : and, as the middle bound, DuckDB’s bare - open-upper placeholder (base[lower:-:step]) — an empty middle base[lower::step] stays a parse error. On for DuckDB only; PostgreSQL slices are two-bound, so it keeps this off despite subscript, and a base[a:b:c] there is a clean parse error at the second :.

§collate: bool

Accept expr COLLATE collation.

§at_time_zone: bool

Accept expr AT TIME ZONE zone.

§semi_structured_access: bool

Accept semi-structured value paths written as base:key[0].field.

A postfix grammar gate over : followed by an identifier-like key, then optional . and [...] path suffixes. It contends with ParameterSyntax::named_colon on the same :+identifier trigger, so enabling both is a LexicalConflict::ColonParameterVersusSliceBound conflict: the scanner would otherwise turn :key into a parameter before the postfix parser could read the path. It also contends one layer up, at the grammar head, with SelectSyntax::prefix_colon_alias — whose alias-before-value form reads the same leading <ident> : — so enabling both is a GrammarConflict::PrefixColonAliasVersusSemiStructuredAccess conflict (no shipped preset pairs them).

§array_constructor: bool

Accept the ARRAY[...] / ARRAY(<query>) array constructors.

§multidim_array_literals: bool

Accept PostgreSQL multidimensional array literals — a bare-bracket sub-row [...] as an element inside an array_constructor, as in ARRAY[[1,2],[3,4]] and deeper nestings.

A pure grammar gate on the array-constructor element position (its dependency on array_constructor is FeatureDependencyViolation::MultidimArrayLiteralsWithoutArrayConstructor), independent of collection_literals: the bare-bracket row is only a value in an array context (a top-level [1,2] is still rejected under PostgreSQL), and PostgreSQL enforces that each bracket level is uniform — every element is a sub-row or every element is a scalar, never a mix (ARRAY[[1,2],3], ARRAY[1,[2,3]], and ARRAY[[1,2],ARRAY[3,4]] are parse errors, matching PG’s expr_list / array_expr_list split). Ragged nestings (ARRAY[[1,2],[3]]) parse-accept — PostgreSQL rejects them at bind time, not in the grammar. A sub-row is represented as an ordinary bracket-spelled ArrayExpr::Elements, so it renders and shapes exactly like a DuckDB list level. DuckDB reaches the same surface through collection_literals (a top-level list is a value there, and levels may mix), so it keeps this off and overrides the POSTGRES spread.

§collection_literals: bool

Accept the DuckDB collection literals: the bare-bracket list [a, b, …], the struct {'k': v, …}, and the map MAP {k: v, …} / MAP(<keys>, <values>).

A pure grammar/lexical gate on the primary-expression [, {, and MAP leads. The bracket list contends for the same [ trigger as an identifier_quotes style opening with [ (T-SQL/SQLite/Lenient bracket identifiers), so enabling both is the LexicalConflict::BracketIdentifierVersusArraySyntax conflict — a dialect picks bracket identifiers or [ collection/array syntax. The key: value separator likewise contends with ParameterSyntax::named_colon on the :+identifier trigger (LexicalConflict::ColonParameterVersusSliceBound, shared with the slice bound). When off, [/{ in primary position surface as a clean parse error (MAP falls back to an ordinary name).

§row_constructor: bool

Accept explicit ROW(...) and implicit (a, b, …) row constructors.

§struct_constructor: bool

Accept BigQuery’s STRUCT(...) value constructor — the typeless STRUCT(1, 2) and named STRUCT(x AS a, y AS b) forms and the typed STRUCT<a INT64, b STRING>(1, 'x') form — on the canonical StructConstructorExpr shape.

A pure parser lookahead gate, the sibling of row_constructor/array_constructor: the (contextual, non-reserved) STRUCT word opens the constructor only when immediately followed by ( (typeless) or < (typed), mirroring the ROW(/ARRAY[ disambiguation — the tokenizer is untouched, and the < opener is committed on a single-token lookahead (no rewind), sound because in a preset that admits this form STRUCT is not a bare column so struct < x is not a competing comparison. When off, STRUCT(...) is left to the ordinary call path and stays an Expr::Function catalog-function call — the non-interference boundary every non-BigQuery preset (PostgreSQL included) keeps.

On for BigQuery and Lenient. BigQuery documents the form and has no differential oracle here (self-consistency + gate-off rejection are the tests); Lenient unions it in. Off for every other preset: DuckDB builds structs with the {...} literal / struct_pack() / row() rather than a STRUCT(...) keyword form, and the Spark-family struct(...) builtin is not verifiable without an engine, so those presets keep struct(...) an ordinary call rather than risk reshaping it. The typed field list here is parsed inline; a bare STRUCT<...> in type position (CAST(x AS STRUCT<...>)) is a separate type-name surface not gated by this flag.

§field_selection: bool

Accept (expr).field composite field selection.

§field_wildcard: bool

Accept the .* composite/whole-row star selector in a value position: the composite expansion (expr).* off a parenthesized primary, and a whole-row tbl.* used as a value (inside a ROW(...) field, a function argument, a comparison, or a tbl.*::type cast) rather than as a select-list projection target. PostgreSQL admits this .* indirection wherever an a_expr is, at the same tight precedence as field_selection (so (a).* + 1 groups as ((a).*) + 1); engine-probed on pg_query PG-17. Gated apart from field_selection because DuckDB parse-accepts (struct).field but parse-rejects every .* value expansion (engine-probed on DuckDB 1.5.4), so it is off there and on for PostgreSQL/Lenient. When off, a . followed by * is left unconsumed and surfaces as the usual downstream parse error. This governs only the value-position star; a plain select-list/RETURNING tbl.* remains a SelectItem::QualifiedWildcard under every preset.

§typed_string_literals: bool

Accept the prefix-typed string literal — a type name whose reading becomes a literal when a string constant follows the type prefix: the standard temporal forms DATE '…' / TIME '…' / TIMESTAMP '…' and the PostgreSQL generalized <type> '…' (float8 '1.5', folded onto a CastSyntax::PrefixTyped cast). One flag covers both, because the two travel together — a dialect with the temporal forms has the generalized one. On for ANSI/PostgreSQL/MySQL/DuckDB/Lenient. SQLite has neither (date '…' juxtaposes a name and a string, a clean parse error there), so it is off; the type keyword then falls back to its ordinary column/function reading and the trailing string surfaces as the usual parse error.

The prefix-typed INTERVAL '…' <fields> literal is split onto its own typed_interval_literal refinement, because MySQL has the other temporal literals but no first-class interval literal.

§typed_interval_literal: bool

Arm the prefix-typed INTERVAL '<amount>' <fields> literal — the ANSI/PostgreSQL interval literal that folds onto LiteralKind::Interval, including the ANSI HOUR TO SECOND composite and the SECOND(p) unit precision. A refinement of typed_string_literals (the interval literal is only reached when that is on), split out because MySQL admits the other prefix-typed temporal literals (DATE/TIME/TIMESTAMP) yet has no interval literal at all: every typed INTERVAL '…' form — standalone or in a +/- operand — is ER_PARSE_ERROR (1064) on mysql:8.4.10 (engine-measured), the only valid MySQL interval being the operator-position INTERVAL <expr> <unit> modelled by mysql_interval_operator.

On for ANSI/PostgreSQL/DuckDB/Lenient. Off for MySQL (the operator reader owns its valid unit-bearing forms; every form that reaches this literal path there — the ANSI TO/precision spellings the operator reader declines, and the unit-less INTERVAL '1' — is one MySQL rejects, so the literal path declines and the INTERVAL keyword falls back to its ordinary reading, a parse error on the trailing string). Off for SQLite, where typed_string_literals is already off and no prefix-typed literal is reached.

§relaxed_interval_syntax: bool

Accept DuckDB’s relaxed INTERVAL literal spellings on top of the standard quoted INTERVAL '1' DAY form: an unquoted integer amount (INTERVAL 3 DAY), a parenthesized-expression amount (INTERVAL (days) DAY), and plural unit spellings (INTERVAL 3 DAYS, INTERVAL '1' hours). All three fold onto the one LiteralKind::Interval shape: the amount round-trips from the literal’s span exactly as the quoted string does, so only the unit qualifier lands on the tag, and a plural unit folds onto its singular IntervalFields — the plural s round-trips from the span (the documented spelling trade). The unquoted/parenthesized amount forms require a trailing unit (a bare INTERVAL 3 is a DuckDB binding error, not a syntax one). On for DuckDB and Lenient; off elsewhere, where the non-standard spellings surface as the usual parse error.

§mysql_interval_operator: bool

Accept the MySQL operator-position interval quantity INTERVAL <expr> <unit> — the INTERVAL 3 DAY operand of MySQL date arithmetic — as an Expr::Interval node.

A behaviour distinct from the ANSI/PostgreSQL/DuckDB typed-string interval literal (typed_string_literals / relaxed_interval_syntax, both folding onto LiteralKind::Interval): MySQL’s INTERVAL is not a first-class value but the second argument of the Item_date_add_interval production, so it carries an arbitrary amount expression (integer, decimal, string, ?, @var, n + 1, (expr), negative) and a mandatory unit keyword drawn from MySQL’s underscore vocabulary — the simple units MICROSECONDYEAR (plus WEEK, QUARTER) and the composites SECOND_MICROSECOND, MINUTE_SECOND, DAY_HOUR, YEAR_MONTH, … (engine-measured on mysql:8.4.10). It admits no ANSI TO composite and no (p) unit precision (INTERVAL '1' HOUR TO SECOND and INTERVAL '1' SECOND(3) are ER_PARSE_ERROR there); a TO/( after the unit makes the operator reader decline so the typed-string interval literal path (typed_interval_literal) owns those spellings under Lenient/PostgreSQL. Under MySQL that literal path is off, so the declined ANSI spellings reject (matching the engine).

On for MySQL and Lenient. When on, an INTERVAL in expression-prefix position is read as this node before the typed-string literal path (MySQL has no first-class interval literal); a form that is not a valid MySQL operator interval — unit-less, an ANSI TO/precision spelling, a bare INTERVAL(a, b) index function — rewinds and falls through, so under Lenient the DuckDB relaxed amounts, plural units, unit-less PostgreSQL literals, and the ANSI TO/precision interval literals still parse (under MySQL they reject, typed_interval_literal being off). The node is modelled as a primary (highest binding power), so MySQL’s position restriction is deliberately not enforced: a standalone SELECT INTERVAL 3 DAY, a leading INTERVAL 3 DAY - x (only + leads on mysql:8), and INTERVAL 3 DAY IS NULL over-accept rather than over-reject the valid operand/DATE_ADD/frame positions a general grammar cannot distinguish. Off elsewhere, where INTERVAL keeps its literal-or-column reading.

§positional_column: bool

Accept DuckDB’s #n positional column reference — a select-list column named by its 1-based output position (Expr::PositionalColumn), used mainly in ORDER BY #1 / GROUP BY #2 but valid wherever a value expression is. Also gates the tokenizer: the #<digits> lexeme is scanned only under a dialect that sets this (DuckDB), so elsewhere # stays a stray byte, a MySQL line comment, or PostgreSQL’s XOR operator per that dialect’s data. Because it claims the # trigger, it is mutually exclusive with the two other # claimants — the hash_bitwise_xor XOR operator (LexicalConflict::HashXorOperatorVersusPositionalColumn) and a CommentSyntax::line_comment_hash line comment (LexicalConflict::HashCommentVersusPositionalColumn); a #-led identifier byte class instead resolves by scan order (the identifier scan precedes this arm), like the XOR case. On for DuckDB only. Lenient, which already commits # to a MySQL line comment, cannot also enable it. When off, #1 surfaces per the dialect’s other # reading (a clean parse error in ANSI/SQLite).

§lambda_keyword: bool

Accept DuckDB’s python-style keyword lambda lambda x, y: body — a prefix production, distinct from the OperatorSyntax::lambda_expressions single-arrow form and folded onto the same Expr::Lambda node with a LambdaParamSpelling::Keyword spelling tag. DuckDB 1.3.0 introduced it and prefers it over the deprecated arrow; the two spellings are separate flags because DuckDB’s roadmap keeps the keyword while dropping the arrow. When on, a lambda word in expression-prefix position opens the production unconditionally rather than reading as an ordinary column — matching DuckDB, which reserves lambda — so a bare lambda, or one not followed by <params>:, is a parse error. On for DuckDB and Lenient.

Implementations§

Source§

impl ExpressionSyntax

Source

pub const ANSI: Self

The ANSI predefined value.

Source§

impl ExpressionSyntax

Source

pub const BIGQUERY: Self

Available on crate feature bigquery only.

BigQuery expression surface: the ANSI baseline plus the STRUCT(...) value constructor (STRUCT(1, 2), STRUCT(x AS a), STRUCT<a INT64>(1)), a documented GoogleSQL form with no differential oracle here. Every other expression knob stays conservatively ANSI.

Source§

impl ExpressionSyntax

Source

pub const DATABRICKS: Self

Available on crate feature databricks only.

Databricks expression surface: the ANSI baseline plus semi-structured colon path access (base:key[0].field), Databricks’ VARIANT/JSON accessor. Every other expression knob is conservatively ANSI.

Source§

impl ExpressionSyntax

Source

pub const DUCKDB: Self

Available on crate feature duckdb only.

The DUCKDB preset for expression syntax.

Source§

impl ExpressionSyntax

Source

pub const LENIENT: Self

Available on crate feature lenient only.

LENIENT: every PostgreSQL postfix/constructor form except the [-punctuation forms.

subscript, array_constructor, and collection_literals are OFF because [ is a bracket identifier-quote opener here (conflict-resolution rule 2): the tokenizer claims [ before the parser can read it as array punctuation. Everything that does not need [ (typecast ::, COLLATE, AT TIME ZONE, ROW(...), field selection, typed literals) is ON.

Source§

impl ExpressionSyntax

Source

pub const MYSQL: Self

Available on crate feature mysql only.

The MYSQL preset for expression syntax.

Source§

impl ExpressionSyntax

Source

pub const POSTGRES: Self

Available on crate feature postgres only.

The POSTGRES preset for expression syntax.

Source§

impl ExpressionSyntax

Source

pub const SNOWFLAKE: Self

Available on crate feature snowflake only.

Snowflake expression surface: the ANSI baseline plus semi-structured path access (base:key[0].field), Snowflake’s VARIANT/OBJECT/ARRAY accessor. Every other expression knob is conservatively ANSI.

Source§

impl ExpressionSyntax

Source

pub const SQLITE: Self

Available on crate feature sqlite only.

The SQLITE preset for expression syntax.

Trait Implementations§

Source§

impl Clone for ExpressionSyntax

Source§

fn clone(&self) -> ExpressionSyntax

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 Copy for ExpressionSyntax

Source§

impl Debug for ExpressionSyntax

Source§

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

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

impl Eq for ExpressionSyntax

Source§

impl PartialEq for ExpressionSyntax

Source§

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

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 = 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.