Skip to main content

sqlparser/ast/
query.rs

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