Skip to main content

sqlparser/ast/
query.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18#[cfg(not(feature = "std"))]
19use alloc::{boxed::Box, vec::Vec};
20
21use helpers::attached_token::AttachedToken;
22#[cfg(feature = "serde")]
23use serde::{Deserialize, Serialize};
24
25#[cfg(feature = "visitor")]
26use sqlparser_derive::{Visit, VisitMut};
27
28use crate::{
29    ast::*,
30    display_utils::{indented_list, SpaceOrNewline},
31    tokenizer::{Token, TokenWithSpan},
32};
33
34/// The most complete variant of a `SELECT` query expression, optionally
35/// including `WITH`, `UNION` / other set operations, and `ORDER BY`.
36#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
37#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
38#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
39#[cfg_attr(feature = "visitor", visit(with = "visit_query"))]
40pub struct Query {
41    /// WITH (common table expressions, or CTEs)
42    pub with: Option<With>,
43    /// SELECT or UNION / EXCEPT / INTERSECT
44    pub body: Box<SetExpr>,
45    /// ORDER BY
46    pub order_by: Option<OrderBy>,
47    /// `LIMIT ... OFFSET ... | LIMIT <offset>, <limit>`
48    pub limit_clause: Option<LimitClause>,
49    /// `FETCH { FIRST | NEXT } <N> [ PERCENT ] { ROW | ROWS } | { ONLY | WITH TIES }`
50    pub fetch: Option<Fetch>,
51    /// `FOR { UPDATE | SHARE } [ OF table_name ] [ SKIP LOCKED | NOWAIT ]`
52    pub locks: Vec<LockClause>,
53    /// `FOR XML { RAW | AUTO | EXPLICIT | PATH } [ , ELEMENTS ]`
54    /// `FOR JSON { AUTO | PATH } [ , INCLUDE_NULL_VALUES ]`
55    /// (MSSQL-specific)
56    pub for_clause: Option<ForClause>,
57    /// ClickHouse syntax: `SELECT * FROM t SETTINGS key1 = value1, key2 = value2`
58    ///
59    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select#settings-in-select-query)
60    pub settings: Option<Vec<Setting>>,
61    /// `SELECT * FROM t FORMAT JSONCompact`
62    ///
63    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/format)
64    /// (ClickHouse-specific)
65    pub format_clause: Option<FormatClause>,
66
67    /// Pipe operator
68    pub pipe_operators: Vec<PipeOperator>,
69}
70
71impl fmt::Display for Query {
72    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73        if let Some(ref with) = self.with {
74            with.fmt(f)?;
75            SpaceOrNewline.fmt(f)?;
76        }
77        self.body.fmt(f)?;
78        if let Some(ref order_by) = self.order_by {
79            f.write_str(" ")?;
80            order_by.fmt(f)?;
81        }
82
83        if let Some(ref limit_clause) = self.limit_clause {
84            limit_clause.fmt(f)?;
85        }
86        if let Some(ref settings) = self.settings {
87            f.write_str(" SETTINGS ")?;
88            display_comma_separated(settings).fmt(f)?;
89        }
90        if let Some(ref fetch) = self.fetch {
91            f.write_str(" ")?;
92            fetch.fmt(f)?;
93        }
94        if !self.locks.is_empty() {
95            f.write_str(" ")?;
96            display_separated(&self.locks, " ").fmt(f)?;
97        }
98        if let Some(ref for_clause) = self.for_clause {
99            f.write_str(" ")?;
100            for_clause.fmt(f)?;
101        }
102        if let Some(ref format) = self.format_clause {
103            f.write_str(" ")?;
104            format.fmt(f)?;
105        }
106        for pipe_operator in &self.pipe_operators {
107            f.write_str(" |> ")?;
108            pipe_operator.fmt(f)?;
109        }
110        Ok(())
111    }
112}
113
114/// Query syntax for ClickHouse ADD PROJECTION statement.
115/// Its syntax is similar to SELECT statement, but it is used to add a new projection to a table.
116/// Syntax is `SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY]`
117///
118/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/projection#add-projection)
119#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
120#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
121#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
122pub struct ProjectionSelect {
123    /// The list of projected select items.
124    pub projection: Vec<SelectItem>,
125    /// Optional `ORDER BY` clause for the projection-select.
126    pub order_by: Option<OrderBy>,
127    /// Optional `GROUP BY` clause for the projection-select.
128    pub group_by: Option<GroupByExpr>,
129}
130
131impl fmt::Display for ProjectionSelect {
132    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133        write!(f, "SELECT {}", display_comma_separated(&self.projection))?;
134        if let Some(ref group_by) = self.group_by {
135            write!(f, " {group_by}")?;
136        }
137        if let Some(ref order_by) = self.order_by {
138            write!(f, " {order_by}")?;
139        }
140        Ok(())
141    }
142}
143
144/// A node in a tree, representing a "query body" expression, roughly:
145/// `SELECT ... [ {UNION|EXCEPT|INTERSECT} SELECT ...]`
146#[allow(clippy::large_enum_variant)]
147#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
148#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
149#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
150pub enum SetExpr {
151    /// Restricted SELECT .. FROM .. HAVING (no ORDER BY or set operations)
152    Select(Box<Select>),
153    /// Parenthesized SELECT subquery, which may include more set operations
154    /// in its body and an optional ORDER BY / LIMIT.
155    Query(Box<Query>),
156    /// UNION/EXCEPT/INTERSECT of two queries
157    /// A set operation combining two query expressions.
158    SetOperation {
159        /// Left operand of the set operation.
160        left: Box<SetExpr>,
161        /// The set operator used (e.g. `UNION`, `EXCEPT`).
162        op: SetOperator,
163        /// Optional quantifier (`ALL`, `DISTINCT`, etc.).
164        set_quantifier: SetQuantifier,
165        /// Right operand of the set operation.
166        right: Box<SetExpr>,
167    },
168    /// `VALUES (...)`
169    Values(Values),
170    /// `INSERT` statement
171    Insert(Statement),
172    /// `UPDATE` statement
173    Update(Statement),
174    /// `DELETE` statement
175    Delete(Statement),
176    /// `MERGE` statement
177    Merge(Statement),
178    /// `TABLE` command
179    Table(Box<Table>),
180}
181
182impl SetExpr {
183    /// If this `SetExpr` is a `SELECT`, returns the [`Select`].
184    pub fn as_select(&self) -> Option<&Select> {
185        if let Self::Select(select) = self {
186            Some(&**select)
187        } else {
188            None
189        }
190    }
191}
192
193impl fmt::Display for SetExpr {
194    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
195        match self {
196            SetExpr::Select(s) => s.fmt(f),
197            SetExpr::Query(q) => {
198                f.write_str("(")?;
199                q.fmt(f)?;
200                f.write_str(")")
201            }
202            SetExpr::Values(v) => v.fmt(f),
203            SetExpr::Insert(v) => v.fmt(f),
204            SetExpr::Update(v) => v.fmt(f),
205            SetExpr::Delete(v) => v.fmt(f),
206            SetExpr::Merge(v) => v.fmt(f),
207            SetExpr::Table(t) => t.fmt(f),
208            SetExpr::SetOperation {
209                left,
210                right,
211                op,
212                set_quantifier,
213            } => {
214                left.fmt(f)?;
215                SpaceOrNewline.fmt(f)?;
216                op.fmt(f)?;
217                match set_quantifier {
218                    SetQuantifier::All
219                    | SetQuantifier::Distinct
220                    | SetQuantifier::ByName
221                    | SetQuantifier::AllByName
222                    | SetQuantifier::DistinctByName => {
223                        f.write_str(" ")?;
224                        set_quantifier.fmt(f)?;
225                    }
226                    SetQuantifier::None => {}
227                }
228                SpaceOrNewline.fmt(f)?;
229                right.fmt(f)?;
230                Ok(())
231            }
232        }
233    }
234}
235
236#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
237#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
238#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
239/// A set operator for combining two `SetExpr`s.
240pub enum SetOperator {
241    /// `UNION` set operator
242    Union,
243    /// `EXCEPT` set operator
244    Except,
245    /// `INTERSECT` set operator
246    Intersect,
247    /// `MINUS` set operator (non-standard)
248    Minus,
249}
250
251impl fmt::Display for SetOperator {
252    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
253        f.write_str(match self {
254            SetOperator::Union => "UNION",
255            SetOperator::Except => "EXCEPT",
256            SetOperator::Intersect => "INTERSECT",
257            SetOperator::Minus => "MINUS",
258        })
259    }
260}
261
262/// A quantifier for [SetOperator].
263// TODO: Restrict parsing specific SetQuantifier in some specific dialects.
264// For example, BigQuery does not support `DISTINCT` for `EXCEPT` and `INTERSECT`
265#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
266#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
267#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
268pub enum SetQuantifier {
269    /// `ALL` quantifier
270    All,
271    /// `DISTINCT` quantifier
272    Distinct,
273    /// `BY NAME` quantifier
274    ByName,
275    /// `ALL BY NAME` quantifier
276    AllByName,
277    /// `DISTINCT BY NAME` quantifier
278    DistinctByName,
279    /// No quantifier specified
280    None,
281}
282
283impl fmt::Display for SetQuantifier {
284    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
285        match self {
286            SetQuantifier::All => write!(f, "ALL"),
287            SetQuantifier::Distinct => write!(f, "DISTINCT"),
288            SetQuantifier::ByName => write!(f, "BY NAME"),
289            SetQuantifier::AllByName => write!(f, "ALL BY NAME"),
290            SetQuantifier::DistinctByName => write!(f, "DISTINCT BY NAME"),
291            SetQuantifier::None => Ok(()),
292        }
293    }
294}
295
296#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
297#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
298/// A [`TABLE` command]( https://www.postgresql.org/docs/current/sql-select.html#SQL-TABLE)
299#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
300/// A (possibly schema-qualified) table reference used in `FROM` clauses.
301pub struct Table {
302    /// Optional table name (absent for e.g. `TABLE` command without argument).
303    pub table_name: Option<String>,
304    /// Optional schema/catalog name qualifying the table.
305    pub schema_name: Option<String>,
306}
307
308impl fmt::Display for Table {
309    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
310        if let Some(ref table_name) = self.table_name {
311            if let Some(ref schema_name) = self.schema_name {
312                write!(f, "TABLE {}.{}", schema_name, table_name,)?;
313            } else {
314                write!(f, "TABLE {}", table_name)?;
315            }
316        } else {
317            write!(f, "TABLE")?;
318        }
319        Ok(())
320    }
321}
322
323/// What did this select look like?
324#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
325#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
326#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
327pub enum SelectFlavor {
328    /// `SELECT *`
329    Standard,
330    /// `FROM ... SELECT *`
331    FromFirst,
332    /// `FROM *`
333    FromFirstNoSelect,
334}
335
336/// MySQL-specific SELECT modifiers that appear after the SELECT keyword.
337///
338/// These modifiers affect query execution and optimization. They can appear in any order after
339/// SELECT and before the column list, can be repeated, and can be interleaved with
340/// DISTINCT/DISTINCTROW/ALL:
341///
342/// ```sql
343/// SELECT
344///     [ALL | DISTINCT | DISTINCTROW]
345///     [HIGH_PRIORITY]
346///     [STRAIGHT_JOIN]
347///     [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
348///     [SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
349///     select_expr [, select_expr] ...
350/// ```
351///
352/// See [MySQL SELECT](https://dev.mysql.com/doc/refman/8.4/en/select.html).
353#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
354#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
355#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
356pub struct SelectModifiers {
357    /// `HIGH_PRIORITY` gives the SELECT higher priority than statements that update a table.
358    ///
359    /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
360    pub high_priority: bool,
361    /// `STRAIGHT_JOIN` forces the optimizer to join tables in the order listed in the FROM clause.
362    ///
363    /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
364    pub straight_join: bool,
365    /// `SQL_SMALL_RESULT` hints that the result set is small, using in-memory temp tables.
366    ///
367    /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
368    pub sql_small_result: bool,
369    /// `SQL_BIG_RESULT` hints that the result set is large, using disk-based temp tables.
370    ///
371    /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
372    pub sql_big_result: bool,
373    /// `SQL_BUFFER_RESULT` forces the result to be put into a temporary table to release locks early.
374    ///
375    /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
376    pub sql_buffer_result: bool,
377    /// `SQL_NO_CACHE` tells MySQL not to cache the query result. (Deprecated in 8.4+.)
378    ///
379    /// <https://dev.mysql.com/doc/refman/8.4/en/select.html>
380    pub sql_no_cache: bool,
381    /// `SQL_CALC_FOUND_ROWS` tells MySQL to calculate the total number of rows. (Deprecated in 8.0.17+.)
382    ///
383    /// - [MySQL SELECT modifiers](https://dev.mysql.com/doc/refman/8.4/en/select.html)
384    /// - [`FOUND_ROWS()`](https://dev.mysql.com/doc/refman/8.4/en/information-functions.html#function_found-rows)
385    pub sql_calc_found_rows: bool,
386}
387
388impl fmt::Display for SelectModifiers {
389    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
390        if self.high_priority {
391            f.write_str(" HIGH_PRIORITY")?;
392        }
393        if self.straight_join {
394            f.write_str(" STRAIGHT_JOIN")?;
395        }
396        if self.sql_small_result {
397            f.write_str(" SQL_SMALL_RESULT")?;
398        }
399        if self.sql_big_result {
400            f.write_str(" SQL_BIG_RESULT")?;
401        }
402        if self.sql_buffer_result {
403            f.write_str(" SQL_BUFFER_RESULT")?;
404        }
405        if self.sql_no_cache {
406            f.write_str(" SQL_NO_CACHE")?;
407        }
408        if self.sql_calc_found_rows {
409            f.write_str(" SQL_CALC_FOUND_ROWS")?;
410        }
411        Ok(())
412    }
413}
414
415impl SelectModifiers {
416    /// Returns true if any of the modifiers are set.
417    pub fn is_any_set(&self) -> bool {
418        // Using irrefutable destructuring to catch fields added in the future
419        let Self {
420            high_priority,
421            straight_join,
422            sql_small_result,
423            sql_big_result,
424            sql_buffer_result,
425            sql_no_cache,
426            sql_calc_found_rows,
427        } = self;
428        *high_priority
429            || *straight_join
430            || *sql_small_result
431            || *sql_big_result
432            || *sql_buffer_result
433            || *sql_no_cache
434            || *sql_calc_found_rows
435    }
436}
437
438/// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may
439/// appear either as the only body item of a `Query`, or as an operand
440/// to a set operation like `UNION`.
441#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
442#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
443#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
444#[cfg_attr(feature = "visitor", visit(with = "visit_select"))]
445pub struct Select {
446    /// Token for the `SELECT` keyword
447    pub select_token: AttachedToken,
448    /// Query optimizer hints
449    ///
450    /// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/optimizer-hints.html)
451    /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Comments.html#GUID-D316D545-89E2-4D54-977F-FC97815CD62E)
452    pub optimizer_hints: Vec<OptimizerHint>,
453    /// `SELECT [DISTINCT] ...`
454    pub distinct: Option<Distinct>,
455    /// MySQL-specific SELECT modifiers.
456    ///
457    /// See [MySQL SELECT](https://dev.mysql.com/doc/refman/8.4/en/select.html).
458    pub select_modifiers: Option<SelectModifiers>,
459    /// MSSQL syntax: `TOP (<N>) [ PERCENT ] [ WITH TIES ]`
460    pub top: Option<Top>,
461    /// Whether the top was located before `ALL`/`DISTINCT`
462    pub top_before_distinct: bool,
463    /// projection expressions
464    pub projection: Vec<SelectItem>,
465    /// Excluded columns from the projection expression which are not specified
466    /// directly after a wildcard.
467    ///
468    /// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_EXCLUDE_list.html)
469    pub exclude: Option<ExcludeSelectItem>,
470    /// INTO
471    pub into: Option<SelectInto>,
472    /// FROM
473    pub from: Vec<TableWithJoins>,
474    /// LATERAL VIEWs
475    pub lateral_views: Vec<LateralView>,
476    /// ClickHouse syntax: `PREWHERE a = 1 WHERE b = 2`,
477    /// and it can be used together with WHERE selection.
478    ///
479    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/prewhere)
480    pub prewhere: Option<Expr>,
481    /// WHERE
482    pub selection: Option<Expr>,
483    /// [START WITH ..] CONNECT BY ..
484    pub connect_by: Vec<ConnectByKind>,
485    /// GROUP BY
486    pub group_by: GroupByExpr,
487    /// CLUSTER BY (Hive)
488    pub cluster_by: Vec<Expr>,
489    /// DISTRIBUTE BY (Hive)
490    pub distribute_by: Vec<Expr>,
491    /// SORT BY (Hive)
492    pub sort_by: Vec<OrderByExpr>,
493    /// HAVING
494    pub having: Option<Expr>,
495    /// WINDOW AS
496    pub named_window: Vec<NamedWindowDefinition>,
497    /// QUALIFY (Snowflake)
498    pub qualify: Option<Expr>,
499    /// The positioning of QUALIFY and WINDOW clauses differ between dialects.
500    /// e.g. BigQuery requires that WINDOW comes after QUALIFY, while DUCKDB accepts
501    /// WINDOW before QUALIFY.
502    /// We accept either positioning and flag the accepted variant.
503    pub window_before_qualify: bool,
504    /// BigQuery syntax: `SELECT AS VALUE | SELECT AS STRUCT`
505    pub value_table_mode: Option<ValueTableMode>,
506    /// Was this a FROM-first query?
507    pub flavor: SelectFlavor,
508}
509
510impl fmt::Display for Select {
511    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
512        match self.flavor {
513            SelectFlavor::Standard => {
514                write!(f, "SELECT")?;
515            }
516            SelectFlavor::FromFirst => {
517                write!(f, "FROM {} SELECT", display_comma_separated(&self.from))?;
518            }
519            SelectFlavor::FromFirstNoSelect => {
520                write!(f, "FROM {}", display_comma_separated(&self.from))?;
521            }
522        }
523
524        for hint in &self.optimizer_hints {
525            f.write_str(" ")?;
526            hint.fmt(f)?;
527        }
528
529        if let Some(value_table_mode) = self.value_table_mode {
530            f.write_str(" ")?;
531            value_table_mode.fmt(f)?;
532        }
533
534        if let Some(ref top) = self.top {
535            if self.top_before_distinct {
536                f.write_str(" ")?;
537                top.fmt(f)?;
538            }
539        }
540        if let Some(ref distinct) = self.distinct {
541            f.write_str(" ")?;
542            distinct.fmt(f)?;
543        }
544        if let Some(ref top) = self.top {
545            if !self.top_before_distinct {
546                f.write_str(" ")?;
547                top.fmt(f)?;
548            }
549        }
550
551        if let Some(ref select_modifiers) = self.select_modifiers {
552            select_modifiers.fmt(f)?;
553        }
554
555        if !self.projection.is_empty() {
556            indented_list(f, &self.projection)?;
557        }
558
559        if let Some(exclude) = &self.exclude {
560            write!(f, " {exclude}")?;
561        }
562
563        if let Some(ref into) = self.into {
564            f.write_str(" ")?;
565            into.fmt(f)?;
566        }
567
568        if self.flavor == SelectFlavor::Standard && !self.from.is_empty() {
569            SpaceOrNewline.fmt(f)?;
570            f.write_str("FROM")?;
571            indented_list(f, &self.from)?;
572        }
573        if !self.lateral_views.is_empty() {
574            for lv in &self.lateral_views {
575                lv.fmt(f)?;
576            }
577        }
578        if let Some(ref prewhere) = self.prewhere {
579            f.write_str(" PREWHERE ")?;
580            prewhere.fmt(f)?;
581        }
582        if let Some(ref selection) = self.selection {
583            SpaceOrNewline.fmt(f)?;
584            f.write_str("WHERE")?;
585            SpaceOrNewline.fmt(f)?;
586            Indent(selection).fmt(f)?;
587        }
588        for clause in &self.connect_by {
589            SpaceOrNewline.fmt(f)?;
590            clause.fmt(f)?;
591        }
592        match &self.group_by {
593            GroupByExpr::All(_) => {
594                SpaceOrNewline.fmt(f)?;
595                self.group_by.fmt(f)?;
596            }
597            GroupByExpr::Expressions(exprs, _) => {
598                if !exprs.is_empty() {
599                    SpaceOrNewline.fmt(f)?;
600                    self.group_by.fmt(f)?;
601                }
602            }
603        }
604        if !self.cluster_by.is_empty() {
605            SpaceOrNewline.fmt(f)?;
606            f.write_str("CLUSTER BY")?;
607            SpaceOrNewline.fmt(f)?;
608            Indent(display_comma_separated(&self.cluster_by)).fmt(f)?;
609        }
610        if !self.distribute_by.is_empty() {
611            SpaceOrNewline.fmt(f)?;
612            f.write_str("DISTRIBUTE BY")?;
613            SpaceOrNewline.fmt(f)?;
614            display_comma_separated(&self.distribute_by).fmt(f)?;
615        }
616        if !self.sort_by.is_empty() {
617            SpaceOrNewline.fmt(f)?;
618            f.write_str("SORT BY")?;
619            SpaceOrNewline.fmt(f)?;
620            Indent(display_comma_separated(&self.sort_by)).fmt(f)?;
621        }
622        if let Some(ref having) = self.having {
623            SpaceOrNewline.fmt(f)?;
624            f.write_str("HAVING")?;
625            SpaceOrNewline.fmt(f)?;
626            Indent(having).fmt(f)?;
627        }
628        if self.window_before_qualify {
629            if !self.named_window.is_empty() {
630                SpaceOrNewline.fmt(f)?;
631                f.write_str("WINDOW")?;
632                SpaceOrNewline.fmt(f)?;
633                display_comma_separated(&self.named_window).fmt(f)?;
634            }
635            if let Some(ref qualify) = self.qualify {
636                SpaceOrNewline.fmt(f)?;
637                f.write_str("QUALIFY")?;
638                SpaceOrNewline.fmt(f)?;
639                qualify.fmt(f)?;
640            }
641        } else {
642            if let Some(ref qualify) = self.qualify {
643                SpaceOrNewline.fmt(f)?;
644                f.write_str("QUALIFY")?;
645                SpaceOrNewline.fmt(f)?;
646                qualify.fmt(f)?;
647            }
648            if !self.named_window.is_empty() {
649                SpaceOrNewline.fmt(f)?;
650                f.write_str("WINDOW")?;
651                SpaceOrNewline.fmt(f)?;
652                display_comma_separated(&self.named_window).fmt(f)?;
653            }
654        }
655        Ok(())
656    }
657}
658
659/// A hive LATERAL VIEW with potential column aliases
660#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
661#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
662#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
663pub struct LateralView {
664    /// LATERAL VIEW
665    pub lateral_view: Expr,
666    /// LATERAL VIEW table name
667    pub lateral_view_name: ObjectName,
668    /// LATERAL VIEW optional column aliases
669    pub lateral_col_alias: Vec<Ident>,
670    /// LATERAL VIEW OUTER
671    pub outer: bool,
672}
673
674impl fmt::Display for LateralView {
675    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
676        write!(
677            f,
678            " LATERAL VIEW{outer} {} {}",
679            self.lateral_view,
680            self.lateral_view_name,
681            outer = if self.outer { " OUTER" } else { "" }
682        )?;
683        if !self.lateral_col_alias.is_empty() {
684            write!(
685                f,
686                " AS {}",
687                display_comma_separated(&self.lateral_col_alias)
688            )?;
689        }
690        Ok(())
691    }
692}
693
694/// An expression used in a named window declaration.
695///
696/// ```sql
697/// WINDOW mywindow AS [named_window_expr]
698/// ```
699#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
700#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
701#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
702pub enum NamedWindowExpr {
703    /// A direct reference to another named window definition.
704    /// [BigQuery]
705    ///
706    /// Example:
707    /// ```sql
708    /// WINDOW mywindow AS prev_window
709    /// ```
710    ///
711    /// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/window-function-calls#ref_named_window
712    NamedWindow(Ident),
713    /// A window expression.
714    ///
715    /// Example:
716    /// ```sql
717    /// WINDOW mywindow AS (ORDER BY 1)
718    /// ```
719    WindowSpec(WindowSpec),
720}
721
722impl fmt::Display for NamedWindowExpr {
723    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
724        match self {
725            NamedWindowExpr::NamedWindow(named_window) => {
726                write!(f, "{named_window}")?;
727            }
728            NamedWindowExpr::WindowSpec(window_spec) => {
729                write!(f, "({window_spec})")?;
730            }
731        };
732        Ok(())
733    }
734}
735
736#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
737#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
738#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
739/// A named window definition: `<name> AS <window specification>`
740pub struct NamedWindowDefinition(pub Ident, pub NamedWindowExpr);
741
742impl fmt::Display for NamedWindowDefinition {
743    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
744        write!(f, "{} AS {}", self.0, self.1)
745    }
746}
747
748#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
749#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
750#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
751/// A `WITH` clause, introducing common table expressions (CTEs).
752pub struct With {
753    /// Token for the `WITH` keyword
754    pub with_token: AttachedToken,
755    /// Whether the `WITH` is recursive (`WITH RECURSIVE`).
756    pub recursive: bool,
757    /// The list of CTEs declared by this `WITH` clause.
758    pub cte_tables: Vec<Cte>,
759}
760
761impl fmt::Display for With {
762    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
763        f.write_str("WITH ")?;
764        if self.recursive {
765            f.write_str("RECURSIVE ")?;
766        }
767        display_comma_separated(&self.cte_tables).fmt(f)?;
768        Ok(())
769    }
770}
771
772#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
773#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
774#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
775/// Indicates whether a CTE is materialized or not.
776pub enum CteAsMaterialized {
777    /// The `WITH` statement specifies `AS MATERIALIZED` behavior
778    Materialized,
779    /// The `WITH` statement specifies `AS NOT MATERIALIZED` behavior
780    NotMaterialized,
781}
782
783impl fmt::Display for CteAsMaterialized {
784    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
785        match *self {
786            CteAsMaterialized::Materialized => {
787                write!(f, "MATERIALIZED")?;
788            }
789            CteAsMaterialized::NotMaterialized => {
790                write!(f, "NOT MATERIALIZED")?;
791            }
792        };
793        Ok(())
794    }
795}
796
797/// A single CTE (used after `WITH`): `<alias> [(col1, col2, ...)] AS <materialized> ( <query> )`
798/// The names in the column list before `AS`, when specified, replace the names
799/// of the columns returned by the query. The parser does not validate that the
800/// number of columns in the query matches the number of columns in the query.
801#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
802#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
803#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
804pub struct Cte {
805    /// The CTE alias (name introduced before the `AS` keyword).
806    pub alias: TableAlias,
807    /// The query that defines the CTE body.
808    pub query: Box<Query>,
809    /// Optional `FROM` identifier for materialized CTEs.
810    pub from: Option<Ident>,
811    /// Optional `AS MATERIALIZED` / `AS NOT MATERIALIZED` hint.
812    pub materialized: Option<CteAsMaterialized>,
813    /// Token for the closing parenthesis of the CTE definition.
814    pub closing_paren_token: AttachedToken,
815}
816
817impl fmt::Display for Cte {
818    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
819        match self.materialized.as_ref() {
820            None => {
821                self.alias.fmt(f)?;
822                f.write_str(" AS (")?;
823                NewLine.fmt(f)?;
824                Indent(&self.query).fmt(f)?;
825                NewLine.fmt(f)?;
826                f.write_str(")")?;
827            }
828            Some(materialized) => {
829                self.alias.fmt(f)?;
830                f.write_str(" AS ")?;
831                materialized.fmt(f)?;
832                f.write_str(" (")?;
833                NewLine.fmt(f)?;
834                Indent(&self.query).fmt(f)?;
835                NewLine.fmt(f)?;
836                f.write_str(")")?;
837            }
838        };
839        if let Some(ref fr) = self.from {
840            write!(f, " FROM {fr}")?;
841        }
842        Ok(())
843    }
844}
845
846/// Represents an expression behind a wildcard expansion in a projection.
847/// `SELECT T.* FROM T;
848#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
849#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
850#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
851pub enum SelectItemQualifiedWildcardKind {
852    /// Expression is an object name.
853    /// e.g. `alias.*` or even `schema.table.*`
854    ObjectName(ObjectName),
855    /// Select star on an arbitrary expression.
856    /// e.g. `STRUCT<STRING>('foo').*`
857    Expr(Expr),
858}
859
860/// One item of the comma-separated list following `SELECT`
861#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
862#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
863#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
864pub enum SelectItem {
865    /// Any expression, not followed by `[ AS ] alias`
866    UnnamedExpr(Expr),
867    /// An expression, followed by `[ AS ] alias`
868    ExprWithAlias {
869        /// The expression being projected.
870        expr: Expr,
871        /// The alias for the expression.
872        alias: Ident,
873    },
874    /// An expression, followed by `[ AS ] (alias1, alias2, ...)`
875    ///
876    /// [Spark SQL](https://spark.apache.org/docs/latest/sql-ref-syntax-qry-select.html)
877    ExprWithAliases {
878        /// The expression being projected.
879        expr: Expr,
880        /// The list of aliases for the expression.
881        aliases: Vec<Ident>,
882    },
883    /// An expression, followed by a wildcard expansion.
884    /// e.g. `alias.*`, `STRUCT<STRING>('foo').*`
885    QualifiedWildcard(SelectItemQualifiedWildcardKind, WildcardAdditionalOptions),
886    /// An unqualified `*`
887    Wildcard(WildcardAdditionalOptions),
888}
889
890impl fmt::Display for SelectItemQualifiedWildcardKind {
891    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
892        match &self {
893            SelectItemQualifiedWildcardKind::ObjectName(object_name) => {
894                write!(f, "{object_name}.*")
895            }
896            SelectItemQualifiedWildcardKind::Expr(expr) => write!(f, "{expr}.*"),
897        }
898    }
899}
900
901/// Single aliased identifier
902///
903/// # Syntax
904/// ```plaintext
905/// <ident> AS <alias>
906/// ```
907#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
908#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
909#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
910pub struct IdentWithAlias {
911    /// The identifier being aliased.
912    pub ident: Ident,
913    /// The alias to apply to `ident`.
914    pub alias: Ident,
915}
916
917impl fmt::Display for IdentWithAlias {
918    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
919        write!(f, "{} AS {}", self.ident, self.alias)
920    }
921}
922
923/// Additional options for wildcards, e.g. Snowflake `EXCLUDE`/`RENAME` and Bigquery `EXCEPT`.
924#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
925#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
926#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
927pub struct WildcardAdditionalOptions {
928    /// The wildcard token `*`
929    pub wildcard_token: AttachedToken,
930    /// `[ILIKE...]`.
931    ///  Snowflake syntax: <https://docs.snowflake.com/en/sql-reference/sql/select#parameters>
932    pub opt_ilike: Option<IlikeSelectItem>,
933    /// `[EXCLUDE...]`.
934    pub opt_exclude: Option<ExcludeSelectItem>,
935    /// `[EXCEPT...]`.
936    ///  Clickhouse syntax: <https://clickhouse.com/docs/en/sql-reference/statements/select#except>
937    pub opt_except: Option<ExceptSelectItem>,
938    /// `[REPLACE]`
939    ///  BigQuery syntax: <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_replace>
940    ///  Clickhouse syntax: <https://clickhouse.com/docs/en/sql-reference/statements/select#replace>
941    ///  Snowflake syntax: <https://docs.snowflake.com/en/sql-reference/sql/select#parameters>
942    pub opt_replace: Option<ReplaceSelectItem>,
943    /// `[RENAME ...]`.
944    pub opt_rename: Option<RenameSelectItem>,
945    /// `[AS <alias>]`.
946    ///  Redshift syntax: <https://docs.aws.amazon.com/redshift/latest/dg/r_SELECT_list.html>
947    pub opt_alias: Option<Ident>,
948}
949
950impl Default for WildcardAdditionalOptions {
951    fn default() -> Self {
952        Self {
953            wildcard_token: TokenWithSpan::wrap(Token::Mul).into(),
954            opt_ilike: None,
955            opt_exclude: None,
956            opt_except: None,
957            opt_replace: None,
958            opt_rename: None,
959            opt_alias: None,
960        }
961    }
962}
963
964impl fmt::Display for WildcardAdditionalOptions {
965    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
966        if let Some(ilike) = &self.opt_ilike {
967            write!(f, " {ilike}")?;
968        }
969        if let Some(exclude) = &self.opt_exclude {
970            write!(f, " {exclude}")?;
971        }
972        if let Some(except) = &self.opt_except {
973            write!(f, " {except}")?;
974        }
975        if let Some(replace) = &self.opt_replace {
976            write!(f, " {replace}")?;
977        }
978        if let Some(rename) = &self.opt_rename {
979            write!(f, " {rename}")?;
980        }
981        if let Some(alias) = &self.opt_alias {
982            write!(f, " AS {alias}")?;
983        }
984        Ok(())
985    }
986}
987
988/// Snowflake `ILIKE` information.
989///
990/// # Syntax
991/// ```plaintext
992/// ILIKE <value>
993/// ```
994#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
995#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
996#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
997pub struct IlikeSelectItem {
998    /// The pattern expression used with `ILIKE`.
999    pub pattern: String,
1000}
1001
1002impl fmt::Display for IlikeSelectItem {
1003    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1004        write!(
1005            f,
1006            "ILIKE '{}'",
1007            value::escape_single_quote_string(&self.pattern)
1008        )?;
1009        Ok(())
1010    }
1011}
1012/// Snowflake `EXCLUDE` information.
1013///
1014/// # Syntax
1015/// ```plaintext
1016/// <col_name>
1017/// | (<col_name>, <col_name>, ...)
1018/// ```
1019#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1020#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1021#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1022pub enum ExcludeSelectItem {
1023    /// Single column name without parenthesis.
1024    ///
1025    /// # Syntax
1026    /// ```plaintext
1027    /// <col_name>
1028    /// ```
1029    Single(ObjectName),
1030    /// Multiple column names inside parenthesis.
1031    /// # Syntax
1032    /// ```plaintext
1033    /// (<col_name>, <col_name>, ...)
1034    /// ```
1035    Multiple(Vec<ObjectName>),
1036}
1037
1038impl fmt::Display for ExcludeSelectItem {
1039    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1040        write!(f, "EXCLUDE")?;
1041        match self {
1042            Self::Single(column) => {
1043                write!(f, " {column}")?;
1044            }
1045            Self::Multiple(columns) => {
1046                write!(f, " ({})", display_comma_separated(columns))?;
1047            }
1048        }
1049        Ok(())
1050    }
1051}
1052
1053/// Snowflake `RENAME` information.
1054///
1055/// # Syntax
1056/// ```plaintext
1057/// <col_name> AS <col_alias>
1058/// | (<col_name> AS <col_alias>, <col_name> AS <col_alias>, ...)
1059/// ```
1060#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1061#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1062#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1063pub enum RenameSelectItem {
1064    /// Single column name with alias without parenthesis.
1065    ///
1066    /// # Syntax
1067    /// ```plaintext
1068    /// <col_name> AS <col_alias>
1069    /// ```
1070    Single(IdentWithAlias),
1071    /// Multiple column names with aliases inside parenthesis.
1072    /// # Syntax
1073    /// ```plaintext
1074    /// (<col_name> AS <col_alias>, <col_name> AS <col_alias>, ...)
1075    /// ```
1076    Multiple(Vec<IdentWithAlias>),
1077}
1078
1079impl fmt::Display for RenameSelectItem {
1080    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1081        write!(f, "RENAME")?;
1082        match self {
1083            Self::Single(column) => {
1084                write!(f, " {column}")?;
1085            }
1086            Self::Multiple(columns) => {
1087                write!(f, " ({})", display_comma_separated(columns))?;
1088            }
1089        }
1090        Ok(())
1091    }
1092}
1093
1094/// Bigquery `EXCEPT` information, with at least one column.
1095///
1096/// # Syntax
1097/// ```plaintext
1098/// EXCEPT (<col_name> [, ...])
1099/// ```
1100#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1101#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1102#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1103pub struct ExceptSelectItem {
1104    /// First guaranteed column.
1105    pub first_element: Ident,
1106    /// Additional columns. This list can be empty.
1107    pub additional_elements: Vec<Ident>,
1108}
1109
1110impl fmt::Display for ExceptSelectItem {
1111    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1112        write!(f, "EXCEPT ")?;
1113        if self.additional_elements.is_empty() {
1114            write!(f, "({})", self.first_element)?;
1115        } else {
1116            write!(
1117                f,
1118                "({}, {})",
1119                self.first_element,
1120                display_comma_separated(&self.additional_elements)
1121            )?;
1122        }
1123        Ok(())
1124    }
1125}
1126
1127/// Bigquery `REPLACE` information.
1128///
1129/// # Syntax
1130/// ```plaintext
1131/// REPLACE (<new_expr> [AS] <col_name>)
1132/// REPLACE (<col_name> [AS] <col_alias>, <col_name> [AS] <col_alias>, ...)
1133/// ```
1134#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1135#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1136#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1137pub struct ReplaceSelectItem {
1138    /// List of replacement elements contained in the `REPLACE(...)` clause.
1139    pub items: Vec<Box<ReplaceSelectElement>>,
1140}
1141
1142impl fmt::Display for ReplaceSelectItem {
1143    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1144        write!(f, "REPLACE")?;
1145        write!(f, " ({})", display_comma_separated(&self.items))?;
1146        Ok(())
1147    }
1148}
1149
1150/// # Syntax
1151/// ```plaintext
1152/// <expr> [AS] <column_name>
1153/// ```
1154#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1155#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1156#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1157pub struct ReplaceSelectElement {
1158    /// Expression producing the replacement value.
1159    pub expr: Expr,
1160    /// The target column name for the replacement.
1161    pub column_name: Ident,
1162    /// Whether the `AS` keyword was present in the original syntax.
1163    pub as_keyword: bool,
1164}
1165
1166impl fmt::Display for ReplaceSelectElement {
1167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1168        if self.as_keyword {
1169            write!(f, "{} AS {}", self.expr, self.column_name)
1170        } else {
1171            write!(f, "{} {}", self.expr, self.column_name)
1172        }
1173    }
1174}
1175
1176impl fmt::Display for SelectItem {
1177    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1178        use core::fmt::Write;
1179        match &self {
1180            SelectItem::UnnamedExpr(expr) => expr.fmt(f),
1181            SelectItem::ExprWithAlias { expr, alias } => {
1182                expr.fmt(f)?;
1183                f.write_str(" AS ")?;
1184                alias.fmt(f)
1185            }
1186            SelectItem::ExprWithAliases { expr, aliases } => {
1187                expr.fmt(f)?;
1188                f.write_str(" AS (")?;
1189                display_comma_separated(aliases).fmt(f)?;
1190                f.write_str(")")
1191            }
1192            SelectItem::QualifiedWildcard(kind, additional_options) => {
1193                kind.fmt(f)?;
1194                additional_options.fmt(f)
1195            }
1196            SelectItem::Wildcard(additional_options) => {
1197                f.write_char('*')?;
1198                additional_options.fmt(f)
1199            }
1200        }
1201    }
1202}
1203
1204#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1205#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1206#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1207/// A left table followed by zero or more joins.
1208pub struct TableWithJoins {
1209    /// The starting table factor (left side) of the join chain.
1210    pub relation: TableFactor,
1211    /// The sequence of joins applied to the relation.
1212    pub joins: Vec<Join>,
1213}
1214
1215impl fmt::Display for TableWithJoins {
1216    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1217        self.relation.fmt(f)?;
1218        for join in &self.joins {
1219            SpaceOrNewline.fmt(f)?;
1220            join.fmt(f)?;
1221        }
1222        Ok(())
1223    }
1224}
1225
1226/// Joins a table to itself to process hierarchical data in the table.
1227///
1228/// See <https://docs.snowflake.com/en/sql-reference/constructs/connect-by>.
1229/// See <https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Hierarchical-Queries.html>
1230#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1231#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1232#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1233pub enum ConnectByKind {
1234    /// CONNECT BY
1235    ConnectBy {
1236        /// the `CONNECT` token
1237        connect_token: AttachedToken,
1238
1239        /// [CONNECT BY] NOCYCLE
1240        ///
1241        /// Optional on [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Hierarchical-Queries.html#GUID-0118DF1D-B9A9-41EB-8556-C6E7D6A5A84E__GUID-5377971A-F518-47E4-8781-F06FEB3EF993)
1242        nocycle: bool,
1243
1244        /// join conditions denoting the hierarchical relationship
1245        relationships: Vec<Expr>,
1246    },
1247
1248    /// START WITH
1249    ///
1250    /// Optional on [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/Hierarchical-Queries.html#GUID-0118DF1D-B9A9-41EB-8556-C6E7D6A5A84E)
1251    /// when comming _after_ the `CONNECT BY`.
1252    StartWith {
1253        /// the `START` token
1254        start_token: AttachedToken,
1255
1256        /// condition selecting the root rows of the hierarchy
1257        condition: Box<Expr>,
1258    },
1259}
1260
1261impl fmt::Display for ConnectByKind {
1262    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1263        match self {
1264            ConnectByKind::ConnectBy {
1265                connect_token: _,
1266                nocycle,
1267                relationships,
1268            } => {
1269                write!(
1270                    f,
1271                    "CONNECT BY {nocycle}{relationships}",
1272                    nocycle = if *nocycle { "NOCYCLE " } else { "" },
1273                    relationships = display_comma_separated(relationships)
1274                )
1275            }
1276            ConnectByKind::StartWith {
1277                start_token: _,
1278                condition,
1279            } => {
1280                write!(f, "START WITH {condition}")
1281            }
1282        }
1283    }
1284}
1285
1286#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1287#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1288#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1289/// A single setting key-value pair.
1290pub struct Setting {
1291    /// Setting name/key.
1292    pub key: Ident,
1293    /// The value expression assigned to the setting.
1294    pub value: Expr,
1295}
1296
1297impl fmt::Display for Setting {
1298    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1299        write!(f, "{} = {}", self.key, self.value)
1300    }
1301}
1302
1303/// An expression optionally followed by an alias.
1304///
1305/// Example:
1306/// ```sql
1307/// 42 AS myint
1308/// ```
1309#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1310#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1311#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1312pub struct ExprWithAlias {
1313    /// The expression.
1314    pub expr: Expr,
1315    /// Optional alias for the expression.
1316    pub alias: Option<Ident>,
1317}
1318
1319impl fmt::Display for ExprWithAlias {
1320    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1321        let ExprWithAlias { expr, alias } = self;
1322        write!(f, "{expr}")?;
1323        if let Some(alias) = alias {
1324            write!(f, " AS {alias}")?;
1325        }
1326        Ok(())
1327    }
1328}
1329
1330/// An expression optionally followed by an alias and order by options.
1331///
1332/// Example:
1333/// ```sql
1334/// 42 AS myint ASC
1335/// ```
1336#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1337#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1338#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1339pub struct ExprWithAliasAndOrderBy {
1340    /// Expression with optional alias.
1341    pub expr: ExprWithAlias,
1342    /// Ordering options applied to the expression.
1343    pub order_by: OrderByOptions,
1344}
1345
1346impl fmt::Display for ExprWithAliasAndOrderBy {
1347    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1348        write!(f, "{}{}", self.expr, self.order_by)
1349    }
1350}
1351
1352/// Arguments to a table-valued function
1353#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1354#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1355#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1356pub struct TableFunctionArgs {
1357    /// The list of arguments passed to the table-valued function.
1358    pub args: Vec<FunctionArg>,
1359    /// ClickHouse-specific `SETTINGS` clause.
1360    /// For example,
1361    /// `SELECT * FROM executable('generate_random.py', TabSeparated, 'id UInt32, random String', SETTINGS send_chunk_header = false, pool_size = 16)`
1362    /// [`executable` table function](https://clickhouse.com/docs/en/engines/table-functions/executable)
1363    pub settings: Option<Vec<Setting>>,
1364}
1365
1366#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1367#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1368#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1369/// Type of index hint (e.g., `USE`, `IGNORE`, `FORCE`).
1370pub enum TableIndexHintType {
1371    /// `USE` hint.
1372    Use,
1373    /// `IGNORE` hint.
1374    Ignore,
1375    /// `FORCE` hint.
1376    Force,
1377}
1378
1379impl fmt::Display for TableIndexHintType {
1380    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1381        f.write_str(match self {
1382            TableIndexHintType::Use => "USE",
1383            TableIndexHintType::Ignore => "IGNORE",
1384            TableIndexHintType::Force => "FORCE",
1385        })
1386    }
1387}
1388
1389#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1390#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1391#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1392/// The kind of index referenced by an index hint (e.g. `USE INDEX`).
1393pub enum TableIndexType {
1394    /// The `INDEX` kind.
1395    Index,
1396    /// The `KEY` kind.
1397    Key,
1398}
1399
1400impl fmt::Display for TableIndexType {
1401    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1402        f.write_str(match self {
1403            TableIndexType::Index => "INDEX",
1404            TableIndexType::Key => "KEY",
1405        })
1406    }
1407}
1408
1409#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1410#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1411#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1412/// Which clause the table index hint applies to.
1413pub enum TableIndexHintForClause {
1414    /// Apply the hint to JOIN clauses.
1415    Join,
1416    /// Apply the hint to `ORDER BY` clauses.
1417    OrderBy,
1418    /// Apply the hint to `GROUP BY` clauses.
1419    GroupBy,
1420}
1421
1422impl fmt::Display for TableIndexHintForClause {
1423    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1424        f.write_str(match self {
1425            TableIndexHintForClause::Join => "JOIN",
1426            TableIndexHintForClause::OrderBy => "ORDER BY",
1427            TableIndexHintForClause::GroupBy => "GROUP BY",
1428        })
1429    }
1430}
1431
1432#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1433#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1434#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1435/// MySQL-style index hints attached to a table (e.g., `USE INDEX(...)`).
1436pub struct TableIndexHints {
1437    /// Type of hint (e.g., `USE`, `FORCE`, or `IGNORE`).
1438    pub hint_type: TableIndexHintType,
1439    /// The index type (e.g., `INDEX`).
1440    pub index_type: TableIndexType,
1441    /// Optional `FOR` clause specifying the scope (JOIN / ORDER BY / GROUP BY).
1442    pub for_clause: Option<TableIndexHintForClause>,
1443    /// List of index names referred to by the hint.
1444    pub index_names: Vec<Ident>,
1445}
1446
1447impl fmt::Display for TableIndexHints {
1448    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1449        write!(f, "{} {} ", self.hint_type, self.index_type)?;
1450        if let Some(for_clause) = &self.for_clause {
1451            write!(f, "FOR {for_clause} ")?;
1452        }
1453        write!(f, "({})", display_comma_separated(&self.index_names))
1454    }
1455}
1456
1457/// A table name or a parenthesized subquery with an optional alias
1458#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1459#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1460#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1461#[cfg_attr(feature = "visitor", visit(with = "visit_table_factor"))]
1462pub enum TableFactor {
1463    /// A named table or relation, possibly with arguments, hints, or sampling.
1464    Table {
1465        #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
1466        /// Table or relation name.
1467        name: ObjectName,
1468        /// Optional alias for the table (e.g. `table AS t`).
1469        alias: Option<TableAlias>,
1470        /// Arguments of a table-valued function, as supported by Postgres
1471        /// and MSSQL. Note that deprecated MSSQL `FROM foo (NOLOCK)` syntax
1472        /// will also be parsed as `args`.
1473        ///
1474        /// This field's value is `Some(v)`, where `v` is a (possibly empty)
1475        /// vector of arguments, in the case of a table-valued function call,
1476        /// whereas it's `None` in the case of a regular table name.
1477        args: Option<TableFunctionArgs>,
1478        /// MSSQL-specific `WITH (...)` hints such as NOLOCK.
1479        with_hints: Vec<Expr>,
1480        /// Optional version qualifier to facilitate table time-travel, as
1481        /// supported by BigQuery and MSSQL.
1482        version: Option<TableVersion>,
1483        //  Optional table function modifier to generate the ordinality for column.
1484        /// For example, `SELECT * FROM generate_series(1, 10) WITH ORDINALITY AS t(a, b);`
1485        /// [WITH ORDINALITY](https://www.postgresql.org/docs/current/functions-srf.html), supported by Postgres.
1486        with_ordinality: bool,
1487        /// [Partition selection](https://dev.mysql.com/doc/refman/8.0/en/partitioning-selection.html), supported by MySQL.
1488        partitions: Vec<Ident>,
1489        /// Optional PartiQL JsonPath: <https://partiql.org/dql/from.html>
1490        json_path: Option<JsonPath>,
1491        /// Optional table sample modifier
1492        /// See: <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#sample-clause>
1493        sample: Option<TableSampleKind>,
1494        /// Optional index hints(mysql)
1495        /// See: <https://dev.mysql.com/doc/refman/8.4/en/index-hints.html>
1496        index_hints: Vec<TableIndexHints>,
1497    },
1498    /// A derived table (a parenthesized subquery), optionally `LATERAL`.
1499    Derived {
1500        /// Whether the derived table is LATERAL.
1501        lateral: bool,
1502        /// The subquery producing the derived table.
1503        subquery: Box<Query>,
1504        /// Optional alias for the derived table.
1505        alias: Option<TableAlias>,
1506        /// Optional table sample modifier
1507        sample: Option<TableSampleKind>,
1508    },
1509    /// `TABLE(<expr>)[ AS <alias> ]`
1510    TableFunction {
1511        /// Expression representing the table function call.
1512        expr: Expr,
1513        /// Optional alias for the table function result.
1514        alias: Option<TableAlias>,
1515    },
1516    /// `e.g. LATERAL FLATTEN(<args>)[ AS <alias> ]`
1517    Function {
1518        /// Whether the function is LATERAL.
1519        lateral: bool,
1520        /// Name of the table function.
1521        name: ObjectName,
1522        /// Arguments passed to the function.
1523        args: Vec<FunctionArg>,
1524        /// Whether `WITH ORDINALITY` was specified to include ordinality.
1525        with_ordinality: bool,
1526        /// Optional alias for the result of the function.
1527        alias: Option<TableAlias>,
1528    },
1529    /// ```sql
1530    /// SELECT * FROM UNNEST ([10,20,30]) as numbers WITH OFFSET;
1531    /// +---------+--------+
1532    /// | numbers | offset |
1533    /// +---------+--------+
1534    /// | 10      | 0      |
1535    /// | 20      | 1      |
1536    /// | 30      | 2      |
1537    /// +---------+--------+
1538    /// ```
1539    UNNEST {
1540        /// Optional alias for the UNNEST table (e.g. `UNNEST(...) AS t`).
1541        alias: Option<TableAlias>,
1542        /// Expressions producing the arrays to be unnested.
1543        array_exprs: Vec<Expr>,
1544        /// Whether `WITH OFFSET` was specified to include element offsets.
1545        with_offset: bool,
1546        /// Optional alias for the offset column when `WITH OFFSET` is used.
1547        with_offset_alias: Option<Ident>,
1548        /// Whether `WITH ORDINALITY` was specified to include ordinality.
1549        with_ordinality: bool,
1550    },
1551    /// The `JSON_TABLE` table-valued function.
1552    /// Part of the SQL standard, but implemented only by MySQL, Oracle, and DB2.
1553    ///
1554    /// <https://modern-sql.com/blog/2017-06/whats-new-in-sql-2016#json_table>
1555    /// <https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html#function_json-table>
1556    ///
1557    /// ```sql
1558    /// SELECT * FROM JSON_TABLE(
1559    ///    '[{"a": 1, "b": 2}, {"a": 3, "b": 4}]',
1560    ///    '$[*]' COLUMNS(
1561    ///        a INT PATH '$.a' DEFAULT '0' ON EMPTY,
1562    ///        b INT PATH '$.b' NULL ON ERROR
1563    ///     )
1564    /// ) AS jt;
1565    /// ````
1566    JsonTable {
1567        /// The JSON expression to be evaluated. It must evaluate to a json string
1568        json_expr: Expr,
1569        /// The path to the array or object to be iterated over.
1570        /// It must evaluate to a json array or object.
1571        json_path: ValueWithSpan,
1572        /// The columns to be extracted from each element of the array or object.
1573        /// Each column must have a name and a type.
1574        columns: Vec<JsonTableColumn>,
1575        /// The alias for the table.
1576        alias: Option<TableAlias>,
1577    },
1578    /// The MSSQL's `OPENJSON` table-valued function.
1579    ///
1580    /// ```sql
1581    /// OPENJSON( jsonExpression [ , path ] )  [ <with_clause> ]
1582    ///
1583    /// <with_clause> ::= WITH ( { colName type [ column_path ] [ AS JSON ] } [ ,...n ] )
1584    /// ````
1585    ///
1586    /// Reference: <https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16#syntax>
1587    OpenJsonTable {
1588        /// The JSON expression to be evaluated. It must evaluate to a json string
1589        json_expr: Expr,
1590        /// The path to the array or object to be iterated over.
1591        /// It must evaluate to a json array or object.
1592        json_path: Option<ValueWithSpan>,
1593        /// The columns to be extracted from each element of the array or object.
1594        /// Each column must have a name and a type.
1595        columns: Vec<OpenJsonTableColumn>,
1596        /// The alias for the table.
1597        alias: Option<TableAlias>,
1598    },
1599    /// Represents a parenthesized table factor. The SQL spec only allows a
1600    /// join expression (`(foo <JOIN> bar [ <JOIN> baz ... ])`) to be nested,
1601    /// possibly several times.
1602    ///
1603    /// The parser may also accept non-standard nesting of bare tables for some
1604    /// dialects, but the information about such nesting is stripped from AST.
1605    NestedJoin {
1606        /// The nested join expression contained in parentheses.
1607        table_with_joins: Box<TableWithJoins>,
1608        /// Optional alias for the nested join.
1609        alias: Option<TableAlias>,
1610    },
1611    /// Represents PIVOT operation on a table.
1612    /// For example `FROM monthly_sales PIVOT(sum(amount) FOR MONTH IN ('JAN', 'FEB'))`
1613    ///
1614    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#pivot_operator)
1615    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constructs/pivot)
1616    /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-68257B27-1C4C-4C47-8140-5C60E0E65D35)
1617    Pivot {
1618        /// The input table to pivot.
1619        table: Box<TableFactor>,
1620        /// Aggregate expressions used as pivot values (optionally aliased).
1621        aggregate_functions: Vec<ExprWithAlias>, // Function expression
1622        /// Columns producing the values to be pivoted.
1623        value_column: Vec<Expr>,
1624        /// Source of pivot values (e.g. list of literals or columns).
1625        value_source: PivotValueSource,
1626        /// Optional expression providing a default when a pivot produces NULL.
1627        default_on_null: Option<Expr>,
1628        /// Optional alias for the pivoted table.
1629        alias: Option<TableAlias>,
1630    },
1631    /// An UNPIVOT operation on a table.
1632    ///
1633    /// Syntax:
1634    /// ```sql
1635    /// table UNPIVOT [ { INCLUDE | EXCLUDE } NULLS ] (value FOR name IN (column1, [ column2, ... ])) [ alias ]
1636    /// ```
1637    ///
1638    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constructs/unpivot)
1639    /// [Databricks](https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot)
1640    /// [BigQuery](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#unpivot_operator)
1641    /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-9B4E0389-413C-4014-94A1-0A0571BDF7E1)
1642    Unpivot {
1643        /// The input table to unpivot.
1644        table: Box<TableFactor>,
1645        /// Expression producing the unpivoted value.
1646        value: Expr,
1647        /// Identifier used for the generated column name.
1648        name: Ident,
1649        /// Columns or expressions to unpivot, optionally aliased.
1650        columns: Vec<ExprWithAlias>,
1651        /// Whether to include or exclude NULLs during unpivot.
1652        null_inclusion: Option<NullInclusion>,
1653        /// Optional alias for the resulting table.
1654        alias: Option<TableAlias>,
1655    },
1656    /// Object unpivoting on a SUPER expression in the FROM clause.
1657    ///
1658    /// Syntax:
1659    /// ```sql
1660    /// UNPIVOT expression AS value_alias [AT attribute_alias]
1661    /// ```
1662    /// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/query-super.html#unpivoting)
1663    UnpivotExpr {
1664        /// SUPER expression to unpivot.
1665        expression: Expr,
1666        /// Alias for the generated unpivoted value.
1667        value_alias: Ident,
1668        /// Optional alias for the generated attribute key/index.
1669        attribute_alias: Option<Ident>,
1670    },
1671    /// A `MATCH_RECOGNIZE` operation on a table.
1672    ///
1673    /// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize>.
1674    MatchRecognize {
1675        /// The input table to apply `MATCH_RECOGNIZE` on.
1676        table: Box<TableFactor>,
1677        /// `PARTITION BY <expr> [, ... ]`
1678        partition_by: Vec<Expr>,
1679        /// `ORDER BY <expr> [, ... ]`
1680        order_by: Vec<OrderByExpr>,
1681        /// `MEASURES <expr> [AS] <alias> [, ... ]`
1682        measures: Vec<Measure>,
1683        /// `ONE ROW PER MATCH | ALL ROWS PER MATCH [ <option> ]`
1684        rows_per_match: Option<RowsPerMatch>,
1685        /// `AFTER MATCH SKIP <option>`
1686        after_match_skip: Option<AfterMatchSkip>,
1687        /// `PATTERN ( <pattern> )`
1688        pattern: MatchRecognizePattern,
1689        /// `DEFINE <symbol> AS <expr> [, ... ]`
1690        symbols: Vec<SymbolDefinition>,
1691        /// The alias for the table.
1692        alias: Option<TableAlias>,
1693    },
1694    /// The `XMLTABLE` table-valued function.
1695    /// Part of the SQL standard, supported by PostgreSQL, Oracle, and DB2.
1696    ///
1697    /// <https://www.postgresql.org/docs/15/functions-xml.html#FUNCTIONS-XML-PROCESSING>
1698    ///
1699    /// ```sql
1700    /// SELECT xmltable.*
1701    /// FROM xmldata,
1702    /// XMLTABLE('//ROWS/ROW'
1703    ///     PASSING data
1704    ///     COLUMNS id int PATH '@id',
1705    ///     ordinality FOR ORDINALITY,
1706    ///     "COUNTRY_NAME" text,
1707    ///     country_id text PATH 'COUNTRY_ID',
1708    ///     size_sq_km float PATH 'SIZE[@unit = "sq_km"]',
1709    ///     size_other text PATH 'concat(SIZE[@unit!="sq_km"], " ", SIZE[@unit!="sq_km"]/@unit)',
1710    ///     premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified'
1711    /// );
1712    /// ````
1713    XmlTable {
1714        /// Optional XMLNAMESPACES clause (empty if not present)
1715        namespaces: Vec<XmlNamespaceDefinition>,
1716        /// The row-generating XPath expression.
1717        row_expression: Expr,
1718        /// The PASSING clause specifying the document expression.
1719        passing: XmlPassingClause,
1720        /// The columns to be extracted from each generated row.
1721        columns: Vec<XmlTableColumn>,
1722        /// The alias for the table.
1723        alias: Option<TableAlias>,
1724    },
1725    /// Snowflake's SEMANTIC_VIEW function for semantic models.
1726    ///
1727    /// <https://docs.snowflake.com/en/sql-reference/constructs/semantic_view>
1728    ///
1729    /// ```sql
1730    /// SELECT * FROM SEMANTIC_VIEW(
1731    ///     tpch_analysis
1732    ///     DIMENSIONS customer.customer_market_segment
1733    ///     METRICS orders.order_average_value
1734    /// );
1735    /// ```
1736    SemanticView {
1737        /// The name of the semantic model
1738        name: ObjectName,
1739        /// List of dimensions or expression referring to dimensions (e.g. DATE_PART('year', col))
1740        dimensions: Vec<Expr>,
1741        /// List of metrics (references to objects like orders.value, value, orders.*)
1742        metrics: Vec<Expr>,
1743        /// List of facts or expressions referring to facts or dimensions.
1744        facts: Vec<Expr>,
1745        /// WHERE clause for filtering
1746        where_clause: Option<Expr>,
1747        /// The alias for the table
1748        alias: Option<TableAlias>,
1749    },
1750}
1751
1752/// The table sample modifier options
1753#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1754#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1755#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1756pub enum TableSampleKind {
1757    /// Table sample located before the table alias option
1758    BeforeTableAlias(Box<TableSample>),
1759    /// Table sample located after the table alias option
1760    AfterTableAlias(Box<TableSample>),
1761}
1762
1763#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1764#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1765#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1766/// Represents a `TABLESAMPLE` clause and its options.
1767pub struct TableSample {
1768    /// Modifier (e.g. `SAMPLE` or `TABLESAMPLE`).
1769    pub modifier: TableSampleModifier,
1770    /// Optional sampling method name (e.g. `BERNOULLI`, `SYSTEM`).
1771    pub name: Option<TableSampleMethod>,
1772    /// Optional sampling quantity (value and optional unit).
1773    pub quantity: Option<TableSampleQuantity>,
1774    /// Optional seed clause.
1775    pub seed: Option<TableSampleSeed>,
1776    /// Optional bucket specification for `BUCKET ... OUT OF ...`-style sampling.
1777    pub bucket: Option<TableSampleBucket>,
1778    /// Optional offset expression for sampling.
1779    pub offset: Option<Expr>,
1780}
1781
1782#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1783#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1784#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1785/// Modifier specifying whether `SAMPLE` or `TABLESAMPLE` keyword was used.
1786pub enum TableSampleModifier {
1787    /// `SAMPLE` modifier.
1788    Sample,
1789    /// `TABLESAMPLE` modifier.
1790    TableSample,
1791}
1792
1793impl fmt::Display for TableSampleModifier {
1794    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1795        match self {
1796            TableSampleModifier::Sample => write!(f, "SAMPLE")?,
1797            TableSampleModifier::TableSample => write!(f, "TABLESAMPLE")?,
1798        }
1799        Ok(())
1800    }
1801}
1802
1803#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1804#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1805#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1806/// Quantity for a `TABLESAMPLE` clause (e.g. `10 PERCENT` or `(10)`).
1807pub struct TableSampleQuantity {
1808    /// Whether the quantity was wrapped in parentheses.
1809    pub parenthesized: bool,
1810    /// The numeric expression specifying the quantity.
1811    pub value: Expr,
1812    /// Optional unit (e.g. `PERCENT`, `ROWS`).
1813    pub unit: Option<TableSampleUnit>,
1814}
1815
1816impl fmt::Display for TableSampleQuantity {
1817    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1818        if self.parenthesized {
1819            write!(f, "(")?;
1820        }
1821        write!(f, "{}", self.value)?;
1822        if let Some(unit) = &self.unit {
1823            write!(f, " {unit}")?;
1824        }
1825        if self.parenthesized {
1826            write!(f, ")")?;
1827        }
1828        Ok(())
1829    }
1830}
1831
1832/// The table sample method names
1833#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1834#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1835#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1836/// Sampling method used by `TABLESAMPLE`.
1837pub enum TableSampleMethod {
1838    /// `ROW` sampling method.
1839    Row,
1840    /// `BERNOULLI` sampling method.
1841    Bernoulli,
1842    /// `SYSTEM` sampling method.
1843    System,
1844    /// `BLOCK` sampling method.
1845    Block,
1846}
1847
1848impl fmt::Display for TableSampleMethod {
1849    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1850        match self {
1851            TableSampleMethod::Bernoulli => write!(f, "BERNOULLI"),
1852            TableSampleMethod::Row => write!(f, "ROW"),
1853            TableSampleMethod::System => write!(f, "SYSTEM"),
1854            TableSampleMethod::Block => write!(f, "BLOCK"),
1855        }
1856    }
1857}
1858
1859#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1860#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1861#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1862/// `SEED` or `REPEATABLE` clause used with sampling.
1863pub struct TableSampleSeed {
1864    /// Seed modifier (e.g. `REPEATABLE` or `SEED`).
1865    pub modifier: TableSampleSeedModifier,
1866    /// The seed value expression.
1867    pub value: ValueWithSpan,
1868}
1869
1870impl fmt::Display for TableSampleSeed {
1871    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1872        write!(f, "{} ({})", self.modifier, self.value)?;
1873        Ok(())
1874    }
1875}
1876
1877#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1878#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1879#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1880/// Modifier specifying how the sample seed is applied.
1881pub enum TableSampleSeedModifier {
1882    /// `REPEATABLE` modifier.
1883    Repeatable,
1884    /// `SEED` modifier.
1885    Seed,
1886}
1887
1888impl fmt::Display for TableSampleSeedModifier {
1889    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1890        match self {
1891            TableSampleSeedModifier::Repeatable => write!(f, "REPEATABLE"),
1892            TableSampleSeedModifier::Seed => write!(f, "SEED"),
1893        }
1894    }
1895}
1896
1897#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1898#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1899#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1900/// Unit used with a `TABLESAMPLE` quantity (rows or percent).
1901pub enum TableSampleUnit {
1902    /// `ROWS` unit.
1903    Rows,
1904    /// `PERCENT` unit.
1905    Percent,
1906}
1907
1908impl fmt::Display for TableSampleUnit {
1909    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1910        match self {
1911            TableSampleUnit::Percent => write!(f, "PERCENT"),
1912            TableSampleUnit::Rows => write!(f, "ROWS"),
1913        }
1914    }
1915}
1916
1917#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1918#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1919#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1920/// Bucket-based sampling clause: `BUCKET <bucket> OUT OF <total> [ON <expr>]`.
1921pub struct TableSampleBucket {
1922    /// The bucket index expression.
1923    pub bucket: ValueWithSpan,
1924    /// The total number of buckets expression.
1925    pub total: ValueWithSpan,
1926    /// Optional `ON <expr>` specification.
1927    pub on: Option<Expr>,
1928}
1929
1930impl fmt::Display for TableSampleBucket {
1931    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1932        write!(f, "BUCKET {} OUT OF {}", self.bucket, self.total)?;
1933        if let Some(on) = &self.on {
1934            write!(f, " ON {on}")?;
1935        }
1936        Ok(())
1937    }
1938}
1939impl fmt::Display for TableSample {
1940    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1941        write!(f, "{}", self.modifier)?;
1942        if let Some(name) = &self.name {
1943            write!(f, " {name}")?;
1944        }
1945        if let Some(quantity) = &self.quantity {
1946            write!(f, " {quantity}")?;
1947        }
1948        if let Some(seed) = &self.seed {
1949            write!(f, " {seed}")?;
1950        }
1951        if let Some(bucket) = &self.bucket {
1952            write!(f, " ({bucket})")?;
1953        }
1954        if let Some(offset) = &self.offset {
1955            write!(f, " OFFSET {offset}")?;
1956        }
1957        Ok(())
1958    }
1959}
1960
1961/// The source of values in a `PIVOT` operation.
1962#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1963#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1964#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1965pub enum PivotValueSource {
1966    /// Pivot on a static list of values.
1967    ///
1968    /// See <https://docs.snowflake.com/en/sql-reference/constructs/pivot#pivot-on-a-specified-list-of-column-values-for-the-pivot-column>.
1969    List(Vec<ExprWithAlias>),
1970    /// Pivot on all distinct values of the pivot column.
1971    ///
1972    /// See <https://docs.snowflake.com/en/sql-reference/constructs/pivot#pivot-on-all-distinct-column-values-automatically-with-dynamic-pivot>.
1973    Any(Vec<OrderByExpr>),
1974    /// Pivot on all values returned by a subquery.
1975    ///
1976    /// See <https://docs.snowflake.com/en/sql-reference/constructs/pivot#pivot-on-column-values-using-a-subquery-with-dynamic-pivot>.
1977    Subquery(Box<Query>),
1978}
1979
1980impl fmt::Display for PivotValueSource {
1981    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1982        match self {
1983            PivotValueSource::List(values) => write!(f, "{}", display_comma_separated(values)),
1984            PivotValueSource::Any(order_by) => {
1985                write!(f, "ANY")?;
1986                if !order_by.is_empty() {
1987                    write!(f, " ORDER BY {}", display_comma_separated(order_by))?;
1988                }
1989                Ok(())
1990            }
1991            PivotValueSource::Subquery(query) => write!(f, "{query}"),
1992        }
1993    }
1994}
1995
1996/// An item in the `MEASURES` subclause of a `MATCH_RECOGNIZE` operation.
1997///
1998/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#measures-specifying-additional-output-columns>.
1999#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2000#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2001#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2002/// An item in the `MEASURES` clause of `MATCH_RECOGNIZE`.
2003pub struct Measure {
2004    /// Expression producing the measure value.
2005    pub expr: Expr,
2006    /// Alias for the measure column.
2007    pub alias: Ident,
2008}
2009
2010impl fmt::Display for Measure {
2011    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2012        write!(f, "{} AS {}", self.expr, self.alias)
2013    }
2014}
2015
2016/// The rows per match option in a `MATCH_RECOGNIZE` operation.
2017///
2018/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#row-s-per-match-specifying-the-rows-to-return>.
2019#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2020#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2021#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2022pub enum RowsPerMatch {
2023    /// `ONE ROW PER MATCH`
2024    OneRow,
2025    /// `ALL ROWS PER MATCH <mode>`
2026    AllRows(Option<EmptyMatchesMode>),
2027}
2028
2029impl fmt::Display for RowsPerMatch {
2030    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2031        match self {
2032            RowsPerMatch::OneRow => write!(f, "ONE ROW PER MATCH"),
2033            RowsPerMatch::AllRows(mode) => {
2034                write!(f, "ALL ROWS PER MATCH")?;
2035                if let Some(mode) = mode {
2036                    write!(f, " {mode}")?;
2037                }
2038                Ok(())
2039            }
2040        }
2041    }
2042}
2043
2044/// The after match skip option in a `MATCH_RECOGNIZE` operation.
2045///
2046/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#after-match-skip-specifying-where-to-continue-after-a-match>.
2047#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2048#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2049#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2050pub enum AfterMatchSkip {
2051    /// `PAST LAST ROW`
2052    PastLastRow,
2053    /// `TO NEXT ROW`
2054    ToNextRow,
2055    /// `TO FIRST <symbol>`
2056    ToFirst(Ident),
2057    /// `TO LAST <symbol>`
2058    ToLast(Ident),
2059}
2060
2061impl fmt::Display for AfterMatchSkip {
2062    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2063        write!(f, "AFTER MATCH SKIP ")?;
2064        match self {
2065            AfterMatchSkip::PastLastRow => write!(f, "PAST LAST ROW"),
2066            AfterMatchSkip::ToNextRow => write!(f, " TO NEXT ROW"),
2067            AfterMatchSkip::ToFirst(symbol) => write!(f, "TO FIRST {symbol}"),
2068            AfterMatchSkip::ToLast(symbol) => write!(f, "TO LAST {symbol}"),
2069        }
2070    }
2071}
2072
2073#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2074#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2075#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2076/// The mode for handling empty matches in a `MATCH_RECOGNIZE` operation.
2077pub enum EmptyMatchesMode {
2078    /// `SHOW EMPTY MATCHES`
2079    Show,
2080    /// `OMIT EMPTY MATCHES`
2081    Omit,
2082    /// `WITH UNMATCHED ROWS`
2083    WithUnmatched,
2084}
2085
2086impl fmt::Display for EmptyMatchesMode {
2087    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2088        match self {
2089            EmptyMatchesMode::Show => write!(f, "SHOW EMPTY MATCHES"),
2090            EmptyMatchesMode::Omit => write!(f, "OMIT EMPTY MATCHES"),
2091            EmptyMatchesMode::WithUnmatched => write!(f, "WITH UNMATCHED ROWS"),
2092        }
2093    }
2094}
2095
2096/// A symbol defined in a `MATCH_RECOGNIZE` operation.
2097///
2098/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#define-defining-symbols>.
2099#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2100#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2101#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2102/// A symbol defined in a `MATCH_RECOGNIZE` operation.
2103pub struct SymbolDefinition {
2104    /// The symbol identifier.
2105    pub symbol: Ident,
2106    /// The expression defining the symbol.
2107    pub definition: Expr,
2108}
2109
2110impl fmt::Display for SymbolDefinition {
2111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2112        write!(f, "{} AS {}", self.symbol, self.definition)
2113    }
2114}
2115
2116/// A symbol in a `MATCH_RECOGNIZE` pattern.
2117#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2118#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2119#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2120pub enum MatchRecognizeSymbol {
2121    /// A named symbol, e.g. `S1`.
2122    Named(Ident),
2123    /// A virtual symbol representing the start of the of partition (`^`).
2124    Start,
2125    /// A virtual symbol representing the end of the partition (`$`).
2126    End,
2127}
2128
2129impl fmt::Display for MatchRecognizeSymbol {
2130    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2131        match self {
2132            MatchRecognizeSymbol::Named(symbol) => write!(f, "{symbol}"),
2133            MatchRecognizeSymbol::Start => write!(f, "^"),
2134            MatchRecognizeSymbol::End => write!(f, "$"),
2135        }
2136    }
2137}
2138
2139/// The pattern in a `MATCH_RECOGNIZE` operation.
2140///
2141/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#pattern-specifying-the-pattern-to-match>.
2142#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2143#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2144#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2145pub enum MatchRecognizePattern {
2146    /// A named symbol such as `S1` or a virtual symbol such as `^`.
2147    Symbol(MatchRecognizeSymbol),
2148    /// {- symbol -}
2149    Exclude(MatchRecognizeSymbol),
2150    /// PERMUTE(symbol_1, ..., symbol_n)
2151    Permute(Vec<MatchRecognizeSymbol>),
2152    /// pattern_1 pattern_2 ... pattern_n
2153    Concat(Vec<MatchRecognizePattern>),
2154    /// ( pattern )
2155    Group(Box<MatchRecognizePattern>),
2156    /// pattern_1 | pattern_2 | ... | pattern_n
2157    Alternation(Vec<MatchRecognizePattern>),
2158    /// e.g. pattern*
2159    Repetition(Box<MatchRecognizePattern>, RepetitionQuantifier),
2160}
2161
2162impl fmt::Display for MatchRecognizePattern {
2163    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2164        use MatchRecognizePattern::*;
2165        match self {
2166            Symbol(symbol) => write!(f, "{symbol}"),
2167            Exclude(symbol) => write!(f, "{{- {symbol} -}}"),
2168            Permute(symbols) => write!(f, "PERMUTE({})", display_comma_separated(symbols)),
2169            Concat(patterns) => write!(f, "{}", display_separated(patterns, " ")),
2170            Group(pattern) => write!(f, "( {pattern} )"),
2171            Alternation(patterns) => write!(f, "{}", display_separated(patterns, " | ")),
2172            Repetition(pattern, op) => write!(f, "{pattern}{op}"),
2173        }
2174    }
2175}
2176
2177/// Determines the minimum and maximum allowed occurrences of a pattern in a
2178/// `MATCH_RECOGNIZE` operation.
2179#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2180#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2181#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2182pub enum RepetitionQuantifier {
2183    /// `*`
2184    ZeroOrMore,
2185    /// `+`
2186    OneOrMore,
2187    /// `?`
2188    AtMostOne,
2189    /// `{n}`
2190    Exactly(u32),
2191    /// `{n,}`
2192    AtLeast(u32),
2193    /// `{,n}`
2194    AtMost(u32),
2195    /// `{n,m}
2196    Range(u32, u32),
2197}
2198
2199impl fmt::Display for RepetitionQuantifier {
2200    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2201        use RepetitionQuantifier::*;
2202        match self {
2203            ZeroOrMore => write!(f, "*"),
2204            OneOrMore => write!(f, "+"),
2205            AtMostOne => write!(f, "?"),
2206            Exactly(n) => write!(f, "{{{n}}}"),
2207            AtLeast(n) => write!(f, "{{{n},}}"),
2208            AtMost(n) => write!(f, "{{,{n}}}"),
2209            Range(n, m) => write!(f, "{{{n},{m}}}"),
2210        }
2211    }
2212}
2213
2214impl fmt::Display for TableFactor {
2215    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2216        match self {
2217            TableFactor::Table {
2218                name,
2219                alias,
2220                args,
2221                with_hints,
2222                version,
2223                partitions,
2224                with_ordinality,
2225                json_path,
2226                sample,
2227                index_hints,
2228            } => {
2229                name.fmt(f)?;
2230                if let Some(json_path) = json_path {
2231                    json_path.fmt(f)?;
2232                }
2233                if !partitions.is_empty() {
2234                    write!(f, " PARTITION ({})", display_comma_separated(partitions))?;
2235                }
2236                if let Some(args) = args {
2237                    write!(f, "(")?;
2238                    write!(f, "{}", display_comma_separated(&args.args))?;
2239                    if let Some(ref settings) = args.settings {
2240                        if !args.args.is_empty() {
2241                            write!(f, ", ")?;
2242                        }
2243                        write!(f, "SETTINGS {}", display_comma_separated(settings))?;
2244                    }
2245                    write!(f, ")")?;
2246                }
2247                if *with_ordinality {
2248                    write!(f, " WITH ORDINALITY")?;
2249                }
2250                if let Some(TableSampleKind::BeforeTableAlias(sample)) = sample {
2251                    write!(f, " {sample}")?;
2252                }
2253                if let Some(alias) = alias {
2254                    write!(f, " {alias}")?;
2255                }
2256                if !index_hints.is_empty() {
2257                    write!(f, " {}", display_separated(index_hints, " "))?;
2258                }
2259                if !with_hints.is_empty() {
2260                    write!(f, " WITH ({})", display_comma_separated(with_hints))?;
2261                }
2262                if let Some(version) = version {
2263                    write!(f, " {version}")?;
2264                }
2265                if let Some(TableSampleKind::AfterTableAlias(sample)) = sample {
2266                    write!(f, " {sample}")?;
2267                }
2268                Ok(())
2269            }
2270            TableFactor::Derived {
2271                lateral,
2272                subquery,
2273                alias,
2274                sample,
2275            } => {
2276                if *lateral {
2277                    write!(f, "LATERAL ")?;
2278                }
2279                f.write_str("(")?;
2280                NewLine.fmt(f)?;
2281                Indent(subquery).fmt(f)?;
2282                NewLine.fmt(f)?;
2283                f.write_str(")")?;
2284                if let Some(alias) = alias {
2285                    write!(f, " {alias}")?;
2286                }
2287                if let Some(TableSampleKind::AfterTableAlias(sample)) = sample {
2288                    write!(f, " {sample}")?;
2289                }
2290                Ok(())
2291            }
2292            TableFactor::Function {
2293                lateral,
2294                name,
2295                args,
2296                with_ordinality,
2297                alias,
2298            } => {
2299                if *lateral {
2300                    write!(f, "LATERAL ")?;
2301                }
2302                write!(f, "{name}")?;
2303                write!(f, "({})", display_comma_separated(args))?;
2304                if *with_ordinality {
2305                    write!(f, " WITH ORDINALITY")?;
2306                }
2307                if let Some(alias) = alias {
2308                    write!(f, " {alias}")?;
2309                }
2310                Ok(())
2311            }
2312            TableFactor::TableFunction { expr, alias } => {
2313                write!(f, "TABLE({expr})")?;
2314                if let Some(alias) = alias {
2315                    write!(f, " {alias}")?;
2316                }
2317                Ok(())
2318            }
2319            TableFactor::UNNEST {
2320                alias,
2321                array_exprs,
2322                with_offset,
2323                with_offset_alias,
2324                with_ordinality,
2325            } => {
2326                write!(f, "UNNEST({})", display_comma_separated(array_exprs))?;
2327
2328                if *with_ordinality {
2329                    write!(f, " WITH ORDINALITY")?;
2330                }
2331
2332                if let Some(alias) = alias {
2333                    write!(f, " {alias}")?;
2334                }
2335                if *with_offset {
2336                    write!(f, " WITH OFFSET")?;
2337                }
2338                if let Some(alias) = with_offset_alias {
2339                    write!(f, " {alias}")?;
2340                }
2341                Ok(())
2342            }
2343            TableFactor::JsonTable {
2344                json_expr,
2345                json_path,
2346                columns,
2347                alias,
2348            } => {
2349                write!(
2350                    f,
2351                    "JSON_TABLE({json_expr}, {json_path} COLUMNS({columns}))",
2352                    columns = display_comma_separated(columns)
2353                )?;
2354                if let Some(alias) = alias {
2355                    write!(f, " {alias}")?;
2356                }
2357                Ok(())
2358            }
2359            TableFactor::OpenJsonTable {
2360                json_expr,
2361                json_path,
2362                columns,
2363                alias,
2364            } => {
2365                write!(f, "OPENJSON({json_expr}")?;
2366                if let Some(json_path) = json_path {
2367                    write!(f, ", {json_path}")?;
2368                }
2369                write!(f, ")")?;
2370                if !columns.is_empty() {
2371                    write!(f, " WITH ({})", display_comma_separated(columns))?;
2372                }
2373                if let Some(alias) = alias {
2374                    write!(f, " {alias}")?;
2375                }
2376                Ok(())
2377            }
2378            TableFactor::NestedJoin {
2379                table_with_joins,
2380                alias,
2381            } => {
2382                write!(f, "({table_with_joins})")?;
2383                if let Some(alias) = alias {
2384                    write!(f, " {alias}")?;
2385                }
2386                Ok(())
2387            }
2388            TableFactor::Pivot {
2389                table,
2390                aggregate_functions,
2391                value_column,
2392                value_source,
2393                default_on_null,
2394                alias,
2395            } => {
2396                write!(
2397                    f,
2398                    "{table} PIVOT({} FOR ",
2399                    display_comma_separated(aggregate_functions),
2400                )?;
2401                if value_column.len() == 1 {
2402                    write!(f, "{}", value_column[0])?;
2403                } else {
2404                    write!(f, "({})", display_comma_separated(value_column))?;
2405                }
2406                write!(f, " IN ({value_source})")?;
2407                if let Some(expr) = default_on_null {
2408                    write!(f, " DEFAULT ON NULL ({expr})")?;
2409                }
2410                write!(f, ")")?;
2411                if let Some(alias) = alias {
2412                    write!(f, " {alias}")?;
2413                }
2414                Ok(())
2415            }
2416            TableFactor::Unpivot {
2417                table,
2418                null_inclusion,
2419                value,
2420                name,
2421                columns,
2422                alias,
2423            } => {
2424                write!(f, "{table} UNPIVOT")?;
2425                if let Some(null_inclusion) = null_inclusion {
2426                    write!(f, " {null_inclusion} ")?;
2427                }
2428                write!(
2429                    f,
2430                    "({} FOR {} IN ({}))",
2431                    value,
2432                    name,
2433                    display_comma_separated(columns)
2434                )?;
2435                if let Some(alias) = alias {
2436                    write!(f, " {alias}")?;
2437                }
2438                Ok(())
2439            }
2440            TableFactor::UnpivotExpr {
2441                expression,
2442                value_alias,
2443                attribute_alias,
2444            } => {
2445                write!(f, "UNPIVOT {expression} AS {value_alias}")?;
2446                if let Some(attribute_alias) = attribute_alias {
2447                    write!(f, " AT {attribute_alias}")?;
2448                }
2449                Ok(())
2450            }
2451            TableFactor::MatchRecognize {
2452                table,
2453                partition_by,
2454                order_by,
2455                measures,
2456                rows_per_match,
2457                after_match_skip,
2458                pattern,
2459                symbols,
2460                alias,
2461            } => {
2462                write!(f, "{table} MATCH_RECOGNIZE(")?;
2463                if !partition_by.is_empty() {
2464                    write!(f, "PARTITION BY {} ", display_comma_separated(partition_by))?;
2465                }
2466                if !order_by.is_empty() {
2467                    write!(f, "ORDER BY {} ", display_comma_separated(order_by))?;
2468                }
2469                if !measures.is_empty() {
2470                    write!(f, "MEASURES {} ", display_comma_separated(measures))?;
2471                }
2472                if let Some(rows_per_match) = rows_per_match {
2473                    write!(f, "{rows_per_match} ")?;
2474                }
2475                if let Some(after_match_skip) = after_match_skip {
2476                    write!(f, "{after_match_skip} ")?;
2477                }
2478                write!(f, "PATTERN ({pattern}) ")?;
2479                write!(f, "DEFINE {})", display_comma_separated(symbols))?;
2480                if let Some(alias) = alias {
2481                    write!(f, " {alias}")?;
2482                }
2483                Ok(())
2484            }
2485            TableFactor::XmlTable {
2486                row_expression,
2487                passing,
2488                columns,
2489                alias,
2490                namespaces,
2491            } => {
2492                write!(f, "XMLTABLE(")?;
2493                if !namespaces.is_empty() {
2494                    write!(
2495                        f,
2496                        "XMLNAMESPACES({}), ",
2497                        display_comma_separated(namespaces)
2498                    )?;
2499                }
2500                write!(
2501                    f,
2502                    "{row_expression}{passing} COLUMNS {columns})",
2503                    columns = display_comma_separated(columns)
2504                )?;
2505                if let Some(alias) = alias {
2506                    write!(f, " {alias}")?;
2507                }
2508                Ok(())
2509            }
2510            TableFactor::SemanticView {
2511                name,
2512                dimensions,
2513                metrics,
2514                facts,
2515                where_clause,
2516                alias,
2517            } => {
2518                write!(f, "SEMANTIC_VIEW({name}")?;
2519
2520                if !dimensions.is_empty() {
2521                    write!(f, " DIMENSIONS {}", display_comma_separated(dimensions))?;
2522                }
2523
2524                if !metrics.is_empty() {
2525                    write!(f, " METRICS {}", display_comma_separated(metrics))?;
2526                }
2527
2528                if !facts.is_empty() {
2529                    write!(f, " FACTS {}", display_comma_separated(facts))?;
2530                }
2531
2532                if let Some(where_clause) = where_clause {
2533                    write!(f, " WHERE {where_clause}")?;
2534                }
2535
2536                write!(f, ")")?;
2537
2538                if let Some(alias) = alias {
2539                    write!(f, " {alias}")?;
2540                }
2541
2542                Ok(())
2543            }
2544        }
2545    }
2546}
2547
2548#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2549#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2550#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2551/// An alias for a table reference, optionally including an explicit `AS` and column names.
2552pub struct TableAlias {
2553    /// Tells whether the alias was introduced with an explicit, preceding "AS"
2554    /// keyword, e.g. `AS name`. Typically, the keyword is preceding the name
2555    /// (e.g. `.. FROM table AS t ..`).
2556    pub explicit: bool,
2557    /// Alias identifier for the table.
2558    pub name: Ident,
2559    /// Optional column aliases declared in parentheses after the table alias.
2560    pub columns: Vec<TableAliasColumnDef>,
2561    /// Optional PartiQL index alias declared with `AT`. For example:
2562    /// ```sql
2563    /// SELECT element, index FROM bar AS b, b.data.scalar_array AS element AT index
2564    /// ```
2565    /// See: <https://docs.aws.amazon.com/redshift/latest/dg/query-super.html>
2566    pub at: Option<Ident>,
2567}
2568
2569impl fmt::Display for TableAlias {
2570    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2571        write!(f, "{}{}", if self.explicit { "AS " } else { "" }, self.name)?;
2572        if !self.columns.is_empty() {
2573            write!(f, " ({})", display_comma_separated(&self.columns))?;
2574        }
2575        if let Some(at) = &self.at {
2576            write!(f, " AT {at}")?;
2577        }
2578        Ok(())
2579    }
2580}
2581
2582/// SQL column definition in a table expression alias.
2583/// Most of the time, the data type is not specified.
2584/// But some table-valued functions do require specifying the data type.
2585///
2586/// See <https://www.postgresql.org/docs/17/queries-table-expressions.html#QUERIES-TABLEFUNCTIONS>
2587#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2588#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2589#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2590pub struct TableAliasColumnDef {
2591    /// Column name alias
2592    pub name: Ident,
2593    /// Some table-valued functions require specifying the data type in the alias.
2594    pub data_type: Option<DataType>,
2595}
2596
2597impl TableAliasColumnDef {
2598    /// Create a new table alias column definition with only a name and no type
2599    pub fn from_name<S: Into<String>>(name: S) -> Self {
2600        TableAliasColumnDef {
2601            name: Ident::new(name),
2602            data_type: None,
2603        }
2604    }
2605}
2606
2607impl fmt::Display for TableAliasColumnDef {
2608    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2609        write!(f, "{}", self.name)?;
2610        if let Some(ref data_type) = self.data_type {
2611            write!(f, " {data_type}")?;
2612        }
2613        Ok(())
2614    }
2615}
2616
2617#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2618#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2619#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2620/// Specifies a table version selection, e.g. `FOR SYSTEM_TIME AS OF` or `AT(...)`.
2621pub enum TableVersion {
2622    /// When the table version is defined using `FOR SYSTEM_TIME AS OF`.
2623    /// For example: `SELECT * FROM tbl FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)`
2624    ForSystemTimeAsOf(Expr),
2625    /// When the table version is defined using `TIMESTAMP AS OF`.
2626    /// Databricks supports this syntax.
2627    /// For example: `SELECT * FROM tbl TIMESTAMP AS OF CURRENT_TIMESTAMP() - INTERVAL 1 HOUR`
2628    TimestampAsOf(Expr),
2629    /// When the table version is defined using `VERSION AS OF`.
2630    /// Databricks supports this syntax.
2631    /// For example: `SELECT * FROM tbl VERSION AS OF 2`
2632    VersionAsOf(Expr),
2633    /// When the table version is defined using a function.
2634    /// For example: `SELECT * FROM tbl AT(TIMESTAMP => '2020-08-14 09:30:00')`
2635    Function(Expr),
2636    /// Snowflake `CHANGES` clause for change tracking queries.
2637    /// For example:
2638    /// ```sql
2639    /// SELECT * FROM t
2640    ///   CHANGES(INFORMATION => DEFAULT)
2641    ///   AT(TIMESTAMP => TO_TIMESTAMP_TZ('...'))
2642    ///   END(TIMESTAMP => TO_TIMESTAMP_TZ('...'))
2643    /// ```
2644    /// <https://docs.snowflake.com/en/sql-reference/constructs/changes>
2645    Changes {
2646        /// The `CHANGES(INFORMATION => ...)` function-call expression.
2647        changes: Expr,
2648        /// The `AT(TIMESTAMP => ...)` function-call expression.
2649        at: Expr,
2650        /// The optional `END(TIMESTAMP => ...)` function-call expression.
2651        end: Option<Expr>,
2652    },
2653}
2654
2655impl Display for TableVersion {
2656    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2657        match self {
2658            TableVersion::ForSystemTimeAsOf(e) => write!(f, "FOR SYSTEM_TIME AS OF {e}")?,
2659            TableVersion::TimestampAsOf(e) => write!(f, "TIMESTAMP AS OF {e}")?,
2660            TableVersion::VersionAsOf(e) => write!(f, "VERSION AS OF {e}")?,
2661            TableVersion::Function(func) => write!(f, "{func}")?,
2662            TableVersion::Changes { changes, at, end } => {
2663                write!(f, "{changes} {at}")?;
2664                if let Some(end) = end {
2665                    write!(f, " {end}")?;
2666                }
2667            }
2668        }
2669        Ok(())
2670    }
2671}
2672
2673#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2674#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2675#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2676/// A single `JOIN` clause including relation and join operator/options.
2677pub struct Join {
2678    /// The joined table factor (table reference or derived table).
2679    pub relation: TableFactor,
2680    /// ClickHouse supports the optional `GLOBAL` keyword before the join operator.
2681    /// See [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/join)
2682    pub global: bool,
2683    /// The join operator and its constraint (INNER/LEFT/RIGHT/CROSS/ASOF/etc.).
2684    pub join_operator: JoinOperator,
2685}
2686
2687impl fmt::Display for Join {
2688    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2689        fn prefix(constraint: &JoinConstraint) -> &'static str {
2690            match constraint {
2691                JoinConstraint::Natural => "NATURAL ",
2692                _ => "",
2693            }
2694        }
2695        fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
2696            struct Suffix<'a>(&'a JoinConstraint);
2697            impl fmt::Display for Suffix<'_> {
2698                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2699                    match self.0 {
2700                        JoinConstraint::On(expr) => write!(f, " ON {expr}"),
2701                        JoinConstraint::Using(attrs) => {
2702                            write!(f, " USING({})", display_comma_separated(attrs))
2703                        }
2704                        _ => Ok(()),
2705                    }
2706                }
2707            }
2708            Suffix(constraint)
2709        }
2710        if self.global {
2711            write!(f, "GLOBAL ")?;
2712        }
2713
2714        match &self.join_operator {
2715            JoinOperator::Join(constraint) => f.write_fmt(format_args!(
2716                "{}JOIN {}{}",
2717                prefix(constraint),
2718                self.relation,
2719                suffix(constraint)
2720            )),
2721            JoinOperator::Inner(constraint) => f.write_fmt(format_args!(
2722                "{}INNER JOIN {}{}",
2723                prefix(constraint),
2724                self.relation,
2725                suffix(constraint)
2726            )),
2727            JoinOperator::Left(constraint) => f.write_fmt(format_args!(
2728                "{}LEFT JOIN {}{}",
2729                prefix(constraint),
2730                self.relation,
2731                suffix(constraint)
2732            )),
2733            JoinOperator::LeftOuter(constraint) => f.write_fmt(format_args!(
2734                "{}LEFT OUTER JOIN {}{}",
2735                prefix(constraint),
2736                self.relation,
2737                suffix(constraint)
2738            )),
2739            JoinOperator::Right(constraint) => f.write_fmt(format_args!(
2740                "{}RIGHT JOIN {}{}",
2741                prefix(constraint),
2742                self.relation,
2743                suffix(constraint)
2744            )),
2745            JoinOperator::RightOuter(constraint) => f.write_fmt(format_args!(
2746                "{}RIGHT OUTER JOIN {}{}",
2747                prefix(constraint),
2748                self.relation,
2749                suffix(constraint)
2750            )),
2751            JoinOperator::FullOuter(constraint) => f.write_fmt(format_args!(
2752                "{}FULL JOIN {}{}",
2753                prefix(constraint),
2754                self.relation,
2755                suffix(constraint)
2756            )),
2757            JoinOperator::CrossJoin(constraint) => f.write_fmt(format_args!(
2758                "CROSS JOIN {}{}",
2759                self.relation,
2760                suffix(constraint)
2761            )),
2762            JoinOperator::Semi(constraint) => f.write_fmt(format_args!(
2763                "{}SEMI JOIN {}{}",
2764                prefix(constraint),
2765                self.relation,
2766                suffix(constraint)
2767            )),
2768            JoinOperator::LeftSemi(constraint) => f.write_fmt(format_args!(
2769                "{}LEFT SEMI JOIN {}{}",
2770                prefix(constraint),
2771                self.relation,
2772                suffix(constraint)
2773            )),
2774            JoinOperator::RightSemi(constraint) => f.write_fmt(format_args!(
2775                "{}RIGHT SEMI JOIN {}{}",
2776                prefix(constraint),
2777                self.relation,
2778                suffix(constraint)
2779            )),
2780            JoinOperator::Anti(constraint) => f.write_fmt(format_args!(
2781                "{}ANTI JOIN {}{}",
2782                prefix(constraint),
2783                self.relation,
2784                suffix(constraint)
2785            )),
2786            JoinOperator::LeftAnti(constraint) => f.write_fmt(format_args!(
2787                "{}LEFT ANTI JOIN {}{}",
2788                prefix(constraint),
2789                self.relation,
2790                suffix(constraint)
2791            )),
2792            JoinOperator::RightAnti(constraint) => f.write_fmt(format_args!(
2793                "{}RIGHT ANTI JOIN {}{}",
2794                prefix(constraint),
2795                self.relation,
2796                suffix(constraint)
2797            )),
2798            JoinOperator::CrossApply => f.write_fmt(format_args!("CROSS APPLY {}", self.relation)),
2799            JoinOperator::OuterApply => f.write_fmt(format_args!("OUTER APPLY {}", self.relation)),
2800            JoinOperator::AsOf {
2801                match_condition,
2802                constraint,
2803            } => f.write_fmt(format_args!(
2804                "ASOF JOIN {} MATCH_CONDITION ({match_condition}){}",
2805                self.relation,
2806                suffix(constraint)
2807            )),
2808            JoinOperator::StraightJoin(constraint) => f.write_fmt(format_args!(
2809                "STRAIGHT_JOIN {}{}",
2810                self.relation,
2811                suffix(constraint)
2812            )),
2813            JoinOperator::ArrayJoin => f.write_fmt(format_args!("ARRAY JOIN {}", self.relation)),
2814            JoinOperator::LeftArrayJoin => {
2815                f.write_fmt(format_args!("LEFT ARRAY JOIN {}", self.relation))
2816            }
2817            JoinOperator::InnerArrayJoin => {
2818                f.write_fmt(format_args!("INNER ARRAY JOIN {}", self.relation))
2819            }
2820        }
2821    }
2822}
2823
2824#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2825#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2826#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2827/// The operator used for joining two tables, e.g. `INNER`, `LEFT`, `CROSS`, `ASOF`, etc.
2828pub enum JoinOperator {
2829    /// Generic `JOIN` with an optional constraint.
2830    Join(JoinConstraint),
2831    /// `INNER JOIN` with an optional constraint.
2832    Inner(JoinConstraint),
2833    /// `LEFT JOIN` with an optional constraint.
2834    Left(JoinConstraint),
2835    /// `LEFT OUTER JOIN` with an optional constraint.
2836    LeftOuter(JoinConstraint),
2837    /// `RIGHT JOIN` with an optional constraint.
2838    Right(JoinConstraint),
2839    /// `RIGHT OUTER JOIN` with an optional constraint.
2840    RightOuter(JoinConstraint),
2841    /// `FULL OUTER JOIN` with an optional constraint.
2842    FullOuter(JoinConstraint),
2843    /// `CROSS JOIN` (constraint usage is non-standard).
2844    CrossJoin(JoinConstraint),
2845    /// `SEMI JOIN` (non-standard)
2846    Semi(JoinConstraint),
2847    /// `LEFT SEMI JOIN` (non-standard)
2848    LeftSemi(JoinConstraint),
2849    /// `RIGHT SEMI JOIN` (non-standard)
2850    RightSemi(JoinConstraint),
2851    /// `ANTI JOIN` (non-standard)
2852    Anti(JoinConstraint),
2853    /// `LEFT ANTI JOIN` (non-standard)
2854    LeftAnti(JoinConstraint),
2855    /// `RIGHT ANTI JOIN` (non-standard)
2856    RightAnti(JoinConstraint),
2857    /// `CROSS APPLY` (non-standard)
2858    CrossApply,
2859    /// `OUTER APPLY` (non-standard)
2860    OuterApply,
2861    /// `ASOF` joins are used for joining time-series tables whose timestamp columns do not match exactly.
2862    ///
2863    /// See <https://docs.snowflake.com/en/sql-reference/constructs/asof-join>.
2864    AsOf {
2865        /// Condition used to match records in the `ASOF` join.
2866        match_condition: Expr,
2867        /// Additional constraint applied to the `ASOF` join.
2868        constraint: JoinConstraint,
2869    },
2870    /// `STRAIGHT_JOIN` (MySQL non-standard behavior)
2871    ///
2872    /// See <https://dev.mysql.com/doc/refman/8.4/en/join.html>.
2873    StraightJoin(JoinConstraint),
2874    /// ClickHouse: `ARRAY JOIN` for unnesting arrays inline.
2875    ///
2876    /// See <https://clickhouse.com/docs/en/sql-reference/statements/select/array-join>.
2877    ArrayJoin,
2878    /// ClickHouse: `LEFT ARRAY JOIN` for unnesting arrays inline (preserves rows with empty arrays).
2879    LeftArrayJoin,
2880    /// ClickHouse: `INNER ARRAY JOIN` for unnesting arrays inline (filters rows with empty arrays).
2881    InnerArrayJoin,
2882}
2883
2884#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2885#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2886#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2887/// Represents how two tables are constrained in a join: `ON`, `USING`, `NATURAL`, or none.
2888pub enum JoinConstraint {
2889    /// `ON <expr>` join condition.
2890    On(Expr),
2891    /// `USING(...)` list of column names.
2892    Using(Vec<ObjectName>),
2893    /// `NATURAL` join (columns matched automatically).
2894    Natural,
2895    /// No constraint specified (e.g. `CROSS JOIN`).
2896    None,
2897}
2898
2899#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2900#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2901#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2902/// The kind of `ORDER BY` clause: either `ALL` with modifiers or a list of expressions.
2903pub enum OrderByKind {
2904    /// `GROUP BY ALL`/`ORDER BY ALL` syntax with optional modifiers.
2905    ///
2906    /// [DuckDB]:  <https://duckdb.org/docs/sql/query_syntax/orderby>
2907    /// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by>
2908    All(OrderByOptions),
2909
2910    /// A standard list of ordering expressions.
2911    Expressions(Vec<OrderByExpr>),
2912}
2913
2914#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2915#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2916#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2917#[cfg_attr(feature = "visitor", visit(with = "visit_order_by"))]
2918/// Represents an `ORDER BY` clause with its kind and optional `INTERPOLATE`.
2919pub struct OrderBy {
2920    /// The kind of ordering (expressions or `ALL`).
2921    pub kind: OrderByKind,
2922
2923    /// Optional `INTERPOLATE` clause (ClickHouse extension).
2924    pub interpolate: Option<Interpolate>,
2925}
2926
2927impl fmt::Display for OrderBy {
2928    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2929        write!(f, "ORDER BY")?;
2930        match &self.kind {
2931            OrderByKind::Expressions(exprs) => {
2932                write!(f, " {}", display_comma_separated(exprs))?;
2933            }
2934            OrderByKind::All(all) => {
2935                write!(f, " ALL{all}")?;
2936            }
2937        }
2938
2939        if let Some(ref interpolate) = self.interpolate {
2940            match &interpolate.exprs {
2941                Some(exprs) => write!(f, " INTERPOLATE ({})", display_comma_separated(exprs))?,
2942                None => write!(f, " INTERPOLATE")?,
2943            }
2944        }
2945
2946        Ok(())
2947    }
2948}
2949
2950/// An `ORDER BY` expression
2951#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2952#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2953#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2954#[cfg_attr(feature = "visitor", visit(with = "visit_order_by_expr"))]
2955pub struct OrderByExpr {
2956    /// The expression to order by.
2957    pub expr: Expr,
2958    /// Ordering options such as `ASC`/`DESC`/`USING <operator>` and `NULLS` behavior.
2959    pub options: OrderByOptions,
2960    /// Optional `WITH FILL` clause (ClickHouse extension) which specifies how to fill gaps.
2961    pub with_fill: Option<WithFill>,
2962}
2963
2964impl From<Ident> for OrderByExpr {
2965    fn from(ident: Ident) -> Self {
2966        OrderByExpr {
2967            expr: Expr::Identifier(ident),
2968            options: OrderByOptions::default(),
2969            with_fill: None,
2970        }
2971    }
2972}
2973
2974impl fmt::Display for OrderByExpr {
2975    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2976        write!(f, "{}", self.expr)?;
2977        write!(f, "{}", self.options)?;
2978        if let Some(ref with_fill) = self.with_fill {
2979            write!(f, " {with_fill}")?
2980        }
2981        Ok(())
2982    }
2983}
2984
2985/// ClickHouse `WITH FILL` modifier for `ORDER BY` clause.
2986/// Supported by [ClickHouse syntax]
2987///
2988/// [ClickHouse syntax]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier>
2989#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2990#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2991#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2992/// `WITH FILL` options for ClickHouse `ORDER BY` expressions.
2993pub struct WithFill {
2994    /// Optional lower bound expression for the fill range (`FROM <expr>`).
2995    pub from: Option<Expr>,
2996    /// Optional upper bound expression for the fill range (`TO <expr>`).
2997    pub to: Option<Expr>,
2998    /// Optional step expression specifying interpolation step (`STEP <expr>`).
2999    pub step: Option<Expr>,
3000}
3001
3002impl fmt::Display for WithFill {
3003    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3004        write!(f, "WITH FILL")?;
3005        if let Some(ref from) = self.from {
3006            write!(f, " FROM {from}")?;
3007        }
3008        if let Some(ref to) = self.to {
3009            write!(f, " TO {to}")?;
3010        }
3011        if let Some(ref step) = self.step {
3012            write!(f, " STEP {step}")?;
3013        }
3014        Ok(())
3015    }
3016}
3017
3018/// ClickHouse `INTERPOLATE` clause for use in `ORDER BY` clause when using `WITH FILL` modifier.
3019/// Supported by [ClickHouse syntax]
3020///
3021/// [ClickHouse syntax]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier>
3022#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3023#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3024#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3025/// An expression used by `WITH FILL`/`INTERPOLATE` to specify interpolation for a column.
3026pub struct InterpolateExpr {
3027    /// The column to interpolate.
3028    pub column: Ident,
3029    /// Optional `AS <expr>` expression specifying how to compute interpolated values.
3030    pub expr: Option<Expr>,
3031}
3032
3033#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3034#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3035#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3036/// `INTERPOLATE` clause used with ClickHouse `WITH FILL` to compute missing values.
3037pub struct Interpolate {
3038    /// Optional list of interpolation expressions.
3039    pub exprs: Option<Vec<InterpolateExpr>>,
3040}
3041
3042impl fmt::Display for InterpolateExpr {
3043    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3044        write!(f, "{}", self.column)?;
3045        if let Some(ref expr) = self.expr {
3046            write!(f, " AS {expr}")?;
3047        }
3048        Ok(())
3049    }
3050}
3051
3052/// The sort order for an `ORDER BY` expression.
3053///
3054/// See PostgreSQL `USING` operator:
3055/// <https://www.postgresql.org/docs/current/sql-select.html>
3056#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3057#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3058#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3059pub enum OrderBySort {
3060    /// `ASC`
3061    Asc,
3062    /// `DESC`
3063    Desc,
3064    /// PostgreSQL `USING <operator>` ordering.
3065    ///
3066    /// See <https://www.postgresql.org/docs/current/sql-select.html>
3067    Using(ObjectName),
3068}
3069
3070#[derive(Default, Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3071#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3072#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3073/// Options for an `ORDER BY` expression.
3074pub struct OrderByOptions {
3075    /// Optional sort order: `ASC`, `DESC`, or `USING <operator>`.
3076    pub sort: Option<OrderBySort>,
3077    /// Optional `NULLS FIRST` (`Some(true)`) or `NULLS LAST` (`Some(false)`).
3078    pub nulls_first: Option<bool>,
3079}
3080
3081impl fmt::Display for OrderByOptions {
3082    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3083        match &self.sort {
3084            Some(OrderBySort::Asc) => write!(f, " ASC")?,
3085            Some(OrderBySort::Desc) => write!(f, " DESC")?,
3086            Some(OrderBySort::Using(op)) => {
3087                if op.0.len() > 1 {
3088                    write!(f, " USING OPERATOR({op})")?;
3089                } else {
3090                    write!(f, " USING {op}")?;
3091                }
3092            }
3093            None => (),
3094        }
3095        match self.nulls_first {
3096            Some(true) => write!(f, " NULLS FIRST")?,
3097            Some(false) => write!(f, " NULLS LAST")?,
3098            None => (),
3099        }
3100        Ok(())
3101    }
3102}
3103
3104#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3105#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3106#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3107/// Represents the different syntactic forms of `LIMIT` clauses.
3108pub enum LimitClause {
3109    /// Standard SQL `LIMIT` syntax (optionally `BY` and `OFFSET`).
3110    ///
3111    /// `LIMIT <limit> [BY <expr>,<expr>,...] [OFFSET <offset>]`
3112    LimitOffset {
3113        /// `LIMIT { <N> | ALL }` expression.
3114        limit: Option<Expr>,
3115        /// Optional `OFFSET` expression with optional `ROW(S)` keyword.
3116        offset: Option<Offset>,
3117        /// Optional `BY { <expr>,... }` list used by some dialects (ClickHouse).
3118        limit_by: Vec<Expr>,
3119    },
3120    /// MySQL-specific syntax: `LIMIT <offset>, <limit>` (order reversed).
3121    OffsetCommaLimit {
3122        /// The offset expression.
3123        offset: Expr,
3124        /// The limit expression.
3125        limit: Expr,
3126    },
3127}
3128
3129impl fmt::Display for LimitClause {
3130    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3131        match self {
3132            LimitClause::LimitOffset {
3133                limit,
3134                limit_by,
3135                offset,
3136            } => {
3137                if let Some(ref limit) = limit {
3138                    write!(f, " LIMIT {limit}")?;
3139                }
3140                if let Some(ref offset) = offset {
3141                    write!(f, " {offset}")?;
3142                }
3143                if !limit_by.is_empty() {
3144                    debug_assert!(limit.is_some());
3145                    write!(f, " BY {}", display_separated(limit_by, ", "))?;
3146                }
3147                Ok(())
3148            }
3149            LimitClause::OffsetCommaLimit { offset, limit } => {
3150                write!(f, " LIMIT {offset}, {limit}")
3151            }
3152        }
3153    }
3154}
3155
3156#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3157#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3158#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3159/// `OFFSET` clause consisting of a value and a rows specifier.
3160pub struct Offset {
3161    /// The numeric expression following `OFFSET`.
3162    pub value: Expr,
3163    /// Whether the offset uses `ROW`/`ROWS` or omits it.
3164    pub rows: OffsetRows,
3165}
3166
3167impl fmt::Display for Offset {
3168    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3169        write!(f, "OFFSET {}{}", self.value, self.rows)
3170    }
3171}
3172
3173/// Stores the keyword after `OFFSET <number>`
3174#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3175#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3176#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3177pub enum OffsetRows {
3178    /// Omitting `ROW`/`ROWS` entirely (non-standard MySQL quirk).
3179    None,
3180    /// `ROW` keyword present.
3181    Row,
3182    /// `ROWS` keyword present.
3183    Rows,
3184}
3185
3186impl fmt::Display for OffsetRows {
3187    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3188        match self {
3189            OffsetRows::None => Ok(()),
3190            OffsetRows::Row => write!(f, " ROW"),
3191            OffsetRows::Rows => write!(f, " ROWS"),
3192        }
3193    }
3194}
3195
3196/// Pipe syntax, first introduced in Google BigQuery.
3197/// Example:
3198///
3199/// ```sql
3200/// FROM Produce
3201/// |> WHERE sales > 0
3202/// |> AGGREGATE SUM(sales) AS total_sales, COUNT(*) AS num_sales
3203///    GROUP BY item;
3204/// ```
3205///
3206/// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#pipe_syntax>
3207#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3208#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3209#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3210pub enum PipeOperator {
3211    /// Limits the number of rows to return in a query, with an optional OFFSET clause to skip over rows.
3212    ///
3213    /// Syntax: `|> LIMIT <n> [OFFSET <m>]`
3214    ///
3215    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#limit_pipe_operator>
3216    Limit {
3217        /// The expression specifying the number of rows to return.
3218        expr: Expr,
3219        /// Optional offset expression provided inline with `LIMIT`.
3220        offset: Option<Expr>,
3221    },
3222    /// Filters the results of the input table.
3223    ///
3224    /// Syntax: `|> WHERE <condition>`
3225    ///
3226    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#where_pipe_operator>
3227    Where {
3228        /// The filter expression.
3229        expr: Expr,
3230    },
3231    /// `ORDER BY <expr> [ASC|DESC], ...`
3232    OrderBy {
3233        /// The ordering expressions.
3234        exprs: Vec<OrderByExpr>,
3235    },
3236    /// Produces a new table with the listed columns, similar to the outermost SELECT clause in a table subquery in standard syntax.
3237    ///
3238    /// Syntax `|> SELECT <expr> [[AS] alias], ...`
3239    ///
3240    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#select_pipe_operator>
3241    Select {
3242        /// The select items to produce.
3243        exprs: Vec<SelectItem>,
3244    },
3245    /// Propagates the existing table and adds computed columns, similar to SELECT *, new_column in standard syntax.
3246    ///
3247    /// Syntax: `|> EXTEND <expr> [[AS] alias], ...`
3248    ///
3249    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#extend_pipe_operator>
3250    Extend {
3251        /// Expressions defining added columns.
3252        exprs: Vec<SelectItem>,
3253    },
3254    /// Replaces the value of a column in the current table, similar to SELECT * REPLACE (expression AS column) in standard syntax.
3255    ///
3256    /// Syntax: `|> SET <column> = <expression>, ...`
3257    ///
3258    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#set_pipe_operator>
3259    Set {
3260        /// Assignments to apply (`column = expr`).
3261        assignments: Vec<Assignment>,
3262    },
3263    /// Removes listed columns from the current table, similar to SELECT * EXCEPT (column) in standard syntax.
3264    ///
3265    /// Syntax: `|> DROP <column>, ...`
3266    ///
3267    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#drop_pipe_operator>
3268    Drop {
3269        /// Columns to drop.
3270        columns: Vec<Ident>,
3271    },
3272    /// Introduces a table alias for the input table, similar to applying the AS alias clause on a table subquery in standard syntax.
3273    ///
3274    /// Syntax: `|> AS <alias>`
3275    ///
3276    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#as_pipe_operator>
3277    As {
3278        /// Alias to assign to the input table.
3279        alias: Ident,
3280    },
3281    /// Performs aggregation on data across grouped rows or an entire table.
3282    ///
3283    /// Syntax: `|> AGGREGATE <agg_expr> [[AS] alias], ...`
3284    ///
3285    /// Syntax:
3286    /// ```norust
3287    /// |> AGGREGATE [<agg_expr> [[AS] alias], ...]
3288    /// GROUP BY <grouping_expr> [AS alias], ...
3289    /// ```
3290    ///
3291    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#aggregate_pipe_operator>
3292    Aggregate {
3293        /// Expressions computed for each row prior to grouping.
3294        full_table_exprs: Vec<ExprWithAliasAndOrderBy>,
3295        /// Grouping expressions for aggregation.
3296        group_by_expr: Vec<ExprWithAliasAndOrderBy>,
3297    },
3298    /// Selects a random sample of rows from the input table.
3299    /// Syntax: `|> TABLESAMPLE SYSTEM (10 PERCENT)
3300    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#tablesample_pipe_operator>
3301    TableSample {
3302        /// Sampling clause describing the sample.
3303        sample: Box<TableSample>,
3304    },
3305    /// Renames columns in the input table.
3306    ///
3307    /// Syntax: `|> RENAME old_name AS new_name, ...`
3308    ///
3309    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#rename_pipe_operator>
3310    Rename {
3311        /// Mappings of old to new identifiers.
3312        mappings: Vec<IdentWithAlias>,
3313    },
3314    /// Combines the input table with one or more tables using UNION.
3315    ///
3316    /// Syntax: `|> UNION [ALL|DISTINCT] (<query>), (<query>), ...`
3317    ///
3318    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#union_pipe_operator>
3319    Union {
3320        /// Set quantifier (`ALL` or `DISTINCT`).
3321        set_quantifier: SetQuantifier,
3322        /// The queries to combine with `UNION`.
3323        queries: Vec<Query>,
3324    },
3325    /// Returns only the rows that are present in both the input table and the specified tables.
3326    ///
3327    /// Syntax: `|> INTERSECT [DISTINCT] (<query>), (<query>), ...`
3328    ///
3329    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#intersect_pipe_operator>
3330    Intersect {
3331        /// Set quantifier for the `INTERSECT` operator.
3332        set_quantifier: SetQuantifier,
3333        /// The queries to intersect.
3334        queries: Vec<Query>,
3335    },
3336    /// Returns only the rows that are present in the input table but not in the specified tables.
3337    ///
3338    /// Syntax: `|> EXCEPT DISTINCT (<query>), (<query>), ...`
3339    ///
3340    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#except_pipe_operator>
3341    Except {
3342        /// Set quantifier for the `EXCEPT` operator.
3343        set_quantifier: SetQuantifier,
3344        /// The queries to exclude from the input set.
3345        queries: Vec<Query>,
3346    },
3347    /// Calls a table function or procedure that returns a table.
3348    ///
3349    /// Syntax: `|> CALL function_name(args) [AS alias]`
3350    ///
3351    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#call_pipe_operator>
3352    Call {
3353        /// The function or procedure to call which returns a table.
3354        function: Function,
3355        /// Optional alias for the result table.
3356        alias: Option<Ident>,
3357    },
3358    /// Pivots data from rows to columns.
3359    ///
3360    /// Syntax: `|> PIVOT(aggregate_function(column) FOR pivot_column IN (value1, value2, ...)) [AS alias]`
3361    ///
3362    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#pivot_pipe_operator>
3363    Pivot {
3364        /// Aggregate functions to compute during pivot.
3365        aggregate_functions: Vec<ExprWithAlias>,
3366        /// Column(s) that provide the pivot values.
3367        value_column: Vec<Ident>,
3368        /// The source of pivot values (literal list or subquery).
3369        value_source: PivotValueSource,
3370        /// Optional alias for the output.
3371        alias: Option<Ident>,
3372    },
3373    /// The `UNPIVOT` pipe operator transforms columns into rows.
3374    ///
3375    /// Syntax:
3376    /// ```sql
3377    /// |> UNPIVOT(value_column FOR name_column IN (column1, column2, ...)) [alias]
3378    /// ```
3379    ///
3380    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#unpivot_pipe_operator>
3381    Unpivot {
3382        /// Output column that will receive the unpivoted value.
3383        value_column: Ident,
3384        /// Column name holding the unpivoted column name.
3385        name_column: Ident,
3386        /// Columns to unpivot.
3387        unpivot_columns: Vec<Ident>,
3388        /// Optional alias for the unpivot result.
3389        alias: Option<Ident>,
3390    },
3391    /// Joins the input table with another table.
3392    ///
3393    /// Syntax: `|> [JOIN_TYPE] JOIN <table> [alias] ON <condition>` or `|> [JOIN_TYPE] JOIN <table> [alias] USING (<columns>)`
3394    ///
3395    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#join_pipe_operator>
3396    Join(Join),
3397}
3398
3399impl fmt::Display for PipeOperator {
3400    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3401        match self {
3402            PipeOperator::Select { exprs } => {
3403                write!(f, "SELECT {}", display_comma_separated(exprs.as_slice()))
3404            }
3405            PipeOperator::Extend { exprs } => {
3406                write!(f, "EXTEND {}", display_comma_separated(exprs.as_slice()))
3407            }
3408            PipeOperator::Set { assignments } => {
3409                write!(f, "SET {}", display_comma_separated(assignments.as_slice()))
3410            }
3411            PipeOperator::Drop { columns } => {
3412                write!(f, "DROP {}", display_comma_separated(columns.as_slice()))
3413            }
3414            PipeOperator::As { alias } => {
3415                write!(f, "AS {alias}")
3416            }
3417            PipeOperator::Limit { expr, offset } => {
3418                write!(f, "LIMIT {expr}")?;
3419                if let Some(offset) = offset {
3420                    write!(f, " OFFSET {offset}")?;
3421                }
3422                Ok(())
3423            }
3424            PipeOperator::Aggregate {
3425                full_table_exprs,
3426                group_by_expr,
3427            } => {
3428                write!(f, "AGGREGATE")?;
3429                if !full_table_exprs.is_empty() {
3430                    write!(
3431                        f,
3432                        " {}",
3433                        display_comma_separated(full_table_exprs.as_slice())
3434                    )?;
3435                }
3436                if !group_by_expr.is_empty() {
3437                    write!(f, " GROUP BY {}", display_comma_separated(group_by_expr))?;
3438                }
3439                Ok(())
3440            }
3441
3442            PipeOperator::Where { expr } => {
3443                write!(f, "WHERE {expr}")
3444            }
3445            PipeOperator::OrderBy { exprs } => {
3446                write!(f, "ORDER BY {}", display_comma_separated(exprs.as_slice()))
3447            }
3448
3449            PipeOperator::TableSample { sample } => {
3450                write!(f, "{sample}")
3451            }
3452            PipeOperator::Rename { mappings } => {
3453                write!(f, "RENAME {}", display_comma_separated(mappings))
3454            }
3455            PipeOperator::Union {
3456                set_quantifier,
3457                queries,
3458            } => Self::fmt_set_operation(f, "UNION", set_quantifier, queries),
3459            PipeOperator::Intersect {
3460                set_quantifier,
3461                queries,
3462            } => Self::fmt_set_operation(f, "INTERSECT", set_quantifier, queries),
3463            PipeOperator::Except {
3464                set_quantifier,
3465                queries,
3466            } => Self::fmt_set_operation(f, "EXCEPT", set_quantifier, queries),
3467            PipeOperator::Call { function, alias } => {
3468                write!(f, "CALL {function}")?;
3469                Self::fmt_optional_alias(f, alias)
3470            }
3471            PipeOperator::Pivot {
3472                aggregate_functions,
3473                value_column,
3474                value_source,
3475                alias,
3476            } => {
3477                write!(
3478                    f,
3479                    "PIVOT({} FOR {} IN ({}))",
3480                    display_comma_separated(aggregate_functions),
3481                    Expr::CompoundIdentifier(value_column.to_vec()),
3482                    value_source
3483                )?;
3484                Self::fmt_optional_alias(f, alias)
3485            }
3486            PipeOperator::Unpivot {
3487                value_column,
3488                name_column,
3489                unpivot_columns,
3490                alias,
3491            } => {
3492                write!(
3493                    f,
3494                    "UNPIVOT({} FOR {} IN ({}))",
3495                    value_column,
3496                    name_column,
3497                    display_comma_separated(unpivot_columns)
3498                )?;
3499                Self::fmt_optional_alias(f, alias)
3500            }
3501            PipeOperator::Join(join) => write!(f, "{join}"),
3502        }
3503    }
3504}
3505
3506impl PipeOperator {
3507    /// Helper function to format optional alias for pipe operators
3508    fn fmt_optional_alias(f: &mut fmt::Formatter<'_>, alias: &Option<Ident>) -> fmt::Result {
3509        if let Some(alias) = alias {
3510            write!(f, " AS {alias}")?;
3511        }
3512        Ok(())
3513    }
3514
3515    /// Helper function to format set operations (UNION, INTERSECT, EXCEPT) with queries
3516    fn fmt_set_operation(
3517        f: &mut fmt::Formatter<'_>,
3518        operation: &str,
3519        set_quantifier: &SetQuantifier,
3520        queries: &[Query],
3521    ) -> fmt::Result {
3522        write!(f, "{operation}")?;
3523        match set_quantifier {
3524            SetQuantifier::None => {}
3525            _ => {
3526                write!(f, " {set_quantifier}")?;
3527            }
3528        }
3529        write!(f, " ")?;
3530        let parenthesized_queries: Vec<String> =
3531            queries.iter().map(|query| format!("({query})")).collect();
3532        write!(f, "{}", display_comma_separated(&parenthesized_queries))
3533    }
3534}
3535
3536#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3537#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3538#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3539/// `FETCH` clause options.
3540pub struct Fetch {
3541    /// `WITH TIES` option is present.
3542    pub with_ties: bool,
3543    /// `PERCENT` modifier is present.
3544    pub percent: bool,
3545    /// Optional quantity expression (e.g. `FETCH FIRST 10 ROWS`).
3546    pub quantity: Option<Expr>,
3547}
3548
3549impl fmt::Display for Fetch {
3550    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3551        let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
3552        if let Some(ref quantity) = self.quantity {
3553            let percent = if self.percent { " PERCENT" } else { "" };
3554            write!(f, "FETCH FIRST {quantity}{percent} ROWS {extension}")
3555        } else {
3556            write!(f, "FETCH FIRST ROWS {extension}")
3557        }
3558    }
3559}
3560
3561#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3562#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3563#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3564/// `FOR ...` locking clause.
3565pub struct LockClause {
3566    /// The kind of lock requested (e.g. `SHARE`, `UPDATE`).
3567    pub lock_type: LockType,
3568    /// Optional object name after `OF` (e.g. `FOR UPDATE OF t1`).
3569    pub of: Option<ObjectName>,
3570    /// Optional non-blocking behavior (`NOWAIT` / `SKIP LOCKED`).
3571    pub nonblock: Option<NonBlock>,
3572}
3573
3574impl fmt::Display for LockClause {
3575    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3576        write!(f, "FOR {}", self.lock_type)?;
3577        if let Some(ref of) = self.of {
3578            write!(f, " OF {of}")?;
3579        }
3580        if let Some(ref nb) = self.nonblock {
3581            write!(f, " {nb}")?;
3582        }
3583        Ok(())
3584    }
3585}
3586
3587#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3588#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3589#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3590/// The lock type used in `FOR <lock>` clauses (e.g. `FOR SHARE`, `FOR UPDATE`).
3591pub enum LockType {
3592    /// `SHARE` lock (shared lock).
3593    Share,
3594    /// `UPDATE` lock (exclusive/update lock).
3595    Update,
3596}
3597
3598impl fmt::Display for LockType {
3599    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3600        let select_lock = match self {
3601            LockType::Share => "SHARE",
3602            LockType::Update => "UPDATE",
3603        };
3604        write!(f, "{select_lock}")
3605    }
3606}
3607
3608#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3609#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3610#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3611/// Non-blocking lock options for `FOR ...` clauses.
3612pub enum NonBlock {
3613    /// `NOWAIT` — do not wait for the lock.
3614    Nowait,
3615    /// `SKIP LOCKED` — skip rows that are locked.
3616    SkipLocked,
3617}
3618
3619impl fmt::Display for NonBlock {
3620    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3621        let nonblock = match self {
3622            NonBlock::Nowait => "NOWAIT",
3623            NonBlock::SkipLocked => "SKIP LOCKED",
3624        };
3625        write!(f, "{nonblock}")
3626    }
3627}
3628
3629#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3630#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3631#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3632/// `ALL`, `DISTINCT`, or `DISTINCT ON (...)` modifiers for `SELECT` lists.
3633pub enum Distinct {
3634    /// `ALL` (keep duplicate rows)
3635    ///
3636    /// Generally this is the default if omitted, but omission should be represented as
3637    /// `None::<Option<Distinct>>`
3638    All,
3639
3640    /// `DISTINCT` (remove duplicate rows)
3641    Distinct,
3642
3643    /// `DISTINCT ON (...)` (Postgres extension)
3644    On(Vec<Expr>),
3645}
3646
3647impl fmt::Display for Distinct {
3648    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3649        match self {
3650            Distinct::All => write!(f, "ALL"),
3651            Distinct::Distinct => write!(f, "DISTINCT"),
3652            Distinct::On(col_names) => {
3653                let col_names = display_comma_separated(col_names);
3654                write!(f, "DISTINCT ON ({col_names})")
3655            }
3656        }
3657    }
3658}
3659
3660#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3661#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3662#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3663/// MSSQL `TOP` clause options.
3664pub struct Top {
3665    /// SQL semantic equivalent of LIMIT but with same structure as FETCH.
3666    /// MSSQL only.
3667    pub with_ties: bool,
3668    /// Apply `PERCENT` extension.
3669    pub percent: bool,
3670    /// The optional quantity (expression or constant) following `TOP`.
3671    pub quantity: Option<TopQuantity>,
3672}
3673
3674#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3675#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3676#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3677/// Quantity used in a `TOP` clause: either an expression or a constant.
3678pub enum TopQuantity {
3679    /// A parenthesized expression (MSSQL syntax: `TOP (expr)`).
3680    Expr(Expr),
3681    /// An unparenthesized integer constant: `TOP 10`.
3682    Constant(u64),
3683}
3684
3685impl fmt::Display for Top {
3686    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3687        let extension = if self.with_ties { " WITH TIES" } else { "" };
3688        if let Some(ref quantity) = self.quantity {
3689            let percent = if self.percent { " PERCENT" } else { "" };
3690            match quantity {
3691                TopQuantity::Expr(quantity) => write!(f, "TOP ({quantity}){percent}{extension}"),
3692                TopQuantity::Constant(quantity) => {
3693                    write!(f, "TOP {quantity}{percent}{extension}")
3694                }
3695            }
3696        } else {
3697            write!(f, "TOP{extension}")
3698        }
3699    }
3700}
3701
3702#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3703#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3704#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3705/// An explicit `VALUES` clause and its rows.
3706pub struct Values {
3707    /// Was there an explicit `ROW` keyword (MySQL)?
3708    /// <https://dev.mysql.com/doc/refman/8.0/en/values.html>
3709    pub explicit_row: bool,
3710    /// `true` if `VALUE` (singular) keyword was used instead of `VALUES`.
3711    /// <https://dev.mysql.com/doc/refman/9.2/en/insert.html>
3712    pub value_keyword: bool,
3713    /// The list of rows, each row is a list of expressions.
3714    pub rows: Vec<Parens<Vec<Expr>>>,
3715}
3716
3717impl fmt::Display for Values {
3718    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3719        match self.value_keyword {
3720            true => f.write_str("VALUE")?,
3721            false => f.write_str("VALUES")?,
3722        };
3723        let prefix = if self.explicit_row { "ROW" } else { "" };
3724        let mut delim = "";
3725        for row in &self.rows {
3726            f.write_str(delim)?;
3727            delim = ",";
3728            SpaceOrNewline.fmt(f)?;
3729            Indent(format_args!("{prefix}({})", display_comma_separated(row))).fmt(f)?;
3730        }
3731        Ok(())
3732    }
3733}
3734
3735#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3736#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3737#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3738/// `SELECT INTO` clause options.
3739pub struct SelectInto {
3740    /// `TEMPORARY` modifier.
3741    pub temporary: bool,
3742    /// `UNLOGGED` modifier.
3743    pub unlogged: bool,
3744    /// `TABLE` keyword present.
3745    pub table: bool,
3746    /// Target(s) of the `INTO` clause.
3747    ///
3748    /// [Postgres]: https://www.postgresql.org/docs/current/sql-selectinto.html
3749    /// [MySQL]: https://dev.mysql.com/doc/refman/9.7/en/select-into.html
3750    pub targets: Vec<Expr>,
3751}
3752
3753impl fmt::Display for SelectInto {
3754    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3755        let temporary = if self.temporary { " TEMPORARY" } else { "" };
3756        let unlogged = if self.unlogged { " UNLOGGED" } else { "" };
3757        let table = if self.table { " TABLE" } else { "" };
3758
3759        write!(
3760            f,
3761            "INTO{}{}{} {}",
3762            temporary,
3763            unlogged,
3764            table,
3765            display_comma_separated(&self.targets)
3766        )
3767    }
3768}
3769
3770/// ClickHouse supports GROUP BY WITH modifiers(includes ROLLUP|CUBE|TOTALS).
3771/// e.g. GROUP BY year WITH ROLLUP WITH TOTALS
3772///
3773/// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#rollup-modifier>
3774#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3775#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3776#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3777/// Modifiers used with `GROUP BY` such as `WITH ROLLUP` or `WITH CUBE`.
3778pub enum GroupByWithModifier {
3779    /// `WITH ROLLUP` modifier.
3780    Rollup,
3781    /// `WITH CUBE` modifier.
3782    Cube,
3783    /// `WITH TOTALS` modifier (ClickHouse).
3784    Totals,
3785    /// Hive supports GROUPING SETS syntax, e.g. `GROUP BY GROUPING SETS(...)`.
3786    ///
3787    /// [Hive]: <https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=30151323#EnhancedAggregation,Cube,GroupingandRollup-GROUPINGSETSclause>
3788    GroupingSets(Expr),
3789}
3790
3791impl fmt::Display for GroupByWithModifier {
3792    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3793        match self {
3794            GroupByWithModifier::Rollup => write!(f, "WITH ROLLUP"),
3795            GroupByWithModifier::Cube => write!(f, "WITH CUBE"),
3796            GroupByWithModifier::Totals => write!(f, "WITH TOTALS"),
3797            GroupByWithModifier::GroupingSets(expr) => {
3798                write!(f, "{expr}")
3799            }
3800        }
3801    }
3802}
3803
3804#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3805#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3806#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3807#[cfg_attr(feature = "visitor", visit(with = "visit_group_by"))]
3808/// Represents the two syntactic forms that `GROUP BY` can take, including
3809/// `GROUP BY ALL` with optional modifiers and ordinary `GROUP BY <exprs>`.
3810pub enum GroupByExpr {
3811    /// ALL syntax of [Snowflake], [DuckDB] and [ClickHouse].
3812    ///
3813    /// [Snowflake]: <https://docs.snowflake.com/en/sql-reference/constructs/group-by#label-group-by-all-columns>
3814    /// [DuckDB]:  <https://duckdb.org/docs/sql/query_syntax/groupby.html>
3815    /// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#group-by-all>
3816    ///
3817    /// ClickHouse also supports WITH modifiers after GROUP BY ALL and expressions.
3818    ///
3819    /// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#rollup-modifier>
3820    All(Vec<GroupByWithModifier>),
3821    /// `GROUP BY <expressions>` with optional modifiers.
3822    Expressions(Vec<Expr>, Vec<GroupByWithModifier>),
3823}
3824
3825impl fmt::Display for GroupByExpr {
3826    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3827        match self {
3828            GroupByExpr::All(modifiers) => {
3829                write!(f, "GROUP BY ALL")?;
3830                if !modifiers.is_empty() {
3831                    write!(f, " {}", display_separated(modifiers, " "))?;
3832                }
3833                Ok(())
3834            }
3835            GroupByExpr::Expressions(col_names, modifiers) => {
3836                f.write_str("GROUP BY")?;
3837                SpaceOrNewline.fmt(f)?;
3838                Indent(display_comma_separated(col_names)).fmt(f)?;
3839                if !modifiers.is_empty() {
3840                    write!(f, " {}", display_separated(modifiers, " "))?;
3841                }
3842                Ok(())
3843            }
3844        }
3845    }
3846}
3847
3848/// `FORMAT` identifier or `FORMAT NULL` clause, specific to ClickHouse.
3849///
3850/// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/format>
3851#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3852#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3853#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3854pub enum FormatClause {
3855    /// The format identifier.
3856    Identifier(Ident),
3857    /// `FORMAT NULL` clause.
3858    Null,
3859}
3860
3861impl fmt::Display for FormatClause {
3862    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3863        match self {
3864            FormatClause::Identifier(ident) => write!(f, "FORMAT {ident}"),
3865            FormatClause::Null => write!(f, "FORMAT NULL"),
3866        }
3867    }
3868}
3869
3870/// FORMAT identifier in input context, specific to ClickHouse.
3871///
3872/// [ClickHouse]: <https://clickhouse.com/docs/en/interfaces/formats>
3873#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3874#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3875#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3876pub struct InputFormatClause {
3877    /// The format identifier.
3878    pub ident: Ident,
3879    /// Optional format parameters.
3880    pub values: Vec<Expr>,
3881}
3882
3883impl fmt::Display for InputFormatClause {
3884    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3885        write!(f, "FORMAT {}", self.ident)?;
3886
3887        if !self.values.is_empty() {
3888            write!(f, " {}", display_comma_separated(self.values.as_slice()))?;
3889        }
3890
3891        Ok(())
3892    }
3893}
3894
3895/// `FOR XML` or `FOR JSON` clause (MSSQL): formats the output of a query as XML or JSON.
3896#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3897#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3898#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3899pub enum ForClause {
3900    /// `FOR BROWSE` clause.
3901    Browse,
3902    /// `FOR JSON ...` clause and its options.
3903    Json {
3904        /// JSON mode (`AUTO` or `PATH`).
3905        for_json: ForJson,
3906        /// Optional `ROOT('...')` parameter.
3907        root: Option<String>,
3908        /// `INCLUDE_NULL_VALUES` flag.
3909        include_null_values: bool,
3910        /// `WITHOUT_ARRAY_WRAPPER` flag.
3911        without_array_wrapper: bool,
3912    },
3913    /// `FOR XML ...` clause and its options.
3914    Xml {
3915        /// XML mode (`RAW`, `AUTO`, `EXPLICIT`, `PATH`).
3916        for_xml: ForXml,
3917        /// `ELEMENTS` flag.
3918        elements: bool,
3919        /// `BINARY BASE64` flag.
3920        binary_base64: bool,
3921        /// Optional `ROOT('...')` parameter.
3922        root: Option<String>,
3923        /// `TYPE` flag.
3924        r#type: bool,
3925    },
3926}
3927
3928impl fmt::Display for ForClause {
3929    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3930        match self {
3931            ForClause::Browse => write!(f, "FOR BROWSE"),
3932            ForClause::Json {
3933                for_json,
3934                root,
3935                include_null_values,
3936                without_array_wrapper,
3937            } => {
3938                write!(f, "FOR JSON ")?;
3939                write!(f, "{for_json}")?;
3940                if let Some(root) = root {
3941                    write!(f, ", ROOT('{root}')")?;
3942                }
3943                if *include_null_values {
3944                    write!(f, ", INCLUDE_NULL_VALUES")?;
3945                }
3946                if *without_array_wrapper {
3947                    write!(f, ", WITHOUT_ARRAY_WRAPPER")?;
3948                }
3949                Ok(())
3950            }
3951            ForClause::Xml {
3952                for_xml,
3953                elements,
3954                binary_base64,
3955                root,
3956                r#type,
3957            } => {
3958                write!(f, "FOR XML ")?;
3959                write!(f, "{for_xml}")?;
3960                if *binary_base64 {
3961                    write!(f, ", BINARY BASE64")?;
3962                }
3963                if *r#type {
3964                    write!(f, ", TYPE")?;
3965                }
3966                if let Some(root) = root {
3967                    write!(f, ", ROOT('{root}')")?;
3968                }
3969                if *elements {
3970                    write!(f, ", ELEMENTS")?;
3971                }
3972                Ok(())
3973            }
3974        }
3975    }
3976}
3977
3978#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3979#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3980#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3981/// Modes for `FOR XML` clause.
3982pub enum ForXml {
3983    /// `RAW` mode with optional root name: `RAW('root')`.
3984    Raw(Option<String>),
3985    /// `AUTO` mode.
3986    Auto,
3987    /// `EXPLICIT` mode.
3988    Explicit,
3989    /// `PATH` mode with optional root: `PATH('root')`.
3990    Path(Option<String>),
3991}
3992
3993impl fmt::Display for ForXml {
3994    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3995        match self {
3996            ForXml::Raw(root) => {
3997                write!(f, "RAW")?;
3998                if let Some(root) = root {
3999                    write!(f, "('{root}')")?;
4000                }
4001                Ok(())
4002            }
4003            ForXml::Auto => write!(f, "AUTO"),
4004            ForXml::Explicit => write!(f, "EXPLICIT"),
4005            ForXml::Path(root) => {
4006                write!(f, "PATH")?;
4007                if let Some(root) = root {
4008                    write!(f, "('{root}')")?;
4009                }
4010                Ok(())
4011            }
4012        }
4013    }
4014}
4015
4016#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4017#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4018#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4019/// Modes for `FOR JSON` clause.
4020pub enum ForJson {
4021    /// `AUTO` mode.
4022    Auto,
4023    /// `PATH` mode.
4024    Path,
4025}
4026
4027impl fmt::Display for ForJson {
4028    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4029        match self {
4030            ForJson::Auto => write!(f, "AUTO"),
4031            ForJson::Path => write!(f, "PATH"),
4032        }
4033    }
4034}
4035
4036/// A single column definition in MySQL's `JSON_TABLE` table valued function.
4037///
4038/// See
4039/// - [MySQL's JSON_TABLE documentation](https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html#function_json-table)
4040/// - [Oracle's JSON_TABLE documentation](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/JSON_TABLE.html)
4041/// - [MariaDB's JSON_TABLE documentation](https://mariadb.com/kb/en/json_table/)
4042///
4043/// ```sql
4044/// SELECT *
4045/// FROM JSON_TABLE(
4046///     '["a", "b"]',
4047///     '$[*]' COLUMNS (
4048///         name FOR ORDINALITY,
4049///         value VARCHAR(20) PATH '$',
4050///         NESTED PATH '$[*]' COLUMNS (
4051///             value VARCHAR(20) PATH '$'
4052///         )
4053///     )
4054/// ) AS jt;
4055/// ```
4056#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4057#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4058#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4059pub enum JsonTableColumn {
4060    /// A named column with a JSON path
4061    Named(JsonTableNamedColumn),
4062    /// The FOR ORDINALITY column, which is a special column that returns the index of the current row in a JSON array.
4063    ForOrdinality(Ident),
4064    /// A set of nested columns, which extracts data from a nested JSON array.
4065    Nested(JsonTableNestedColumn),
4066}
4067
4068impl fmt::Display for JsonTableColumn {
4069    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4070        match self {
4071            JsonTableColumn::Named(json_table_named_column) => {
4072                write!(f, "{json_table_named_column}")
4073            }
4074            JsonTableColumn::ForOrdinality(ident) => write!(f, "{ident} FOR ORDINALITY"),
4075            JsonTableColumn::Nested(json_table_nested_column) => {
4076                write!(f, "{json_table_nested_column}")
4077            }
4078        }
4079    }
4080}
4081
4082/// A nested column in a JSON_TABLE column list
4083///
4084/// See <https://mariadb.com/kb/en/json_table/#nested-paths>
4085#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4086#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4087#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4088/// A nested column in a `JSON_TABLE` column list.
4089pub struct JsonTableNestedColumn {
4090    /// JSON path expression (must be a literal `Value`).
4091    pub path: ValueWithSpan,
4092    /// Columns extracted from the matched nested array.
4093    pub columns: Vec<JsonTableColumn>,
4094}
4095
4096impl fmt::Display for JsonTableNestedColumn {
4097    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4098        write!(
4099            f,
4100            "NESTED PATH {} COLUMNS ({})",
4101            self.path,
4102            display_comma_separated(&self.columns)
4103        )
4104    }
4105}
4106
4107/// A single column definition in MySQL's `JSON_TABLE` table valued function.
4108///
4109/// See <https://mariadb.com/kb/en/json_table/#path-columns>
4110///
4111/// ```sql
4112///         value VARCHAR(20) PATH '$'
4113/// ```
4114#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4115#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4116#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4117pub struct JsonTableNamedColumn {
4118    /// The name of the column to be extracted.
4119    pub name: Ident,
4120    /// The type of the column to be extracted.
4121    pub r#type: DataType,
4122    /// The path to the column to be extracted. Must be a literal string.
4123    pub path: ValueWithSpan,
4124    /// true if the column is a boolean set to true if the given path exists
4125    pub exists: bool,
4126    /// The empty handling clause of the column
4127    pub on_empty: Option<JsonTableColumnErrorHandling>,
4128    /// The error handling clause of the column
4129    pub on_error: Option<JsonTableColumnErrorHandling>,
4130}
4131
4132impl fmt::Display for JsonTableNamedColumn {
4133    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4134        write!(
4135            f,
4136            "{} {}{} PATH {}",
4137            self.name,
4138            self.r#type,
4139            if self.exists { " EXISTS" } else { "" },
4140            self.path
4141        )?;
4142        if let Some(on_empty) = &self.on_empty {
4143            write!(f, " {on_empty} ON EMPTY")?;
4144        }
4145        if let Some(on_error) = &self.on_error {
4146            write!(f, " {on_error} ON ERROR")?;
4147        }
4148        Ok(())
4149    }
4150}
4151
4152/// Stores the error handling clause of a `JSON_TABLE` table valued function:
4153/// {NULL | DEFAULT json_string | ERROR} ON {ERROR | EMPTY }
4154#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4155#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4156#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4157/// Error/empty-value handling for `JSON_TABLE` columns.
4158pub enum JsonTableColumnErrorHandling {
4159    /// `NULL` — return NULL when the path does not match.
4160    Null,
4161    /// `DEFAULT <value>` — use the provided `Value` as a default.
4162    Default(ValueWithSpan),
4163    /// `ERROR` — raise an error.
4164    Error,
4165}
4166
4167impl fmt::Display for JsonTableColumnErrorHandling {
4168    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4169        match self {
4170            JsonTableColumnErrorHandling::Null => write!(f, "NULL"),
4171            JsonTableColumnErrorHandling::Default(json_string) => {
4172                write!(f, "DEFAULT {json_string}")
4173            }
4174            JsonTableColumnErrorHandling::Error => write!(f, "ERROR"),
4175        }
4176    }
4177}
4178
4179/// A single column definition in MSSQL's `OPENJSON WITH` clause.
4180///
4181/// ```sql
4182/// colName type [ column_path ] [ AS JSON ]
4183/// ```
4184///
4185/// Reference: <https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16#syntax>
4186#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4187#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4188#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4189pub struct OpenJsonTableColumn {
4190    /// The name of the column to be extracted.
4191    pub name: Ident,
4192    /// The type of the column to be extracted.
4193    pub r#type: DataType,
4194    /// The path to the column to be extracted. Must be a literal string.
4195    pub path: Option<String>,
4196    /// The `AS JSON` option.
4197    pub as_json: bool,
4198}
4199
4200impl fmt::Display for OpenJsonTableColumn {
4201    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4202        write!(f, "{} {}", self.name, self.r#type)?;
4203        if let Some(path) = &self.path {
4204            write!(f, " '{}'", value::escape_single_quote_string(path))?;
4205        }
4206        if self.as_json {
4207            write!(f, " AS JSON")?;
4208        }
4209        Ok(())
4210    }
4211}
4212
4213/// BigQuery supports ValueTables which have 2 modes:
4214/// `SELECT [ALL | DISTINCT] AS STRUCT`
4215/// `SELECT [ALL | DISTINCT] AS VALUE`
4216///
4217/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#value_tables>
4218/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_list>
4219#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4220#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4221#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4222/// Mode of BigQuery value tables, e.g. `AS STRUCT` or `AS VALUE`.
4223pub enum ValueTableMode {
4224    /// `AS STRUCT`
4225    AsStruct,
4226    /// `AS VALUE`
4227    AsValue,
4228    /// `DISTINCT AS STRUCT`
4229    DistinctAsStruct,
4230    /// `DISTINCT AS VALUE`
4231    DistinctAsValue,
4232}
4233
4234impl fmt::Display for ValueTableMode {
4235    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4236        match self {
4237            ValueTableMode::AsStruct => write!(f, "AS STRUCT"),
4238            ValueTableMode::AsValue => write!(f, "AS VALUE"),
4239            ValueTableMode::DistinctAsStruct => write!(f, "DISTINCT AS STRUCT"),
4240            ValueTableMode::DistinctAsValue => write!(f, "DISTINCT AS VALUE"),
4241        }
4242    }
4243}
4244
4245/// The `FROM` clause of an `UPDATE TABLE` statement
4246#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4247#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4248#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4249pub enum UpdateTableFromKind {
4250    /// Update Statement where the 'FROM' clause is before the 'SET' keyword (Supported by Snowflake)
4251    /// For Example: `UPDATE FROM t1 SET t1.name='aaa'`
4252    BeforeSet(Vec<TableWithJoins>),
4253    /// Update Statement where the 'FROM' clause is after the 'SET' keyword (Which is the standard way)
4254    /// For Example: `UPDATE SET t1.name='aaa' FROM t1`
4255    AfterSet(Vec<TableWithJoins>),
4256}
4257
4258/// Defines the options for an XmlTable column: Named or ForOrdinality
4259#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4260#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4261#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4262pub enum XmlTableColumnOption {
4263    /// A named column with a type, optional path, and default value.
4264    NamedInfo {
4265        /// The type of the column to be extracted.
4266        r#type: DataType,
4267        /// The path to the column to be extracted. If None, defaults to the column name.
4268        path: Option<Expr>,
4269        /// Default value if path does not match
4270        default: Option<Expr>,
4271        /// Whether the column is nullable (NULL=true, NOT NULL=false)
4272        nullable: bool,
4273    },
4274    /// The FOR ORDINALITY marker
4275    ForOrdinality,
4276}
4277
4278/// A single column definition in XMLTABLE
4279///
4280/// ```sql
4281/// COLUMNS
4282///     id int PATH '@id',
4283///     ordinality FOR ORDINALITY,
4284///     "COUNTRY_NAME" text,
4285///     country_id text PATH 'COUNTRY_ID',
4286///     size_sq_km float PATH 'SIZE[@unit = "sq_km"]',
4287///     size_other text PATH 'concat(SIZE[@unit!="sq_km"], " ", SIZE[@unit!="sq_km"]/@unit)',
4288///     premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified'
4289/// ```
4290#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4291#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4292#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4293pub struct XmlTableColumn {
4294    /// The name of the column.
4295    pub name: Ident,
4296    /// Column options: type/path/default or FOR ORDINALITY
4297    pub option: XmlTableColumnOption,
4298}
4299
4300impl fmt::Display for XmlTableColumn {
4301    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4302        write!(f, "{}", self.name)?;
4303        match &self.option {
4304            XmlTableColumnOption::NamedInfo {
4305                r#type,
4306                path,
4307                default,
4308                nullable,
4309            } => {
4310                write!(f, " {type}")?;
4311                if let Some(p) = path {
4312                    write!(f, " PATH {p}")?;
4313                }
4314                if let Some(d) = default {
4315                    write!(f, " DEFAULT {d}")?;
4316                }
4317                if !*nullable {
4318                    write!(f, " NOT NULL")?;
4319                }
4320                Ok(())
4321            }
4322            XmlTableColumnOption::ForOrdinality => {
4323                write!(f, " FOR ORDINALITY")
4324            }
4325        }
4326    }
4327}
4328
4329/// Argument passed in the XMLTABLE PASSING clause
4330#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4331#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4332#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4333/// Argument passed in the `XMLTABLE PASSING` clause.
4334pub struct XmlPassingArgument {
4335    /// Expression to pass to the XML table.
4336    pub expr: Expr,
4337    /// Optional alias for the argument.
4338    pub alias: Option<Ident>,
4339    /// `true` if `BY VALUE` is specified for the argument.
4340    pub by_value: bool,
4341}
4342
4343impl fmt::Display for XmlPassingArgument {
4344    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4345        if self.by_value {
4346            write!(f, "BY VALUE ")?;
4347        }
4348        write!(f, "{}", self.expr)?;
4349        if let Some(alias) = &self.alias {
4350            write!(f, " AS {alias}")?;
4351        }
4352        Ok(())
4353    }
4354}
4355
4356/// The PASSING clause for XMLTABLE
4357#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4358#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4359#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4360/// The PASSING clause for `XMLTABLE`.
4361pub struct XmlPassingClause {
4362    /// The list of passed arguments.
4363    pub arguments: Vec<XmlPassingArgument>,
4364}
4365
4366impl fmt::Display for XmlPassingClause {
4367    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4368        if !self.arguments.is_empty() {
4369            write!(f, " PASSING {}", display_comma_separated(&self.arguments))?;
4370        }
4371        Ok(())
4372    }
4373}
4374
4375/// Represents a single XML namespace definition in the XMLNAMESPACES clause.
4376///
4377/// `namespace_uri AS namespace_name`
4378#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4379#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4380#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4381pub struct XmlNamespaceDefinition {
4382    /// The namespace URI (a text expression).
4383    pub uri: Expr,
4384    /// The alias for the namespace (a simple identifier).
4385    pub name: Ident,
4386}
4387
4388impl fmt::Display for XmlNamespaceDefinition {
4389    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4390        write!(f, "{} AS {}", self.uri, self.name)
4391    }
4392}