squonk_ast/ast/expr.rs
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 Moderately AI Inc.
3
4//! Scalar-expression AST nodes: the `Expr` tree and its operand shapes.
5
6use super::{
7 DataType, Extension, Ident, IntervalFields, Literal, NoExt, ObjectName, OrderByExpr, Query,
8 SetQuantifier, WildcardOptions, WindowSpec,
9};
10use crate::vocab::{Meta, Symbol};
11use thin_vec::ThinVec;
12
13/// SQL expressions for the M1 parser surface.
14///
15/// Each variant carries `Meta` so the expression node itself has side-table
16/// identity. Child nodes keep their own metadata; `Meta` remains structural
17/// equality-neutral.
18#[derive(Clone, Debug, PartialEq, Eq, Hash)]
19#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
20#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
21pub enum Expr<X: Extension = NoExt> {
22 /// A column reference: a bare or qualified name (`c`, `t.c`, `s.t.c`).
23 Column {
24 /// The referenced name, one or more dot-separated identifier parts.
25 name: ObjectName,
26 /// Source location and node identity.
27 meta: Meta,
28 },
29 /// A literal constant: a number, string, boolean, `NULL`, or typed date/time value.
30 Literal {
31 /// The literal value; see [`Literal`].
32 literal: Literal,
33 /// Source location and node identity.
34 meta: Meta,
35 },
36 /// A binary operator application: `left op right` (`a + b`, `x AND y`, `p || q`).
37 BinaryOp {
38 /// Left-hand operand.
39 left: Box<Expr<X>>,
40 /// The binary operator joining the two operands.
41 op: BinaryOperator,
42 /// Right-hand operand.
43 right: Box<Expr<X>>,
44 /// Source location and node identity.
45 meta: Meta,
46 },
47 /// A unary operator application: prefix (`-x`, `NOT p`, `+n`) or postfix, per the operator.
48 UnaryOp {
49 /// The unary operator applied to the operand.
50 op: UnaryOperator,
51 /// The operand the operator applies to.
52 expr: Box<Expr<X>>,
53 /// Source location and node identity.
54 meta: Meta,
55 },
56 /// A function, aggregate, or window call (`count(*)`, `substr(s, 1, 3)`); see [`FunctionCall`].
57 Function {
58 /// The call's target, arguments, and any `OVER`/`FILTER`/`WITHIN GROUP` clauses; see [`FunctionCall`].
59 call: Box<FunctionCall<X>>,
60 /// Source location and node identity.
61 meta: Meta,
62 },
63 /// A `CASE` expression: searched (`CASE WHEN … THEN …`) or simple (`CASE x WHEN …`); see [`CaseExpr`].
64 Case {
65 /// The optional operand, `WHEN`/`THEN` arms, and optional `ELSE`; see [`CaseExpr`].
66 case: Box<CaseExpr<X>>,
67 /// Source location and node identity.
68 meta: Meta,
69 },
70 /// An `EXTRACT(field FROM source)` datetime-field extraction; see [`ExtractExpr`].
71 Extract {
72 /// The extracted field and the source expression; see [`ExtractExpr`].
73 extract: Box<ExtractExpr<X>>,
74 /// Source location and node identity.
75 meta: Meta,
76 },
77 /// A type cast: standard `CAST(expr AS type)`, PostgreSQL `expr::type`, or DuckDB `TRY_CAST`.
78 Cast {
79 /// The expression being cast.
80 expr: Box<Expr<X>>,
81 /// The target data type.
82 data_type: Box<DataType<X>>,
83 /// Whether the cast was spelled `CAST(expr AS type)` or `expr::type`.
84 syntax: CastSyntax,
85 /// DuckDB's `TRY_CAST(expr AS type)` null-on-failure cast. This is *semantics*,
86 /// not a spelling: a failed `TRY_CAST` yields `NULL` where `CAST` raises, so it
87 /// is a distinct flag rather than a [`CastSyntax`] variant. DuckDB's
88 /// own serialized tree carries the same `try_cast` boolean on its one `CAST`
89 /// node. Always `false` for the `::` and prefix-typed spellings, which have no
90 /// try form.
91 try_cast: bool,
92 /// Source location and node identity.
93 meta: Meta,
94 },
95 /// A null test: `<expr> IS [NOT] NULL`, or its postfix synonyms — one-word
96 /// `<expr> ISNULL` / `<expr> NOTNULL` and the two-word `<expr> NOT NULL`.
97 ///
98 /// `negated` is the `NOT` axis (`IS NOT NULL` / `NOTNULL` / `NOT NULL`);
99 /// [`spelling`](NullTestSpelling) records whether the source wrote the standard
100 /// `IS [NOT] NULL`, the one-word `ISNULL`/`NOTNULL` postfix, or the two-word `NOT NULL`
101 /// postfix so rendering round-trips. The one-word synonyms are gated by
102 /// [`OperatorSyntax::null_test_postfix`](crate::dialect::OperatorSyntax) and the two-word
103 /// form by [`PredicateSyntax::null_test_two_word_postfix`](crate::dialect::PredicateSyntax)
104 /// (they diverge — see the flag docs); the standard spelling is always available.
105 IsNull {
106 /// Expression evaluated by this syntax.
107 expr: Box<Expr<X>>,
108 /// Whether the negated form was present in the source.
109 negated: bool,
110 /// Exact source spelling retained for faithful rendering.
111 spelling: NullTestSpelling,
112 /// Source location and node identity.
113 meta: Meta,
114 },
115 /// A truth-value test: `<expr> IS [NOT] {TRUE | FALSE | UNKNOWN}` (SQL:2016 F571).
116 ///
117 /// The postfix sibling of [`IsNull`](Self::IsNull) — a unary predicate carrying a
118 /// `negated` flag for the `IS NOT` form and binding at comparison precedence — with a
119 /// [`TruthValue`] tag recording which of the three truth values was tested. A distinct
120 /// node rather than a widening of `IsNull`: the standard models truth tests and the null
121 /// test as separate predicates (`<boolean test>` vs `<null predicate>`), and the operand
122 /// is a boolean value here rather than an arbitrary comparable.
123 ///
124 /// Reachable only under
125 /// [`OperatorSyntax::truth_value_tests`](crate::dialect::OperatorSyntax) (ANSI /
126 /// PostgreSQL / MySQL / DuckDB / Lenient). SQLite has no truth-value predicate: its `IS`
127 /// is a general null-safe equality, so it folds `IS TRUE` / `IS FALSE` onto
128 /// [`IsNotDistinctFrom`](BinaryOperator::IsNotDistinctFrom) against the boolean literal and
129 /// reads `IS UNKNOWN` as equality against an identifier named `unknown` (engine-measured
130 /// via rusqlite) — so the flag stays off there and this node is never produced.
131 IsTruth {
132 /// Expression evaluated by this syntax.
133 expr: Box<Expr<X>>,
134 /// Value supplied by this syntax.
135 value: TruthValue,
136 /// Whether the negated form was present in the source.
137 negated: bool,
138 /// Source location and node identity.
139 meta: Meta,
140 },
141 /// A Unicode-normalization test: `<expr> IS [NOT] [NFC|NFD|NFKC|NFKD] NORMALIZED`
142 /// (SQL:2016 T061).
143 ///
144 /// The postfix sibling of [`IsNull`](Self::IsNull)/[`IsTruth`](Self::IsTruth) — a unary
145 /// predicate carrying a `negated` flag for the `IS NOT` form, binding at comparison
146 /// precedence — testing whether a string is in the given Unicode normal form. `form` is
147 /// the optional [`NormalizationForm`]; `None` is the bare `IS NORMALIZED`, which defaults
148 /// to NFC. Gated by
149 /// [`PredicateSyntax::is_normalized`](crate::dialect::PredicateSyntax).
150 IsNormalized {
151 /// Expression evaluated by this syntax.
152 expr: Box<Expr<X>>,
153 /// Optional form for this syntax.
154 form: Option<NormalizationForm>,
155 /// Whether the negated form was present in the source.
156 negated: bool,
157 /// Source location and node identity.
158 meta: Meta,
159 },
160 /// A range test: `<expr> [NOT] BETWEEN [SYMMETRIC] <low> AND <high>`.
161 ///
162 /// `symmetric` records the SQL-standard `SYMMETRIC` modifier, which — unlike the
163 /// default `ASYMMETRIC` — is semantically load-bearing: it permits `low > high` by
164 /// testing the value against the ordered pair, so it is kept as data rather than
165 /// dropped. The explicit `ASYMMETRIC` noise word is the default and is not retained
166 /// (it renders back as the bare form). Gated by
167 /// [`PredicateSyntax::between_symmetric`](crate::dialect::PredicateSyntax).
168 Between {
169 /// Expression evaluated by this syntax.
170 expr: Box<Expr<X>>,
171 /// The lower bound of the range.
172 low: Box<Expr<X>>,
173 /// The upper bound of the range.
174 high: Box<Expr<X>>,
175 /// Whether the negated form was present in the source.
176 negated: bool,
177 /// Whether the symmetric form was present in the source.
178 symmetric: bool,
179 /// Source location and node identity.
180 meta: Meta,
181 },
182 /// A pattern-match predicate: `<expr> [NOT] LIKE|ILIKE|SIMILAR TO <pattern>
183 /// [ESCAPE <c>]`.
184 ///
185 /// One canonical shape covers all three spellings; [`LikeSpelling`]
186 /// records which the source used so it round-trips. Like the other comparison
187 /// predicates ([`Between`](Self::Between)/[`InList`](Self::InList)) it carries a
188 /// `negated` flag for the `NOT` form and binds at comparison precedence. The
189 /// optional `escape` holds the ISO `ESCAPE '<c>'` character (usually a string
190 /// literal); `None` when the source wrote no `ESCAPE`.
191 Like {
192 /// Expression evaluated by this syntax.
193 expr: Box<Expr<X>>,
194 /// The pattern to match against.
195 pattern: Box<Expr<X>>,
196 /// Optional escape for this syntax.
197 escape: Option<Box<Expr<X>>>,
198 /// Whether the negated form was present in the source.
199 negated: bool,
200 /// Exact source spelling retained for faithful rendering.
201 spelling: LikeSpelling,
202 /// Source location and node identity.
203 meta: Meta,
204 },
205 /// A list-membership test: `<expr> [NOT] IN (v1, v2, …)`.
206 InList {
207 /// The value tested for membership.
208 expr: Box<Expr<X>>,
209 /// The candidate values, in source order.
210 list: ThinVec<Expr<X>>,
211 /// Whether the negated form was present in the source.
212 negated: bool,
213 /// Source location and node identity.
214 meta: Meta,
215 },
216 /// A subquery-membership test: `<expr> [NOT] IN (<subquery>)`.
217 InSubquery {
218 /// The value tested for membership.
219 expr: Box<Expr<X>>,
220 /// The subquery whose rows form the candidate set.
221 subquery: Box<Query<X>>,
222 /// Whether the negated form was present in the source.
223 negated: bool,
224 /// Source location and node identity.
225 meta: Meta,
226 },
227 /// DuckDB's unparenthesized `<expr> [NOT] IN <rhs>` list-membership operator, where
228 /// the right operand is a single value expression rather than a parenthesized list
229 /// or subquery: `z IN y` (DuckDB desugars it to `contains(y, z)`), distinct from the
230 /// standard `IN (…)` forms ([`InList`](Self::InList) / [`InSubquery`](Self::InSubquery)).
231 /// A new canonical node, not a widening of `InList`: the two round-trip to
232 /// different surface syntax (`x IN y` vs `x IN (y)`), and DuckDB models them as
233 /// distinct constructs (a `contains` function call vs a `COMPARE_IN`).
234 ///
235 /// `rhs` is DuckDB's restricted `c_expr` right operand: a column/qualified reference,
236 /// function call, subscript (`y[1]`), array/struct/map literal, `CAST`/`CASE`, or a
237 /// parameter — but never a leading constant or unary sign (`IN 4` / `IN 'a'` / `IN -5`
238 /// are DuckDB parser errors, an LALR grammar-generator restriction the parser
239 /// replicates via a leading-token gate). Binds tighter than the comparison operators
240 /// and the standard `IN (list)` predicate (`z = w IN y` is `z = (w IN y)`; measured on
241 /// 1.5.4), left-associative. Reachable only under
242 /// [`PredicateSyntax::unparenthesized_in_list`](crate::dialect::PredicateSyntax)
243 /// (DuckDB / Lenient).
244 InExpr {
245 /// The value tested for membership.
246 expr: Box<Expr<X>>,
247 /// The single-value right operand (DuckDB's restricted `c_expr`).
248 rhs: Box<Expr<X>>,
249 /// Whether the negated form was present in the source.
250 negated: bool,
251 /// Source location and node identity.
252 meta: Meta,
253 },
254 /// An `EXISTS (<subquery>)` test — true when the subquery returns at least one row.
255 Exists {
256 /// The subquery tested for row existence.
257 query: Box<Query<X>>,
258 /// Source location and node identity.
259 meta: Meta,
260 },
261 /// A quantified comparison against a subquery: `<expr> op {ANY | ALL | SOME} (<subquery>)`.
262 QuantifiedComparison {
263 /// Left-hand operand.
264 left: Box<Expr<X>>,
265 /// The comparison operator applied against each row.
266 op: BinaryOperator,
267 /// Whether the comparison is `ANY`/`SOME` or `ALL`.
268 quantifier: Quantifier,
269 /// The subquery supplying the right-hand rows.
270 subquery: Box<Query<X>>,
271 /// Source location and node identity.
272 meta: Meta,
273 },
274 /// A quantified comparison whose right operand is a scalar list/array *value*
275 /// rather than a subquery: DuckDB `ax = ANY (b)` over a `LIST`/`ARRAY` column or
276 /// literal, `x = ANY ([1, 2, 3])`, PostgreSQL `x = ANY (ARRAY[…])`.
277 ///
278 /// A distinct node from [`QuantifiedComparison`](Self::QuantifiedComparison), not a
279 /// widening of its `subquery` field: the reference engine models the two
280 /// as separate constructs — the array form is PostgreSQL's `ScalarArrayOpExpr` (the
281 /// operator is applied elementwise to an array value) while the subquery form is an
282 /// `AnySublink`/`AllSublink` (the operator ranges over a query's rows). The operands
283 /// differ in kind (a value [`Expr`] vs a [`Query`]) and in evaluation, so folding
284 /// them onto one node would misrepresent the engine's shape. The parser splits the
285 /// two on the parenthesized content exactly as `IN (…)` splits `InSubquery` from
286 /// `InList`: a leading query keyword is the subquery form, anything else is this one.
287 ///
288 /// `array` is the operand expression as written (the list literal `[…]`, an
289 /// `ARRAY[…]` constructor, or a bare column). Reachable only under
290 /// [`OperatorSyntax::quantified_comparison_lists`](crate::dialect::OperatorSyntax)
291 /// (DuckDB/PostgreSQL/Lenient); the subquery form's
292 /// [`quantified_comparisons`](crate::dialect::OperatorSyntax::quantified_comparisons)
293 /// gate is a prerequisite (both are on wherever this is).
294 QuantifiedList {
295 /// Left-hand operand.
296 left: Box<Expr<X>>,
297 /// Operator applied by this expression.
298 op: BinaryOperator,
299 /// Whether the quantifier is `ANY`/`SOME` or `ALL`.
300 quantifier: Quantifier,
301 /// The array/list right operand.
302 array: Box<Expr<X>>,
303 /// Source location and node identity.
304 meta: Meta,
305 },
306 /// A pattern-match predicate quantified over an array operand: PostgreSQL
307 /// `<expr> [NOT] LIKE|ILIKE {ANY | ALL | SOME} (<array>)` — `'foo' LIKE ANY
308 /// (ARRAY['%a', '%o'])`.
309 ///
310 /// A distinct node from [`Like`](Self::Like), for the same reason
311 /// [`QuantifiedList`](Self::QuantifiedList) is distinct from a plain
312 /// comparison: PostgreSQL models the plain `<expr> LIKE <pattern>` as an
313 /// `OpExpr` over the `~~` operator, but the quantified form as a
314 /// `ScalarArrayOpExpr` applying `~~`/`~~*` elementwise across an array value.
315 /// The operands differ in kind (a single pattern [`Expr`] vs an array-valued
316 /// operand) and in evaluation, so folding a quantifier onto `Like` would
317 /// misrepresent the engine's shape. `SIMILAR TO` has no quantified form
318 /// (PostgreSQL rejects `SIMILAR TO ANY`), so `spelling` is only ever
319 /// [`Like`](LikeSpelling::Like)/[`ILike`](LikeSpelling::ILike) here.
320 ///
321 /// `pattern` is the array operand as written. Reachable only under
322 /// [`PredicateSyntax::pattern_match_quantifier`](crate::dialect::PredicateSyntax)
323 /// (PostgreSQL/Lenient).
324 QuantifiedLike {
325 /// Left-hand operand.
326 left: Box<Expr<X>>,
327 /// The array of patterns to match against.
328 pattern: Box<Expr<X>>,
329 /// Whether the quantifier is `ANY`/`SOME` or `ALL`.
330 quantifier: Quantifier,
331 /// Whether the negated form was present in the source.
332 negated: bool,
333 /// Exact source spelling retained for faithful rendering.
334 spelling: LikeSpelling,
335 /// Source location and node identity.
336 meta: Meta,
337 },
338 /// A scalar subquery used as a value: `(SELECT …)`.
339 Subquery {
340 /// The parenthesized subquery evaluated as a scalar value.
341 query: Box<Query<X>>,
342 /// Source location and node identity.
343 meta: Meta,
344 },
345 /// A placeholder parameter bound at execute time (`?`, `$1`, `:name`); see [`ParameterKind`].
346 Parameter {
347 /// Which placeholder syntax was used; see [`ParameterKind`].
348 kind: ParameterKind,
349 /// Source location and node identity.
350 meta: Meta,
351 },
352 /// A DuckDB `#n` positional column reference — a select-list column named by its
353 /// 1-based output position, used mainly in `ORDER BY #1` / `GROUP BY #2` but valid
354 /// wherever a value expression is (`SELECT #1 + 1`). A new canonical node,
355 /// not folded onto an integer [`Literal`](Self::Literal): the `#` sigil carries the
356 /// "resolve to the n-th projected column" semantics DuckDB's binder acts on, which a
357 /// bare integer does not. Distinct from a prepared-statement
358 /// [`Parameter`](Self::Parameter) placeholder (a hole bound at execute time) — this
359 /// reads a column already in the query. `index` is the parsed position, always `>= 1`
360 /// (DuckDB rejects `#0` at parse time — "Positional reference node needs to be >= 1").
361 /// Reachable only under
362 /// [`ExpressionSyntax::positional_column`](crate::dialect::ExpressionSyntax), which
363 /// also gates the `#<digits>` lexeme.
364 PositionalColumn {
365 /// The 1-based select-list position (always `>= 1`).
366 index: u32,
367 /// Source location and node identity.
368 meta: Meta,
369 },
370 /// A MySQL session-variable read: a user-defined `@name` variable or a server
371 /// `@@[scope.]name` system variable, evaluated as a value expression.
372 ///
373 /// Distinct from a prepared-statement placeholder ([`Parameter`](Self::Parameter)):
374 /// a placeholder is a hole bound at execute time, whereas this reads the current
375 /// value of the named variable in place. One canonical shape covers all
376 /// four surface forms; the [`SessionVariableKind`] tag records the sigil (`@` vs
377 /// `@@`) and the optional system scope so `@x`, `@@x`, `@@global.x`, and
378 /// `@@session.x` each round-trip exactly. `name` is the interned variable name,
379 /// exact-case (sigil and scope stripped), so it renders verbatim like an
380 /// identifier.
381 SessionVariable {
382 /// Which sigil/scope form (`@`/`@@`/`@@global.`/`@@session.`); see [`SessionVariableKind`].
383 kind: SessionVariableKind,
384 /// Name referenced by this syntax.
385 name: Symbol,
386 /// Source location and node identity.
387 meta: Meta,
388 },
389 /// A PostgreSQL array element/slice access: `base[index]` or
390 /// `base[lower:upper]` (boxed; see [`SubscriptExpr`]).
391 Subscript {
392 /// The array element/slice access; see [`SubscriptExpr`].
393 subscript: Box<SubscriptExpr<X>>,
394 /// Source location and node identity.
395 meta: Meta,
396 },
397 /// A colon-led semi-structured value path: `base:key[0].field` (boxed; see
398 /// [`SemiStructuredAccessExpr`]).
399 SemiStructuredAccess {
400 /// The semi-structured path access; see [`SemiStructuredAccessExpr`].
401 semi_structured_access: Box<SemiStructuredAccessExpr<X>>,
402 /// Source location and node identity.
403 meta: Meta,
404 },
405 /// A PostgreSQL `expr COLLATE collation` collation override (boxed; see
406 /// [`CollateExpr`]).
407 Collate {
408 /// The collation override; see [`CollateExpr`].
409 collate: Box<CollateExpr<X>>,
410 /// Source location and node identity.
411 meta: Meta,
412 },
413 /// A MySQL operator-position interval quantity: `INTERVAL <value> <unit>` — the
414 /// `INTERVAL 3 DAY` operand of MySQL date arithmetic (`d - INTERVAL 3 DAY`,
415 /// `INTERVAL 1 DAY + d`, `DATE_ADD(d, INTERVAL 1 DAY)`, a window-frame bound).
416 ///
417 /// Distinct from the ANSI/PostgreSQL typed-string interval *literal*
418 /// [`LiteralKind::Interval`](crate::ast::LiteralKind::Interval): MySQL's `INTERVAL` is
419 /// not a standalone value but the second operand of the date-add/date-sub production
420 /// (`Item_date_add_interval`), so it carries an arbitrary amount *expression* and a
421 /// mandatory unit keyword rather than a quoted amount string and an optional ANSI
422 /// qualifier. Gated by
423 /// [`ExpressionSyntax::mysql_interval_operator`](crate::dialect::ExpressionSyntax); see
424 /// that flag for the position/unit boundary. The `unit` reuses the shared
425 /// [`IntervalFields`] vocabulary but always renders in MySQL's underscore spelling
426 /// (`DAY_HOUR`, `YEAR_MONTH`), never the ANSI `TO` composite.
427 Interval {
428 /// The interval amount — an arbitrary expression (`3`, `'3-2'`, `?`, `@v`, `n + 1`).
429 value: Box<Expr<X>>,
430 /// The unit keyword (`DAY`, `HOUR_SECOND`, `YEAR_MONTH`, …).
431 unit: IntervalFields,
432 /// Source location and node identity.
433 meta: Meta,
434 },
435 /// A PostgreSQL `expr AT TIME ZONE zone` time-zone conversion (boxed; see
436 /// [`AtTimeZoneExpr`]).
437 AtTimeZone {
438 /// The time-zone conversion; see [`AtTimeZoneExpr`].
439 at_time_zone: Box<AtTimeZoneExpr<X>>,
440 /// Source location and node identity.
441 meta: Meta,
442 },
443 /// An array constructor: PostgreSQL `ARRAY[...]` / `ARRAY(<query>)` or the
444 /// DuckDB bare-bracket list literal `[...]` (boxed; see [`ArrayExpr`]).
445 Array {
446 /// The array/list constructor; see [`ArrayExpr`].
447 array: Box<ArrayExpr<X>>,
448 /// Source location and node identity.
449 meta: Meta,
450 },
451 /// A DuckDB struct literal `{'key': value, …}` (boxed; see [`StructExpr`]).
452 Struct {
453 /// The struct literal; see [`StructExpr`].
454 r#struct: Box<StructExpr<X>>,
455 /// Source location and node identity.
456 meta: Meta,
457 },
458 /// A BigQuery `STRUCT(...)` value constructor: the typeless `STRUCT(1, 2)` /
459 /// `STRUCT(x AS a, y AS b)` forms and the typed `STRUCT<a INT64, b STRING>(1, 'x')`
460 /// form (boxed; see [`StructConstructorExpr`]). Distinct from the DuckDB brace
461 /// literal [`Struct`](Self::Struct) and from an ordinary `struct(...)` catalog-function
462 /// call, which a dialect without
463 /// [`ExpressionSyntax::struct_constructor`](crate::dialect::ExpressionSyntax) keeps as
464 /// a [`Function`](Self::Function).
465 StructConstructor {
466 /// The `STRUCT(...)` constructor; see [`StructConstructorExpr`].
467 constructor: Box<StructConstructorExpr<X>>,
468 /// Source location and node identity.
469 meta: Meta,
470 },
471 /// A DuckDB map literal `MAP {k: v, …}` (boxed; see [`MapExpr`]).
472 ///
473 /// Only the brace form is a dedicated grammar production; the two-list
474 /// `MAP(<keys>, <values>)` spelling is an ordinary call to the (case-insensitive)
475 /// `map` function, so it parses as [`Function`](Self::Function) like any other
476 /// call.
477 Map {
478 /// The map literal; see [`MapExpr`].
479 map: Box<MapExpr<X>>,
480 /// Source location and node identity.
481 meta: Meta,
482 },
483 /// A row constructor: explicit `ROW(...)` or the implicit parenthesized
484 /// `(a, b, …)` form (boxed; see [`RowExpr`]).
485 Row {
486 /// The row constructor; see [`RowExpr`].
487 row: Box<RowExpr<X>>,
488 /// Source location and node identity.
489 meta: Meta,
490 },
491 /// A PostgreSQL composite navigation off a value: `(expr).field` field selection
492 /// or the `(expr).*` / whole-row `tbl.*` star expansion (boxed; see
493 /// [`FieldSelectionExpr`]).
494 FieldSelection {
495 /// The composite field selection; see [`FieldSelectionExpr`].
496 field_selection: Box<FieldSelectionExpr<X>>,
497 /// Source location and node identity.
498 meta: Meta,
499 },
500 /// A general infix operator application — the explicit `a OPERATOR(schema.+) b`
501 /// or a bare symbolic operator `a ~ b` / `a <-> b` (boxed; see [`NamedOperatorExpr`]).
502 NamedOperator {
503 /// The named/infix operator application; see [`NamedOperatorExpr`].
504 named_operator: Box<NamedOperatorExpr<X>>,
505 /// Source location and node identity.
506 meta: Meta,
507 },
508 /// A general prefix operator application: `@ x` (absolute value), `|/ x` (square
509 /// root), `@@ box` (centre), or a fully user-defined prefix operator `@#@ x` (boxed;
510 /// see [`PrefixOperatorExpr`]).
511 PrefixOperator {
512 /// The prefix operator application; see [`PrefixOperatorExpr`].
513 prefix_operator: Box<PrefixOperatorExpr<X>>,
514 /// Source location and node identity.
515 meta: Meta,
516 },
517 /// A general postfix operator application: `10!` (factorial), `1 ~`, `1 <->`, or any
518 /// other trailing symbolic operator (boxed; see [`PostfixOperatorExpr`]). DuckDB is the
519 /// only enabler — it keeps the postfix reading PostgreSQL removed in 14.
520 PostfixOperator {
521 /// The postfix operator application; see [`PostfixOperatorExpr`].
522 postfix_operator: Box<PostfixOperatorExpr<X>>,
523 /// Source location and node identity.
524 meta: Meta,
525 },
526 /// A DuckDB single-arrow lambda: `x -> x + 1` / `(x, y) -> x + y` (boxed; see
527 /// [`LambdaExpr`]).
528 Lambda {
529 /// The lambda expression; see [`LambdaExpr`].
530 lambda: Box<LambdaExpr<X>>,
531 /// Source location and node identity.
532 meta: Meta,
533 },
534 /// DuckDB's `COLUMNS(<selector>)` column-set selector, a star expression that
535 /// stands wherever a value expression does (`SELECT COLUMNS('re')`,
536 /// `sum(COLUMNS(*))`, `COLUMNS(*)::JSON`). A new canonical node, not a function
537 /// call: DuckDB models it as its `STAR` node with `columns: true`, and
538 /// modelling it as a call would lose the star semantics the structural oracle
539 /// compares against. Reachable only under
540 /// [`CallSyntax::columns_expression`](crate::dialect::ExpressionSyntax).
541 ///
542 /// `pattern` is the selector argument: `None` for the star form `COLUMNS(*)` /
543 /// `COLUMNS(t.*)` (mirroring DuckDB's null `expr`), `Some(e)` for
544 /// `COLUMNS(<expr>)` — the regex string `COLUMNS('re')`, the lambda
545 /// `COLUMNS(c -> …)`, the name list `COLUMNS([…])`, or a bare column. `qualifier`
546 /// and `options` belong to the star form only (both always `None` alongside a
547 /// `pattern`): `qualifier` is the relation of a qualified star `COLUMNS(t.*)` —
548 /// exactly one name part, DuckDB rejects `COLUMNS(s.t.*)` (probed on 1.5.4) — and
549 /// `options` carries the `EXCLUDE`/`REPLACE`/`RENAME` modifiers DuckDB allows
550 /// inside the star form (`COLUMNS(* EXCLUDE i)`, `COLUMNS(t.* EXCLUDE (k))`).
551 ///
552 /// `spelling` records which of DuckDB's three surface forms of the star node the
553 /// source used (one-shape-plus-tag), all the same STAR node in the engine:
554 /// [`Columns`](ColumnsSpelling::Columns) is the `COLUMNS(<selector>)` wrapper
555 /// (DuckDB's STAR `columns:true`); [`Unpack`](ColumnsSpelling::Unpack) is the
556 /// `*COLUMNS(<selector>)` spread-into-arguments prefix (same node, unpack flag set)
557 /// admitted in call/`IN`-list argument positions; [`Star`](ColumnsSpelling::Star) is
558 /// the bare `*` / `t.*` written without the wrapper (DuckDB's STAR `columns:false`),
559 /// admitted in the `ORDER BY` and `UNPIVOT` `ON`/`IN` positions. A `Star` spelling
560 /// never carries a `pattern` (the bare star has no selector argument).
561 Columns {
562 /// Optional qualifier for this syntax.
563 qualifier: Option<ObjectName>,
564 /// Optional pattern for this syntax.
565 pattern: Option<Box<Expr<X>>>,
566 /// Options supplied in source order.
567 options: Option<Box<WildcardOptions<X>>>,
568 /// Exact source spelling retained for faithful rendering.
569 spelling: ColumnsSpelling,
570 /// Source location and node identity.
571 meta: Meta,
572 },
573 /// A SQL special value function with a dedicated grammar production rather than
574 /// an ordinary call: a nullary keyword form (`CURRENT_DATE`, `CURRENT_USER`,
575 /// `USER`, …) or one of the temporal forms that take an optional precision
576 /// (`CURRENT_TIME(p)`, `LOCALTIMESTAMP(p)`, …). PostgreSQL lowers these to
577 /// `SQLValueFunction`; the keyword is the whole construct, so there is no
578 /// argument list. Held inline (the keyword tag plus an optional precision is
579 /// small) rather than boxed.
580 SpecialFunction {
581 /// Which special-value function; see [`SpecialFunctionKeyword`].
582 keyword: SpecialFunctionKeyword,
583 /// The `(precision)` modifier, only valid on the temporal forms
584 /// (`CURRENT_TIME`, `CURRENT_TIMESTAMP`, `LOCALTIME`, `LOCALTIMESTAMP`).
585 precision: Option<u32>,
586 /// Source location and node identity.
587 meta: Meta,
588 },
589 /// A SQL/JSON query function: `JSON_VALUE` / `JSON_QUERY` / `JSON_EXISTS`
590 /// (SQL:2016, PostgreSQL's `JsonFuncExpr`; boxed, see [`JsonFuncExpr`]).
591 JsonFunc {
592 /// The SQL/JSON query function; see [`JsonFuncExpr`].
593 json_func: Box<JsonFuncExpr<X>>,
594 /// Source location and node identity.
595 meta: Meta,
596 },
597 /// A SQL/JSON object constructor: `JSON_OBJECT(k : v, …)` (boxed; see
598 /// [`JsonObjectExpr`]).
599 JsonObject {
600 /// The `JSON_OBJECT(...)` constructor; see [`JsonObjectExpr`].
601 json_object: Box<JsonObjectExpr<X>>,
602 /// Source location and node identity.
603 meta: Meta,
604 },
605 /// A SQL/JSON array constructor: `JSON_ARRAY(v, …)` or `JSON_ARRAY(<query>)`
606 /// (boxed; see [`JsonArrayExpr`]).
607 JsonArray {
608 /// The `JSON_ARRAY(...)` constructor; see [`JsonArrayExpr`].
609 json_array: Box<JsonArrayExpr<X>>,
610 /// Source location and node identity.
611 meta: Meta,
612 },
613 /// A SQL/JSON aggregate constructor: `JSON_OBJECTAGG(k : v …)` or
614 /// `JSON_ARRAYAGG(v …)` (boxed; see [`JsonAggregateExpr`]).
615 JsonAggregate {
616 /// The SQL/JSON aggregate; see [`JsonAggregateExpr`].
617 json_aggregate: Box<JsonAggregateExpr<X>>,
618 /// Source location and node identity.
619 meta: Meta,
620 },
621 /// A bare SQL/JSON constructor: `JSON(x)` / `JSON_SCALAR(x)` /
622 /// `JSON_SERIALIZE(x)` (boxed; see [`JsonConstructorExpr`]).
623 JsonConstructor {
624 /// The bare SQL/JSON constructor; see [`JsonConstructorExpr`].
625 json_constructor: Box<JsonConstructorExpr<X>>,
626 /// Source location and node identity.
627 meta: Meta,
628 },
629 /// The SQL/JSON `expr IS [NOT] JSON [type] [WITH|WITHOUT UNIQUE [KEYS]]`
630 /// predicate (boxed; see [`IsJsonExpr`]).
631 IsJson {
632 /// The operand, optional JSON type, and uniqueness clause; see [`IsJsonExpr`].
633 is_json: Box<IsJsonExpr<X>>,
634 /// Source location and node identity.
635 meta: Meta,
636 },
637 /// A SQL/XML expression function — `xmlelement`/`xmlforest`/`xmlconcat`/
638 /// `xmlparse`/`xmlpi`/`xmlroot`/`xmlserialize`/`xmlexists` (SQL:2006, PostgreSQL's
639 /// `XmlExpr`/`XmlSerialize`). One kind-tagged [`XmlFunc`] enum carries all eight
640 /// (boxed; the shapes differ, so a single fat inline variant would tax every
641 /// `Expr`).
642 XmlFunc {
643 /// The specific XML function and its arguments; see [`XmlFunc`].
644 xml_func: Box<XmlFunc<X>>,
645 /// Source location and node identity.
646 meta: Meta,
647 },
648 /// The SQL/XML `<expr> IS [NOT] DOCUMENT` predicate (PostgreSQL's `XmlExpr` with
649 /// `IS_DOCUMENT`). Held inline like [`IsNull`](Self::IsNull) — a boxed operand,
650 /// a negation flag, no clause tail.
651 IsDocument {
652 /// The operand tested for being a valid XML document.
653 expr: Box<Expr<X>>,
654 /// Whether the negated form was present in the source.
655 negated: bool,
656 /// Source location and node identity.
657 meta: Meta,
658 },
659 /// A standard-SQL string special form — the `SUBSTRING`/`POSITION`/`OVERLAY`/
660 /// `TRIM` keyword-argument grammar (SQL-92 E021 + SQL:1999 T312, PostgreSQL's
661 /// `func_expr_common_subexpr` string productions). One kind-tagged [`StringFunc`]
662 /// enum carries all five shapes (boxed; the shapes differ, so a single fat
663 /// inline variant would tax every `Expr`). The comma plain-call spellings
664 /// (`substring(x, 1, 2)`, `trim(x, y)`) stay ordinary [`Function`](Self::Function)
665 /// calls — this node holds only the keyword-argument surface.
666 StringFunc {
667 /// The specific string function and its keyword arguments; see [`StringFunc`].
668 string_func: Box<StringFunc<X>>,
669 /// Source location and node identity.
670 meta: Meta,
671 },
672 /// Dialect extension node supplied by the extension type.
673 Other {
674 /// The dialect extension node value.
675 ext: X,
676 /// Source location and node identity.
677 meta: Meta,
678 },
679}
680
681/// Which of DuckDB's three surface spellings of the [`Expr::Columns`] star node the
682/// source used.
683///
684/// All three lower to the one STAR node in the engine (one-shape-plus-tag);
685/// the tag is what lets the shared shape round-trip to the exact spelling.
686#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
687#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
688#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
689pub enum ColumnsSpelling {
690 /// `COLUMNS(<selector>)` — the wrapped column-set selector (DuckDB's STAR node with
691 /// `columns:true`).
692 Columns,
693 /// `*COLUMNS(<selector>)` — the unpack prefix that spreads the selected columns into
694 /// the enclosing call / `IN`-list argument list (`struct_pack(*COLUMNS(*))`,
695 /// `2 IN (*COLUMNS(*))`). The same wrapped node with DuckDB's unpack flag set; a bare
696 /// `*` never carries it.
697 Unpack,
698 /// A bare `*` / `t.*` written without the `COLUMNS(...)` wrapper (DuckDB's STAR node
699 /// with `columns:false`), admitted in the `ORDER BY` sort key and the `UNPIVOT`
700 /// `ON`/`IN` column positions. Always pattern-free.
701 Star,
702}
703
704/// A SQL special value function keyword (PostgreSQL `SQLValueFunction`).
705///
706/// Each names a dedicated grammar production whose whole spelling is the keyword;
707/// the four temporal forms additionally accept a parenthesized precision, carried
708/// on [`Expr::SpecialFunction`] rather than here so the keyword stays a copy tag.
709#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
710#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
711#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
712pub enum SpecialFunctionKeyword {
713 /// `CURRENT_CATALOG` — the current database/catalog name.
714 CurrentCatalog,
715 /// `CURRENT_DATE` — the current date.
716 CurrentDate,
717 /// `CURRENT_ROLE` — the current role name.
718 CurrentRole,
719 /// `CURRENT_SCHEMA` — the current schema name.
720 CurrentSchema,
721 /// `CURRENT_TIME` — the current time of day (optional precision).
722 CurrentTime,
723 /// `CURRENT_TIMESTAMP` — the current date and time (optional precision).
724 CurrentTimestamp,
725 /// `CURRENT_USER` — the current authorization identifier.
726 CurrentUser,
727 /// `LOCALTIME` — the current local time of day (optional precision).
728 LocalTime,
729 /// `LOCALTIMESTAMP` — the current local date and time (optional precision).
730 LocalTimestamp,
731 /// `SESSION_USER` — the session authorization identifier.
732 SessionUser,
733 /// `SYSTEM_USER` — the operating-system-level user identifier.
734 SystemUser,
735 /// `USER` — synonym for `CURRENT_USER`.
736 User,
737 /// MySQL `UTC_DATE` — the UTC-clock analogue of `CURRENT_DATE`. Nullary.
738 UtcDate,
739 /// MySQL `UTC_TIME` — the UTC-clock analogue of `CURRENT_TIME`; takes an optional
740 /// fractional-seconds precision (`UTC_TIME(6)`).
741 UtcTime,
742 /// MySQL `UTC_TIMESTAMP` — the UTC-clock analogue of `CURRENT_TIMESTAMP`; takes an
743 /// optional fractional-seconds precision (`UTC_TIMESTAMP(6)`).
744 UtcTimestamp,
745}
746
747/// How a cast is spelled.
748///
749/// One canonical [`Expr::Cast`] shape covers all three spellings; this
750/// tag records which surface form the source used so rendering round-trips: the
751/// standard `CAST(expr AS type)` call, the PostgreSQL `expr::type` postfix
752/// operator, or the PostgreSQL prefixed typed string constant `type 'string'`.
753#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
754#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
755#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
756pub enum CastSyntax {
757 /// `CAST(expr AS type)`.
758 Call,
759 /// `expr::type` (PostgreSQL).
760 DoubleColon,
761 /// `type 'string'` — a typed string constant whose semantics are a cast of the
762 /// string to the named type (PostgreSQL's generalized `ConstTypename Sconst` /
763 /// `func_name Sconst`, e.g. `float8 'NaN'`, `int4 '42'`, `double precision
764 /// '1.5'`). The operand is always a string constant; the canonical shape is the
765 /// same [`Expr::Cast`] as `'NaN'::float8` and `CAST('NaN' AS float8)`, so only
766 /// this tag and the rendered spelling distinguish the three.
767 PrefixTyped,
768 /// `CONVERT(<expr>, <type>)` — MySQL's comma-form cast, the same canonical
769 /// [`Expr::Cast`] shape as `CAST(<expr> AS <type>)` with only this tag (and the
770 /// rendered spelling) distinguishing it. The target is the identical restricted
771 /// `cast_type` set as `CAST` under
772 /// [`CallSyntax::restricted_cast_targets`](crate::dialect::CallSyntax) — engine-measured
773 /// on mysql:8.4, `CONVERT(1, INT)` / `CONVERT(x, VARCHAR)` reject exactly as the
774 /// matching `CAST` forms do, and the charset-annotated `CHAR` target rides in free via
775 /// the shared type grammar. Recognized only under
776 /// [`CallSyntax::convert_function`](crate::dialect::CallSyntax); MySQL-only. The
777 /// transcoding `CONVERT(<expr> USING <charset>)` form is a *different* production —
778 /// [`StringFunc::ConvertUsing`], not a cast.
779 Convert,
780}
781
782/// A subscript into an array/list value: an element access `base[index]`, a
783/// two-bound slice `base[lower:upper]`, or a DuckDB three-bound slice with a step
784/// `base[lower:upper:step]`.
785///
786/// [`kind`](SubscriptExpr::kind) distinguishes the three forms. An index carries its
787/// index in `lower` (`upper`/`step` both `None`); a two-bound slice may omit either
788/// bound (`base[lower:]`, `base[:upper]`, `base[:]`); a three-bound slice may omit the
789/// lower bound and the step (`base[:upper:step]`, `base[lower:upper:]`) but not the
790/// middle bound — DuckDB spells an open upper bound as the `-` placeholder, carried
791/// here as `upper == None` (an empty middle `base[lower::step]` is a DuckDB parse
792/// error). Boxed inside [`Expr::Subscript`] to keep the hot expression enum within its
793/// size budget.
794#[derive(Clone, Debug, PartialEq, Eq, Hash)]
795#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
796#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
797pub struct SubscriptExpr<X: Extension = NoExt> {
798 /// The value being subscripted.
799 pub base: Expr<X>,
800 /// The element index ([`SubscriptKind::Index`]) or the slice lower bound, if present.
801 pub lower: Option<Expr<X>>,
802 /// The slice upper bound, if present. Always `None` for an index; under
803 /// [`SubscriptKind::SliceWithStep`] a `None` is the `-` open-upper placeholder (an
804 /// absent middle bound is a parse error there), not an omitted bound.
805 pub upper: Option<Expr<X>>,
806 /// The slice step, if present. Only reachable under [`SubscriptKind::SliceWithStep`],
807 /// and `None` there for an omitted trailing step (`base[lower:upper:]`); always `None`
808 /// for an index or a two-bound slice.
809 pub step: Option<Expr<X>>,
810 /// Which bracketed form the subscript holds; see [`SubscriptKind`].
811 pub kind: SubscriptKind,
812 /// Source location and node identity.
813 pub meta: Meta,
814}
815
816/// Which bracketed form an [`Expr::Subscript`] holds — the colon count in the brackets.
817///
818/// The tag drives rendering: a slice re-emits its `:` separators (and, for a stepped
819/// slice, the `-` open-upper placeholder) that a bare index does not.
820#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
821#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
822#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
823pub enum SubscriptKind {
824 /// `base[index]` — a single element access; the index is in
825 /// [`lower`](SubscriptExpr::lower).
826 Index,
827 /// `base[lower:upper]` — a two-bound slice; either bound may be omitted.
828 Slice,
829 /// `base[lower:upper:step]` — a DuckDB three-bound slice with a step. The lower bound
830 /// and the step may each be omitted; the middle bound may not be empty, so a `None`
831 /// [`upper`](SubscriptExpr::upper) renders as the `-` open-upper placeholder.
832 SliceWithStep,
833}
834
835/// A semi-structured object/array path rooted at a value expression.
836///
837/// The first segment is introduced by `:` and later segments use JSON-path-like
838/// `.`/`[...]` suffixes. Kept distinct from PostgreSQL [`Expr::Subscript`] and
839/// [`Expr::FieldSelection`]: those address SQL arrays/composites, while this node
840/// preserves the Snowflake/Databricks-style semi-structured path surface.
841#[derive(Clone, Debug, PartialEq, Eq, Hash)]
842#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
843#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
844pub struct SemiStructuredAccessExpr<X: Extension = NoExt> {
845 /// The value the path is rooted at.
846 pub base: Expr<X>,
847 /// path in source order.
848 pub path: ThinVec<SemiStructuredPathSegment<X>>,
849 /// Source location and node identity.
850 pub meta: Meta,
851}
852
853/// One segment of a semi-structured value path.
854#[derive(Clone, Debug, PartialEq, Eq, Hash)]
855#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
856#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
857pub enum SemiStructuredPathSegment<X: Extension = NoExt> {
858 /// A field/key segment, written as `:key` for the first segment or `.key` after that.
859 Key {
860 /// The field/key name.
861 key: Ident,
862 /// Source location and node identity.
863 meta: Meta,
864 },
865 /// An array/list index segment, written as `[index]`.
866 Index {
867 /// Index referenced by this syntax.
868 index: Box<Expr<X>>,
869 /// Source location and node identity.
870 meta: Meta,
871 },
872}
873
874/// A PostgreSQL `expr COLLATE collation` collation override.
875///
876/// Boxed inside [`Expr::Collate`] to keep the hot expression enum within its size
877/// budget.
878#[derive(Clone, Debug, PartialEq, Eq, Hash)]
879#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
880#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
881pub struct CollateExpr<X: Extension = NoExt> {
882 /// Expression evaluated by this syntax.
883 pub expr: Expr<X>,
884 /// The collation name.
885 pub collation: ObjectName,
886 /// Source location and node identity.
887 pub meta: Meta,
888}
889
890/// A PostgreSQL `expr AT TIME ZONE zone` time-zone conversion.
891///
892/// Boxed inside [`Expr::AtTimeZone`] to keep the hot expression enum within its
893/// size budget.
894#[derive(Clone, Debug, PartialEq, Eq, Hash)]
895#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
896#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
897pub struct AtTimeZoneExpr<X: Extension = NoExt> {
898 /// Expression evaluated by this syntax.
899 pub expr: Expr<X>,
900 /// The target time zone.
901 pub zone: Expr<X>,
902 /// Source location and node identity.
903 pub meta: Meta,
904}
905
906/// An array/list constructor.
907///
908/// Either an element list (`ARRAY[a, b]`, possibly empty `ARRAY[]`, or the DuckDB
909/// bare-bracket `[a, b]`) or a subquery (`ARRAY(SELECT …)`). Boxed inside
910/// [`Expr::Array`] to keep the hot expression enum within its size budget.
911#[derive(Clone, Debug, PartialEq, Eq, Hash)]
912#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
913#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
914pub enum ArrayExpr<X: Extension = NoExt> {
915 /// `ARRAY[a, b, …]` / `[a, b, …]` (or empty `ARRAY[]` / `[]`).
916 Elements {
917 /// elements in source order.
918 elements: ThinVec<Expr<X>>,
919 /// Whether the `ARRAY` keyword was written (vs. the bare `[…]` form).
920 spelling: ArraySpelling,
921 /// Source location and node identity.
922 meta: Meta,
923 },
924 /// `ARRAY(<query>)` — always the keyword form (DuckDB has no bracket-subquery
925 /// spelling).
926 Subquery {
927 /// Query governed by this node.
928 query: Box<Query<X>>,
929 /// Source location and node identity.
930 meta: Meta,
931 },
932 /// A DuckDB list comprehension `[element for var in source (if filter)?]`
933 /// (boxed; see [`ListComprehension`]). A distinct list-literal production from the
934 /// element/subquery forms above: the same `[…]` bracket opens it, but the
935 /// `for` after the first element selects the comprehension rather than an element
936 /// list. Gated by
937 /// [`collection_literals`](crate::dialect::ExpressionSyntax::collection_literals) —
938 /// the same flag that admits the bracket list.
939 Comprehension {
940 /// The list comprehension; see [`ListComprehension`].
941 comprehension: Box<ListComprehension<X>>,
942 /// Source location and node identity.
943 meta: Meta,
944 },
945}
946
947/// Surface spelling for an array element constructor ([`ArrayExpr::Elements`]).
948///
949/// The keyword `ARRAY[…]` (SQL:1999 / PostgreSQL) and the bare `[…]` (DuckDB) are one
950/// canonical shape; this tag records which the source used so rendering
951/// round-trips exactly. Each spelling has its own acceptance gate —
952/// [`ExpressionSyntax::array_constructor`](crate::dialect::ExpressionSyntax::array_constructor)
953/// for the keyword,
954/// [`collection_literals`](crate::dialect::ExpressionSyntax::collection_literals) for
955/// the bracket — so a dialect can admit either independently.
956#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
957#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
958#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
959pub enum ArraySpelling {
960 /// The `ARRAY[…]` keyword-prefixed constructor.
961 Keyword,
962 /// The DuckDB bare-bracket `[…]` list literal.
963 Bracket,
964}
965
966/// A DuckDB list comprehension `[element for var in source (if filter)?]`.
967///
968/// Python-style syntax DuckDB desugars to `list_transform`/`list_filter`: it maps
969/// `element` over each `var` drawn from `source`, keeping only those matching the
970/// optional `filter`. The canonical node keeps the source spelling so a
971/// comprehension round-trips; DuckDB binds it only inside `COLUMNS(…)` when `source`
972/// is a column star, but that is a bind-time rule past this parse-level shape. Boxed
973/// inside [`ArrayExpr::Comprehension`] to keep the array node within its size budget.
974#[derive(Clone, Debug, PartialEq, Eq, Hash)]
975#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
976#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
977pub struct ListComprehension<X: Extension = NoExt> {
978 /// The output expression evaluated for each iteration.
979 pub element: Box<Expr<X>>,
980 /// Loop variables: one name (`for x in …`) or two (`for x, i in …` — value plus
981 /// 1-based index). DuckDB's binder rejects three or more (lambda max 2); the
982 /// parser admits a non-empty list so the multi-var form is representable.
983 pub vars: ThinVec<Ident>,
984 /// Input source for this syntax.
985 pub source: ComprehensionSource<X>,
986 /// Optional filter for this syntax.
987 pub filter: Option<Box<Expr<X>>>,
988 /// Source location and node identity.
989 pub meta: Meta,
990}
991
992/// The source of a [`ListComprehension`] — the thing iterated over.
993///
994/// A general list-valued expression, or the DuckDB column-star source that is valid
995/// only inside `COLUMNS(…)` (`[x for x in *]`, `[x for x in (* EXCLUDE (i))]`). The star
996/// is a distinct spelling rather than an expression because DuckDB has no bare `*`
997/// value expression — it is grammar special to this slot — and because it cannot
998/// canonicalize to `COLUMNS(*)` (DuckDB rejects a `COLUMNS` nested inside another).
999#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1000#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1001#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1002pub enum ComprehensionSource<X: Extension = NoExt> {
1003 /// A general list-valued expression source (`[y for y in <expr>]`).
1004 Expr {
1005 /// Expression evaluated by this syntax.
1006 expr: Box<Expr<X>>,
1007 /// Source location and node identity.
1008 meta: Meta,
1009 },
1010 /// The DuckDB column-star source: a bare `*` or a parenthesized `(* …)`, optionally
1011 /// carrying the `EXCLUDE`/`REPLACE`/`RENAME` wildcard modifiers (only legal in the
1012 /// parenthesized form). `parenthesized` records the `(…)` spelling so it round-trips.
1013 Star {
1014 /// Whether the parenthesized form was present in the source.
1015 parenthesized: bool,
1016 /// Options supplied in source order.
1017 options: Option<Box<WildcardOptions<X>>>,
1018 /// Source location and node identity.
1019 meta: Meta,
1020 },
1021}
1022
1023/// A DuckDB struct literal `{'key': value, …}`.
1024///
1025/// The fields keep source order (a struct is positional as well as named). Boxed
1026/// inside [`Expr::Struct`] to keep the hot expression enum within its size budget.
1027#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1028#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1029#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1030pub struct StructExpr<X: Extension = NoExt> {
1031 /// fields in source order.
1032 pub fields: ThinVec<StructField<X>>,
1033 /// Source location and node identity.
1034 pub meta: Meta,
1035}
1036
1037/// One `key: value` field of a [`StructExpr`].
1038///
1039/// The key is a field *name*, not a value — DuckDB rejects a non-identifier key
1040/// (`{1: 'x'}` is a syntax error) — so it is an interned [`Symbol`] rather than an
1041/// expression. One canonical shape covers the three key spellings; the
1042/// [`StructKeySpelling`] tag records which the source used so `{'a': 1}`, `{a: 1}`,
1043/// and `{"a": 1}` each round-trip exactly.
1044#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1045#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1046#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1047pub struct StructField<X: Extension = NoExt> {
1048 /// The interned field name.
1049 pub key: Symbol,
1050 /// Source spelling used for the key spelling.
1051 pub key_spelling: StructKeySpelling,
1052 /// Value supplied by this syntax.
1053 pub value: Expr<X>,
1054 /// Source location and node identity.
1055 pub meta: Meta,
1056}
1057
1058/// How a [`StructField`] key was spelled.
1059///
1060/// The surface-form tag for the one canonical struct-field shape,
1061/// mirroring [`CastSyntax`]: DuckDB folds all three to the same field name, so only
1062/// this tag and the rendered spelling distinguish them.
1063#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1064#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1065#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1066pub enum StructKeySpelling {
1067 /// A single-quoted string key, as in `{'key': v}`.
1068 SingleQuoted,
1069 /// A bare identifier key, as in `{key: v}`.
1070 Bare,
1071 /// A double-quoted identifier key, as in `{"key": v}`.
1072 DoubleQuoted,
1073}
1074
1075/// A BigQuery `STRUCT(...)` value constructor — the typeless `STRUCT(1, 2)` /
1076/// `STRUCT(x AS a)` forms and the typed `STRUCT<a INT64, b STRING>(1, 'x')` form.
1077///
1078/// Mirrors sqlparser-rs's `Expr::Struct { values, fields }`, reshaped to this crate's
1079/// canonical-shape-plus-owned-sub-nodes convention: `args` are the positional value
1080/// arguments (each optionally `AS`-aliased in the typeless form, which sqlparser-rs
1081/// spells as a separate `Expr::Named` node), and `fields` are the typed field
1082/// declarations from the `STRUCT<...>` angle-bracket prefix. `fields` is empty for the
1083/// typeless form — BigQuery requires at least one type inside `<...>`, so an empty list
1084/// is the unambiguous "typeless" marker and no separate flag is needed. Boxed inside
1085/// [`Expr::StructConstructor`] to keep the hot expression enum within its size budget.
1086#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1087#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1088#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1089pub struct StructConstructorExpr<X: Extension = NoExt> {
1090 /// fields in source order.
1091 pub fields: ThinVec<StructConstructorField<X>>,
1092 /// Arguments in source order.
1093 pub args: ThinVec<StructConstructorArg<X>>,
1094 /// Source location and node identity.
1095 pub meta: Meta,
1096}
1097
1098/// One typed field declaration of a typed [`StructConstructorExpr`]: `name TYPE` in
1099/// `STRUCT<a INT64>`, or an anonymous `TYPE` in `STRUCT<INT64>` (BigQuery permits both).
1100///
1101/// A dedicated node rather than the type-side
1102/// [`StructTypeField`](crate::ast::StructTypeField): BigQuery's angle-bracket field name
1103/// is *optional*, whereas the DuckDB paren composite type ([`DataType::Struct`](crate::ast::DataType))
1104/// requires it, so the two grammars carry different name arities and cannot share one shape.
1105#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1106#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1107#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1108pub struct StructConstructorField<X: Extension = NoExt> {
1109 /// Name referenced by this syntax.
1110 pub name: Option<Ident>,
1111 /// Data type named by this syntax.
1112 pub ty: DataType<X>,
1113 /// Source location and node identity.
1114 pub meta: Meta,
1115}
1116
1117/// One positional value argument of a [`StructConstructorExpr`], optionally aliased with
1118/// `AS name` (`STRUCT(1 AS a)`).
1119///
1120/// The alias is only grammatical in the typeless form; the typed form takes its field
1121/// names from the `STRUCT<...>` prefix, so `alias` is always `None` there.
1122#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1123#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1124#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1125pub struct StructConstructorArg<X: Extension = NoExt> {
1126 /// Value supplied by this syntax.
1127 pub value: Expr<X>,
1128 /// Alias assigned by this syntax.
1129 pub alias: Option<Ident>,
1130 /// Source location and node identity.
1131 pub meta: Meta,
1132}
1133
1134/// A DuckDB map literal `MAP {k1: v1, k2: v2, …}` (possibly empty `MAP {}`).
1135///
1136/// Unlike a [`StructExpr`] field name, a map key is an arbitrary value expression
1137/// (`MAP {1: 'a'}`, `MAP {[1,2]: 'x'}`), so the entries hold [`MapEntry`] expression
1138/// pairs. Boxed inside [`Expr::Map`] to keep the hot expression enum within its size
1139/// budget.
1140#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1141#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1142#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1143pub struct MapExpr<X: Extension = NoExt> {
1144 /// entries in source order.
1145 pub entries: ThinVec<MapEntry<X>>,
1146 /// Source location and node identity.
1147 pub meta: Meta,
1148}
1149
1150#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1151#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1152#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1153/// An SQL map entry.
1154pub struct MapEntry<X: Extension = NoExt> {
1155 /// The map entry key expression.
1156 pub key: Expr<X>,
1157 /// Value supplied by this syntax.
1158 pub value: Expr<X>,
1159 /// Source location and node identity.
1160 pub meta: Meta,
1161}
1162
1163/// A row constructor: explicit `ROW(a, b, …)` (or empty `ROW()`) or the implicit
1164/// parenthesized `(a, b, …)` form.
1165///
1166/// `explicit` records whether the `ROW` keyword was written, since the two
1167/// spellings are otherwise the same construct. Boxed inside
1168/// [`Expr::Row`] to keep the hot expression enum within its size budget.
1169#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1170#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1171#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1172pub struct RowExpr<X: Extension = NoExt> {
1173 /// fields in source order.
1174 pub fields: ThinVec<Expr<X>>,
1175 /// Whether the `ROW` keyword was written (vs. the implicit `(a, b)` form).
1176 pub explicit: bool,
1177 /// Source location and node identity.
1178 pub meta: Meta,
1179}
1180
1181/// A PostgreSQL composite navigation off a value: `(expr).field`, `(expr).*`, or a
1182/// whole-row `tbl.*` used as a value.
1183///
1184/// PostgreSQL models both selectors as one `.`-indirection off an operand (a
1185/// `String` attribute name or an `A_Star`); this shares that shape, with
1186/// [`selector`](Self::selector) distinguishing the named field from the star. A
1187/// whole-row `tbl.*` written in a *value* position (a `ROW(...)` field, a function
1188/// argument, a cast operand) parses to this node with the bare column as `base` and a
1189/// [`FieldSelector::Star`] selector — distinct from a select-list `tbl.*`, which is a
1190/// [`SelectItem::QualifiedWildcard`](crate::ast::SelectItem::QualifiedWildcard)
1191/// projection target. Boxed inside [`Expr::FieldSelection`] to keep the hot expression
1192/// enum within its size budget.
1193#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1194#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1195#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1196pub struct FieldSelectionExpr<X: Extension = NoExt> {
1197 /// The composite value being navigated.
1198 pub base: Expr<X>,
1199 /// Which selector applies — a named field or the whole-composite star; see [`FieldSelector`].
1200 pub selector: FieldSelector,
1201 /// Source location and node identity.
1202 pub meta: Meta,
1203}
1204
1205/// Which composite selector a [`FieldSelectionExpr`] applies to its `base`.
1206///
1207/// PostgreSQL's `.`-indirection element is either a named attribute (`.field`) or the
1208/// whole-composite star (`.*`); the two are the same grammar production and bind
1209/// identically, so one node carries both with this tag. The star form is gated apart
1210/// from the named form ([`ExpressionSyntax::field_wildcard`](crate::dialect::ExpressionSyntax::field_wildcard)
1211/// vs [`field_selection`](crate::dialect::ExpressionSyntax::field_selection)): DuckDB
1212/// admits `.field` but rejects every `.*` value expansion (engine-probed 1.5.4).
1213#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1214#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1215#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1216pub enum FieldSelector {
1217 /// A named composite attribute: `(expr).field`.
1218 Field {
1219 /// The selected attribute name.
1220 field: Ident,
1221 /// Source location and node identity.
1222 meta: Meta,
1223 },
1224 /// The whole-composite / whole-row star: `(expr).*` or a value-position `tbl.*`.
1225 Star {
1226 /// Source location and node identity.
1227 meta: Meta,
1228 },
1229}
1230
1231/// A PostgreSQL explicit-operator infix application: `a OPERATOR(schema.op) b`.
1232///
1233/// `OPERATOR(...)` names an operator explicitly, optionally schema-qualified
1234/// (`OPERATOR(pg_catalog.+)`), and binds at PostgreSQL's "any other operator" rank
1235/// — the same `%left Op OPERATOR` precedence as `||`. Boxed inside
1236/// [`Expr::NamedOperator`] to keep the hot expression enum within its size budget.
1237#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1238#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1239#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1240pub struct NamedOperatorExpr<X: Extension = NoExt> {
1241 /// Left-hand operand.
1242 pub left: Expr<X>,
1243 /// The optional schema qualification (`pg_catalog` in `OPERATOR(pg_catalog.+)`);
1244 /// an empty name when the operator is unqualified (`OPERATOR(+)`) or bare.
1245 pub schema: ObjectName,
1246 /// The operator symbol spelling (`+`, `->>`, `~`, `<->`), interned exact-case so it
1247 /// round-trips. The operator is always symbolic, never a word, so it is held as
1248 /// a bare [`Symbol`] rather than an [`Ident`].
1249 pub op: Symbol,
1250 /// Right-hand operand.
1251 pub right: Expr<X>,
1252 /// Which surface form spelled the operator application — the explicit
1253 /// `OPERATOR(schema.op)` keyword or a bare `a op b`.
1254 pub spelling: NamedOperatorSpelling,
1255 /// Source location and node identity.
1256 pub meta: Meta,
1257}
1258
1259/// How a [`NamedOperatorExpr`] was spelled — the whole surface form.
1260///
1261/// Under the general operator surface
1262/// ([`OperatorSyntax::custom_operators`](crate::dialect::OperatorSyntax::custom_operators);
1263/// PostgreSQL is the current enabler) a dialect admits ANY operator from its `Op` character
1264/// class over a user-extensible operator set, and a bare `a ~ b` / `a <-> b` / `a @#@ b` is
1265/// the SAME grammar production as the explicit `a OPERATOR(schema.op) b` — both name the
1266/// operator, at the "any other operator" precedence. This tag records which surface the
1267/// source used so rendering round-trips exactly (PostgreSQL's own deparse keeps the bare form
1268/// bare and the qualified form wrapped: `OPERATOR(~)` normalizes to `~`, but
1269/// `OPERATOR(pg_catalog.+)` stays wrapped — engine-measured). The [`Bare`](Self::Bare)
1270/// form is always unqualified (a bare operator carries no schema); the
1271/// [`OperatorKeyword`](Self::OperatorKeyword) form carries the optional schema.
1272#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1273#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1274#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1275pub enum NamedOperatorSpelling {
1276 /// The explicit `a OPERATOR(schema.op) b` keyword form (may be schema-qualified).
1277 OperatorKeyword,
1278 /// A bare `a op b` — a general symbolic operator (regex `~`/`!~`/`~*`/`!~*`,
1279 /// geometric/network/text-search ops, or a fully user-defined operator), munched under
1280 /// [`OperatorSyntax::custom_operators`](crate::dialect::OperatorSyntax::custom_operators).
1281 Bare,
1282}
1283
1284/// A prefix operator application: the symbolic operator token, then its operand, as in
1285/// `@ -5` (absolute value), `|/ 25` (square root), `||/ 27` (cube root), `@@ box`
1286/// (centre point), or a fully user-defined prefix operator `@#@ 24`.
1287///
1288/// Under the general operator surface
1289/// ([`OperatorSyntax::custom_operators`](crate::dialect::OperatorSyntax::custom_operators);
1290/// PostgreSQL is the current enabler) a dialect admits ANY operator from its `Op` character
1291/// class in prefix position (PostgreSQL grammar `qual_Op a_expr %prec Op`), so — like the
1292/// bare infix [`NamedOperatorExpr`] — this is one canonical shape carrying the interned
1293/// operator spelling rather than an enumerated set. It binds at the "any other operator" rank
1294/// ([`BindingPowerTable::any_operator`](crate::precedence::BindingPowerTable::any_operator)),
1295/// the same tier the bare infix operators use. Boxed inside [`Expr::PrefixOperator`] to
1296/// keep the hot expression enum within its size budget. Distinct from the fixed
1297/// [`UnaryOperator`] prefixes (`+`/`-`/`NOT`/`~`), which have their own tight precedence
1298/// and dedicated node.
1299#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1300#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1301#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1302pub struct PrefixOperatorExpr<X: Extension = NoExt> {
1303 /// The operator symbol spelling (`@`, `|/`, `@@`, `@#@`), interned exact-case so it
1304 /// round-trips. Always symbolic, never a word, so a bare [`Symbol`] rather than an
1305 /// [`Ident`].
1306 pub op: Symbol,
1307 /// The operand the prefix operator applies to.
1308 pub operand: Expr<X>,
1309 /// Source location and node identity.
1310 pub meta: Meta,
1311}
1312
1313/// A postfix operator application: the operand, then the trailing symbolic operator token, as
1314/// in `10 !` (factorial), `1 ~`, `1 <->`, `1 &`, or a fully user-defined operator `1 @#@`.
1315///
1316/// DuckDB keeps the generalized postfix reading PostgreSQL removed in version 14
1317/// ([`OperatorSyntax::postfix_operators`](crate::dialect::OperatorSyntax::postfix_operators);
1318/// DuckDB is the only enabler): any operator from its `Op` character class — the general
1319/// residue (the interned [`Symbol`] of a `Custom` operator token, e.g. `!!`/`<->`/`~*`), the
1320/// lone `~`/`!`/`@`, and the dedicated symbolic infix operators (`&`/`|`/`<<`/`>>`/`||`/`<@`/
1321/// `@>`/`^@`) — folds here when no operand follows it. Like the bare infix
1322/// [`NamedOperatorExpr`] it is one canonical shape carrying the interned operator spelling
1323/// rather than an enumerated set. It binds at the "any other operator" left rank
1324/// ([`BindingPowerTable::any_operator`](crate::precedence::BindingPowerTable::any_operator)),
1325/// so a tighter operand groups first (`2 * 3 !` is `(2 * 3)!`) while the postfix stays a
1326/// complete unary token (`1 ! < 2` is `(1!) < 2`). Boxed inside [`Expr::PostfixOperator`] to
1327/// keep the hot expression enum within its size budget. The infix reading wins whenever an
1328/// operand *does* follow (`1 ! + 2` is the infix `1 ! (+2)`), so this node is reached only in
1329/// the operand-absent position.
1330#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1331#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1332#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1333pub struct PostfixOperatorExpr<X: Extension = NoExt> {
1334 /// The operand the postfix operator applies to.
1335 pub operand: Expr<X>,
1336 /// The operator symbol spelling (`!`, `~`, `<->`, `@#@`), interned exact-case so it
1337 /// round-trips. Always symbolic, never a word, so a bare [`Symbol`] rather than an
1338 /// [`Ident`].
1339 pub op: Symbol,
1340 /// Source location and node identity.
1341 pub meta: Meta,
1342}
1343
1344/// A DuckDB single-arrow lambda: bound parameters and a body, as in
1345/// `list_transform([1, 2, 3], x -> x + 1)` or `list_reduce(l, (x, y) -> x + y)`.
1346///
1347/// One canonical shape for the new construct: a lambda has no existing
1348/// shape to fold onto — DuckDB's own tree confirms it with a dedicated `LAMBDA`
1349/// node. The parameters are plain unqualified identifiers, never expressions:
1350/// DuckDB's binder rejects anything else ("Parameters must be unqualified
1351/// comma-separated names like x or (x, y)", probed on 1.5.4), and our parser
1352/// applies that same shape test to the `->` left operand to pick this node over
1353/// the JSON-arrow operator — see
1354/// [`OperatorSyntax::lambda_expressions`](crate::dialect::OperatorSyntax::lambda_expressions)
1355/// for the whole disambiguation story. The `->` binds at the JSON-arrow rank (it is
1356/// the same token), so the body captures everything tighter (`x -> x + 1` is
1357/// `x -> (x + 1)`). Boxed inside [`Expr::Lambda`] to keep the hot expression enum
1358/// within its size budget.
1359#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1360#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1361#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1362pub struct LambdaExpr<X: Extension = NoExt> {
1363 /// The bound parameter names, in source order (always at least one — DuckDB
1364 /// rejects an empty `() -> …` at parse time).
1365 pub params: ThinVec<Ident>,
1366 /// Exact source spelling retained for faithful rendering.
1367 pub spelling: LambdaParamSpelling,
1368 /// The lambda body expression.
1369 pub body: Expr<X>,
1370 /// Source location and node identity.
1371 pub meta: Meta,
1372}
1373
1374/// How a [`LambdaExpr`] was spelled — the whole surface form, arrow versus keyword.
1375///
1376/// The surface-form tag for the one canonical lambda shape, mirroring
1377/// [`ArraySpelling`]. The three arrow forms differ only in how the parameter list is
1378/// delimited: DuckDB accepts a bare single name, a parenthesized list, and — because
1379/// `(x, y)` and `ROW(x, y)` parse to the same row node there — the explicit `ROW(…)`
1380/// keyword form (all three probed against 1.5.4). The [`Keyword`](Self::Keyword) form is
1381/// the python-style spelling `lambda x, y: body` DuckDB 1.3.0 introduced (and now
1382/// prefers over the deprecated arrow): a distinct surface for the same node. The forms
1383/// bind the same parameters, so only this tag and the rendered spelling distinguish them.
1384/// [`Bare`](Self::Bare) implies exactly one parameter; the parser upholds that invariant.
1385#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1386#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1387#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1388pub enum LambdaParamSpelling {
1389 /// A bare single parameter with the arrow, as in `x -> x + 1`.
1390 Bare,
1391 /// A parenthesized list with the arrow, as in `(x, y) -> x + y` (also the single
1392 /// `(x) -> …`).
1393 Parenthesized,
1394 /// The explicit row-keyword list with the arrow, as in `ROW(x, y) -> x + y`.
1395 RowKeyword,
1396 /// The python-style keyword spelling `lambda x, y: body` (comma-separated bare names,
1397 /// a `:` before the body). DuckDB's current preferred spelling.
1398 Keyword,
1399}
1400
1401/// A prepared-statement parameter placeholder.
1402///
1403/// One canonical shape: the placeholder *meaning* is the data, while
1404/// which surface forms a dialect accepts is gated by
1405/// [`ParameterSyntax`](crate::dialect::ParameterSyntax). The positional index, the
1406/// anonymous-by-occurrence form, and a by-name binding are distinct values (not a
1407/// single surface tag) because they differ semantically, not merely in spelling.
1408#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1409#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1410#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1411pub enum ParameterKind {
1412 /// PostgreSQL positional `$1`, `$2`, … — the carried value is the 1-based index.
1413 Positional(u32),
1414 /// SQLite numbered `?1`, `?123` — the `?`-spelled positional parameter (distinct from
1415 /// PostgreSQL's `$`-spelled [`Positional`](Self::Positional) so it round-trips as `?N`).
1416 /// The carried value is the 1-based index; SQLite restricts it to `1..=32766`
1417 /// (`SQLITE_MAX_VARIABLE_NUMBER`), enforced at parse time.
1418 Numbered(u32),
1419 /// Anonymous positional `?` (ODBC/JDBC); its ordinal is its occurrence order.
1420 Anonymous,
1421 /// A named placeholder bound by name rather than position (`:name`, `@name`).
1422 ///
1423 /// `name` is the interned name *without* its sigil; [`ParameterSigil`] records
1424 /// which sigil spelled it, so a dialect accepting both forms round-trips each
1425 /// exactly. The by-name binding is a distinct meaning from the
1426 /// positional/anonymous forms, hence a value here rather than only a tag.
1427 Named {
1428 /// Name referenced by this syntax.
1429 name: Symbol,
1430 /// Which sigil introduced the name; see [`ParameterSigil`].
1431 sigil: ParameterSigil,
1432 },
1433}
1434
1435/// Which sigil introduced a named parameter placeholder.
1436///
1437/// The surface-form tag on [`ParameterKind::Named`]: one canonical named-parameter
1438/// shape covers the spellings, and this records which the source used —
1439/// the colon form (`:name`; Oracle, SQLite, JDBC/psycopg), the at-sign form
1440/// (`@name`; T-SQL, SQLite), or the dollar form (`$name`; SQLite) — so rendering
1441/// restores the original sigil.
1442#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1443#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1444#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1445pub enum ParameterSigil {
1446 /// `:name`.
1447 Colon,
1448 /// `@name`.
1449 At,
1450 /// `$name` — SQLite's dollar-named placeholder. Disjoint from the PostgreSQL
1451 /// positional `$1` ([`ParameterKind::Positional`]) by its follow byte (an
1452 /// identifier, not a digit).
1453 Dollar,
1454}
1455
1456/// Which session-variable form an [`Expr::SessionVariable`] names.
1457///
1458/// One flat enum over the four valid MySQL spellings, so an impossible pairing — a
1459/// `@`-user variable carrying an explicit system scope — is unrepresentable rather
1460/// than a runtime invariant (make illegal states unrepresentable). The system forms
1461/// differ semantically, not merely in spelling: `@@x` reads the server's implicit
1462/// scope for the variable while `@@global.x` / `@@session.x` force one, so each is
1463/// its own value, and the sigil (`@` vs `@@`) is recovered from the
1464/// variant so every form round-trips.
1465#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1466#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1467#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1468pub enum SessionVariableKind {
1469 /// `@name` — a user-defined session variable.
1470 User,
1471 /// `@@name` — a system variable at the server's implicit scope.
1472 System,
1473 /// `@@global.name` — a system variable read at global scope.
1474 SystemGlobal,
1475 /// `@@session.name` — a system variable read at session scope.
1476 SystemSession,
1477}
1478
1479/// A function or aggregate call: `name([DISTINCT] args | *)` plus the optional
1480/// aggregate modifiers an ordered-set / filtered aggregate carries.
1481///
1482/// Boxed inside [`Expr::Function`] so the hot expression enum stays within its
1483/// size budget. The same canonical shape covers plain scalar calls
1484/// (`COALESCE`, `NULLIF`, `GREATEST`, `LEAST`, …) and aggregates; unused modifier
1485/// fields stay at their empty defaults (one shape per construct).
1486#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1487#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1488#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1489pub struct FunctionCall<X: Extension = NoExt> {
1490 /// Name referenced by this syntax.
1491 pub name: ObjectName,
1492 /// The `ALL` / `DISTINCT` argument quantifier, as in `count(DISTINCT x)` or
1493 /// `count(ALL x)`; `None` for a call written with no quantifier. `DISTINCT ON`
1494 /// is a SELECT-list-only form, so an aggregate never carries it.
1495 pub quantifier: Option<SetQuantifier>,
1496 /// The argument list, each a positional or PostgreSQL named argument (see
1497 /// [`FunctionArg`]). Empty for a no-arg call or a `*` call.
1498 pub args: ThinVec<FunctionArg<X>>,
1499 /// `*` as the sole argument, as in `count(*)`. Mutually exclusive with `args`.
1500 pub wildcard: bool,
1501 /// `ORDER BY` inside an ordered-set aggregate, as in `array_agg(x ORDER BY y)`.
1502 pub order_by: ThinVec<OrderByExpr<X>>,
1503 /// `WITHIN GROUP (ORDER BY <keys>)` — the SQL:2008 ordered-set aggregate clause
1504 /// (T612/T614), as in `percentile_cont(0.5) WITHIN GROUP (ORDER BY x)`. A
1505 /// post-argument clause parsed after the `)`, mirroring the optionality of
1506 /// [`filter`](Self::filter) and [`over`](Self::over); `None` when absent, and the
1507 /// list is non-empty when present (the grammar requires a sort key). Distinct from
1508 /// the in-parenthesis [`order_by`](Self::order_by): PostgreSQL admits at most one of
1509 /// the two, and they render in different positions.
1510 pub within_group: Option<ThinVec<OrderByExpr<X>>>,
1511 /// `SEPARATOR <string>` — the MySQL `GROUP_CONCAT(... SEPARATOR ',')` delimiter,
1512 /// an in-parenthesis argument tail parsed after [`order_by`](Self::order_by) and
1513 /// before the closing `)`. Gated for acceptance by
1514 /// [`AggregateCallSyntax::group_concat_separator`](crate::dialect::ExpressionSyntax):
1515 /// `None` when the dialect leaves the flag off or the clause is unwritten. The
1516 /// delimiter is always a string constant, so it is a bare [`Literal`] rather than a
1517 /// general expression — one canonical field on the shared call shape,
1518 /// not a `GROUP_CONCAT`-specific node.
1519 pub separator: Option<Literal>,
1520 /// `FILTER (WHERE <predicate>)` applied to an aggregate.
1521 pub filter: Option<Box<Expr<X>>>,
1522 /// Whether the [`filter`](Self::filter) clause wrote the standard `WHERE` keyword
1523 /// (`FILTER (WHERE p)`) or DuckDB's keyword-less `FILTER (p)`. A pure fidelity tag —
1524 /// the [`FilterWhereSpelling`] round-trips the surface spelling. Carries the canonical
1525 /// [`Where`](FilterWhereSpelling::Where) when no filter is present.
1526 pub filter_where: FilterWhereSpelling,
1527 /// The `OVER (…)` / `OVER name` window clause that makes this a window
1528 /// function call; `None` for a plain scalar or aggregate call.
1529 pub over: Option<WindowSpec<X>>,
1530 /// `IGNORE NULLS` / `RESPECT NULLS` null-treatment written *inside* the call
1531 /// parentheses, after the argument list (and any in-parenthesis `ORDER BY`), as in
1532 /// DuckDB's `last(s IGNORE NULLS) OVER (…)`. `None` when unwritten. One canonical
1533 /// field on the shared call shape, the [`NullTreatment`] tag recording
1534 /// which the source used so it round-trips. Gated for acceptance by
1535 /// [`AggregateCallSyntax::null_treatment`](crate::dialect::CallSyntax): DuckDB spells the
1536 /// SQL:2016 null-treatment inside the parentheses (the standard's post-`)` position
1537 /// engine-rejects on 1.5.4), so it rides the in-parenthesis tail like
1538 /// [`separator`](Self::separator) rather than a post-argument clause. When the
1539 /// dialect leaves the flag off, `IGNORE`/`RESPECT` is left unconsumed and the
1540 /// unmatched `)` surfaces as a clean parse error.
1541 pub null_treatment: Option<NullTreatment>,
1542 /// The MySQL window-function post-`)` tail — the SQL:2016
1543 /// `[FROM {FIRST | LAST}] [{RESPECT | IGNORE} NULLS]` clauses a null-treatment
1544 /// window function carries *between* its argument `)` and its `OVER` clause, as in
1545 /// `NTH_VALUE(x, 2) FROM FIRST RESPECT NULLS OVER (…)`. `None` when no tail was
1546 /// written. A separate field from the in-parenthesis DuckDB
1547 /// [`null_treatment`](Self::null_treatment) precisely because the surface *position*
1548 /// differs: MySQL spells these after the `)` and rejects the in-paren spelling
1549 /// (`ER_PARSE_ERROR`, 1064), while DuckDB rejects the post-`)` one — so the two
1550 /// positions round-trip as distinct fields on the shared call shape
1551 /// rather than a shared field plus a position tag the DuckDB path would also carry.
1552 /// Gated for acceptance by
1553 /// [`AggregateCallSyntax::window_function_tail`](crate::dialect::CallSyntax): MySQL admits it
1554 /// only on the null-treatment window functions
1555 /// (`LEAD`/`LAG`/`FIRST_VALUE`/`LAST_VALUE`/`NTH_VALUE`, with `FROM FIRST` on
1556 /// `NTH_VALUE` alone), enforced by the parser's window-grammar gate.
1557 pub window_tail: Option<WindowFunctionTail>,
1558 /// Source location and node identity.
1559 pub meta: Meta,
1560}
1561
1562/// One argument of a [`FunctionCall`]: a bare positional value, or a PostgreSQL
1563/// named argument `name => value` / `name := value`, optionally prefixed by the
1564/// `VARIADIC` array-spread marker (`VARIADIC arr`, `VARIADIC name => arr`).
1565///
1566/// One canonical shape covers all three spellings: a positional
1567/// argument is `{ name: None, syntax: Positional, value }`, while a named argument
1568/// carries `name: Some(_)` and an [`ArgSyntax`] surface tag recording which arrow
1569/// the source wrote so it round-trips. `name` being `Some` ⟺ `syntax` is a named
1570/// form is an invariant the parser upholds. The argument is a spanned node so the
1571/// `name => value` extent has side-table identity of its own.
1572#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1573#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1574#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1575pub struct FunctionArg<X: Extension = NoExt> {
1576 /// The argument name for a named argument (`name` in `name => value`);
1577 /// `None` for a positional argument.
1578 pub name: Option<Symbol>,
1579 /// The `VARIADIC` marker that spreads an array over a variadic parameter
1580 /// (`f(a, VARIADIC arr)`). A parse-layer prefix the parser admits only on the
1581 /// *last* argument of a call and never alongside an `ALL`/`DISTINCT` quantifier
1582 /// (both PostgreSQL and DuckDB parse-reject the other positions); it composes with
1583 /// the `name => value` named form, so it is a flag on the argument rather than a
1584 /// separate call-level field. `false` for an ordinary argument.
1585 pub variadic: bool,
1586 /// Which surface form spelled this argument (positional, `=>`, or `:=`).
1587 pub syntax: ArgSyntax,
1588 /// Value supplied by this syntax.
1589 pub value: Expr<X>,
1590 /// Source location and node identity.
1591 pub meta: Meta,
1592}
1593
1594/// How a [`FunctionArg`] was spelled.
1595///
1596/// The surface-form tag for the one canonical [`FunctionArg`] shape,
1597/// mirroring [`CastSyntax`]: a positional argument carries no name, while the two
1598/// PostgreSQL named-argument arrows are otherwise the same construct (`=>` is
1599/// current, `:=` is the deprecated spelling PostgreSQL still accepts), so this
1600/// records which the source used to restore it on render.
1601#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1602#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1603#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1604pub enum ArgSyntax {
1605 /// A bare positional argument, as in `f(x)`.
1606 Positional,
1607 /// A named argument written `name => value`.
1608 Arrow,
1609 /// A named argument written with the deprecated `name := value` spelling.
1610 ColonEquals,
1611}
1612
1613/// The `IGNORE NULLS` / `RESPECT NULLS` null-treatment on a window/aggregate
1614/// [`FunctionCall`] (SQL:2016 window functions; DuckDB spells it inside the call
1615/// parentheses).
1616///
1617/// Two spellings of the same construct kept as data so the surface round-trips
1618/// (the [`ArgSyntax`] precedent): `RESPECT NULLS` is the default the
1619/// engine may canonicalize away, but the parser preserves whichever the source wrote.
1620#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1621#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1622#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1623pub enum NullTreatment {
1624 /// `IGNORE NULLS` — skip null values when computing the window/aggregate result.
1625 IgnoreNulls,
1626 /// `RESPECT NULLS` — include null values (the default).
1627 RespectNulls,
1628}
1629
1630/// The MySQL window-function post-`)` argument tail (SQL:2016):
1631/// `[FROM {FIRST | LAST}] [{RESPECT | IGNORE} NULLS]`, written between a null-treatment
1632/// window function's argument `)` and its `OVER` clause.
1633///
1634/// Both clauses are independently optional and appear in this fixed order (the reverse
1635/// order is a mysql:8 `ER_PARSE_ERROR`); the struct is only constructed when at least
1636/// one is present, so a [`FunctionCall::window_tail`] of `Some` always carries a
1637/// clause. The [`NullTreatment`] value is reused from the in-parenthesis DuckDB form —
1638/// only its surface *position* differs (post-`)` here, in-paren there), which is why
1639/// this is a separate field rather than a shared one.
1640#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1641#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1642#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1643pub struct WindowFunctionTail {
1644 /// `FROM FIRST` / `FROM LAST` — which end of the frame `NTH_VALUE` counts its `N`th
1645 /// row from. `None` when unwritten. On mysql:8 only `FROM FIRST` is accepted (and
1646 /// only on `NTH_VALUE`); `FROM LAST` is grammar-admitted but feature-rejected
1647 /// (`ER_NOT_SUPPORTED_YET`, 1235), so the MySQL parser never produces
1648 /// [`FromFirstLast::Last`].
1649 pub from_first_last: Option<FromFirstLast>,
1650 /// `RESPECT NULLS` / `IGNORE NULLS` — the post-`)` null treatment. `None` when
1651 /// unwritten. On mysql:8 only `RESPECT NULLS` is accepted; `IGNORE NULLS` is
1652 /// grammar-admitted but feature-rejected (`ER_NOT_SUPPORTED_YET`, 1235), so the
1653 /// MySQL parser never produces [`NullTreatment::IgnoreNulls`] in this position.
1654 pub null_treatment: Option<NullTreatment>,
1655}
1656
1657/// `FROM FIRST` / `FROM LAST` — which end of the window frame `NTH_VALUE` counts its
1658/// `N`th row from (SQL:2016 `from_first_last`).
1659///
1660/// Two spellings of the same construct kept as data so the surface round-trips (the
1661/// [`NullTreatment`] precedent). `FROM FIRST` is the default; `FROM LAST` completes the
1662/// surface for a dialect that admits it (mysql:8 feature-rejects it, so its parser only
1663/// ever produces `First`).
1664#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1665#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1666#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1667pub enum FromFirstLast {
1668 /// `FROM FIRST` — count from the first row of the frame (the default).
1669 First,
1670 /// `FROM LAST` — count from the last row of the frame.
1671 Last,
1672}
1673
1674/// A `CASE` expression in either standard form.
1675///
1676/// Searched `CASE WHEN cond THEN result … [ELSE result] END` has no `operand`;
1677/// simple `CASE operand WHEN value THEN result … END` carries the `operand` each
1678/// `WHEN` value is compared against. Boxed inside [`Expr::Case`] to keep the hot
1679/// expression enum within its size budget.
1680#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1681#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1682#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1683pub struct CaseExpr<X: Extension = NoExt> {
1684 /// Optional operand for this syntax.
1685 pub operand: Option<Box<Expr<X>>>,
1686 /// The `WHEN … THEN …` branches, in source order (always at least one).
1687 pub when_clauses: ThinVec<WhenClause<X>>,
1688 /// Optional else result for this syntax.
1689 pub else_result: Option<Box<Expr<X>>>,
1690 /// Source location and node identity.
1691 pub meta: Meta,
1692}
1693
1694#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1695#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1696#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1697/// An SQL when clause.
1698pub struct WhenClause<X: Extension = NoExt> {
1699 /// Predicate that controls this clause.
1700 pub condition: Expr<X>,
1701 /// The value produced when the condition holds.
1702 pub result: Expr<X>,
1703 /// Source location and node identity.
1704 pub meta: Meta,
1705}
1706
1707/// An `EXTRACT(<field> FROM <source>)` expression.
1708///
1709/// `field` is the datetime field name (`YEAR`, `MONTH`, …) interned as an
1710/// identifier; `source` is the value it is pulled from. Boxed inside
1711/// [`Expr::Extract`] to keep the hot expression enum within its size budget.
1712#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1713#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1714#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1715pub struct ExtractExpr<X: Extension = NoExt> {
1716 /// The datetime field name (`YEAR`, `MONTH`, …).
1717 pub field: Ident,
1718 /// The value the field is pulled from.
1719 pub source: Box<Expr<X>>,
1720 /// Source location and node identity.
1721 pub meta: Meta,
1722}
1723
1724/// The SQL/JSON `FORMAT JSON [ENCODING <enc>]` specifier (SQL:2016).
1725///
1726/// The only spellable format is `JSON` (PostgreSQL rejects `FORMAT JSONB` at raw
1727/// parse), so the struct's mere presence records "`FORMAT JSON` was written"; the
1728/// optional `encoding` is the `ENCODING` tail. PostgreSQL validates the encoding
1729/// name against `UTF8`/`UTF16`/`UTF32` *at raw parse* ("unrecognized JSON encoding"),
1730/// so it is a closed [`JsonEncoding`] rather than a free identifier.
1731#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1732#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1733#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1734pub struct JsonFormat {
1735 /// Optional encoding for this syntax.
1736 pub encoding: Option<JsonEncoding>,
1737}
1738
1739/// A SQL/JSON `ENCODING` name — the closed set PostgreSQL accepts at raw parse.
1740#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1741#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1742#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1743pub enum JsonEncoding {
1744 /// `UTF8` encoding.
1745 Utf8,
1746 /// `UTF16` encoding.
1747 Utf16,
1748 /// `UTF32` encoding.
1749 Utf32,
1750}
1751
1752/// A SQL/JSON value expression — an operand with an optional [`JsonFormat`]
1753/// (`<expr> [FORMAT JSON [ENCODING …]]`, PostgreSQL's `JsonValueExpr`).
1754///
1755/// The context item of a query function, each element of a `JSON_ARRAY` value
1756/// list, the value half of an object member, and the argument of `JSON`/
1757/// `JSON_SERIALIZE`/aggregates all take this shape.
1758#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1759#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1760#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1761pub struct JsonValueExpr<X: Extension = NoExt> {
1762 /// Expression evaluated by this syntax.
1763 pub expr: Box<Expr<X>>,
1764 /// Optional format for this syntax.
1765 pub format: Option<JsonFormat>,
1766 /// Source location and node identity.
1767 pub meta: Meta,
1768}
1769
1770#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1771#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1772#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1773/// An SQL json returning.
1774pub struct JsonReturning<X: Extension = NoExt> {
1775 /// Data type named by this syntax.
1776 pub data_type: Box<DataType<X>>,
1777 /// Optional format for this syntax.
1778 pub format: Option<JsonFormat>,
1779 /// Source location and node identity.
1780 pub meta: Meta,
1781}
1782
1783/// One SQL/JSON `PASSING` binding: `<value> [FORMAT JSON] AS <name>`.
1784///
1785/// The `FORMAT` rides the [`JsonValueExpr`] value; the name is a `ColLabel`
1786/// (interns any quote style).
1787#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1788#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1789#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1790pub struct JsonPassingArg<X: Extension = NoExt> {
1791 /// Value supplied by this syntax.
1792 pub value: JsonValueExpr<X>,
1793 /// Name referenced by this syntax.
1794 pub name: Ident,
1795 /// Source location and node identity.
1796 pub meta: Meta,
1797}
1798
1799/// A SQL/JSON `ON EMPTY` / `ON ERROR` behaviour handler (PostgreSQL's
1800/// `JsonBehavior`).
1801///
1802/// One shared grammar backs every slot: PostgreSQL accepts any behaviour in any
1803/// `ON EMPTY`/`ON ERROR` position at raw parse (the per-function legality — e.g.
1804/// `JSON_VALUE` cannot yield `EMPTY ARRAY` — is a parse-*analysis* check, not a
1805/// syntax rule), so the [`JsonBehaviorKind`] set is not restricted per function.
1806/// `default_expr` is `Some` exactly when `kind` is [`Default`](JsonBehaviorKind::Default).
1807#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1808#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1809#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1810pub struct JsonBehavior<X: Extension = NoExt> {
1811 /// Which behaviour applies (`NULL`/`ERROR`/`DEFAULT`/…); see [`JsonBehaviorKind`].
1812 pub kind: JsonBehaviorKind,
1813 /// Optional default expr for this syntax.
1814 pub default_expr: Option<Box<Expr<X>>>,
1815 /// Source location and node identity.
1816 pub meta: Meta,
1817}
1818
1819#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1820#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1821#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1822/// The SQL json behavior kind forms represented by the AST.
1823pub enum JsonBehaviorKind {
1824 /// `ERROR` — raise an error.
1825 Error,
1826 /// `NULL` — yield SQL null.
1827 Null,
1828 /// `TRUE` — yield `TRUE` (`JSON_EXISTS` only).
1829 True,
1830 /// `FALSE` — yield `FALSE` (`JSON_EXISTS` only).
1831 False,
1832 /// `UNKNOWN` — yield unknown (`JSON_EXISTS` only).
1833 Unknown,
1834 /// `EMPTY` — PostgreSQL's shorthand for `EMPTY ARRAY`; kept distinct so it
1835 /// round-trips to the bare spelling.
1836 Empty,
1837 /// `EMPTY ARRAY` — yield an empty JSON array.
1838 EmptyArray,
1839 /// `EMPTY OBJECT` — yield an empty JSON object.
1840 EmptyObject,
1841 /// `DEFAULT <expr>` — the fallback value carried in
1842 /// [`JsonBehavior::default_expr`].
1843 Default,
1844}
1845
1846/// The SQL/JSON `WRAPPER` behaviour of `JSON_QUERY` (SQL:2016).
1847///
1848/// The optional `ARRAY` keyword and the `UNCONDITIONAL` default are semantically
1849/// inert (PostgreSQL normalizes them away), so this closed enum folds
1850/// `WITH [UNCONDITIONAL] [ARRAY] WRAPPER` onto [`Unconditional`](Self::Unconditional)
1851/// and `WITHOUT [ARRAY] WRAPPER` onto [`Without`](Self::Without) — the render
1852/// re-parses to the same value.
1853#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1854#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1855#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1856pub enum JsonWrapperBehavior {
1857 /// No wrapper clause written.
1858 Unspecified,
1859 /// `WITHOUT [ARRAY] WRAPPER`.
1860 Without,
1861 /// `WITH [UNCONDITIONAL] [ARRAY] WRAPPER`.
1862 Unconditional,
1863 /// `WITH CONDITIONAL [ARRAY] WRAPPER`.
1864 Conditional,
1865}
1866
1867/// The SQL/JSON `QUOTES` behaviour of `JSON_QUERY` (SQL:2016).
1868///
1869/// The `ON SCALAR STRING` tail is semantically inert (PostgreSQL normalizes it
1870/// away), so it is not preserved.
1871#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1872#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1873#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1874pub enum JsonQuotesBehavior {
1875 /// No quotes clause written.
1876 Unspecified,
1877 /// `KEEP QUOTES [ON SCALAR STRING]`.
1878 Keep,
1879 /// `OMIT QUOTES [ON SCALAR STRING]`.
1880 Omit,
1881}
1882
1883/// Which SQL/JSON query function a [`JsonFuncExpr`] is.
1884#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1885#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1886#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1887pub enum JsonFuncKind {
1888 /// `JSON_VALUE` — extract a scalar SQL value at the path.
1889 Value,
1890 /// `JSON_QUERY` — extract a JSON fragment at the path.
1891 Query,
1892 /// `JSON_EXISTS` — test whether the path matches.
1893 Exists,
1894}
1895
1896/// A SQL/JSON query function — `JSON_VALUE` / `JSON_QUERY` / `JSON_EXISTS`
1897/// (SQL:2016; PostgreSQL's one `JsonFuncExpr` node with an `op` tag).
1898///
1899/// One canonical shape with a [`JsonFuncKind`] tag covers all three, mirroring the
1900/// engine. The three differ in which trailing clauses their grammar admits — only
1901/// `JSON_QUERY` takes `wrapper`/`quotes`; `JSON_EXISTS` takes neither `returning`
1902/// nor `on_empty`; only `JSON_QUERY`/`JSON_VALUE` take `on_empty` — and the parser
1903/// enforces those restrictions, so an illegal field stays `None`/`Unspecified`.
1904#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1905#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1906#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1907pub struct JsonFuncExpr<X: Extension = NoExt> {
1908 /// Which function this is (`JSON_VALUE`/`JSON_QUERY`/`JSON_EXISTS`); see [`JsonFuncKind`].
1909 pub kind: JsonFuncKind,
1910 /// The JSON value the path is applied to.
1911 pub context: JsonValueExpr<X>,
1912 /// The SQL/JSON path expression.
1913 pub path: Box<Expr<X>>,
1914 /// The `PASSING` argument bindings, in source order.
1915 pub passing: ThinVec<JsonPassingArg<X>>,
1916 /// The optional `RETURNING <type>` clause; see [`JsonReturning`].
1917 pub returning: Option<JsonReturning<X>>,
1918 /// The `WITH`/`WITHOUT WRAPPER` behaviour; see [`JsonWrapperBehavior`].
1919 pub wrapper: JsonWrapperBehavior,
1920 /// The `KEEP`/`OMIT QUOTES` behaviour; see [`JsonQuotesBehavior`].
1921 pub quotes: JsonQuotesBehavior,
1922 /// Optional on empty for this syntax.
1923 pub on_empty: Option<JsonBehavior<X>>,
1924 /// Optional on error for this syntax.
1925 pub on_error: Option<JsonBehavior<X>>,
1926 /// Source location and node identity.
1927 pub meta: Meta,
1928}
1929
1930/// Whether a SQL/JSON object member was spelled `key : value` or `key VALUE value`.
1931///
1932/// The optional leading `KEY` keyword is inert (PostgreSQL normalizes it away) and
1933/// is not preserved.
1934#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1935#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1936#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1937pub enum JsonKeyValueSpelling {
1938 /// `key : value`.
1939 Colon,
1940 /// `key VALUE value`.
1941 Value,
1942}
1943
1944/// One SQL/JSON object member: `[KEY] <key> {: | VALUE} <value> [FORMAT JSON]`.
1945#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1946#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1947#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1948pub struct JsonKeyValue<X: Extension = NoExt> {
1949 /// The member key expression.
1950 pub key: Box<Expr<X>>,
1951 /// Value supplied by this syntax.
1952 pub value: JsonValueExpr<X>,
1953 /// Exact source spelling retained for faithful rendering.
1954 pub spelling: JsonKeyValueSpelling,
1955 /// Source location and node identity.
1956 pub meta: Meta,
1957}
1958
1959/// The SQL/JSON null-handling clause of a constructor: `ABSENT ON NULL` (drop null
1960/// entries) or `NULL ON NULL` (keep them). `None` records that no clause was written
1961/// — the two constructors default oppositely (`JSON_OBJECT` keeps, `JSON_ARRAY`
1962/// drops), so the render must not synthesize the absent clause.
1963#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1964#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1965#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1966pub enum JsonNullClause {
1967 /// `ABSENT ON NULL` — drop members/elements whose value is null.
1968 AbsentOnNull,
1969 /// `NULL ON NULL` — keep members/elements whose value is null.
1970 NullOnNull,
1971}
1972
1973/// A SQL/JSON object constructor: `JSON_OBJECT([members] [null] [unique]
1974/// [RETURNING …])` (SQL:2016).
1975///
1976/// `entries` may be empty (`JSON_OBJECT()` / `JSON_OBJECT(RETURNING …)`).
1977/// `unique_keys` is `Some(true)` for `WITH UNIQUE [KEYS]`, `Some(false)` for
1978/// `WITHOUT UNIQUE [KEYS]`, `None` when unwritten (the inert `KEYS` word is not
1979/// preserved). This is the standard constructor only; the legacy
1980/// `json_object(text[])` function keeps the ordinary [`Expr::Function`] shape.
1981#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1982#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
1983#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
1984pub struct JsonObjectExpr<X: Extension = NoExt> {
1985 /// entries in source order.
1986 pub entries: ThinVec<JsonKeyValue<X>>,
1987 /// Optional null clause for this syntax.
1988 pub null_clause: Option<JsonNullClause>,
1989 /// Whether the unique keys form was present in the source.
1990 pub unique_keys: Option<bool>,
1991 /// The optional `RETURNING <type>` clause; see [`JsonReturning`].
1992 pub returning: Option<JsonReturning<X>>,
1993 /// Source location and node identity.
1994 pub meta: Meta,
1995}
1996
1997/// The body of a [`JsonArrayExpr`] — a value list or a subquery, PostgreSQL's two
1998/// distinct `JSON_ARRAY` productions.
1999#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2000#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2001#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2002pub enum JsonArrayBody<X: Extension = NoExt> {
2003 /// `JSON_ARRAY(v, … [null])` — a (possibly empty) value list with an optional
2004 /// null-handling clause.
2005 Values {
2006 /// Child items in source order.
2007 items: ThinVec<JsonValueExpr<X>>,
2008 /// Optional null clause for this syntax.
2009 null_clause: Option<JsonNullClause>,
2010 /// Source location and node identity.
2011 meta: Meta,
2012 },
2013 /// `JSON_ARRAY(<query> [FORMAT JSON])` — a subquery whose rows become elements.
2014 Query {
2015 /// Query governed by this node.
2016 query: Box<Query<X>>,
2017 /// Optional format for this syntax.
2018 format: Option<JsonFormat>,
2019 /// Source location and node identity.
2020 meta: Meta,
2021 },
2022}
2023
2024/// A SQL/JSON array constructor: `JSON_ARRAY(<body> [RETURNING …])` (SQL:2016).
2025#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2026#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2027#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2028pub struct JsonArrayExpr<X: Extension = NoExt> {
2029 /// Statement or query body governed by this node.
2030 pub body: JsonArrayBody<X>,
2031 /// The optional `RETURNING <type>` clause; see [`JsonReturning`].
2032 pub returning: Option<JsonReturning<X>>,
2033 /// Source location and node identity.
2034 pub meta: Meta,
2035}
2036
2037/// The body of a [`JsonAggregateExpr`] — the object or array aggregate shape.
2038#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2039#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2040#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2041pub enum JsonAggregateBody<X: Extension = NoExt> {
2042 /// `JSON_OBJECTAGG(k {: | VALUE} v [unique])` — one member, no `ORDER BY`.
2043 Object {
2044 /// The single key/value member; see [`JsonKeyValue`].
2045 entry: JsonKeyValue<X>,
2046 /// Whether the unique keys form was present in the source.
2047 unique_keys: Option<bool>,
2048 /// Source location and node identity.
2049 meta: Meta,
2050 },
2051 /// `JSON_ARRAYAGG(v [ORDER BY …])` — one value with an optional sort.
2052 Array {
2053 /// Value supplied by this syntax.
2054 value: JsonValueExpr<X>,
2055 /// Ordering terms in source order.
2056 order_by: ThinVec<OrderByExpr<X>>,
2057 /// Source location and node identity.
2058 meta: Meta,
2059 },
2060}
2061
2062/// A SQL/JSON aggregate constructor — `JSON_OBJECTAGG` / `JSON_ARRAYAGG`
2063/// (SQL:2016). Shares the ordinary-aggregate `FILTER (WHERE …)` / `OVER (…)` tail.
2064#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2065#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2066#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2067pub struct JsonAggregateExpr<X: Extension = NoExt> {
2068 /// The object or array aggregate body; see [`JsonAggregateBody`].
2069 pub body: JsonAggregateBody<X>,
2070 /// Optional null clause for this syntax.
2071 pub null_clause: Option<JsonNullClause>,
2072 /// The optional `RETURNING <type>` clause; see [`JsonReturning`].
2073 pub returning: Option<JsonReturning<X>>,
2074 /// Optional filter for this syntax.
2075 pub filter: Option<Box<Expr<X>>>,
2076 /// Optional over for this syntax.
2077 pub over: Option<Box<WindowSpec<X>>>,
2078 /// Source location and node identity.
2079 pub meta: Meta,
2080}
2081
2082/// Which bare SQL/JSON constructor a [`JsonConstructorExpr`] is.
2083#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2084#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2085#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2086pub enum JsonConstructorKind {
2087 /// `JSON(<value> [WITH|WITHOUT UNIQUE [KEYS]])`.
2088 Json,
2089 /// `JSON_SCALAR(<expr>)` — a plain argument, no `FORMAT`/`RETURNING`/`UNIQUE`.
2090 Scalar,
2091 /// `JSON_SERIALIZE(<value> [RETURNING <type> [FORMAT JSON]])`.
2092 Serialize,
2093}
2094
2095/// A bare SQL/JSON constructor — `JSON(x)` / `JSON_SCALAR(x)` / `JSON_SERIALIZE(x)`
2096/// (SQL:2016). The unused fields per kind stay `None` (the parser admits only each
2097/// kind's grammar): `unique_keys` is `JSON`-only, `returning` is `JSON_SERIALIZE`-only,
2098/// and `JSON_SCALAR`'s value never carries a `FORMAT`.
2099#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2100#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2101#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2102pub struct JsonConstructorExpr<X: Extension = NoExt> {
2103 /// Which constructor this is (`JSON`/`JSON_SCALAR`/`JSON_SERIALIZE`); see [`JsonConstructorKind`].
2104 pub kind: JsonConstructorKind,
2105 /// Value supplied by this syntax.
2106 pub value: JsonValueExpr<X>,
2107 /// Whether the unique keys form was present in the source.
2108 pub unique_keys: Option<bool>,
2109 /// The optional `RETURNING <type>` clause; see [`JsonReturning`].
2110 pub returning: Option<JsonReturning<X>>,
2111 /// Source location and node identity.
2112 pub meta: Meta,
2113}
2114
2115/// The type constraint of an `IS JSON` predicate: `IS JSON [VALUE|ARRAY|OBJECT|SCALAR]`.
2116#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2117#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2118#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2119pub enum JsonItemType {
2120 /// Bare `IS JSON` — any JSON type.
2121 Any,
2122 /// `IS JSON VALUE` — any JSON scalar, array, or object.
2123 Value,
2124 /// `IS JSON ARRAY` — a JSON array.
2125 Array,
2126 /// `IS JSON OBJECT` — a JSON object.
2127 Object,
2128 /// `IS JSON SCALAR` — a JSON scalar (not an array or object).
2129 Scalar,
2130}
2131
2132/// The SQL/JSON `<expr> IS [NOT] JSON [type] [WITH|WITHOUT UNIQUE [KEYS]]` predicate
2133/// (SQL:2016; PostgreSQL's `JsonIsPredicate`).
2134///
2135/// Binds at `IS`-predicate precedence like the other `IS` tests. `unique_keys`
2136/// records `WITH UNIQUE [KEYS]` (the inert `KEYS` word and the default `WITHOUT`
2137/// spelling are not preserved).
2138#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2139#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2140#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2141pub struct IsJsonExpr<X: Extension = NoExt> {
2142 /// Expression evaluated by this syntax.
2143 pub expr: Box<Expr<X>>,
2144 /// Whether the negated form was present in the source.
2145 pub negated: bool,
2146 /// The asserted JSON type (`VALUE`/`ARRAY`/`OBJECT`/`SCALAR`/any); see [`JsonItemType`].
2147 pub item_type: JsonItemType,
2148 /// Whether the unique keys form was present in the source.
2149 pub unique_keys: bool,
2150 /// Source location and node identity.
2151 pub meta: Meta,
2152}
2153
2154/// A SQL/XML expression function (SQL:2006; PostgreSQL `func_expr_common_subexpr`).
2155///
2156/// One kind-tagged enum for the eight special forms PostgreSQL lowers to `XmlExpr`
2157/// (and `XmlSerialize`): each differs in the clause grammar inside its parens, so a
2158/// per-form variant carries exactly that form's fields (the aggregate `xmlagg` is an
2159/// *ordinary* aggregate, not a keyword special form, so it is not here). The
2160/// contextual keywords each form opens with — `NAME`, `DOCUMENT`/`CONTENT`,
2161/// `VERSION`, `STANDALONE`, `PASSING`, `INDENT`, `WHITESPACE` — stay unreserved
2162/// (usable as ordinary names elsewhere); they are consumed only inside these parens.
2163#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2164#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2165#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2166pub enum XmlFunc<X: Extension = NoExt> {
2167 /// `xmlelement(NAME <name> [, xmlattributes(<attr>, …)] [, <content>, …])`.
2168 /// The `xmlattributes(…)` list, when present, precedes the content list (PostgreSQL
2169 /// rejects content before it); either list may be empty.
2170 Element {
2171 /// Name referenced by this syntax.
2172 name: Ident,
2173 /// attributes in source order.
2174 attributes: ThinVec<XmlAttribute<X>>,
2175 /// content in source order.
2176 content: ThinVec<Expr<X>>,
2177 /// Source location and node identity.
2178 meta: Meta,
2179 },
2180 /// `xmlforest(<value> [AS <name>], …)` — a non-empty list of the same
2181 /// `<value> [AS <name>]` element shape as an `xmlelement` attribute (reusing
2182 /// [`XmlAttribute`]).
2183 Forest {
2184 /// elements in source order.
2185 elements: ThinVec<XmlAttribute<X>>,
2186 /// Source location and node identity.
2187 meta: Meta,
2188 },
2189 /// `xmlconcat(<value>, …)` — a non-empty ordinary expression list.
2190 Concat {
2191 /// Arguments in source order.
2192 args: ThinVec<Expr<X>>,
2193 /// Source location and node identity.
2194 meta: Meta,
2195 },
2196 /// `xmlparse({DOCUMENT | CONTENT} <value> [{PRESERVE | STRIP} WHITESPACE])`.
2197 Parse {
2198 /// Whether the input is a `DOCUMENT` or a `CONTENT` fragment; see [`XmlDocumentOrContent`].
2199 option: XmlDocumentOrContent,
2200 /// The XML value to parse.
2201 arg: Box<Expr<X>>,
2202 /// The `PRESERVE`/`STRIP WHITESPACE` handling; see [`XmlWhitespaceOption`].
2203 whitespace: XmlWhitespaceOption,
2204 /// Source location and node identity.
2205 meta: Meta,
2206 },
2207 /// `xmlpi(NAME <name> [, <content>])` — a single optional content expression.
2208 Pi {
2209 /// Name referenced by this syntax.
2210 name: Ident,
2211 /// Optional content for this syntax.
2212 content: Option<Box<Expr<X>>>,
2213 /// Source location and node identity.
2214 meta: Meta,
2215 },
2216 /// `xmlroot(<value>, VERSION {<expr> | NO VALUE} [, STANDALONE {YES | NO | NO VALUE}])`.
2217 /// The `VERSION` clause is mandatory: `version` is `None` exactly for `NO VALUE`
2218 /// (an unwritten clause is not representable, matching PostgreSQL's grammar).
2219 Root {
2220 /// The XML value to modify.
2221 arg: Box<Expr<X>>,
2222 /// Optional version for this syntax.
2223 version: Option<Box<Expr<X>>>,
2224 /// The `STANDALONE {YES | NO | NO VALUE}` clause; see [`XmlStandalone`].
2225 standalone: XmlStandalone,
2226 /// Source location and node identity.
2227 meta: Meta,
2228 },
2229 /// `xmlserialize({DOCUMENT | CONTENT} <value> AS <type> [[NO] INDENT])`.
2230 Serialize {
2231 /// Whether the input is a `DOCUMENT` or a `CONTENT` fragment; see [`XmlDocumentOrContent`].
2232 option: XmlDocumentOrContent,
2233 /// The XML value to serialize.
2234 arg: Box<Expr<X>>,
2235 /// Data type named by this syntax.
2236 data_type: Box<DataType<X>>,
2237 /// The `[NO] INDENT` option; see [`XmlIndentOption`].
2238 indent: XmlIndentOption,
2239 /// Source location and node identity.
2240 meta: Meta,
2241 },
2242 /// `xmlexists(<path> PASSING [BY {REF | VALUE}] <doc> [BY {REF | VALUE}])`.
2243 /// The passing mechanism is admitted on either side of the document argument
2244 /// (PostgreSQL's `xmlexists_argument`); each side round-trips independently.
2245 Exists {
2246 /// The XPath expression to evaluate.
2247 path: Box<Expr<X>>,
2248 /// Optional mechanism before for this syntax.
2249 mechanism_before: Option<XmlPassingMechanism>,
2250 /// The XML document the path is tested against.
2251 arg: Box<Expr<X>>,
2252 /// Optional mechanism after for this syntax.
2253 mechanism_after: Option<XmlPassingMechanism>,
2254 /// Source location and node identity.
2255 meta: Meta,
2256 },
2257}
2258
2259/// One `<value> [AS <name>]` element of an `xmlelement` attribute list or an
2260/// `xmlforest` list. The `AS <name>` label is a `ColLabel` (any keyword admitted);
2261/// `None` when the element is a bare value (PostgreSQL derives the tag at analysis).
2262#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2263#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2264#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2265pub struct XmlAttribute<X: Extension = NoExt> {
2266 /// Value supplied by this syntax.
2267 pub value: Box<Expr<X>>,
2268 /// Name referenced by this syntax.
2269 pub name: Option<Ident>,
2270 /// Source location and node identity.
2271 pub meta: Meta,
2272}
2273
2274/// The `DOCUMENT` / `CONTENT` mode word of `xmlparse` / `xmlserialize`.
2275#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2276#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2277#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2278pub enum XmlDocumentOrContent {
2279 /// `DOCUMENT` — the input is a single well-formed XML document.
2280 Document,
2281 /// `CONTENT` — the input is an XML content fragment.
2282 Content,
2283}
2284
2285/// The optional whitespace-handling clause of `xmlparse`.
2286#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2287#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2288#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2289pub enum XmlWhitespaceOption {
2290 /// No clause written.
2291 Unspecified,
2292 /// `PRESERVE WHITESPACE`.
2293 Preserve,
2294 /// `STRIP WHITESPACE`.
2295 Strip,
2296}
2297
2298/// The optional indentation clause of `xmlserialize`.
2299#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2300#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2301#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2302pub enum XmlIndentOption {
2303 /// No clause written.
2304 Unspecified,
2305 /// `INDENT`.
2306 Indent,
2307 /// `NO INDENT`.
2308 NoIndent,
2309}
2310
2311/// The optional `STANDALONE` clause value of `xmlroot`.
2312#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2313#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2314#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2315pub enum XmlStandalone {
2316 /// No `STANDALONE` clause written.
2317 Unspecified,
2318 /// `STANDALONE YES`.
2319 Yes,
2320 /// `STANDALONE NO`.
2321 No,
2322 /// `STANDALONE NO VALUE`.
2323 NoValue,
2324}
2325
2326/// The `BY REF` / `BY VALUE` passing mechanism of `xmlexists`. Both spellings are
2327/// admitted at parse (PostgreSQL treats `BY REF` as the default and rejects `BY
2328/// VALUE` only later), so the tag round-trips the exact source word.
2329#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2330#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2331#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2332pub enum XmlPassingMechanism {
2333 /// `BY REF` — pass the XML by reference (PostgreSQL's default).
2334 ByRef,
2335 /// `BY VALUE` — pass the XML by value.
2336 ByValue,
2337}
2338
2339/// A standard-SQL string special form (SQL-92 E021-06/-09/-11 + SQL:1999 T312;
2340/// PostgreSQL's `func_expr_common_subexpr` string productions).
2341///
2342/// One kind-tagged enum for the keyword-argument string functions: each variant
2343/// carries exactly its form's typed fields, and every operand keyword (`FROM`,
2344/// `FOR`, `SIMILAR`, `ESCAPE`, `PLACING`, `IN`, `LEADING`/`TRAILING`/`BOTH`) is
2345/// grammar, not data. The comma plain-call spellings (`substring(x, 1, 2)`,
2346/// `trim(x, y)`, `overlay(a, b, c)`) are *not* here — they stay ordinary
2347/// [`FunctionCall`]s, so the plain-call surface every engine also accepts is
2348/// unaffected by the special forms.
2349#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2350#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2351#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2352pub enum StringFunc<X: Extension = NoExt> {
2353 /// `SUBSTRING(<expr> FROM <start> [FOR <count>])` and its variants: PostgreSQL
2354 /// admits `FOR <count>` alone and the reversed `FOR <count> FROM <start>`
2355 /// spelling (both orders fold onto the same fields and render canonically
2356 /// `FROM`-first), so at least one of `start`/`count` is always present. The
2357 /// string-pattern form `SUBSTRING(x FROM 'pat')`/`… FOR '#'` is this same
2358 /// production (the regex reading is runtime semantics, not grammar).
2359 Substring {
2360 /// Expression evaluated by this syntax.
2361 expr: Box<Expr<X>>,
2362 /// The `FROM <start>` operand, `None` for the `FOR`-only form.
2363 start: Option<Box<Expr<X>>>,
2364 /// The `FOR <count>` operand, `None` for the `FROM`-only form.
2365 count: Option<Box<Expr<X>>>,
2366 /// Source location and node identity.
2367 meta: Meta,
2368 },
2369 /// PostgreSQL's `SUBSTRING(<expr> SIMILAR <pattern> ESCAPE <escape>)` regex
2370 /// form (SQL:1999 `<regular expression substring function>`). All three
2371 /// operands are mandatory (`SUBSTRING(x SIMILAR p)` without `ESCAPE` rejects,
2372 /// engine-verified).
2373 SubstringSimilar {
2374 /// Expression evaluated by this syntax.
2375 expr: Box<Expr<X>>,
2376 /// The SQL-regex pattern.
2377 pattern: Box<Expr<X>>,
2378 /// The escape-character expression.
2379 escape: Box<Expr<X>>,
2380 /// Source location and node identity.
2381 meta: Meta,
2382 },
2383 /// `POSITION(<substr> IN <string>)` (SQL-92 E021-11). The operands are the
2384 /// restricted `b_expr` in PostgreSQL/DuckDB (`POSITION(1 IN 2 OR 3)` rejects)
2385 /// and MySQL's asymmetric `bit_expr IN expr` under
2386 /// [`StringFuncForms::position_asymmetric_operands`](crate::dialect::CallSyntax).
2387 /// There is no plain-call spelling: every keyword-form engine parse-rejects
2388 /// `position(a, b)`.
2389 Position {
2390 /// The substring to search for.
2391 substr: Box<Expr<X>>,
2392 /// The string searched within.
2393 string: Box<Expr<X>>,
2394 /// Source location and node identity.
2395 meta: Meta,
2396 },
2397 /// `OVERLAY(<target> PLACING <replacement> FROM <start> [FOR <count>])`
2398 /// (SQL:1999 T312). `FROM <start>` is mandatory — `OVERLAY(x PLACING y)` and
2399 /// the `FOR`-without-`FROM` form parse-reject on every keyword-form engine.
2400 Overlay {
2401 /// Object targeted by this syntax.
2402 target: Box<Expr<X>>,
2403 /// The replacement string spliced in.
2404 replacement: Box<Expr<X>>,
2405 /// The 1-based start position.
2406 start: Box<Expr<X>>,
2407 /// Optional count for this syntax.
2408 count: Option<Box<Expr<X>>>,
2409 /// Source location and node identity.
2410 meta: Meta,
2411 },
2412 /// `TRIM([{BOTH | LEADING | TRAILING}] [<chars>] FROM <sources>…)` (SQL-92
2413 /// E021-09) plus PostgreSQL's loose `trim_list` tails under
2414 /// [`StringFuncForms::trim_list_syntax`](crate::dialect::CallSyntax): a bare
2415 /// `FROM <list>`, a side without `FROM` (`TRIM(TRAILING ' foo ')`), and a
2416 /// multi-expression list (`TRIM('a' FROM 'b', 'c')`). At least one of
2417 /// `side`/`from` is present — a bare `TRIM(x)`/`TRIM(x, y)` is an ordinary
2418 /// call, never this node.
2419 Trim {
2420 /// The written `BOTH`/`LEADING`/`TRAILING` side, `None` when omitted.
2421 side: Option<TrimSide>,
2422 /// The trim-character expression written before `FROM`; `None` for the
2423 /// bare-`FROM` and side-without-`FROM` forms.
2424 trim_chars: Option<Box<Expr<X>>>,
2425 /// Whether `FROM` was written (distinguishes `TRIM(TRAILING ' foo ')`
2426 /// from `TRIM(TRAILING FROM ' foo ')` — both are valid PostgreSQL with
2427 /// different meanings, so the bit is load-bearing for round-trips).
2428 from: bool,
2429 /// The source expression list after `FROM` (or the bare list when a side
2430 /// is written without `FROM`). PostgreSQL's `trim_list` is an `expr_list`,
2431 /// so more than one source parses there; the restricted dialects hold this
2432 /// to exactly one at parse.
2433 sources: ThinVec<Expr<X>>,
2434 /// Source location and node identity.
2435 meta: Meta,
2436 },
2437 /// PostgreSQL's `COLLATION FOR (<expr>)` — the common-subexpr that reports the
2438 /// collation name derived for its operand. PostgreSQL gives it a dedicated
2439 /// `COLLATION FOR '(' a_expr ')'` production that lowers to a
2440 /// `pg_catalog.pg_collation_for(<expr>)` call, but the surface keyword form is
2441 /// kept here (not folded to a [`FunctionCall`]) so it round-trips as written. The
2442 /// parentheses and single `a_expr` operand are mandatory — `COLLATION FOR 'x'`,
2443 /// `COLLATION FOR ()`, and a two-argument list all parse-reject (engine-verified).
2444 CollationFor {
2445 /// Expression evaluated by this syntax.
2446 expr: Box<Expr<X>>,
2447 /// Source location and node identity.
2448 meta: Meta,
2449 },
2450 /// MySQL's `CONVERT(<expr> USING <charset>)` transcoding form — reinterprets its
2451 /// string operand in another character set (the grammar's
2452 /// `CONVERT '(' expr USING charset_name ')'`). Distinct from the comma-form cast
2453 /// [`CastSyntax::Convert`]: this changes the charset, not the type, so it is a string
2454 /// special form rather than a cast. The operand is a full `a_expr`
2455 /// (`CONVERT(1+2 USING utf8mb4)` parses, engine-verified); `charset` is a MySQL
2456 /// `charset_name` — an `ident_or_text` (a bare or backtick identifier, or a quoted
2457 /// string, round-tripping by the [`Ident`]'s quote style) or the `BINARY` transcoding
2458 /// name (`CONVERT(x USING binary)`), which reaches here as a bare [`Ident`]. Recognized
2459 /// only under [`CallSyntax::convert_function`](crate::dialect::CallSyntax); MySQL-only.
2460 ConvertUsing {
2461 /// Expression evaluated by this syntax.
2462 expr: Box<Expr<X>>,
2463 /// The target character set name.
2464 charset: Ident,
2465 /// Source location and node identity.
2466 meta: Meta,
2467 },
2468 /// MySQL's full-text search `MATCH (<col>, …) AGAINST (<expr> [<modifier>])`
2469 /// (`simple_expr: MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')'`).
2470 /// The `columns` are a comma list of column references (bare or 1–3-part dotted
2471 /// [`Expr::Column`]s — an arbitrary expression, literal, function call, or empty
2472 /// list all parse-reject, engine-verified); `against` is a MySQL `bit_expr` (below
2473 /// the comparison level, so a trailing `IN`/`WITH` opens the modifier rather than an
2474 /// `IN` predicate). The optional [`MatchSearchModifier`] is exactly one of the four
2475 /// documented combinations; `None` is the default (no modifier words) and round-trips
2476 /// as written rather than as an explicit `IN NATURAL LANGUAGE MODE`. Recognized only
2477 /// under [`StringFuncForms::match_against`](crate::dialect::CallSyntax); MySQL-only, and
2478 /// distinct from SQLite's infix `<expr> MATCH <expr>` operator. Semantic constraints
2479 /// (a full-text index must cover the columns, the operand must be constant) are a
2480 /// server binding concern, not grammar.
2481 MatchAgainst {
2482 /// Columns in source order.
2483 columns: ThinVec<Expr<X>>,
2484 /// The full-text search expression.
2485 against: Box<Expr<X>>,
2486 /// Optional modifier for this syntax.
2487 modifier: Option<MatchSearchModifier>,
2488 /// Source location and node identity.
2489 meta: Meta,
2490 },
2491 /// `CEIL(<expr> TO <field>)` / `CEILING(<expr> TO <field>)` — a rounding-field
2492 /// keyword form distinct from the ordinary `CEIL(<expr>)` call and the comma-form
2493 /// scale spelling `CEIL(<expr>, <scale>)` (which stays an ordinary [`FunctionCall`]:
2494 /// no probed oracle grammar admits the `TO` tail, engine-verified against pg_query,
2495 /// DuckDB, and mysql:8.4). The field (`DAY`, `HOUR`, …) is stored as written and
2496 /// validated, if at all, by the consuming engine at analysis time, not parse.
2497 /// Recognized only under
2498 /// [`StringFuncForms::ceil_to_field`](crate::dialect::StringFuncForms::ceil_to_field).
2499 CeilTo {
2500 /// Expression evaluated by this syntax.
2501 expr: Box<Expr<X>>,
2502 /// The rounding field (`DAY`, `HOUR`, …).
2503 field: Ident,
2504 /// Exact source spelling retained for faithful rendering.
2505 spelling: CeilSpelling,
2506 /// Source location and node identity.
2507 meta: Meta,
2508 },
2509 /// `FLOOR(<expr> TO <field>)` — a rounding-field keyword form distinct from the
2510 /// ordinary `FLOOR(<expr>)` call and the comma-form scale spelling
2511 /// `FLOOR(<expr>, <scale>)` (which stays an ordinary [`FunctionCall`]: no probed
2512 /// oracle grammar admits the `TO` tail, engine-verified against pg_query, DuckDB, and
2513 /// mysql:8.4). Unlike [`StringFunc::CeilTo`], `FLOOR` has no `FLOORING` synonym, so
2514 /// there is no spelling field to track. The field (`DAY`, `HOUR`, …) is stored as
2515 /// written and validated, if at all, by the consuming engine at analysis time, not
2516 /// parse. Recognized only under
2517 /// [`StringFuncForms::floor_to_field`](crate::dialect::StringFuncForms::floor_to_field).
2518 FloorTo {
2519 /// Expression evaluated by this syntax.
2520 expr: Box<Expr<X>>,
2521 /// The rounding field (`DAY`, `HOUR`, …).
2522 field: Ident,
2523 /// Source location and node identity.
2524 meta: Meta,
2525 },
2526}
2527
2528/// The optional search modifier of a MySQL [`StringFunc::MatchAgainst`] — one of the
2529/// four documented full-text combinations. `WITH QUERY EXPANSION` combines only with
2530/// the (implicit or explicit) natural-language mode; `IN BOOLEAN MODE WITH QUERY
2531/// EXPANSION` parse-rejects (engine-verified).
2532#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2533#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2534#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2535pub enum MatchSearchModifier {
2536 /// `IN NATURAL LANGUAGE MODE`.
2537 NaturalLanguage,
2538 /// `IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION`.
2539 NaturalLanguageQueryExpansion,
2540 /// `IN BOOLEAN MODE`.
2541 Boolean,
2542 /// `WITH QUERY EXPANSION`.
2543 QueryExpansion,
2544}
2545
2546/// The `BOTH` / `LEADING` / `TRAILING` side word of a [`StringFunc::Trim`].
2547#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2548#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2549#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2550pub enum TrimSide {
2551 /// `TRIM(BOTH …)` — trim the character from both ends.
2552 Both,
2553 /// `TRIM(LEADING …)` — trim from the start only.
2554 Leading,
2555 /// `TRIM(TRAILING …)` — trim from the end only.
2556 Trailing,
2557}
2558
2559/// Quantifier used by `op ANY/ALL/SOME (<query>)` predicates.
2560#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2561#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2562#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2563pub enum Quantifier {
2564 /// `ANY` — the predicate holds for at least one row/element.
2565 Any,
2566 /// `ALL` — the predicate holds for every row/element.
2567 All,
2568 /// `SOME` — standard synonym for `ANY`.
2569 Some,
2570}
2571
2572/// Closed operator keys for dialect binding-power tables.
2573#[derive(Clone, Debug, PartialEq, Eq, Hash)]
2574#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2575#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2576pub enum BinaryOperator {
2577 /// `+` — addition.
2578 Plus,
2579 /// `-` — subtraction.
2580 Minus,
2581 /// `*` — multiplication.
2582 Multiply,
2583 /// `/` — division.
2584 Divide,
2585 /// Modulo, spelled `%` everywhere and additionally `MOD` in MySQL. The two
2586 /// spellings are one operator; the [`ModuloSpelling`] tag records
2587 /// which the source used so it round-trips.
2588 Modulo(ModuloSpelling),
2589 /// Integer division — a distinct operator from `/` (it truncates to an integer), so
2590 /// it gets its own key rather than reusing [`Divide`](Self::Divide). Two
2591 /// dialect-disjoint spellings fold onto it: MySQL's `DIV` keyword and
2592 /// DuckDB's `//` symbol; the [`IntegerDivideSpelling`] tag records which the source
2593 /// used so it round-trips. Binds at multiplicative precedence.
2594 IntegerDivide(IntegerDivideSpelling),
2595 /// Arithmetic exponentiation, spelled `^`. A distinct operator from the
2596 /// [`BitwiseXor`](Self::BitwiseXor) `^` (a dialect gives the `^` lexeme one meaning or the
2597 /// other — engine truth): under
2598 /// [`CaretOperator::Exponent`](crate::dialect::CaretOperator)
2599 /// (PostgreSQL/DuckDB) `^` is arithmetic power,
2600 /// and binds at its OWN precedence tier — tighter than `*`/`/`/`%`
2601 /// ([`multiplicative`](crate::precedence::BindingPowerTable::multiplicative)) and looser
2602 /// than the unary sign, left-associative (`2 ^ 3 ^ 2` is `(2 ^ 3) ^ 2`, `2 ^ 3 * 2` is
2603 /// `(2 ^ 3) * 2` — engine-measured on pg_query). Its binding power is the dedicated
2604 /// [`exponent`](crate::precedence::BindingPowerTable::exponent) row, not the multiplicative
2605 /// rank the other arithmetic operators share.
2606 Exponent,
2607 /// `||` — string concatenation.
2608 StringConcat,
2609 /// PostgreSQL `@>` containment — "left contains right" over arrays, ranges, and
2610 /// `jsonb`. Binds at PostgreSQL's "any other operator" precedence (the rank shared
2611 /// with [`StringConcat`](Self::StringConcat)), left-associative.
2612 Contains,
2613 /// PostgreSQL `<@` containment — "left is contained by right", the mirror of
2614 /// [`Contains`](Self::Contains). Same "any other operator" precedence.
2615 ContainedBy,
2616 /// DuckDB `^@` — "left string starts with right string". Binds at the "any other
2617 /// operator" precedence. Gated by [`starts_with_operator`](crate::dialect::OperatorSyntax::starts_with_operator).
2618 StartsWith,
2619 /// The `&&` overlap operator — "do the two operands overlap?" over arrays, ranges
2620 /// (PostgreSQL), and geometries (DuckDB, whose `&&` is bounding-box overlap). The one
2621 /// operator key for the `&&` spelling across dialects that give it this meaning:
2622 /// DuckDB routes it here through [`DoubleAmpersand::Overlaps`], and PostgreSQL's
2623 /// range/array `&&` (deferred) would fold onto the same variant. Binds at the "any
2624 /// other operator" precedence (the [`Contains`](Self::Contains) rank), left-associative.
2625 ///
2626 /// Distinct from [`Overlaps`](Self::Overlaps), the SQL-standard `OVERLAPS` *keyword*
2627 /// period predicate over `(start, end)` rows — a different surface (keyword vs symbol),
2628 /// operand shape (two-element rows vs scalars), and render (`OVERLAPS` vs `&&`).
2629 ///
2630 /// [`DoubleAmpersand::Overlaps`]: crate::dialect::DoubleAmpersand::Overlaps
2631 Overlap,
2632 /// PostgreSQL `->` JSON access — object field / array element returned as
2633 /// `json`/`jsonb`. Same "any other operator" precedence.
2634 JsonGet,
2635 /// PostgreSQL `->>` JSON access — object field / array element returned as `text`,
2636 /// the text-typed form of [`JsonGet`](Self::JsonGet). Same precedence.
2637 JsonGetText,
2638 /// PostgreSQL `?` `jsonb` key/element existence — "does the right text string exist as
2639 /// a top-level key (object) or array element (array) of the left `jsonb`?". Binds at
2640 /// PostgreSQL's "any other operator" precedence (the [`Contains`](Self::Contains) rank),
2641 /// left-associative. Lexed only under [`OperatorSyntax::jsonb_operators`]; the `?` byte
2642 /// is otherwise a stray byte in PostgreSQL (it has no `?` parameter) or the anonymous
2643 /// placeholder elsewhere.
2644 ///
2645 /// [`OperatorSyntax::jsonb_operators`]: crate::dialect::OperatorSyntax::jsonb_operators
2646 JsonExists,
2647 /// PostgreSQL `?|` `jsonb` any-key existence — "does any of the right `text[]` strings
2648 /// exist as a top-level key/element of the left `jsonb`?". Same "any other operator"
2649 /// precedence as [`JsonExists`](Self::JsonExists).
2650 JsonExistsAny,
2651 /// PostgreSQL `?&` `jsonb` all-keys existence — "do all of the right `text[]` strings
2652 /// exist as top-level keys/elements of the left `jsonb`?". Same precedence.
2653 JsonExistsAll,
2654 /// PostgreSQL `@?` — "does the right `jsonpath` return any item for the left `jsonb`?".
2655 /// Same "any other operator" precedence.
2656 JsonPathExists,
2657 /// PostgreSQL `@@` — the match operator: for `jsonb @@ jsonpath` it returns the result
2658 /// of the JSON-path predicate check, and it is also the `tsvector @@ tsquery` full-text
2659 /// search match. One operator key for the shared `@@` spelling; same "any other operator"
2660 /// precedence.
2661 JsonPathMatch,
2662 /// PostgreSQL `#>` — extract the `jsonb` sub-object at the right `text[]` path, returned
2663 /// as `jsonb`. Same "any other operator" precedence.
2664 JsonExtractPath,
2665 /// PostgreSQL `#>>` — extract the `jsonb` sub-object at the right `text[]` path, returned
2666 /// as `text`, the text-typed form of [`JsonExtractPath`](Self::JsonExtractPath). Same
2667 /// precedence.
2668 JsonExtractPathText,
2669 /// PostgreSQL `#-` — delete the field/element of the left `jsonb` at the right `text[]`
2670 /// path. Same "any other operator" precedence. The `#-` lexeme is munched over the two
2671 /// contiguous bytes ahead of the bare `#` bitwise-XOR (engine-verified: `5#-3` is
2672 /// `5 #- 3`, while a space splits it into `#` then `-3`).
2673 JsonDeletePath,
2674 /// Bitwise OR, spelled `|` (PostgreSQL, MySQL, SQLite, DuckDB). In PostgreSQL/SQLite/
2675 /// DuckDB it shares one "bitwise" precedence with `&`/`<<`/`>>` (between additive and
2676 /// comparison); MySQL ranks it strictly looser than `&` (the load-bearing per-dialect
2677 /// precedence split), so its binding power is dialect data
2678 /// ([`BindingPowerTable::bitwise_or`](crate::precedence::BindingPowerTable::bitwise_or)).
2679 BitwiseOr,
2680 /// Bitwise AND, spelled `&` (PostgreSQL, MySQL, SQLite, DuckDB). Shares the one bitwise
2681 /// rank with `|`/`<<`/`>>` in PostgreSQL/SQLite/DuckDB; binds tighter than `|` and
2682 /// looser than the shifts in MySQL (dialect data, see
2683 /// [`BindingPowerTable::bitwise_and`](crate::precedence::BindingPowerTable::bitwise_and)).
2684 BitwiseAnd,
2685 /// Bitwise left shift, spelled `<<` (PostgreSQL, MySQL, SQLite, DuckDB). Grouped with
2686 /// [`BitwiseShiftRight`](Self::BitwiseShiftRight) at one shift rank in every dialect —
2687 /// looser than additive everywhere (`1 << 2 + 3` is `1 << (2 + 3)`, engine-measured on
2688 /// SQLite/PG/DuckDB) — but that rank sits *below* additive and *above* `&` in MySQL
2689 /// (dialect data,
2690 /// [`BindingPowerTable::bitwise_shift`](crate::precedence::BindingPowerTable::bitwise_shift)).
2691 BitwiseShiftLeft,
2692 /// Bitwise right shift, spelled `>>` (PostgreSQL, MySQL, SQLite, DuckDB). The mirror of
2693 /// [`BitwiseShiftLeft`](Self::BitwiseShiftLeft); same shift rank.
2694 BitwiseShiftRight,
2695 /// Bitwise exclusive-or. Two dialect-disjoint spellings fold onto this one operator:
2696 /// PostgreSQL's `#` and MySQL's `^`. The [`BitwiseXorSpelling`] tag is
2697 /// load-bearing for validity, not only fidelity — PostgreSQL rejects `^` as XOR (there
2698 /// `^` is exponentiation) and MySQL treats `#` as a comment — so a normalized render
2699 /// would not re-parse under the dialect that produced it (the same contract
2700 /// [`IsNotDistinctFrom`](Self::IsNotDistinctFrom) keeps). The two spellings *also* bind
2701 /// at different precedences: PostgreSQL's `#` is an "any other operator" (looser than
2702 /// additive), MySQL's `^` binds tighter than `*` — dialect data on
2703 /// [`BindingPowerTable::bitwise_xor`](crate::precedence::BindingPowerTable::bitwise_xor).
2704 /// Distinct from the *logical* [`Xor`](Self::Xor) keyword operator (MySQL `XOR`).
2705 BitwiseXor(BitwiseXorSpelling),
2706 /// Equality, spelled `=` everywhere and additionally `==` in SQLite. The two
2707 /// spellings are one operator; the [`EqualsSpelling`] tag records
2708 /// which the source used so it round-trips.
2709 Eq(EqualsSpelling),
2710 /// Inequality, spelled `<>` (SQL-standard) everywhere and additionally `!=`
2711 /// (C-style) in every bundled dialect. The two spellings are one operator; the
2712 /// [`NotEqSpelling`] tag records which the source used so it round-trips.
2713 NotEq(NotEqSpelling),
2714 /// `<` — less-than.
2715 Lt,
2716 /// `<=` — less-than-or-equal.
2717 LtEq,
2718 /// `>` — greater-than.
2719 Gt,
2720 /// `>=` — greater-than-or-equal.
2721 GtEq,
2722 /// The null-safe inequality predicate `IS DISTINCT FROM` (SQL:1999 T151): true when
2723 /// the operands differ, treating `NULL` as an ordinary comparable value rather than
2724 /// yielding `NULL`. The parser recognizes it in the `IS` predicate arm, not the
2725 /// symbolic-operator loop. Binds at comparison precedence, non-associative like `=`
2726 /// (PostgreSQL `a_expr IS DISTINCT FROM a_expr %prec IS`, gram.y). Two
2727 /// interchangeable-semantics spellings fold onto it: the SQL:1999 `IS DISTINCT FROM`
2728 /// keyword form and SQLite's bare `IS NOT` (`a IS NOT b`, SQLite's general negated
2729 /// `IS`). The [`IsDistinctFromSpelling`] tag records which the source used so the
2730 /// surface round-trips, mirroring the [`IsNotDistinctFrom`](Self::IsNotDistinctFrom)
2731 /// complement.
2732 IsDistinctFrom(IsDistinctFromSpelling),
2733 /// The complement of [`IsDistinctFrom`](Self::IsDistinctFrom): the null-safe
2734 /// equality predicate, true when the operands are equal or both `NULL`. A distinct
2735 /// operator key at the same comparison precedence. Two interchangeable-semantics
2736 /// spellings fold onto it: the SQL:1999 `IS NOT DISTINCT FROM` keyword
2737 /// form (which SQLite's general `IS` also produces), recognized in the `IS`-predicate
2738 /// arm; and MySQL's `<=>` operator, recognized in the symbolic-operator loop. The
2739 /// [`IsNotDistinctFromSpelling`] tag records which the source used. Unlike the other
2740 /// spelling tags this is load-bearing for validity, not only fidelity: MySQL rejects
2741 /// the keyword form and the other dialects reject `<=>`, so the spelling cannot be
2742 /// normalized away without producing input the same dialect fails to re-parse.
2743 IsNotDistinctFrom(IsNotDistinctFromSpelling),
2744 /// MySQL `RLIKE` / `REGEXP` regular-expression match. The two keywords are
2745 /// synonyms folding onto one operator; the [`RegexpSpelling`] tag
2746 /// records which the source used. Binds at comparison precedence (like `LIKE`).
2747 Regexp(RegexpSpelling),
2748 /// SQLite's `GLOB` pattern-match operator — case-sensitive Unix-glob matching
2749 /// (`*`/`?`/`[…]`). A keyword infix operator ([`KeywordOperators::Sqlite`]), the
2750 /// SQLite analogue of MySQL's `RLIKE`. Binds at comparison precedence (like
2751 /// `LIKE`/`REGEXP`).
2752 ///
2753 /// [`KeywordOperators::Sqlite`]: crate::dialect::KeywordOperators::Sqlite
2754 Glob,
2755 /// SQLite's `MATCH` operator — a grammar hook whose meaning is supplied by an
2756 /// application-defined function (FTS, R-Tree). A keyword infix operator
2757 /// ([`KeywordOperators::Sqlite`]) sibling of [`Glob`](Self::Glob); binds at
2758 /// comparison precedence. The bundled engine registers no `match` backing, so a
2759 /// bare `prepare` rejects it — it is grammar-only, guarded by round-trip rather
2760 /// than an accept/reject oracle.
2761 ///
2762 /// [`KeywordOperators::Sqlite`]: crate::dialect::KeywordOperators::Sqlite
2763 Match,
2764 /// The SQL-standard `OVERLAPS` period predicate (SQL:2016 F251): `(s1, e1) OVERLAPS
2765 /// (s2, e2)` — true when the two time periods, each given as a `(start, end |
2766 /// duration)` pair, share any instant. Both operands are exactly-two-element rows
2767 /// ([`Expr::Row`], bare parenthesized pair or `ROW(...)`), a shape the parser enforces
2768 /// (a scalar, a single-element grouping, or a three-element row is a parse error,
2769 /// matching PostgreSQL's `row OVERLAPS row` production and its wrong-arity `ereport`).
2770 /// The boolean result is not itself a row, so the predicate never chains
2771 /// (`x OVERLAPS y OVERLAPS z` rejects) — modelled non-associative. Binds tighter than
2772 /// the comparison operators (`x OVERLAPS y = TRUE` groups `(x OVERLAPS y) = TRUE`) and
2773 /// looser than the arithmetic/`Op` rank, its own PostgreSQL `%nonassoc OVERLAPS` gram.y
2774 /// row. Gated by
2775 /// [`PredicateSyntax::overlaps_period_predicate`](crate::dialect::PredicateSyntax::overlaps_period_predicate).
2776 Overlaps,
2777 /// `AND` — logical conjunction.
2778 And,
2779 /// MySQL `XOR` logical exclusive-or. Binds between `AND` and `OR` in precedence.
2780 Xor,
2781 /// `OR` — logical disjunction.
2782 Or,
2783}
2784
2785/// Surface spelling for the modulo operator [`BinaryOperator::Modulo`].
2786///
2787/// `%` is universal; MySQL additionally spells the same operation with the `MOD`
2788/// keyword. The canonical AST keeps one modulo operator and this tag
2789/// only records which spelling the source used so rendering round-trips exactly.
2790#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2791#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2792#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2793pub enum ModuloSpelling {
2794 /// The `%` operator.
2795 Percent,
2796 /// The MySQL `MOD` keyword.
2797 Mod,
2798}
2799
2800/// Surface spelling for the integer-division operator [`BinaryOperator::IntegerDivide`].
2801///
2802/// Integer division has two dialect-disjoint spellings that fold onto one operator:
2803/// MySQL's `DIV` keyword and DuckDB's `//` symbol. Neither dialect accepts the
2804/// other's spelling (MySQL has no `//` operator — a bare `//` is a syntax error there — and
2805/// DuckDB has no `DIV` keyword), so this tag is load-bearing for validity, not only
2806/// fidelity, mirroring [`BitwiseXorSpelling`]: a normalized render would not re-parse under
2807/// the dialect that produced it.
2808#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2809#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2810#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2811pub enum IntegerDivideSpelling {
2812 /// The MySQL `DIV` keyword.
2813 Div,
2814 /// The DuckDB `//` operator.
2815 SlashSlash,
2816}
2817
2818/// Surface spelling for the equality operator [`BinaryOperator::Eq`].
2819///
2820/// `=` is universal; SQLite additionally spells the same comparison with a doubled
2821/// `==`. The canonical AST keeps one equality operator and this tag only
2822/// records which spelling the source used so rendering round-trips exactly.
2823#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2824#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2825#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2826pub enum EqualsSpelling {
2827 /// The `=` operator.
2828 Single,
2829 /// The SQLite `==` operator.
2830 Double,
2831}
2832
2833/// Whether an aggregate `FILTER (…)` clause wrote the SQL-standard `WHERE` keyword
2834/// before its predicate ([`FunctionCall::filter_where`]).
2835///
2836/// SQL:2003 (and PostgreSQL/SQLite) require `FILTER (WHERE <predicate>)`; DuckDB
2837/// additionally accepts the keyword-less `FILTER (<predicate>)`
2838/// ([`AggregateCallSyntax::filter_optional_where`](crate::dialect::AggregateCallSyntax::filter_optional_where)).
2839/// The canonical AST keeps one filtered-aggregate shape and this tag records which the
2840/// source used so rendering round-trips exactly, mirroring [`EqualsSpelling`]. Only
2841/// meaningful when [`FunctionCall::filter`] is `Some`; a call with no filter carries
2842/// the canonical [`Where`](Self::Where).
2843#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2844#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2845#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2846pub enum FilterWhereSpelling {
2847 /// The SQL-standard `FILTER (WHERE <predicate>)` spelling (the canonical form).
2848 Where,
2849 /// DuckDB's keyword-less `FILTER (<predicate>)` spelling.
2850 Omitted,
2851}
2852
2853/// Surface spelling for the inequality operator [`BinaryOperator::NotEq`].
2854///
2855/// The SQL-standard `<>` is universal; every bundled dialect additionally spells the
2856/// same comparison with the C-style `!=`. The canonical AST keeps one inequality
2857/// operator and this tag only records which spelling the source used so rendering
2858/// round-trips exactly, mirroring [`EqualsSpelling`]. A fidelity tag, not a validity
2859/// one: both spellings parse under every dialect, so the canonical `<>` re-parses
2860/// wherever the source `!=` did.
2861#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2862#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2863#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2864pub enum NotEqSpelling {
2865 /// The SQL-standard `<>` operator (the canonical spelling).
2866 AngleBracket,
2867 /// The C-style `!=` operator.
2868 Bang,
2869}
2870
2871/// Surface spelling for the null-safe inequality operator
2872/// [`BinaryOperator::IsDistinctFrom`].
2873///
2874/// The predicate has two interchangeable-semantics spellings: the SQL:1999
2875/// `IS DISTINCT FROM` keyword form and SQLite's bare `IS NOT` (SQLite's general
2876/// negated `IS`). The canonical AST keeps one operator and this tag records which the
2877/// source used so rendering round-trips, mirroring [`IsNotDistinctFromSpelling`]. Both
2878/// spellings are valid under SQLite (which accepts the explicit keyword form too), so
2879/// this is a fidelity tag rather than a validity one.
2880#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2881#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2882#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2883pub enum IsDistinctFromSpelling {
2884 /// The `IS DISTINCT FROM` keyword form (SQL:1999 T151).
2885 Keyword,
2886 /// SQLite's bare `IS NOT`: `a IS NOT b` is null-safe inequality, folding onto this
2887 /// operator. Renders back as bare `IS NOT` so the surface round-trips.
2888 Is,
2889}
2890
2891/// Surface spelling for the null-safe equality operator
2892/// [`BinaryOperator::IsNotDistinctFrom`].
2893///
2894/// The predicate has two interchangeable-semantics spellings: the SQL:1999
2895/// `IS NOT DISTINCT FROM` keyword form (which SQLite's general `IS` also folds onto)
2896/// and MySQL's `<=>` operator. The canonical AST keeps one operator and this
2897/// tag records which the source used so rendering round-trips. Unlike the sibling
2898/// spelling tags this is load-bearing for validity, not only fidelity: MySQL rejects
2899/// `IS NOT DISTINCT FROM` and the other dialects reject `<=>`, so a normalized render
2900/// would not re-parse under the dialect that produced it.
2901#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2902#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2903#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2904pub enum IsNotDistinctFromSpelling {
2905 /// The `IS NOT DISTINCT FROM` keyword form (SQL:1999 T151).
2906 Keyword,
2907 /// The MySQL `<=>` null-safe-equality operator.
2908 NullSafeEq,
2909 /// SQLite's bare general `IS`: `a IS b` is null-safe equality, folding onto this
2910 /// operator (SQLite also accepts the explicit `IS NOT DISTINCT FROM`, which keeps
2911 /// [`Keyword`](Self::Keyword)). Renders back as bare `IS` so the surface round-trips.
2912 Is,
2913}
2914
2915/// Which truth value an [`Expr::IsTruth`] predicate tests (SQL:2016 F571,
2916/// `<truth value>` in the `<boolean test>` grammar). The three-valued-logic constants:
2917/// `TRUE`, `FALSE`, and `UNKNOWN` (the boolean `NULL`).
2918#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2919#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2920#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2921pub enum TruthValue {
2922 /// `IS [NOT] TRUE`.
2923 True,
2924 /// `IS [NOT] FALSE`.
2925 False,
2926 /// `IS [NOT] UNKNOWN`.
2927 Unknown,
2928}
2929
2930/// Surface spelling for the bitwise exclusive-or operator [`BinaryOperator::BitwiseXor`].
2931///
2932/// XOR has two dialect-disjoint spellings that fold onto one operator:
2933/// PostgreSQL's `#` and MySQL's `^`. Unlike the cosmetic spelling tags, this is
2934/// load-bearing for validity, mirroring [`IsNotDistinctFromSpelling`]: PostgreSQL's `^`
2935/// is *exponentiation* (not XOR) and MySQL's `#` opens a comment, so each dialect rejects
2936/// the other's spelling — a normalized render would not re-parse. The two also differ in
2937/// precedence, which lives on the dialect's binding-power table, not here.
2938#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2939#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2940#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2941pub enum BitwiseXorSpelling {
2942 /// The PostgreSQL `#` operator.
2943 Hash,
2944 /// The MySQL `^` operator.
2945 Caret,
2946}
2947
2948/// Surface spelling for the regex-match operator [`BinaryOperator::Regexp`].
2949///
2950/// MySQL spells regular-expression match two interchangeable ways, `RLIKE` and its
2951/// `REGEXP` synonym. The canonical AST keeps one operator and this tag
2952/// records which keyword the source used so rendering round-trips exactly.
2953#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2954#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2955#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2956pub enum RegexpSpelling {
2957 /// The `RLIKE` keyword.
2958 Rlike,
2959 /// The `REGEXP` keyword.
2960 Regexp,
2961}
2962
2963/// Surface spelling for the pattern-match predicate [`Expr::Like`].
2964///
2965/// SQL spells pattern matching three interchangeable-shape ways — case-sensitive
2966/// `LIKE` (SQL-92 core E021-08), PostgreSQL's case-insensitive `ILIKE`, and the
2967/// regex-flavoured `SIMILAR TO` (SQL:1999 F841). The canonical AST keeps one
2968/// [`Expr::Like`] node and this tag records which keyword the source
2969/// used so rendering round-trips exactly, mirroring [`RegexpSpelling`].
2970#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2971#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2972#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2973pub enum LikeSpelling {
2974 /// The `LIKE` keyword.
2975 Like,
2976 /// The `ILIKE` keyword (PostgreSQL).
2977 ILike,
2978 /// The `SIMILAR TO` keyword pair (SQL:1999 F841).
2979 SimilarTo,
2980}
2981
2982/// Surface spelling for the null test [`Expr::IsNull`].
2983///
2984/// SQL's `<expr> IS [NOT] NULL` has one-word postfix synonyms in PostgreSQL and SQLite —
2985/// `<expr> ISNULL` (for `IS NULL`) and `<expr> NOTNULL` (for `IS NOT NULL`). The canonical
2986/// AST keeps one [`Expr::IsNull`] node with its `negated` flag and this tag records which
2987/// keyword form the source used so rendering round-trips, mirroring [`LikeSpelling`].
2988#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2989#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
2990#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
2991pub enum NullTestSpelling {
2992 /// The standard two/three-word form `IS NULL` / `IS NOT NULL`.
2993 Is,
2994 /// The one-word postfix synonym `ISNULL` (for `IS NULL`) / `NOTNULL` (for `IS NOT NULL`)
2995 /// — PostgreSQL and SQLite.
2996 Postfix,
2997 /// The two-word postfix synonym `<expr> NOT NULL` (for `IS NOT NULL`) — a `NOT`-led
2998 /// predicate spelling distinct from the one-word [`Postfix`](Self::Postfix) `NOTNULL`.
2999 /// Only ever paired with `negated: true` (there is no un-negated two-word form).
3000 /// SQLite and DuckDB accept it; PostgreSQL, despite the one-word synonyms, rejects it
3001 /// (engine-measured), so it rides its own
3002 /// [`PredicateSyntax::null_test_two_word_postfix`](crate::dialect::PredicateSyntax) gate
3003 /// rather than [`OperatorSyntax::null_test_postfix`](crate::dialect::OperatorSyntax).
3004 PostfixNotNull,
3005}
3006
3007/// Surface spelling for the [`StringFunc::CeilTo`] head word — `CEIL` vs its `CEILING`
3008/// synonym, recorded so rendering round-trips the word the source wrote.
3009#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
3010#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
3011#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
3012pub enum CeilSpelling {
3013 /// Source used the `CEIL` spelling.
3014 Ceil,
3015 /// Source used the `CEILING` spelling.
3016 Ceiling,
3017}
3018
3019/// The Unicode normal form named in an `<expr> IS [NOT] <form> NORMALIZED` test
3020/// ([`Expr::IsNormalized`]).
3021#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
3022#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
3023#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
3024pub enum NormalizationForm {
3025 /// Normalization Form C (canonical composition) — the default when `IS NORMALIZED`
3026 /// names no form.
3027 Nfc,
3028 /// Normalization Form D (canonical decomposition).
3029 Nfd,
3030 /// Normalization Form KC (compatibility composition).
3031 Nfkc,
3032 /// Normalization Form KD (compatibility decomposition).
3033 Nfkd,
3034}
3035
3036/// Unary expression operators.
3037#[derive(Clone, Debug, PartialEq, Eq, Hash)]
3038#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
3039#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
3040pub enum UnaryOperator {
3041 /// `NOT` — logical negation.
3042 Not,
3043 /// `-` — arithmetic negation.
3044 Minus,
3045 /// `+` — unary plus (identity).
3046 Plus,
3047 /// Bitwise complement, spelled `~` (PostgreSQL, MySQL, SQLite, DuckDB). A prefix
3048 /// operator whose binding power is dialect data
3049 /// ([`prefix_bitwise_not`](crate::precedence::BindingPowerTable::prefix_bitwise_not)):
3050 /// it binds tightly (like the unary sign) in SQLite/MySQL, but in PostgreSQL/DuckDB it
3051 /// is looser than the arithmetic operators and tighter than the binary bitwise family
3052 /// (`~ 1 + 1` is `~ (1 + 1)` but `~ 1 & 3` is `(~ 1) & 3` — engine-measured).
3053 BitwiseNot,
3054 /// Oracle/Snowflake `PRIOR <expr>` — inside a `CONNECT BY` condition, marks the
3055 /// operand taken from the *parent* row of the hierarchical walk (Oracle *SQL
3056 /// Language Reference*, hierarchical queries; Snowflake `CONNECT BY`). It is an
3057 /// expression-level operator meaningful only in that clause: the parser produces it
3058 /// solely while parsing a [`Select::connect_by`](crate::ast::Select) condition
3059 /// (gated by [`SelectSyntax::connect_by_clause`](crate::dialect::SelectSyntax)), so
3060 /// the global expression grammar admits no bare `PRIOR` and a `prior` elsewhere
3061 /// stays an ordinary column name. Binds like the unary sign (tighter than
3062 /// comparison), so `PRIOR a = b` groups as `(PRIOR a) = b`.
3063 Prior,
3064}