Skip to main content

mz_sql_parser/ast/defs/
expr.rs

1// Copyright 2018 sqlparser-rs contributors. All rights reserved.
2// Copyright Materialize, Inc. and contributors. All rights reserved.
3//
4// This file is derived from the sqlparser-rs project, available at
5// https://github.com/andygrove/sqlparser-rs. It was incorporated
6// directly into Materialize on December 21, 2019.
7//
8// Licensed under the Apache License, Version 2.0 (the "License");
9// you may not use this file except in compliance with the License.
10// You may obtain a copy of the License in the LICENSE file at the
11// root of this repository, or online at
12//
13//     http://www.apache.org/licenses/LICENSE-2.0
14//
15// Unless required by applicable law or agreed to in writing, software
16// distributed under the License is distributed on an "AS IS" BASIS,
17// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18// See the License for the specific language governing permissions and
19// limitations under the License.
20
21use std::{fmt, mem};
22
23use itertools::Itertools;
24use mz_ore::soft_assert_eq_or_log;
25use mz_sql_lexer::keywords::*;
26
27use crate::ast::display::{self, AstDisplay, AstFormatter};
28use crate::ast::{AstInfo, Ident, OrderByExpr, Query, UnresolvedItemName, Value};
29
30/// An SQL expression of any type.
31///
32/// The parser does not distinguish between expressions of different types
33/// (e.g. boolean vs string), so the caller must handle expressions of
34/// inappropriate type, like `WHERE 1` or `SELECT 1=1`, as necessary.
35#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
36pub enum Expr<T: AstInfo> {
37    /// Identifier e.g. table name or column name. The parser always
38    /// constructs this with a non-empty `Vec`.
39    Identifier(Vec<Ident>),
40    /// Qualified wildcard, e.g. `alias.*` or `schema.table.*`.
41    QualifiedWildcard(Vec<Ident>),
42    /// A field access, like `(expr).foo`.
43    FieldAccess {
44        expr: Box<Expr<T>>,
45        field: Ident,
46    },
47    /// A wildcard field access, like `(expr).*`.
48    ///
49    /// Note that this is different from `QualifiedWildcard` in that the
50    /// wildcard access occurs on an arbitrary expression, rather than a
51    /// qualified name. The distinction is important for PostgreSQL
52    /// compatibility.
53    WildcardAccess(Box<Expr<T>>),
54    /// A positional parameter, e.g., `$1` or `$42`
55    Parameter(usize),
56    /// Boolean negation
57    Not {
58        expr: Box<Expr<T>>,
59    },
60    /// Boolean and
61    And {
62        left: Box<Expr<T>>,
63        right: Box<Expr<T>>,
64    },
65    /// Boolean or
66    Or {
67        left: Box<Expr<T>>,
68        right: Box<Expr<T>>,
69    },
70    /// `IS {NULL, TRUE, FALSE, UNKNOWN}` expression
71    IsExpr {
72        expr: Box<Expr<T>>,
73        construct: IsExprConstruct<T>,
74        negated: bool,
75    },
76    /// `[ NOT ] IN (val1, val2, ...)`
77    InList {
78        expr: Box<Expr<T>>,
79        list: Vec<Expr<T>>,
80        negated: bool,
81    },
82    /// `[ NOT ] IN (SELECT ...)`
83    InSubquery {
84        expr: Box<Expr<T>>,
85        subquery: Box<Query<T>>,
86        negated: bool,
87    },
88    /// `<expr> [ NOT ] {LIKE, ILIKE} <pattern> [ ESCAPE <escape> ]`
89    Like {
90        expr: Box<Expr<T>>,
91        pattern: Box<Expr<T>>,
92        escape: Option<Box<Expr<T>>>,
93        case_insensitive: bool,
94        negated: bool,
95    },
96    /// `<expr> [ NOT ] BETWEEN <low> AND <high>`
97    Between {
98        expr: Box<Expr<T>>,
99        negated: bool,
100        low: Box<Expr<T>>,
101        high: Box<Expr<T>>,
102    },
103    /// Unary or binary operator
104    Op {
105        op: Op,
106        expr1: Box<Expr<T>>,
107        expr2: Option<Box<Expr<T>>>,
108    },
109    /// CAST an expression to a different data type e.g. `CAST(foo AS VARCHAR(123))`
110    Cast {
111        expr: Box<Expr<T>>,
112        data_type: T::DataType,
113    },
114    /// `expr COLLATE collation`
115    Collate {
116        expr: Box<Expr<T>>,
117        collation: UnresolvedItemName,
118    },
119    /// `COALESCE(<expr>, ...)` or `GREATEST(<expr>, ...)` or `LEAST(<expr>`, ...)
120    ///
121    /// While COALESCE/GREATEST/LEAST have the same syntax as a function call,
122    /// their semantics are extremely unusual, and are better captured with a
123    /// dedicated AST node.
124    HomogenizingFunction {
125        function: HomogenizingFunction,
126        exprs: Vec<Expr<T>>,
127    },
128    /// NULLIF(expr, expr)
129    ///
130    /// While NULLIF has the same syntax as a function call, it is not evaluated
131    /// as a function within Postgres.
132    NullIf {
133        l_expr: Box<Expr<T>>,
134        r_expr: Box<Expr<T>>,
135    },
136    /// Nested expression e.g. `(foo > bar)` or `(1)`
137    Nested(Box<Expr<T>>),
138    /// A row constructor like `ROW(<expr>...)` or `(<expr>, <expr>...)`.
139    Row {
140        exprs: Vec<Expr<T>>,
141    },
142    /// A literal value, such as string, number, date or NULL
143    Value(Value),
144    /// Scalar function call e.g. `LEFT(foo, 5)`
145    Function(Function<T>),
146    /// `CASE [<operand>] WHEN <condition> THEN <result> ... [ELSE <result>] END`
147    ///
148    /// Note we only recognize a complete single expression as `<condition>`,
149    /// not `< 0` nor `1, 2, 3` as allowed in a `<simple when clause>` per
150    /// <https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#simple-when-clause>
151    Case {
152        operand: Option<Box<Expr<T>>>,
153        conditions: Vec<Expr<T>>,
154        results: Vec<Expr<T>>,
155        else_result: Option<Box<Expr<T>>>,
156    },
157    /// An exists expression `EXISTS(SELECT ...)`, used in expressions like
158    /// `WHERE EXISTS (SELECT ...)`.
159    Exists(Box<Query<T>>),
160    /// A parenthesized subquery `(SELECT ...)`, used in expression like
161    /// `SELECT (subquery) AS x` or `WHERE (subquery) = x`
162    Subquery(Box<Query<T>>),
163    /// `<expr> <op> ANY/SOME (<query>)`
164    AnySubquery {
165        left: Box<Expr<T>>,
166        op: Op,
167        right: Box<Query<T>>,
168    },
169    /// `<expr> <op> ANY (<array_expr>)`
170    AnyExpr {
171        left: Box<Expr<T>>,
172        op: Op,
173        right: Box<Expr<T>>,
174    },
175    /// `<expr> <op> ALL (<query>)`
176    AllSubquery {
177        left: Box<Expr<T>>,
178        op: Op,
179        right: Box<Query<T>>,
180    },
181    /// `<expr> <op> ALL (<array_expr>)`
182    AllExpr {
183        left: Box<Expr<T>>,
184        op: Op,
185        right: Box<Expr<T>>,
186    },
187    /// `ARRAY[<expr>*]`
188    Array(Vec<Expr<T>>),
189    ArraySubquery(Box<Query<T>>),
190    /// `LIST[<expr>*]`
191    List(Vec<Expr<T>>),
192    ListSubquery(Box<Query<T>>),
193    /// `MAP[<expr>*]`
194    Map(Vec<MapEntry<T>>),
195    MapSubquery(Box<Query<T>>),
196    /// `<expr>([<expr>(:<expr>)?])+`
197    Subscript {
198        expr: Box<Expr<T>>,
199        positions: Vec<SubscriptPosition<T>>,
200    },
201}
202
203impl<T: AstInfo> AstDisplay for Expr<T> {
204    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
205        match self {
206            Expr::Identifier(s) => f.write_node(&display::separated(s, ".")),
207            Expr::QualifiedWildcard(q) => {
208                f.write_node(&display::separated(q, "."));
209                f.write_str(".*");
210            }
211            Expr::FieldAccess { expr, field } => {
212                write_dot_receiver(f, expr);
213                f.write_str(".");
214                f.write_node(field);
215            }
216            Expr::WildcardAccess(expr) => {
217                write_dot_receiver(f, expr);
218                f.write_str(".*");
219            }
220            Expr::Parameter(n) => f.write_str(&format!("${}", n)),
221            Expr::Not { expr } => {
222                f.write_str("NOT ");
223                // `NOT` binds tighter than `AND`/`OR`, so an operand exposing a
224                // looser operator on its left spine (`NOT (a OR b)`) must keep its
225                // parens once `Nested` is stripped. We use `left_edge`, since the
226                // `NOT` sits to the operand's left.
227                write_binary_operand(f, expr, left_edge(expr) < prec::NOT);
228            }
229            Expr::And { left, right } => {
230                write_binary_operand(f, left, right_edge(left) < prec::AND);
231                f.write_str(" AND ");
232                write_binary_operand(f, right, left_edge(right) <= prec::AND);
233            }
234            Expr::Or { left, right } => {
235                write_binary_operand(f, left, right_edge(left) < prec::OR);
236                f.write_str(" OR ");
237                write_binary_operand(f, right, left_edge(right) <= prec::OR);
238            }
239            Expr::IsExpr {
240                expr,
241                negated,
242                construct,
243            } => {
244                write_binary_operand(f, expr, right_edge(expr) < prec::IS);
245                f.write_str(" IS ");
246                if *negated {
247                    f.write_str("NOT ");
248                }
249                // `IS DISTINCT FROM <rhs>` parses the RHS at the `IS` precedence
250                // (see `Parser::parse_is`), so a RHS whose left spine binds at or
251                // below `IS` re-associates out of the `IS` unless parenthesized
252                // (`a IS DISTINCT FROM b OR c` is `(a IS DISTINCT FROM b) OR c`).
253                // The other constructs (`NULL`/`TRUE`/…) are bare keywords.
254                if let IsExprConstruct::DistinctFrom(rhs) = construct {
255                    f.write_str("DISTINCT FROM ");
256                    write_binary_operand(f, rhs, left_edge(rhs) <= prec::IS);
257                } else {
258                    f.write_node(construct);
259                }
260            }
261            Expr::InList {
262                expr,
263                list,
264                negated,
265            } => {
266                write_binary_operand(f, expr, right_edge(expr) < prec::LIKE);
267                f.write_str(" ");
268                if *negated {
269                    f.write_str("NOT ");
270                }
271                f.write_str("IN (");
272                f.write_node(&display::comma_separated(list));
273                f.write_str(")");
274            }
275            Expr::InSubquery {
276                expr,
277                subquery,
278                negated,
279            } => {
280                write_binary_operand(f, expr, right_edge(expr) < prec::LIKE);
281                f.write_str(" ");
282                if *negated {
283                    f.write_str("NOT ");
284                }
285                f.write_str("IN (");
286                f.write_node(&subquery);
287                f.write_str(")");
288            }
289            Expr::Like {
290                expr,
291                pattern,
292                escape,
293                case_insensitive,
294                negated,
295            } => {
296                write_binary_operand(f, expr, right_edge(expr) < prec::LIKE);
297                f.write_str(" ");
298                if *negated {
299                    f.write_str("NOT ");
300                }
301                if *case_insensitive {
302                    f.write_str("I");
303                }
304                f.write_str("LIKE ");
305                // The pattern and escape parse at `Like` precedence and sit to the
306                // right of the keyword, so an operand exposing a precedence at or
307                // below `Like` on its left spine (e.g. an `IN`/`LIKE`/`BETWEEN` at
308                // equal precedence) re-associates unless parenthesized.
309                // `a LIKE b IN (q)` parses as `(a LIKE b) IN (q)`. When an `ESCAPE`
310                // follows, the pattern is *also* immediately left of `ESCAPE`: a
311                // `[I]LIKE` exposed on the pattern's right spine would steal the
312                // `ESCAPE` as its own (`a LIKE NOT b LIKE c ESCAPE d` parses the
313                // escape onto the inner `b LIKE c`), so guard the right edge too.
314                let pattern_parens = left_edge(pattern) <= prec::LIKE
315                    || (escape.is_some() && right_edge(pattern) <= prec::LIKE);
316                write_binary_operand(f, pattern, pattern_parens);
317                if let Some(escape) = escape {
318                    f.write_str(" ESCAPE ");
319                    write_binary_operand(f, escape, left_edge(escape) <= prec::LIKE);
320                }
321            }
322            Expr::Between {
323                expr,
324                negated,
325                low,
326                high,
327            } => {
328                // The subject is the LHS of the `BETWEEN` infix (parsed at
329                // `Like`). A spine exposed at or below `Like` on its right would
330                // pull `BETWEEN` inside it (`a OR b BETWEEN …` is `a OR (b BETWEEN
331                // …)`), so parenthesize via `right_edge`. Parser ASTs wrap such a
332                // subject in `Nested` (`ATOM`), so they're unaffected.
333                write_binary_operand(f, expr, right_edge(expr) < prec::LIKE);
334                if *negated {
335                    f.write_str(" NOT");
336                }
337                f.write_str(" BETWEEN ");
338                write_between_bound(f, low);
339                f.write_str(" AND ");
340                write_between_bound(f, high);
341            }
342            Expr::Op { op, expr1, expr2 } => {
343                if let Some(expr2) = expr2 {
344                    // Binary operators are left-associative: parenthesize an
345                    // operand that would re-associate once `Nested` is stripped.
346                    // The left by its `right_edge` (strictly looser than `op`), the
347                    // right by its `left_edge` (equal-or-looser, as equal
348                    // re-associates left). See those helpers for the spine
349                    // reasoning.
350                    let p = binary_op_precedence(op);
351                    write_binary_operand(f, expr1, right_edge(expr1) < p);
352                    f.write_str(" ");
353                    f.write_str(op);
354                    f.write_str(" ");
355                    write_binary_operand(f, expr2, left_edge(expr2) <= p);
356                } else {
357                    f.write_str(op);
358                    f.write_str(" ");
359                    if prefix_operand_needs_parens(op, expr1.as_ref()) {
360                        f.write_str("(");
361                        f.write_node(&expr1);
362                        f.write_str(")");
363                    } else {
364                        f.write_node(&expr1);
365                    }
366                }
367            }
368            Expr::Cast { expr, data_type } => {
369                // `::` binds very tightly, so a non-self-delimiting operand must
370                // be parenthesized or the cast re-associates into its spine.
371                // `CAST(-0 AS int4)` (i.e. `Cast(- 0)`) would otherwise print as
372                // `- 0::int4` and reparse as `- (0::int4)`. The parser wraps such
373                // operands in `Expr::Nested`, but `normalize` strips those, so the
374                // printer must re-add them (mirroring the `Collate` arm). `Nested`
375                // is itself self-delimiting, so parser-produced ASTs don't double up.
376                if prints_self_delimiting(expr) {
377                    f.write_node(&expr);
378                } else {
379                    f.write_str("(");
380                    f.write_node(&expr);
381                    f.write_str(")");
382                }
383                f.write_str("::");
384                f.write_node(data_type);
385            }
386            Expr::Collate { expr, collation } => {
387                // `COLLATE` binds very tightly (`PostfixCollateAt`), so a
388                // low-precedence operand must be parenthesized or the collation
389                // re-associates onto its rightmost sub-operand — `a + b COLLATE c`
390                // would reparse as `a + (b COLLATE c)`. (Round-trip parens are
391                // stripped by `normalize`, so the printer must re-add them.)
392                if prints_self_delimiting(expr) {
393                    f.write_node(&expr);
394                } else {
395                    f.write_str("(");
396                    f.write_node(&expr);
397                    f.write_str(")");
398                }
399                f.write_str(" COLLATE ");
400                f.write_node(&collation);
401            }
402            Expr::HomogenizingFunction { function, exprs } => {
403                f.write_node(function);
404                f.write_str("(");
405                f.write_node(&display::comma_separated(exprs));
406                f.write_str(")");
407            }
408            Expr::NullIf { l_expr, r_expr } => {
409                f.write_str("NULLIF(");
410                f.write_node(&display::comma_separated(&[l_expr, r_expr]));
411                f.write_str(")");
412            }
413            Expr::Nested(ast) => {
414                f.write_str("(");
415                f.write_node(&ast);
416                f.write_str(")");
417            }
418            Expr::Row { exprs } => {
419                f.write_str("ROW(");
420                f.write_node(&display::comma_separated(exprs));
421                f.write_str(")");
422            }
423            Expr::Value(v) => {
424                f.write_node(v);
425            }
426            Expr::Function(fun) => {
427                f.write_node(fun);
428            }
429            Expr::Case {
430                operand,
431                conditions,
432                results,
433                else_result,
434            } => {
435                f.write_str("CASE");
436                if let Some(operand) = operand {
437                    f.write_str(" ");
438                    f.write_node(&operand);
439                }
440                for (c, r) in conditions.iter().zip_eq(results) {
441                    f.write_str(" WHEN ");
442                    f.write_node(c);
443                    f.write_str(" THEN ");
444                    f.write_node(r);
445                }
446
447                if let Some(else_result) = else_result {
448                    f.write_str(" ELSE ");
449                    f.write_node(&else_result);
450                }
451                f.write_str(" END")
452            }
453            Expr::Exists(s) => {
454                f.write_str("EXISTS (");
455                f.write_node(&s);
456                f.write_str(")");
457            }
458            Expr::Subquery(s) => {
459                f.write_str("(");
460                f.write_node(&s);
461                f.write_str(")");
462            }
463            Expr::AnySubquery { left, op, right } => {
464                write_quantified_left(f, left, op);
465                f.write_str(" ");
466                f.write_str(op);
467                f.write_str(" ANY (");
468                f.write_node(&right);
469                f.write_str(")");
470            }
471            Expr::AnyExpr { left, op, right } => {
472                write_quantified_left(f, left, op);
473                f.write_str(" ");
474                f.write_str(op);
475                f.write_str(" ANY (");
476                f.write_node(&right);
477                f.write_str(")");
478            }
479            Expr::AllSubquery { left, op, right } => {
480                write_quantified_left(f, left, op);
481                f.write_str(" ");
482                f.write_str(op);
483                f.write_str(" ALL (");
484                f.write_node(&right);
485                f.write_str(")");
486            }
487            Expr::AllExpr { left, op, right } => {
488                write_quantified_left(f, left, op);
489                f.write_str(" ");
490                f.write_str(op);
491                f.write_str(" ALL (");
492                f.write_node(&right);
493                f.write_str(")");
494            }
495            Expr::Array(exprs) => {
496                f.write_str("ARRAY[");
497                f.write_node(&display::comma_separated(exprs));
498                f.write_str("]");
499            }
500            Expr::ArraySubquery(s) => {
501                f.write_str("ARRAY(");
502                f.write_node(&s);
503                f.write_str(")");
504            }
505            Expr::List(exprs) => {
506                f.write_str("LIST[");
507                f.write_node(&display::comma_separated(exprs));
508                f.write_str("]");
509            }
510            Expr::ListSubquery(s) => {
511                f.write_str("LIST(");
512                f.write_node(&s);
513                f.write_str(")");
514            }
515            Expr::Map(exprs) => {
516                f.write_str("MAP[");
517                f.write_node(&display::comma_separated(exprs));
518                f.write_str("]");
519            }
520            Expr::MapSubquery(s) => {
521                f.write_str("MAP(");
522                f.write_node(&s);
523                f.write_str(")");
524            }
525            Expr::Subscript { expr, positions } => {
526                write_subscript_receiver(f, expr);
527                f.write_str("[");
528
529                let mut first = true;
530
531                for p in positions {
532                    if first {
533                        first = false
534                    } else {
535                        f.write_str("][");
536                    }
537                    f.write_node(p);
538                }
539
540                f.write_str("]");
541            }
542        }
543    }
544}
545impl_display_t!(Expr);
546
547/// Write `expr` as the receiver of a `.` operator (used by `FieldAccess` and
548/// `WildcardAccess`), parenthesizing when the receiver could re-bind the
549/// trailing dot on reparse. The `.` token has very high precedence and both
550/// the lexer and parser greedily extend adjacent tokens: `1.x` tokenizes the
551/// number `1.` and leaves `x` as an alias, and `'a'::T.x` consumes `T.x` as a
552/// qualified type name. The whitelist below covers receivers that print as
553/// self-terminating syntax (parenthesized exprs, function calls, bracketed
554/// collections, etc.). Anything else gets explicit parens.
555///
556/// A bare `Identifier`/`QualifiedWildcard` receiver is *not* safe: `a` then
557/// `.b`/`.*` prints as `a.b`/`a.*`, which reparses as the qualified identifier
558/// `Identifier([a, b])` / `QualifiedWildcard([a])` rather than a field/wildcard
559/// access. The parser only ever builds those accesses over a parenthesized
560/// receiver (`(a).b`), so it wraps the name in `Expr::Nested`. A bare name here
561/// is a `Nested`-stripped AST and must be re-parenthesized. A `FieldAccess` /
562/// `WildcardAccess` receiver *is* safe, because its own printing already
563/// parenthesizes a bare-name base (`(a).b.c`), so the chain stays self-delimiting.
564///
565/// The quantified-subquery forms (`AnySubquery`/`AllSubquery`, printed
566/// `<expr> <op> ANY (<query>)`) are likewise *not* safe: they end in a `(query)`
567/// that is only a sub-part, so a trailing `.x`/`.*` binds to that inner subquery
568/// rather than the whole expression. (Contrast `Subquery`/`ArraySubquery`/… which
569/// are a single `(…)`/`ARRAY(…)` primary, so a trailing dot attaches to the whole
570/// thing.)
571fn write_dot_receiver<W: fmt::Write, T: AstInfo>(f: &mut AstFormatter<W>, expr: &Expr<T>) {
572    let safe = matches!(
573        expr,
574        Expr::FieldAccess { .. }
575            | Expr::WildcardAccess(_)
576            | Expr::Parameter(_)
577            | Expr::Nested(_)
578            | Expr::Row { .. }
579            | Expr::Function(_)
580            | Expr::Case { .. }
581            | Expr::Exists(_)
582            | Expr::Subquery(_)
583            | Expr::Array(_)
584            | Expr::ArraySubquery(_)
585            | Expr::List(_)
586            | Expr::ListSubquery(_)
587            | Expr::Map(_)
588            | Expr::MapSubquery(_)
589            | Expr::Subscript { .. }
590            | Expr::HomogenizingFunction { .. }
591            | Expr::NullIf { .. }
592            | Expr::Value(
593                Value::String(_)
594                    | Value::Boolean(_)
595                    | Value::Null
596                    | Value::HexString(_)
597                    | Value::Interval(_)
598            )
599    );
600    if safe {
601        f.write_node(expr);
602    } else {
603        f.write_str("(");
604        f.write_node(expr);
605        f.write_str(")");
606    }
607}
608
609/// Write `left` as the LHS of `<left> <op> ANY/ALL (...)`. The printed `<op>` is an
610/// ordinary binary infix. It can be any operator the parser accepts here, from
611/// `=`/`<` (`Cmp`) all the way down to `*`/`/`/`%` (`MultiplyDivide`), and on
612/// reparse it binds into any operator exposed on `left`'s right spine that is
613/// *strictly looser* than `<op>` itself, stealing that suffix into the quantified
614/// expression's left rather than wrapping the whole `left`. So parenthesize
615/// exactly when `left`'s [`right_edge`] binds looser than `<op>`'s own precedence
616/// ([`binary_op_precedence`]), mirroring the binary-`Op` arm. Using the operator's
617/// real precedence (not a fixed `Like` threshold) both parenthesizes a
618/// tighter-binding `<op>` over a looser left and leaves an equal-or-tighter left
619/// bare (`a = b = ANY (…)`, `a LIKE b = ANY (…)`), which the old fixed threshold
620/// over-parenthesized. The tighter-binding case, `(a + b) * ANY (…)`, would
621/// otherwise print `a + b * ANY (…)` and reparse as the different
622/// `a + (b * ANY (…))`. [`right_edge`] also sees a looser spine hidden under
623/// right-transparent prefixes, e.g. the `NOT`'s `IN` in `- NOT a IN (b) = ANY (…)`.
624fn write_quantified_left<W: fmt::Write, T: AstInfo>(
625    f: &mut AstFormatter<W>,
626    expr: &Expr<T>,
627    op: &Op,
628) {
629    let needs_parens = right_edge(expr) < binary_op_precedence(op);
630    if needs_parens {
631        f.write_str("(");
632        f.write_node(expr);
633        f.write_str(")");
634    } else {
635        f.write_node(expr);
636    }
637}
638
639/// Write `bound` as a `BETWEEN … AND …` bound. The parser parses both bounds with
640/// `parse_subexpr(Precedence::Like)` (see `Parser::parse_between`), starting fresh
641/// with nothing to the bound's left, so it walks the bound's *left spine* and
642/// stops at the first operator binding at or below `Like`, leaving that operator
643/// outside the bound (`x BETWEEN 1 IS NULL AND y` parses `1` as the bound, then
644/// expects `AND` but finds `IS`). A bound is therefore safe bare only when its
645/// left edge binds strictly above `Like`. Use [`left_edge`] (not [`right_edge`],
646/// which closes at `ATOM` for the right-closing `IS NULL`/`= ANY (…)`/`IN (…)`
647/// forms whose looseness is on the left). The parser wraps these bounds in
648/// `Expr::Nested` (which is `ATOM`, so it prints bare). This re-adds the parens
649/// for ASTs where that wrapper is absent.
650fn write_between_bound<W: fmt::Write, T: AstInfo>(f: &mut AstFormatter<W>, bound: &Expr<T>) {
651    let needs_parens = left_edge(bound) <= prec::LIKE;
652    if needs_parens {
653        f.write_str("(");
654        f.write_node(bound);
655        f.write_str(")");
656    } else {
657        f.write_node(bound);
658    }
659}
660
661/// Output-precedence ranks, derived directly from the parser's [`Precedence`]
662/// ladder (higher binds tighter) so it stays the single source of truth:
663/// reordering or inserting a parser level reranks these automatically, and only
664/// the variant each rank maps to is maintained by hand. They classify the *top*
665/// operator an expr prints with, so the binary-operator printer can parenthesize
666/// an operand that would otherwise re-associate on reparse. `ATOM`, the one rank
667/// with no parser counterpart, is layered one above the tightest parser level to
668/// mark the self-delimiting primaries. They never need parens.
669///
670/// [`Precedence`]: crate::parser::Precedence
671// `Precedence` is a fieldless enum with a handful of variants, so reading each
672// discriminant with `as u8` is exact and lossless.
673#[allow(clippy::as_conversions)]
674mod prec {
675    use crate::parser::Precedence;
676
677    pub const OR: u8 = Precedence::Or as u8;
678    pub const AND: u8 = Precedence::And as u8;
679    pub const NOT: u8 = Precedence::PrefixNot as u8;
680    pub const IS: u8 = Precedence::Is as u8;
681    pub const CMP: u8 = Precedence::Cmp as u8;
682    pub const LIKE: u8 = Precedence::Like as u8;
683    pub const OTHER: u8 = Precedence::Other as u8;
684    pub const PLUS_MINUS: u8 = Precedence::PlusMinus as u8;
685    pub const MULTIPLY_DIVIDE: u8 = Precedence::MultiplyDivide as u8;
686    // The `COLLATE` and postfix (`::`/`[…]`) parser levels live between
687    // `MULTIPLY_DIVIDE` and `ATOM`, but neither edge function ever *returns* them:
688    // those forms are self-delimiting (their own operand is parenthesized when it
689    // isn't), so both their edges rank `ATOM`. Kept for parity with the ladder.
690    #[allow(dead_code)]
691    pub const COLLATE: u8 = Precedence::PostfixCollateAt as u8;
692    pub const PREFIX: u8 = Precedence::PrefixPlusMinus as u8;
693    #[allow(dead_code)]
694    pub const POSTFIX: u8 = Precedence::PostfixSubscriptCast as u8;
695    pub const ATOM: u8 = Precedence::PostfixSubscriptCast as u8 + 1;
696}
697
698/// The precedence of a binary operator, mirroring `Parser::get_next_precedence`.
699/// A namespaced `OPERATOR(...)` binds at `OTHER`, like the parser.
700fn binary_op_precedence(op: &Op) -> u8 {
701    if op.namespace.is_some() {
702        return prec::OTHER;
703    }
704    match op.op.as_str() {
705        "=" | "<" | "<=" | "<>" | "!=" | ">" | ">=" => prec::CMP,
706        "+" | "-" => prec::PLUS_MINUS,
707        "*" | "/" | "%" => prec::MULTIPLY_DIVIDE,
708        _ => prec::OTHER,
709    }
710}
711
712/// The precedence at which a prefix operator (`Op` with no second operand)
713/// parses its operand, mirroring `Parser::parse_prefix`: `-`/`+` at
714/// `PrefixPlusMinus`, but `~` (and namespaced prefixes) at `Other`, so `~ a + b`
715/// parses as `~ (a + b)`. `~` binds looser than `+`/`-`/`*`.
716fn unary_prec(op: &Op) -> u8 {
717    if op.namespace.is_none() && (op.op == "-" || op.op == "+") {
718        prec::PREFIX
719    } else {
720        prec::OTHER
721    }
722}
723
724/// The loosest precedence exposed on `expr`'s *right spine*, the precedence at
725/// which an operator printed immediately to its right would bind *into* it
726/// rather than wrap it. For a left operand / subject of a construct that prints
727/// to its right, this is what decides parenthesization (its mirror, [`left_edge`],
728/// decides right operands), because a prefix operator and the right operand of a
729/// binary/`BETWEEN`/`LIKE`/`IS DISTINCT FROM` are right-transparent:
730/// `- NOT a IN (b)` exposes the `NOT`'s `IN` on the right even though its top node
731/// is unary `-`. Forms that close with a bracket on the right (`(…)`, `[…]`,
732/// `::type`, `IS NULL`) are `ATOM`.
733fn right_edge<T: AstInfo>(expr: &Expr<T>) -> u8 {
734    match expr {
735        // Right-transparent binary infixes: an operator tighter than this one
736        // binds into the right operand, which itself may expose a looser spine.
737        Expr::Or { right, .. } => prec::OR.min(right_edge(right)),
738        Expr::And { right, .. } => prec::AND.min(right_edge(right)),
739        Expr::Op {
740            op, expr2: Some(r), ..
741        } => binary_op_precedence(op).min(right_edge(r)),
742        // Prefix operators expose their operand's right spine.
743        Expr::Op {
744            op,
745            expr1,
746            expr2: None,
747        } => unary_prec(op).min(right_edge(expr1)),
748        Expr::Not { expr } => prec::NOT.min(right_edge(expr)),
749        // `IS DISTINCT FROM x` exposes `x`, while `IS NULL`/`TRUE`/… close.
750        Expr::IsExpr {
751            construct: IsExprConstruct::DistinctFrom(x),
752            ..
753        } => prec::IS.min(right_edge(x)),
754        // `… BETWEEN low AND high` exposes `high`. `… [I]LIKE pat [ESCAPE esc]`
755        // exposes the rightmost of `esc`/`pat`.
756        Expr::Between { high, .. } => prec::LIKE.min(right_edge(high)),
757        Expr::Like {
758            pattern, escape, ..
759        } => {
760            let rightmost = escape.as_deref().unwrap_or_else(|| pattern.as_ref());
761            prec::LIKE.min(right_edge(rightmost))
762        }
763        // Everything else closes on the right (a bracket, a keyword, a literal,
764        // or `IS NULL`-style), so nothing binds into it.
765        _ => prec::ATOM,
766    }
767}
768
769/// The loosest precedence exposed on `expr`'s *left spine*, the mirror of
770/// [`right_edge`]. For a *right* operand (an operator on its left), this is what
771/// decides parenthesization: a left-associative operator printed to its left
772/// reaches into the left spine and re-associates if that spine exposes a
773/// precedence at or below the operator's. The top operator alone is not enough,
774/// because a left-nested chain can bury a looser operator down its left edge:
775/// `387 = ANY (...) LIKE a IN (...)` has a top `IN` (`Like`) but exposes the
776/// `= ANY` (`Cmp`) on its left, so a tighter `<>` to its left
777/// (`48 <> 387 = ANY (...) ...`) would steal the `<>` into the `= ANY`'s left
778/// rather than leave it as the `<>`'s right operand. Forms that open with their
779/// own token on the left (a prefix operator, a keyword, `(…)`, a literal) are
780/// `ATOM`.
781fn left_edge<T: AstInfo>(expr: &Expr<T>) -> u8 {
782    match expr {
783        // Left-transparent infixes / postfix-keyword constructs: the subject (or
784        // left operand) sits on the left spine, so descend into it.
785        Expr::Or { left, .. } => prec::OR.min(left_edge(left)),
786        Expr::And { left, .. } => prec::AND.min(left_edge(left)),
787        Expr::Op {
788            op,
789            expr1,
790            expr2: Some(_),
791        } => binary_op_precedence(op).min(left_edge(expr1)),
792        Expr::IsExpr { expr, .. } => prec::IS.min(left_edge(expr)),
793        Expr::AnyExpr { left, .. }
794        | Expr::AllExpr { left, .. }
795        | Expr::AnySubquery { left, .. }
796        | Expr::AllSubquery { left, .. } => prec::CMP.min(left_edge(left)),
797        Expr::Like { expr, .. }
798        | Expr::Between { expr, .. }
799        | Expr::InList { expr, .. }
800        | Expr::InSubquery { expr, .. } => prec::LIKE.min(left_edge(expr)),
801        // Everything else leads with its own token on the left: a prefix
802        // operator (`-`/`+`/`~`/`NOT`), a keyword, `(…)`, `ARRAY[…]`, a literal,
803        // or a `COLLATE`/`::`/`[…]` whose own operand the printer parenthesizes
804        // when it isn't self-delimiting. Nothing to the left binds into it.
805        _ => prec::ATOM,
806    }
807}
808
809/// Write `operand` for a binary operator, parenthesizing it iff `needs_parens`.
810fn write_binary_operand<W: fmt::Write, T: AstInfo>(
811    f: &mut AstFormatter<W>,
812    operand: &Expr<T>,
813    needs_parens: bool,
814) {
815    if needs_parens {
816        f.write_str("(");
817        f.write_node(operand);
818        f.write_str(")");
819    } else {
820        f.write_node(operand);
821    }
822}
823
824/// Whether `expr` prints in a *self-delimiting* form — atomic, or wrapped in its
825/// own brackets/parens (`name(...)`, `(…)`, `ARRAY[…]`, `CASE … END`, …) — so it
826/// is safe to print immediately to the left of a tight postfix operator (`::`,
827/// `COLLATE`, or the `IN` delimiter of the `position(<needle> IN …)` special
828/// form) without the operator re-associating into the expression's spine.
829///
830/// Anything with an exposed operator spine is *not* self-delimiting: a tight
831/// postfix would bind to its rightmost sub-operand (`a + b COLLATE c` parses as
832/// `a + (b COLLATE c)`), and the `position` `IN` delimiter would split on an
833/// inner `IN`/comparison (`a IN (q) ->> b`). Callers must parenthesize / fall
834/// back for those. Postfix forms (`::`/`COLLATE`/`[…]`) are self-delimiting only
835/// when their own inner operand is.
836fn prints_self_delimiting<T: AstInfo>(expr: &Expr<T>) -> bool {
837    match expr {
838        Expr::Value(_)
839        | Expr::Identifier(_)
840        | Expr::QualifiedWildcard(_)
841        | Expr::Parameter(_)
842        | Expr::Function(_)
843        | Expr::HomogenizingFunction { .. }
844        | Expr::NullIf { .. }
845        | Expr::Subquery(_)
846        | Expr::Exists(_)
847        | Expr::Nested(_)
848        | Expr::Array(_)
849        | Expr::ArraySubquery(_)
850        | Expr::List(_)
851        | Expr::ListSubquery(_)
852        | Expr::Map(_)
853        | Expr::MapSubquery(_)
854        | Expr::Case { .. }
855        | Expr::Row { .. } => true,
856        // The postfix `::` / `COLLATE` / `[…]` forms print as `<inner><suffix>`,
857        // so they are safe only when their inner operand is.
858        Expr::Cast { expr, .. } | Expr::Collate { expr, .. } | Expr::Subscript { expr, .. } => {
859            prints_self_delimiting(expr)
860        }
861        _ => false,
862    }
863}
864
865/// Whether the operand of a prefix operator (an `Op` with no second operand)
866/// must be parenthesized so the printed expression reparses to the same tree.
867/// Both printers (`AstDisplay` and `mz-sql-pretty`) must use it, so they agree.
868pub fn prefix_operand_needs_parens<T: AstInfo>(op: &Op, operand: &Expr<T>) -> bool {
869    if unary_prec(op) == prec::PREFIX {
870        bare_prefix_operand_needs_parens(operand)
871    } else {
872        // An `Other`-level prefix (`~`, a namespaced `OPERATOR(...)`) reparses
873        // its operand at `Other`, so the operand re-associates exactly when its
874        // left spine exposes that level or looser, as for the right operand of
875        // a binary operator.
876        left_edge(operand) <= prec::OTHER
877    }
878}
879
880/// Whether the operand of a bare prefix `-`/`+` must be parenthesized to
881/// round-trip. Such a prefix op binds *tighter* than `COLLATE`/`AT TIME ZONE`
882/// and the binary/comparison operators, but *looser* than the postfix
883/// `::`/`[…]` forms, and `- <number>` additionally lexes as a negative literal.
884/// So peel the tight postfixes (`::`/`[…]`). If the chain bottoms out at a
885/// numeric literal, the sign would fold into it, and if it bottoms out at
886/// anything other than a self-delimiting non-`COLLATE` primary (a `COLLATE`, a
887/// binary op, …), the prefix op would re-associate. Both need parens.
888/// (`a + b COLLATE c` reparses as `a + (b COLLATE c)`, and `- x COLLATE c` as
889/// `(- x) COLLATE c`.)
890fn bare_prefix_operand_needs_parens<T: AstInfo>(operand: &Expr<T>) -> bool {
891    let mut e = operand;
892    let mut saw_postfix = false;
893    loop {
894        match e {
895            Expr::Cast { expr, .. } | Expr::Subscript { expr, .. } => {
896                saw_postfix = true;
897                e = expr.as_ref();
898            }
899            Expr::Value(Value::Number(_)) => return saw_postfix,
900            // Another prefix operator (`+ + x`, `- ~ x`, `NOT NOT x`) stacks
901            // directly: prefix operators don't re-associate, and the inner
902            // operator symbol sits between the outer one and any digit so there
903            // is no `- <number>` fold. Always safe — and crucially, NOT adding
904            // parens here keeps deep unary chains from exploding the nesting
905            // depth (and overflowing the stack) on reparse.
906            Expr::Op { expr2: None, .. } | Expr::Not { .. } => return false,
907            // Self-delimiting, but a top-level `COLLATE` binds looser than the
908            // prefix op, so it (unlike `::`/`[…]`) is not safe here.
909            _ => return !(prints_self_delimiting(e) && !matches!(e, Expr::Collate { .. })),
910        }
911    }
912}
913
914/// Write `expr` as the receiver of a `[…]` subscript. An unparenthesized
915/// `Identifier(["map"])` reparses as `Token::Keyword(MAP)` followed by `[`,
916/// which dispatches to `parse_map` (the map-literal grammar) instead of a
917/// regular subscript. Parenthesize identifiers whose last component is a
918/// context-sensitive keyword so the round trip stays an identifier subscript.
919fn write_subscript_receiver<W: fmt::Write, T: AstInfo>(f: &mut AstFormatter<W>, expr: &Expr<T>) {
920    let needs_parens = match expr {
921        // A bare keyword identifier (`map`, `list`, …) dispatches to the
922        // map/list-literal grammar before `[`, so it needs parens even though
923        // identifiers are otherwise safe receivers.
924        Expr::Identifier(idents) => idents
925            .last()
926            .and_then(|id| id.as_keyword())
927            .map(|kw| kw.is_context_sensitive_keyword())
928            .unwrap_or(false),
929        // Self-delimiting primaries, the bracketed collections, and the postfix
930        // forms that end in an identifier or `)` are safe: a following `[…]`
931        // attaches to the whole receiver as a fresh subscript.
932        Expr::QualifiedWildcard(_)
933        | Expr::Parameter(_)
934        | Expr::Value(_)
935        | Expr::Function(_)
936        | Expr::HomogenizingFunction { .. }
937        | Expr::NullIf { .. }
938        | Expr::Nested(_)
939        | Expr::Subquery(_)
940        | Expr::Exists(_)
941        | Expr::Case { .. }
942        | Expr::Row { .. }
943        | Expr::Array(_)
944        | Expr::ArraySubquery(_)
945        | Expr::List(_)
946        | Expr::ListSubquery(_)
947        | Expr::Map(_)
948        | Expr::MapSubquery(_)
949        | Expr::FieldAccess { .. }
950        | Expr::WildcardAccess(_)
951        | Expr::Collate { .. } => false,
952        // `Cast`: the type parser swallows a following `[…]` as an array suffix
953        // (`a::int4[1]` is `a` cast to `int4[]`, not a subscript of `a::int4`).
954        // `Subscript`: consecutive `[…]` flatten into one node (`a[1][2]` is a
955        // single subscript), so a nested subscript receiver must be parenthesized
956        // to stay nested. Everything else (operators, `IS`/`LIKE`/… constructs)
957        // binds looser than `[` and would re-associate, so parenthesize by default.
958        _ => true,
959    };
960    if needs_parens {
961        f.write_str("(");
962        f.write_node(expr);
963        f.write_str(")");
964    } else {
965        f.write_node(expr);
966    }
967}
968
969impl<T: AstInfo> Expr<T> {
970    pub fn null() -> Expr<T> {
971        Expr::Value(Value::Null)
972    }
973
974    pub fn number<S>(n: S) -> Expr<T>
975    where
976        S: Into<String>,
977    {
978        Expr::Value(Value::Number(n.into()))
979    }
980
981    pub fn negate(self) -> Expr<T> {
982        Expr::Not {
983            expr: Box::new(self),
984        }
985    }
986
987    pub fn and(self, right: Expr<T>) -> Expr<T> {
988        Expr::And {
989            left: Box::new(self),
990            right: Box::new(right),
991        }
992    }
993
994    pub fn or(self, right: Expr<T>) -> Expr<T> {
995        Expr::Or {
996            left: Box::new(self),
997            right: Box::new(right),
998        }
999    }
1000
1001    pub fn binop(self, op: Op, right: Expr<T>) -> Expr<T> {
1002        Expr::Op {
1003            op,
1004            expr1: Box::new(self),
1005            expr2: Some(Box::new(right)),
1006        }
1007    }
1008
1009    pub fn lt(self, right: Expr<T>) -> Expr<T> {
1010        self.binop(Op::bare("<"), right)
1011    }
1012
1013    pub fn lt_eq(self, right: Expr<T>) -> Expr<T> {
1014        self.binop(Op::bare("<="), right)
1015    }
1016
1017    pub fn gt(self, right: Expr<T>) -> Expr<T> {
1018        self.binop(Op::bare(">"), right)
1019    }
1020
1021    pub fn gt_eq(self, right: Expr<T>) -> Expr<T> {
1022        self.binop(Op::bare(">="), right)
1023    }
1024
1025    pub fn equals(self, right: Expr<T>) -> Expr<T> {
1026        self.binop(Op::bare("="), right)
1027    }
1028
1029    pub fn not_equals(self, right: Expr<T>) -> Expr<T> {
1030        self.binop(Op::bare("<>"), right)
1031    }
1032
1033    pub fn minus(self, right: Expr<T>) -> Expr<T> {
1034        self.binop(Op::bare("-"), right)
1035    }
1036
1037    pub fn multiply(self, right: Expr<T>) -> Expr<T> {
1038        self.binop(Op::bare("*"), right)
1039    }
1040
1041    pub fn modulo(self, right: Expr<T>) -> Expr<T> {
1042        self.binop(Op::bare("%"), right)
1043    }
1044
1045    pub fn divide(self, right: Expr<T>) -> Expr<T> {
1046        self.binop(Op::bare("/"), right)
1047    }
1048
1049    pub fn cast(self, data_type: T::DataType) -> Expr<T> {
1050        Expr::Cast {
1051            expr: Box::new(self),
1052            data_type,
1053        }
1054    }
1055
1056    pub fn call(name: T::ItemName, args: Vec<Expr<T>>) -> Expr<T> {
1057        Expr::Function(Function {
1058            name,
1059            args: FunctionArgs::args(args),
1060            filter: None,
1061            over: None,
1062            distinct: false,
1063        })
1064    }
1065
1066    pub fn call_nullary(name: T::ItemName) -> Expr<T> {
1067        Expr::call(name, vec![])
1068    }
1069
1070    pub fn call_unary(self, name: T::ItemName) -> Expr<T> {
1071        Expr::call(name, vec![self])
1072    }
1073
1074    pub fn take(&mut self) -> Expr<T> {
1075        mem::replace(self, Expr::Identifier(vec![]))
1076    }
1077}
1078
1079/// A reference to an operator.
1080#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1081pub struct Op {
1082    /// Any namespaces that preceded the operator.
1083    pub namespace: Option<Vec<Ident>>,
1084    /// The operator itself.
1085    pub op: String,
1086}
1087
1088impl AstDisplay for Op {
1089    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1090        if let Some(namespace) = &self.namespace {
1091            f.write_str("OPERATOR(");
1092            for name in namespace {
1093                f.write_node(name);
1094                f.write_str(".");
1095            }
1096            f.write_str(&self.op);
1097            f.write_str(")");
1098        } else {
1099            f.write_str(&self.op)
1100        }
1101    }
1102}
1103impl_display!(Op);
1104
1105impl Op {
1106    /// Constructs a new unqualified operator reference.
1107    pub fn bare<S>(op: S) -> Op
1108    where
1109        S: Into<String>,
1110    {
1111        Op {
1112            namespace: None,
1113            op: op.into(),
1114        }
1115    }
1116}
1117
1118#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1119pub enum HomogenizingFunction {
1120    Coalesce,
1121    Greatest,
1122    Least,
1123}
1124
1125impl AstDisplay for HomogenizingFunction {
1126    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1127        match self {
1128            HomogenizingFunction::Coalesce => f.write_str("COALESCE"),
1129            HomogenizingFunction::Greatest => f.write_str("GREATEST"),
1130            HomogenizingFunction::Least => f.write_str("LEAST"),
1131        }
1132    }
1133}
1134impl_display!(HomogenizingFunction);
1135
1136#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1137pub struct MapEntry<T: AstInfo> {
1138    pub key: Expr<T>,
1139    pub value: Expr<T>,
1140}
1141
1142impl<T: AstInfo> AstDisplay for MapEntry<T> {
1143    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1144        f.write_node(&self.key);
1145        f.write_str(" => ");
1146        f.write_node(&self.value);
1147    }
1148}
1149impl_display_t!(MapEntry);
1150
1151#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1152pub struct SubscriptPosition<T: AstInfo> {
1153    pub start: Option<Expr<T>>,
1154    pub end: Option<Expr<T>>,
1155    // i.e. did this subscript include a colon
1156    pub explicit_slice: bool,
1157}
1158
1159impl<T: AstInfo> AstDisplay for SubscriptPosition<T> {
1160    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1161        if let Some(start) = &self.start {
1162            f.write_node(start);
1163        }
1164        if self.explicit_slice {
1165            f.write_str(":");
1166            if let Some(end) = &self.end {
1167                f.write_node(end);
1168            }
1169        }
1170    }
1171}
1172impl_display_t!(SubscriptPosition);
1173
1174/// A window specification (i.e. `OVER (PARTITION BY .. ORDER BY .. etc.)`)
1175/// Includes potential IGNORE NULLS or RESPECT NULLS from before the OVER clause.
1176#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1177pub struct WindowSpec<T: AstInfo> {
1178    pub partition_by: Vec<Expr<T>>,
1179    pub order_by: Vec<OrderByExpr<T>>,
1180    pub window_frame: Option<WindowFrame>,
1181    // Note that IGNORE NULLS and RESPECT NULLS are mutually exclusive. We validate that not both
1182    // are present during HIR planning.
1183    pub ignore_nulls: bool,
1184    pub respect_nulls: bool,
1185}
1186
1187impl<T: AstInfo> AstDisplay for WindowSpec<T> {
1188    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1189        if self.ignore_nulls {
1190            f.write_str(" IGNORE NULLS");
1191        }
1192        if self.respect_nulls {
1193            f.write_str(" RESPECT NULLS");
1194        }
1195        f.write_str(" OVER (");
1196        let mut delim = "";
1197        if !self.partition_by.is_empty() {
1198            delim = " ";
1199            f.write_str("PARTITION BY ");
1200            f.write_node(&display::comma_separated(&self.partition_by));
1201        }
1202        if !self.order_by.is_empty() {
1203            f.write_str(delim);
1204            delim = " ";
1205            f.write_str("ORDER BY ");
1206            f.write_node(&display::comma_separated(&self.order_by));
1207        }
1208        if let Some(window_frame) = &self.window_frame {
1209            if let Some(end_bound) = &window_frame.end_bound {
1210                f.write_str(delim);
1211                f.write_node(&window_frame.units);
1212                f.write_str(" BETWEEN ");
1213                f.write_node(&window_frame.start_bound);
1214                f.write_str(" AND ");
1215                f.write_node(&*end_bound);
1216            } else {
1217                f.write_str(delim);
1218                f.write_node(&window_frame.units);
1219                f.write_str(" ");
1220                f.write_node(&window_frame.start_bound);
1221            }
1222        }
1223        f.write_str(")");
1224    }
1225}
1226impl_display_t!(WindowSpec);
1227
1228/// Specifies the data processed by a window function, e.g.
1229/// `RANGE UNBOUNDED PRECEDING` or `ROWS BETWEEN 5 PRECEDING AND CURRENT ROW`.
1230///
1231/// Note: The parser does not validate the specified bounds; the caller should
1232/// reject invalid bounds like `ROWS UNBOUNDED FOLLOWING` before execution.
1233#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1234pub struct WindowFrame {
1235    pub units: WindowFrameUnits,
1236    pub start_bound: WindowFrameBound,
1237    /// The right bound of the `BETWEEN .. AND` clause. The end bound of `None`
1238    /// indicates the shorthand form (e.g. `ROWS 1 PRECEDING`), which must
1239    /// behave the same as `end_bound = WindowFrameBound::CurrentRow`.
1240    pub end_bound: Option<WindowFrameBound>,
1241    // TBD: EXCLUDE
1242}
1243
1244#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1245pub enum WindowFrameUnits {
1246    Rows,
1247    Range,
1248    Groups,
1249}
1250
1251impl AstDisplay for WindowFrameUnits {
1252    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1253        f.write_str(match self {
1254            WindowFrameUnits::Rows => "ROWS",
1255            WindowFrameUnits::Range => "RANGE",
1256            WindowFrameUnits::Groups => "GROUPS",
1257        })
1258    }
1259}
1260impl_display!(WindowFrameUnits);
1261
1262/// Specifies [WindowFrame]'s `start_bound` and `end_bound`
1263#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1264pub enum WindowFrameBound {
1265    /// `CURRENT ROW`
1266    CurrentRow,
1267    /// `<N> PRECEDING` or `UNBOUNDED PRECEDING`
1268    Preceding(Option<u64>),
1269    /// `<N> FOLLOWING` or `UNBOUNDED FOLLOWING`.
1270    Following(Option<u64>),
1271}
1272
1273impl AstDisplay for WindowFrameBound {
1274    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1275        match self {
1276            WindowFrameBound::CurrentRow => f.write_str("CURRENT ROW"),
1277            WindowFrameBound::Preceding(None) => f.write_str("UNBOUNDED PRECEDING"),
1278            WindowFrameBound::Following(None) => f.write_str("UNBOUNDED FOLLOWING"),
1279            WindowFrameBound::Preceding(Some(n)) => {
1280                f.write_str(n);
1281                f.write_str(" PRECEDING");
1282            }
1283            WindowFrameBound::Following(Some(n)) => {
1284                f.write_str(n);
1285                f.write_str(" FOLLOWING");
1286            }
1287        }
1288    }
1289}
1290impl_display!(WindowFrameBound);
1291
1292/// A function call
1293#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1294pub struct Function<T: AstInfo> {
1295    pub name: T::ItemName,
1296    pub args: FunctionArgs<T>,
1297    // aggregate functions may specify e.g. `COUNT(DISTINCT X) FILTER (WHERE ...)`
1298    pub filter: Option<Box<Expr<T>>>,
1299    pub over: Option<WindowSpec<T>>,
1300    // aggregate functions may specify eg `COUNT(DISTINCT x)`
1301    pub distinct: bool,
1302}
1303
1304impl<T: AstInfo> AstDisplay for Function<T> {
1305    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1306        self.fmt_call(f, true);
1307    }
1308}
1309
1310impl<T: AstInfo> Function<T> {
1311    /// Render this call in table-function position (`FROM f(...)`, `ROWS FROM
1312    /// (f(...))`), where the `extract(a FROM b)` / `position(a IN b)` special
1313    /// forms are *not* valid syntax — only the scalar-expression parser
1314    /// dispatches to them. Forces the plain comma form (with the name quoted
1315    /// to dodge the special grammar) so the round trip stays stable.
1316    pub(crate) fn fmt_table_call<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1317        self.fmt_call(f, false);
1318    }
1319
1320    fn fmt_call<W: fmt::Write>(&self, f: &mut AstFormatter<W>, allow_special_form: bool) {
1321        // This block handles printing function calls that have special parsing. In stable mode, the
1322        // name is quoted and so won't get the special parsing. We only need to print the special
1323        // formats in non-stable mode.
1324        //
1325        // The special forms (`position(a IN b)`, `extract(field FROM source)`)
1326        // have no syntax for `DISTINCT`, a within-group `ORDER BY`, a `FILTER`,
1327        // or an `OVER` window. A call literally named `"position"`/`"extract"`
1328        // that carries any of those modifiers (only reachable via the quoted
1329        // name — the real special grammar doesn't accept them) must therefore
1330        // fall through to the plain quoted-call form, or the special form
1331        // silently drops them on display.
1332        let has_call_modifiers = self.distinct
1333            || self.filter.is_some()
1334            || self.over.is_some()
1335            || matches!(&self.args, FunctionArgs::Args { order_by, .. } if !order_by.is_empty());
1336        if allow_special_form && !f.stable() && !has_call_modifiers {
1337            let special: Option<(&str, &[Option<Keyword>])> =
1338                match self.name.to_ast_string_stable().as_str() {
1339                    // `extract(field FROM source)` parses `field` into a string
1340                    // literal, so the special form only round-trips when arg0 is
1341                    // a string. A generic `"extract"(a, b)` with a non-string
1342                    // first arg must use the plain (quoted) call form.
1343                    r#""extract""#
1344                        if self.args.len() == Some(2)
1345                            && matches!(self.args.first(), Some(Expr::Value(Value::String(_)))) =>
1346                    {
1347                        Some(("extract", &[None, Some(FROM)]))
1348                    }
1349                    // `position(<needle> IN <haystack>)` parses the needle at
1350                    // `Precedence::Like`, so a low-precedence needle (`NOT`, a
1351                    // comparison, `IS`, a boolean connective, a quantified
1352                    // comparison, ...) printed bare before the `IN` would swallow
1353                    // or stop short of the delimiter. Only use the special form
1354                    // with a needle that's safe to sit left of `IN`.
1355                    r#""position""#
1356                        if self.args.len() == Some(2)
1357                            && self.args.first().is_some_and(prints_self_delimiting) =>
1358                    {
1359                        Some(("position", &[None, Some(IN)]))
1360                    }
1361
1362                    // "trim" doesn't need to appear here because it changes the function name (to
1363                    // "btrim", "ltrim", or "rtrim"), but only "trim" is parsed specially. "substring"
1364                    // supports comma-delimited arguments, so doesn't need to be here.
1365                    _ => None,
1366                };
1367            if let Some((name, kws)) = special {
1368                f.write_str(name);
1369                f.write_str("(");
1370                self.args.intersperse_function_argument_keywords(f, kws);
1371                f.write_str(")");
1372                return;
1373            }
1374        }
1375
1376        // If the function name clashes with a keyword that has its own special
1377        // parser form, an unquoted name on reparse would trigger the
1378        // special-grammar parser instead of a regular function call. Emit the
1379        // always-quoted stable form so the regular function-call path is
1380        // preserved. The list tracks the `(Token::Keyword(KW), Some(Token::LParen))`
1381        // dispatch in `parse_prefix` (array, coalesce, ...); add a new entry
1382        // whenever a keyword grows special-grammar parens. (The `ANY`/`ALL`/`SOME`
1383        // quantifier keywords are handled more generally by `can_be_printed_bare`,
1384        // since they're also unsafe as bare identifiers, e.g. `0 # some`.)
1385        let name_stable = self.name.to_ast_string_stable();
1386        let needs_quote_to_disambiguate = matches!(
1387            name_stable.as_str(),
1388            r#""array""#
1389                | r#""coalesce""#
1390                | r#""exists""#
1391                | r#""extract""#
1392                | r#""greatest""#
1393                | r#""least""#
1394                | r#""list""#
1395                | r#""map""#
1396                | r#""normalize""#
1397                | r#""nullif""#
1398                | r#""operator""#
1399                | r#""position""#
1400                | r#""row""#
1401                | r#""substring""#
1402                | r#""trim""#
1403        );
1404        if needs_quote_to_disambiguate {
1405            f.write_str(&name_stable);
1406        } else {
1407            f.write_node(&self.name);
1408        }
1409        f.write_str("(");
1410        if self.distinct {
1411            f.write_str("DISTINCT ")
1412        }
1413        f.write_node(&self.args);
1414        f.write_str(")");
1415        if let Some(filter) = &self.filter {
1416            f.write_str(" FILTER (WHERE ");
1417            f.write_node(&filter);
1418            f.write_str(")");
1419        }
1420        if let Some(o) = &self.over {
1421            f.write_node(o);
1422        }
1423    }
1424}
1425impl_display_t!(Function);
1426
1427/// Arguments for a function call.
1428#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1429pub enum FunctionArgs<T: AstInfo> {
1430    /// The special star argument, as in `count(*)`.
1431    Star,
1432    /// A normal list of arguments.
1433    Args {
1434        args: Vec<Expr<T>>,
1435        order_by: Vec<OrderByExpr<T>>,
1436    },
1437}
1438
1439impl<T: AstInfo> FunctionArgs<T> {
1440    pub fn args(args: Vec<Expr<T>>) -> Self {
1441        Self::Args {
1442            args,
1443            order_by: vec![],
1444        }
1445    }
1446
1447    /// The first positional argument, if any (the `*` form has none).
1448    pub fn first(&self) -> Option<&Expr<T>> {
1449        match self {
1450            FunctionArgs::Star => None,
1451            FunctionArgs::Args { args, .. } => args.first(),
1452        }
1453    }
1454
1455    /// Returns the number of arguments. Star (`*`) is None.
1456    pub fn len(&self) -> Option<usize> {
1457        match self {
1458            FunctionArgs::Star => None,
1459            FunctionArgs::Args { args, .. } => Some(args.len()),
1460        }
1461    }
1462
1463    /// Prints associated keywords before each argument
1464    fn intersperse_function_argument_keywords<W: fmt::Write>(
1465        &self,
1466        f: &mut AstFormatter<W>,
1467        kws: &[Option<Keyword>],
1468    ) {
1469        let args = match self {
1470            FunctionArgs::Star => unreachable!(),
1471            FunctionArgs::Args { args, .. } => args,
1472        };
1473        soft_assert_eq_or_log!(args.len(), kws.len());
1474        let mut delim = "";
1475        for (arg, kw) in args.iter().zip_eq(kws) {
1476            if let Some(kw) = kw {
1477                f.write_str(delim);
1478                f.write_str(kw.as_str());
1479                delim = " ";
1480            }
1481            f.write_str(delim);
1482            f.write_node(arg);
1483            delim = " ";
1484        }
1485    }
1486}
1487
1488impl<T: AstInfo> AstDisplay for FunctionArgs<T> {
1489    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1490        match self {
1491            FunctionArgs::Star => f.write_str("*"),
1492            FunctionArgs::Args { args, order_by } => {
1493                f.write_node(&display::comma_separated(args));
1494                if !order_by.is_empty() {
1495                    f.write_str(" ORDER BY ");
1496                    f.write_node(&display::comma_separated(order_by));
1497                }
1498            }
1499        }
1500    }
1501}
1502impl_display_t!(FunctionArgs);
1503
1504#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1505pub enum IsExprConstruct<T: AstInfo> {
1506    Null,
1507    True,
1508    False,
1509    Unknown,
1510    DistinctFrom(Box<Expr<T>>),
1511}
1512
1513impl<T: AstInfo> AstDisplay for IsExprConstruct<T> {
1514    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1515        match self {
1516            IsExprConstruct::Null => f.write_str("NULL"),
1517            IsExprConstruct::True => f.write_str("TRUE"),
1518            IsExprConstruct::False => f.write_str("FALSE"),
1519            IsExprConstruct::Unknown => f.write_str("UNKNOWN"),
1520            IsExprConstruct::DistinctFrom(e) => {
1521                f.write_str("DISTINCT FROM ");
1522                e.fmt(f);
1523            }
1524        }
1525    }
1526}
1527impl_display_t!(IsExprConstruct);