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