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