pub struct QueryTailSyntax {Show 15 fields
pub fetch_first: bool,
pub limit_offset_comma: bool,
pub locking_clauses: bool,
pub key_lock_strengths: bool,
pub stacked_locking_clauses: bool,
pub using_sample: bool,
pub leading_offset: bool,
pub limit_expressions: bool,
pub limit_percent: bool,
pub with_ties_requires_order_by: bool,
pub pipe_syntax: bool,
pub limit_by_clause: bool,
pub settings_clause: bool,
pub format_clause: bool,
pub for_xml_json_clause: bool,
}Expand description
Dialect-owned query-tail syntax accepted by the parser.
The clauses parsed by the query-tail sequence that runs after the SELECT body. Split
out of SelectSyntax at its 16-field line as the query-tail axis, distinct from the
SELECT-core and grouping axes. Each flag is a grammar gate: when off the introducing
keyword is left unconsumed and the clause surfaces as a clean parse error.
Fields§
§fetch_first: boolAccept the standard OFFSET <n> { ROW | ROWS } and FETCH { FIRST | NEXT } <count> { ROW | ROWS } ONLY row-limiting spelling.
limit_offset_comma: boolAccept the MySQL/MariaDB/SQLite LIMIT <offset>, <count> two-argument
comma form. It is a spelling of the same row limit as
LIMIT <count> OFFSET <offset>, so it folds into the one canonical
Limit shape tagged
LimitSyntax::LimitOffset — never a
new node. The comma binds the offset first, the count second (the reverse
of LIMIT <count> OFFSET <offset>), which is exactly why it must be dialect
data: reading the arguments in the wrong order silently swaps them.
locking_clauses: boolAccept a trailing row-locking clause (FOR UPDATE/FOR SHARE [OF …] [NOWAIT|SKIP LOCKED], plus MySQL’s legacy LOCK IN SHARE MODE), written after
LIMIT. PostgreSQL and MySQL share this modern surface, so it folds into one
canonical LockingClause on the query,
gated here. When off (ANSI/SQLite/DuckDB, none of which admit a query-tail lock
clause), the FOR/LOCK keyword is left unconsumed and surfaces as a clean
parse error — the same reject mechanism the other query-tail gates use. On for
PostgreSQL / MySQL / Lenient, off elsewhere. The gate covers the shared modern
surface — a single FOR UPDATE/FOR SHARE clause with an OF <table>, … list
and a wait tail. PostgreSQL’s NO KEY UPDATE/KEY SHARE strengths and its
stacked clauses ride the further key_lock_strengths
and stacked_locking_clauses gates; the clause
before LIMIT is still deferred.
key_lock_strengths: boolAccept PostgreSQL’s FOR NO KEY UPDATE / FOR KEY SHARE row-locking strengths —
the two levels between FOR UPDATE and FOR SHARE
(LockStrength::NoKeyUpdate /
LockStrength::KeyShare). Requires
locking_clauses (it refines the strength keyword after
FOR; the dependency is FeatureDependencyViolation::KeyLockStrengthsWithoutLockingClauses);
when off, the NO/KEY after FOR is never a strength lead, so
FOR NO KEY UPDATE / FOR KEY SHARE surface as clean parse errors — the
over-acceptance guard MySQL relies on (its grammar has only UPDATE/SHARE,
engine-verified). PostgreSQL alone spells the KEY/NO KEY refinements
(libpg_query for_locking_strength), so this is on for PostgreSQL / Lenient, off
elsewhere. FOR KEY UPDATE and FOR NO KEY SHARE stay rejected under both
settings — PostgreSQL pairs NO KEY only with UPDATE and KEY only with
SHARE (probed on libpg_query, pg-locking-clause-strengths-and-stacking).
stacked_locking_clauses: boolAccept several stacked row-locking clauses on one query
(FOR UPDATE OF a FOR SHARE OF b) — PostgreSQL applies a distinct lock per table
group, so Query::locking holds a list. Requires
locking_clauses (it repeats the shared clause; the
dependency is FeatureDependencyViolation::StackedLockingClausesWithoutLockingClauses);
when off, exactly one clause is parsed and any following FOR/LOCK is left
unconsumed, surfacing as a trailing-input parse error — the over-acceptance guard
MySQL relies on (its grammar admits exactly one locking clause, engine-verified by
mysql-select-tails-locking-hints-partition). On for PostgreSQL / Lenient, off
elsewhere.
using_sample: boolAccept DuckDB’s USING SAMPLE <entry> query-level sample clause
(Select::sample), written after QUALIFY and before
the enclosing query’s ORDER BY (SELECT … USING SAMPLE 3 ORDER BY …). The entry is
DuckDB’s tablesample_entry: a count-first <size> [ROWS|PERCENT|%] [ '(' method [',' seed] ')' ] or a method-first method '(' <size> ')' [REPEATABLE '(' seed ')'].
On for DuckDB / Lenient, off elsewhere; when off the USING keyword in that position
is left to fail as an unexpected statement token (matching the engines that lack the
clause). Distinct from the table-factor TABLESAMPLE
(TableExpressionSyntax::table_sample).
leading_offset: boolAccept a leading OFFSET <count> [LIMIT <count>] row-skip written without a
preceding LIMIT (PostgreSQL’s [LIMIT …] [OFFSET …] where either may come
first). On for ANSI/PostgreSQL/MySQL/DuckDB/Lenient. SQLite spells the skip only as
LIMIT <count> OFFSET <count> / LIMIT <offset>, <count> — a bare OFFSET with no
LIMIT is a syntax error there — so it is off; the OFFSET keyword is then left
unconsumed and surfaces as a clean parse error. The OFFSET that trails a LIMIT
is unaffected (parsed by the LIMIT branch).
limit_expressions: boolAccept an arbitrary expression as a LIMIT/OFFSET row count. On for
ANSI/PostgreSQL/SQLite/DuckDB/Lenient, whose row limits admit a general expression
(LIMIT 1 + 1, LIMIT (SELECT n FROM cfg)). MySQL restricts the count to an
unsigned integer literal or a ? placeholder (its limit_clause grammar), so it is
off there: an operand that parses to anything else is the syntax error MySQL reports
(engine-measured-rejected on mysql:8 — LIMIT 1 + 1 / LIMIT (SELECT 1)). The whole
operand is still parsed, then rejected on shape, so the diagnostic points at it. The
plain LIMIT <int> / LIMIT ? / comma / OFFSET <int> forms are unaffected.
limit_percent: boolAccept DuckDB’s percentage LIMIT — a numeric-literal count directly followed by
a % operator or the PERCENT keyword (LIMIT 40 PERCENT, LIMIT 35%), which
returns that fraction of the result rows rather than a row number. On for
DuckDB/Lenient only; off for ANSI/PostgreSQL/MySQL/SQLite, whose LIMIT has no
percentage form. With the flag off the marker is left unconsumed — a % folds as
modulo (needing a right operand) and a trailing PERCENT is leftover input — so
both surface as the parse error those dialects report. DuckDB folds the marker
only onto a bare numeric literal at a clause boundary: LIMIT 10 % 3 stays
ordinary modulo, and LIMIT a PERCENT / LIMIT (1 + 1) PERCENT are DuckDB syntax
errors (verified on 1.5.4), so the gate does not over-accept them.
with_ties_requires_order_by: boolEnforce PostgreSQL’s gram.y validity checks on FETCH FIRST … WITH TIES — the two
semantic guards insertSelectOptions raises during raw parsing (so pg_query, a
parse-only oracle, rejects them): WITH TIES requires a governing ORDER BY at the
same query level (WITH TIES cannot be specified without ORDER BY clause), and
WITH TIES cannot combine with a SKIP LOCKED locking clause (SKIP LOCKED and WITH TIES options cannot be used together). On for PostgreSQL only; other dialects
with fetch_first keep accepting both forms unchanged. When off, neither guard fires.
The name carries the load-bearing ORDER BY guard; the SKIP LOCKED combination
guard is the same gram.y check site and rides along.
pipe_syntax: boolAccept BigQuery/ZetaSQL query pipe syntax: a trailing chain of |> operators
that post-process a query result one step at a time
(FROM t |> WHERE x |> SELECT a), modelled as
Query::pipe_operators. This gate does double
duty — it is read by the tokenizer to munch |> (pipe-arrow) as a single token
(off, the two bytes stay | then >, so no dialect’s lexing shifts) and by the
parser to admit the trailing |>-operator chain. When off (every shipped preset),
a |> after a query is never a pipe separator and surfaces as a clean parse error,
exactly as today.
Off for every shipped preset. This surface belongs to no engine we oracle
against — the BigQuery preset that would home it deliberately defers it (a
considered judgment; see that preset’s module docs) — so with no differential
oracle to verify it, every shipped dialect (including DuckDB, which inherits the
PostgreSQL value) leaves it off, and conformance sweeps see zero movement. LENIENT
leaves it off for now as well: although the lenient charter admits any
conflict-free pure-acceptance form (and |> is conflict-free — its munch is
feature-gated, shadowing nothing), the framework ships only the reference WHERE
operator, so enabling it in LENIENT today would make the “parse anything” preset
accept |> WHERE while rejecting every other pipe operator — a fragment a reader of
the lenient module could not predict, violating that module’s honesty bar. Once the
pipe-operator surface is coherent (the planner-parity-pipe-* tickets land),
LENIENT should flip this on as a pure-acceptance addition.
limit_by_clause: boolAccept ClickHouse LIMIT n [OFFSET m] BY expr, … — per-group row limiting,
written after ORDER BY and before the ordinary LIMIT tail (both may appear
in one query), modelled as Query::limit_by. The
parser reads a leading LIMIT speculatively and treats it as LIMIT BY only
when a BY follows the count and optional OFFSET; otherwise it rewinds and the
token is the ordinary LIMIT, so a plain LIMIT n / LIMIT n OFFSET m parses
identically whether this gate is on or off.
On for the ClickHouse preset and Lenient. ClickHouse has no differential oracle,
so this is a no-oracle acceptance addition carried by the ClickHouse preset and the
permissive union (the apply_join precedent): every oracle-compared dialect
(ANSI/PostgreSQL/MySQL/SQLite/DuckDB) leaves it off — they parse-reject a BY
after LIMIT — so conformance sweeps see zero movement.
settings_clause: boolAccept ClickHouse SETTINGS name = value, … — query-level setting overrides
written after the ordinary LIMIT tail, modelled as
Query::settings. SETTINGS is matched as a
contextual keyword (it stays an ordinary identifier elsewhere); each pair is an
identifier = value, the value a general expression.
On for the ClickHouse preset and Lenient. ClickHouse has no differential oracle,
so this is a no-oracle acceptance addition carried by the ClickHouse preset and the
permissive union (the limit_by_clause precedent): every oracle-compared dialect
(ANSI/PostgreSQL/MySQL/SQLite/DuckDB) leaves it off — they parse-reject a trailing
SETTINGS … as unconsumed input — so conformance sweeps see zero movement.
format_clause: boolAccept ClickHouse FORMAT <name> — the output-format clause that closes the
query, modelled as Query::format. FORMAT is
matched as a contextual keyword (it stays an ordinary identifier elsewhere); the
format name is a bare, case-sensitive identifier (JSON, TabSeparated, Null),
not a string literal.
On for the ClickHouse preset and Lenient. ClickHouse has no differential oracle,
so this is a no-oracle acceptance addition carried by the ClickHouse preset and the
permissive union (the settings_clause precedent): every oracle-compared dialect
(ANSI/PostgreSQL/MySQL/SQLite/DuckDB) leaves it off — they parse-reject a trailing
FORMAT … as unconsumed input — so conformance sweeps see zero movement.
for_xml_json_clause: boolAccept MSSQL’s FOR XML {RAW|AUTO|EXPLICIT|PATH} [, …] and
FOR JSON {AUTO|PATH} [, …] result-shaping tails, which serialize the result
set as XML/JSON rather than a rowset, modelled as
Query::for_clause (see ForClause).
The modes and their directives (ELEMENTS [XSINIL|ABSENT], BINARY BASE64,
TYPE, ROOT ['name'], INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER) are typed
data; the accepted grammar follows the MSSQL FOR XML / FOR JSON
documentation (no MSSQL oracle, so that is the recorded acceptance bound).
Leading-keyword dispatch, follow-token partitioned against locking. FOR
also introduces the row-locking clauses (locking_clauses).
The two share the FOR lead but split on the follow token — XML/JSON here
versus UPDATE/SHARE/NO/KEY for locking — so the dispatch is unambiguous
under every preset combination and needs no
GrammarConflict entry: the locking parser
declines a FOR whose follow token is XML/JSON (so a stacked
FOR UPDATE … FOR XML still reaches this clause), and this clause declines a
FOR whose follow token is anything else.
On for MSSQL and Lenient. MSSQL has no differential oracle, so this is a
no-oracle acceptance addition carried by the MSSQL preset and the permissive
union: every oracle-compared dialect (ANSI/PostgreSQL/MySQL/SQLite/DuckDB) leaves
it off — they parse-reject a trailing FOR XML/FOR JSON as unconsumed input
(or, where locking_clauses is on, reject XML/JSON after FOR) — so
conformance sweeps see zero movement.
Implementations§
Source§impl QueryTailSyntax
impl QueryTailSyntax
Sourcepub const CLICKHOUSE: Self
Available on crate feature clickhouse only.
pub const CLICKHOUSE: Self
clickhouse only.The CLICKHOUSE preset for query tail syntax.
Source§impl QueryTailSyntax
impl QueryTailSyntax
Sourcepub const DATABRICKS: Self
Available on crate feature databricks only.
pub const DATABRICKS: Self
databricks only.The DATABRICKS preset for query tail syntax.
Source§impl QueryTailSyntax
impl QueryTailSyntax
Sourcepub const MSSQL: Self
Available on crate feature mssql only.
pub const MSSQL: Self
mssql only.MSSQL query-tail surface: the ANSI baseline plus the FOR XML/FOR JSON
result-shaping tail. MSSQL has no query-tail row-locking clause (it spells
isolation with WITH (…) table hints, TableExpressionSyntax::MSSQL), so
locking_clauses stays off and the FOR lead is unambiguously the
result-shaping clause here.
Trait Implementations§
Source§impl Clone for QueryTailSyntax
impl Clone for QueryTailSyntax
Source§fn clone(&self) -> QueryTailSyntax
fn clone(&self) -> QueryTailSyntax
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more