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: boolAccept the expr::type typecast operator.
subscript: boolAccept base[index] element access and base[lower:upper] slicing.
slice_step: boolAccept 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: boolAccept expr COLLATE collation.
at_time_zone: boolAccept expr AT TIME ZONE zone.
semi_structured_access: boolAccept 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: boolAccept the ARRAY[...] / ARRAY(<query>) array constructors.
multidim_array_literals: boolAccept 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: boolAccept 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: boolAccept explicit ROW(...) and implicit (a, b, …) row constructors.
struct_constructor: boolAccept 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: boolAccept (expr).field composite field selection.
field_wildcard: boolAccept 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: boolAccept 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: boolArm 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: boolAccept 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: boolAccept 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 MICROSECOND…YEAR (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: boolAccept 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: boolAccept 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
impl ExpressionSyntax
Sourcepub const BIGQUERY: Self
Available on crate feature bigquery only.
pub const BIGQUERY: Self
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
impl ExpressionSyntax
Sourcepub const DATABRICKS: Self
Available on crate feature databricks only.
pub const DATABRICKS: Self
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
impl ExpressionSyntax
Sourcepub const LENIENT: Self
Available on crate feature lenient only.
pub const LENIENT: Self
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.
Trait Implementations§
Source§impl Clone for ExpressionSyntax
impl Clone for ExpressionSyntax
Source§fn clone(&self) -> ExpressionSyntax
fn clone(&self) -> ExpressionSyntax
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more