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        /// Optional alias for the result of the function.
1526        alias: Option<TableAlias>,
1527    },
1528    /// ```sql
1529    /// SELECT * FROM UNNEST ([10,20,30]) as numbers WITH OFFSET;
1530    /// +---------+--------+
1531    /// | numbers | offset |
1532    /// +---------+--------+
1533    /// | 10      | 0      |
1534    /// | 20      | 1      |
1535    /// | 30      | 2      |
1536    /// +---------+--------+
1537    /// ```
1538    UNNEST {
1539        /// Optional alias for the UNNEST table (e.g. `UNNEST(...) AS t`).
1540        alias: Option<TableAlias>,
1541        /// Expressions producing the arrays to be unnested.
1542        array_exprs: Vec<Expr>,
1543        /// Whether `WITH OFFSET` was specified to include element offsets.
1544        with_offset: bool,
1545        /// Optional alias for the offset column when `WITH OFFSET` is used.
1546        with_offset_alias: Option<Ident>,
1547        /// Whether `WITH ORDINALITY` was specified to include ordinality.
1548        with_ordinality: bool,
1549    },
1550    /// The `JSON_TABLE` table-valued function.
1551    /// Part of the SQL standard, but implemented only by MySQL, Oracle, and DB2.
1552    ///
1553    /// <https://modern-sql.com/blog/2017-06/whats-new-in-sql-2016#json_table>
1554    /// <https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html#function_json-table>
1555    ///
1556    /// ```sql
1557    /// SELECT * FROM JSON_TABLE(
1558    ///    '[{"a": 1, "b": 2}, {"a": 3, "b": 4}]',
1559    ///    '$[*]' COLUMNS(
1560    ///        a INT PATH '$.a' DEFAULT '0' ON EMPTY,
1561    ///        b INT PATH '$.b' NULL ON ERROR
1562    ///     )
1563    /// ) AS jt;
1564    /// ````
1565    JsonTable {
1566        /// The JSON expression to be evaluated. It must evaluate to a json string
1567        json_expr: Expr,
1568        /// The path to the array or object to be iterated over.
1569        /// It must evaluate to a json array or object.
1570        json_path: ValueWithSpan,
1571        /// The columns to be extracted from each element of the array or object.
1572        /// Each column must have a name and a type.
1573        columns: Vec<JsonTableColumn>,
1574        /// The alias for the table.
1575        alias: Option<TableAlias>,
1576    },
1577    /// The MSSQL's `OPENJSON` table-valued function.
1578    ///
1579    /// ```sql
1580    /// OPENJSON( jsonExpression [ , path ] )  [ <with_clause> ]
1581    ///
1582    /// <with_clause> ::= WITH ( { colName type [ column_path ] [ AS JSON ] } [ ,...n ] )
1583    /// ````
1584    ///
1585    /// Reference: <https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16#syntax>
1586    OpenJsonTable {
1587        /// The JSON expression to be evaluated. It must evaluate to a json string
1588        json_expr: Expr,
1589        /// The path to the array or object to be iterated over.
1590        /// It must evaluate to a json array or object.
1591        json_path: Option<ValueWithSpan>,
1592        /// The columns to be extracted from each element of the array or object.
1593        /// Each column must have a name and a type.
1594        columns: Vec<OpenJsonTableColumn>,
1595        /// The alias for the table.
1596        alias: Option<TableAlias>,
1597    },
1598    /// Represents a parenthesized table factor. The SQL spec only allows a
1599    /// join expression (`(foo <JOIN> bar [ <JOIN> baz ... ])`) to be nested,
1600    /// possibly several times.
1601    ///
1602    /// The parser may also accept non-standard nesting of bare tables for some
1603    /// dialects, but the information about such nesting is stripped from AST.
1604    NestedJoin {
1605        /// The nested join expression contained in parentheses.
1606        table_with_joins: Box<TableWithJoins>,
1607        /// Optional alias for the nested join.
1608        alias: Option<TableAlias>,
1609    },
1610    /// Represents PIVOT operation on a table.
1611    /// For example `FROM monthly_sales PIVOT(sum(amount) FOR MONTH IN ('JAN', 'FEB'))`
1612    ///
1613    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#pivot_operator)
1614    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constructs/pivot)
1615    /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-68257B27-1C4C-4C47-8140-5C60E0E65D35)
1616    Pivot {
1617        /// The input table to pivot.
1618        table: Box<TableFactor>,
1619        /// Aggregate expressions used as pivot values (optionally aliased).
1620        aggregate_functions: Vec<ExprWithAlias>, // Function expression
1621        /// Columns producing the values to be pivoted.
1622        value_column: Vec<Expr>,
1623        /// Source of pivot values (e.g. list of literals or columns).
1624        value_source: PivotValueSource,
1625        /// Optional expression providing a default when a pivot produces NULL.
1626        default_on_null: Option<Expr>,
1627        /// Optional alias for the pivoted table.
1628        alias: Option<TableAlias>,
1629    },
1630    /// An UNPIVOT operation on a table.
1631    ///
1632    /// Syntax:
1633    /// ```sql
1634    /// table UNPIVOT [ { INCLUDE | EXCLUDE } NULLS ] (value FOR name IN (column1, [ column2, ... ])) [ alias ]
1635    /// ```
1636    ///
1637    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/constructs/unpivot)
1638    /// [Databricks](https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot)
1639    /// [BigQuery](https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#unpivot_operator)
1640    /// [Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__GUID-9B4E0389-413C-4014-94A1-0A0571BDF7E1)
1641    Unpivot {
1642        /// The input table to unpivot.
1643        table: Box<TableFactor>,
1644        /// Expression producing the unpivoted value.
1645        value: Expr,
1646        /// Identifier used for the generated column name.
1647        name: Ident,
1648        /// Columns or expressions to unpivot, optionally aliased.
1649        columns: Vec<ExprWithAlias>,
1650        /// Whether to include or exclude NULLs during unpivot.
1651        null_inclusion: Option<NullInclusion>,
1652        /// Optional alias for the resulting table.
1653        alias: Option<TableAlias>,
1654    },
1655    /// A `MATCH_RECOGNIZE` operation on a table.
1656    ///
1657    /// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize>.
1658    MatchRecognize {
1659        /// The input table to apply `MATCH_RECOGNIZE` on.
1660        table: Box<TableFactor>,
1661        /// `PARTITION BY <expr> [, ... ]`
1662        partition_by: Vec<Expr>,
1663        /// `ORDER BY <expr> [, ... ]`
1664        order_by: Vec<OrderByExpr>,
1665        /// `MEASURES <expr> [AS] <alias> [, ... ]`
1666        measures: Vec<Measure>,
1667        /// `ONE ROW PER MATCH | ALL ROWS PER MATCH [ <option> ]`
1668        rows_per_match: Option<RowsPerMatch>,
1669        /// `AFTER MATCH SKIP <option>`
1670        after_match_skip: Option<AfterMatchSkip>,
1671        /// `PATTERN ( <pattern> )`
1672        pattern: MatchRecognizePattern,
1673        /// `DEFINE <symbol> AS <expr> [, ... ]`
1674        symbols: Vec<SymbolDefinition>,
1675        /// The alias for the table.
1676        alias: Option<TableAlias>,
1677    },
1678    /// The `XMLTABLE` table-valued function.
1679    /// Part of the SQL standard, supported by PostgreSQL, Oracle, and DB2.
1680    ///
1681    /// <https://www.postgresql.org/docs/15/functions-xml.html#FUNCTIONS-XML-PROCESSING>
1682    ///
1683    /// ```sql
1684    /// SELECT xmltable.*
1685    /// FROM xmldata,
1686    /// XMLTABLE('//ROWS/ROW'
1687    ///     PASSING data
1688    ///     COLUMNS id int PATH '@id',
1689    ///     ordinality FOR ORDINALITY,
1690    ///     "COUNTRY_NAME" text,
1691    ///     country_id text PATH 'COUNTRY_ID',
1692    ///     size_sq_km float PATH 'SIZE[@unit = "sq_km"]',
1693    ///     size_other text PATH 'concat(SIZE[@unit!="sq_km"], " ", SIZE[@unit!="sq_km"]/@unit)',
1694    ///     premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified'
1695    /// );
1696    /// ````
1697    XmlTable {
1698        /// Optional XMLNAMESPACES clause (empty if not present)
1699        namespaces: Vec<XmlNamespaceDefinition>,
1700        /// The row-generating XPath expression.
1701        row_expression: Expr,
1702        /// The PASSING clause specifying the document expression.
1703        passing: XmlPassingClause,
1704        /// The columns to be extracted from each generated row.
1705        columns: Vec<XmlTableColumn>,
1706        /// The alias for the table.
1707        alias: Option<TableAlias>,
1708    },
1709    /// Snowflake's SEMANTIC_VIEW function for semantic models.
1710    ///
1711    /// <https://docs.snowflake.com/en/sql-reference/constructs/semantic_view>
1712    ///
1713    /// ```sql
1714    /// SELECT * FROM SEMANTIC_VIEW(
1715    ///     tpch_analysis
1716    ///     DIMENSIONS customer.customer_market_segment
1717    ///     METRICS orders.order_average_value
1718    /// );
1719    /// ```
1720    SemanticView {
1721        /// The name of the semantic model
1722        name: ObjectName,
1723        /// List of dimensions or expression referring to dimensions (e.g. DATE_PART('year', col))
1724        dimensions: Vec<Expr>,
1725        /// List of metrics (references to objects like orders.value, value, orders.*)
1726        metrics: Vec<Expr>,
1727        /// List of facts or expressions referring to facts or dimensions.
1728        facts: Vec<Expr>,
1729        /// WHERE clause for filtering
1730        where_clause: Option<Expr>,
1731        /// The alias for the table
1732        alias: Option<TableAlias>,
1733    },
1734}
1735
1736/// The table sample modifier options
1737#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1738#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1739#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1740pub enum TableSampleKind {
1741    /// Table sample located before the table alias option
1742    BeforeTableAlias(Box<TableSample>),
1743    /// Table sample located after the table alias option
1744    AfterTableAlias(Box<TableSample>),
1745}
1746
1747#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1748#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1749#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1750/// Represents a `TABLESAMPLE` clause and its options.
1751pub struct TableSample {
1752    /// Modifier (e.g. `SAMPLE` or `TABLESAMPLE`).
1753    pub modifier: TableSampleModifier,
1754    /// Optional sampling method name (e.g. `BERNOULLI`, `SYSTEM`).
1755    pub name: Option<TableSampleMethod>,
1756    /// Optional sampling quantity (value and optional unit).
1757    pub quantity: Option<TableSampleQuantity>,
1758    /// Optional seed clause.
1759    pub seed: Option<TableSampleSeed>,
1760    /// Optional bucket specification for `BUCKET ... OUT OF ...`-style sampling.
1761    pub bucket: Option<TableSampleBucket>,
1762    /// Optional offset expression for sampling.
1763    pub offset: Option<Expr>,
1764}
1765
1766#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1767#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1768#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1769/// Modifier specifying whether `SAMPLE` or `TABLESAMPLE` keyword was used.
1770pub enum TableSampleModifier {
1771    /// `SAMPLE` modifier.
1772    Sample,
1773    /// `TABLESAMPLE` modifier.
1774    TableSample,
1775}
1776
1777impl fmt::Display for TableSampleModifier {
1778    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1779        match self {
1780            TableSampleModifier::Sample => write!(f, "SAMPLE")?,
1781            TableSampleModifier::TableSample => write!(f, "TABLESAMPLE")?,
1782        }
1783        Ok(())
1784    }
1785}
1786
1787#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1788#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1789#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1790/// Quantity for a `TABLESAMPLE` clause (e.g. `10 PERCENT` or `(10)`).
1791pub struct TableSampleQuantity {
1792    /// Whether the quantity was wrapped in parentheses.
1793    pub parenthesized: bool,
1794    /// The numeric expression specifying the quantity.
1795    pub value: Expr,
1796    /// Optional unit (e.g. `PERCENT`, `ROWS`).
1797    pub unit: Option<TableSampleUnit>,
1798}
1799
1800impl fmt::Display for TableSampleQuantity {
1801    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1802        if self.parenthesized {
1803            write!(f, "(")?;
1804        }
1805        write!(f, "{}", self.value)?;
1806        if let Some(unit) = &self.unit {
1807            write!(f, " {unit}")?;
1808        }
1809        if self.parenthesized {
1810            write!(f, ")")?;
1811        }
1812        Ok(())
1813    }
1814}
1815
1816/// The table sample method names
1817#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1818#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1819#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1820/// Sampling method used by `TABLESAMPLE`.
1821pub enum TableSampleMethod {
1822    /// `ROW` sampling method.
1823    Row,
1824    /// `BERNOULLI` sampling method.
1825    Bernoulli,
1826    /// `SYSTEM` sampling method.
1827    System,
1828    /// `BLOCK` sampling method.
1829    Block,
1830}
1831
1832impl fmt::Display for TableSampleMethod {
1833    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1834        match self {
1835            TableSampleMethod::Bernoulli => write!(f, "BERNOULLI"),
1836            TableSampleMethod::Row => write!(f, "ROW"),
1837            TableSampleMethod::System => write!(f, "SYSTEM"),
1838            TableSampleMethod::Block => write!(f, "BLOCK"),
1839        }
1840    }
1841}
1842
1843#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1844#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1845#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1846/// `SEED` or `REPEATABLE` clause used with sampling.
1847pub struct TableSampleSeed {
1848    /// Seed modifier (e.g. `REPEATABLE` or `SEED`).
1849    pub modifier: TableSampleSeedModifier,
1850    /// The seed value expression.
1851    pub value: ValueWithSpan,
1852}
1853
1854impl fmt::Display for TableSampleSeed {
1855    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1856        write!(f, "{} ({})", self.modifier, self.value)?;
1857        Ok(())
1858    }
1859}
1860
1861#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1862#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1863#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1864/// Modifier specifying how the sample seed is applied.
1865pub enum TableSampleSeedModifier {
1866    /// `REPEATABLE` modifier.
1867    Repeatable,
1868    /// `SEED` modifier.
1869    Seed,
1870}
1871
1872impl fmt::Display for TableSampleSeedModifier {
1873    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1874        match self {
1875            TableSampleSeedModifier::Repeatable => write!(f, "REPEATABLE"),
1876            TableSampleSeedModifier::Seed => write!(f, "SEED"),
1877        }
1878    }
1879}
1880
1881#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
1882#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1883#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1884/// Unit used with a `TABLESAMPLE` quantity (rows or percent).
1885pub enum TableSampleUnit {
1886    /// `ROWS` unit.
1887    Rows,
1888    /// `PERCENT` unit.
1889    Percent,
1890}
1891
1892impl fmt::Display for TableSampleUnit {
1893    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1894        match self {
1895            TableSampleUnit::Percent => write!(f, "PERCENT"),
1896            TableSampleUnit::Rows => write!(f, "ROWS"),
1897        }
1898    }
1899}
1900
1901#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1902#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1903#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1904/// Bucket-based sampling clause: `BUCKET <bucket> OUT OF <total> [ON <expr>]`.
1905pub struct TableSampleBucket {
1906    /// The bucket index expression.
1907    pub bucket: ValueWithSpan,
1908    /// The total number of buckets expression.
1909    pub total: ValueWithSpan,
1910    /// Optional `ON <expr>` specification.
1911    pub on: Option<Expr>,
1912}
1913
1914impl fmt::Display for TableSampleBucket {
1915    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1916        write!(f, "BUCKET {} OUT OF {}", self.bucket, self.total)?;
1917        if let Some(on) = &self.on {
1918            write!(f, " ON {on}")?;
1919        }
1920        Ok(())
1921    }
1922}
1923impl fmt::Display for TableSample {
1924    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1925        write!(f, "{}", self.modifier)?;
1926        if let Some(name) = &self.name {
1927            write!(f, " {name}")?;
1928        }
1929        if let Some(quantity) = &self.quantity {
1930            write!(f, " {quantity}")?;
1931        }
1932        if let Some(seed) = &self.seed {
1933            write!(f, " {seed}")?;
1934        }
1935        if let Some(bucket) = &self.bucket {
1936            write!(f, " ({bucket})")?;
1937        }
1938        if let Some(offset) = &self.offset {
1939            write!(f, " OFFSET {offset}")?;
1940        }
1941        Ok(())
1942    }
1943}
1944
1945/// The source of values in a `PIVOT` operation.
1946#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1947#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1948#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1949pub enum PivotValueSource {
1950    /// Pivot on a static list of values.
1951    ///
1952    /// See <https://docs.snowflake.com/en/sql-reference/constructs/pivot#pivot-on-a-specified-list-of-column-values-for-the-pivot-column>.
1953    List(Vec<ExprWithAlias>),
1954    /// Pivot on all distinct values of the pivot column.
1955    ///
1956    /// See <https://docs.snowflake.com/en/sql-reference/constructs/pivot#pivot-on-all-distinct-column-values-automatically-with-dynamic-pivot>.
1957    Any(Vec<OrderByExpr>),
1958    /// Pivot on all values returned by a subquery.
1959    ///
1960    /// See <https://docs.snowflake.com/en/sql-reference/constructs/pivot#pivot-on-column-values-using-a-subquery-with-dynamic-pivot>.
1961    Subquery(Box<Query>),
1962}
1963
1964impl fmt::Display for PivotValueSource {
1965    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1966        match self {
1967            PivotValueSource::List(values) => write!(f, "{}", display_comma_separated(values)),
1968            PivotValueSource::Any(order_by) => {
1969                write!(f, "ANY")?;
1970                if !order_by.is_empty() {
1971                    write!(f, " ORDER BY {}", display_comma_separated(order_by))?;
1972                }
1973                Ok(())
1974            }
1975            PivotValueSource::Subquery(query) => write!(f, "{query}"),
1976        }
1977    }
1978}
1979
1980/// An item in the `MEASURES` subclause of a `MATCH_RECOGNIZE` operation.
1981///
1982/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#measures-specifying-additional-output-columns>.
1983#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1984#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1985#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1986/// An item in the `MEASURES` clause of `MATCH_RECOGNIZE`.
1987pub struct Measure {
1988    /// Expression producing the measure value.
1989    pub expr: Expr,
1990    /// Alias for the measure column.
1991    pub alias: Ident,
1992}
1993
1994impl fmt::Display for Measure {
1995    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1996        write!(f, "{} AS {}", self.expr, self.alias)
1997    }
1998}
1999
2000/// The rows per match option in a `MATCH_RECOGNIZE` operation.
2001///
2002/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#row-s-per-match-specifying-the-rows-to-return>.
2003#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2004#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2005#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2006pub enum RowsPerMatch {
2007    /// `ONE ROW PER MATCH`
2008    OneRow,
2009    /// `ALL ROWS PER MATCH <mode>`
2010    AllRows(Option<EmptyMatchesMode>),
2011}
2012
2013impl fmt::Display for RowsPerMatch {
2014    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2015        match self {
2016            RowsPerMatch::OneRow => write!(f, "ONE ROW PER MATCH"),
2017            RowsPerMatch::AllRows(mode) => {
2018                write!(f, "ALL ROWS PER MATCH")?;
2019                if let Some(mode) = mode {
2020                    write!(f, " {mode}")?;
2021                }
2022                Ok(())
2023            }
2024        }
2025    }
2026}
2027
2028/// The after match skip option in a `MATCH_RECOGNIZE` operation.
2029///
2030/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#after-match-skip-specifying-where-to-continue-after-a-match>.
2031#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2032#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2033#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2034pub enum AfterMatchSkip {
2035    /// `PAST LAST ROW`
2036    PastLastRow,
2037    /// `TO NEXT ROW`
2038    ToNextRow,
2039    /// `TO FIRST <symbol>`
2040    ToFirst(Ident),
2041    /// `TO LAST <symbol>`
2042    ToLast(Ident),
2043}
2044
2045impl fmt::Display for AfterMatchSkip {
2046    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2047        write!(f, "AFTER MATCH SKIP ")?;
2048        match self {
2049            AfterMatchSkip::PastLastRow => write!(f, "PAST LAST ROW"),
2050            AfterMatchSkip::ToNextRow => write!(f, " TO NEXT ROW"),
2051            AfterMatchSkip::ToFirst(symbol) => write!(f, "TO FIRST {symbol}"),
2052            AfterMatchSkip::ToLast(symbol) => write!(f, "TO LAST {symbol}"),
2053        }
2054    }
2055}
2056
2057#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2058#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2059#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2060/// The mode for handling empty matches in a `MATCH_RECOGNIZE` operation.
2061pub enum EmptyMatchesMode {
2062    /// `SHOW EMPTY MATCHES`
2063    Show,
2064    /// `OMIT EMPTY MATCHES`
2065    Omit,
2066    /// `WITH UNMATCHED ROWS`
2067    WithUnmatched,
2068}
2069
2070impl fmt::Display for EmptyMatchesMode {
2071    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2072        match self {
2073            EmptyMatchesMode::Show => write!(f, "SHOW EMPTY MATCHES"),
2074            EmptyMatchesMode::Omit => write!(f, "OMIT EMPTY MATCHES"),
2075            EmptyMatchesMode::WithUnmatched => write!(f, "WITH UNMATCHED ROWS"),
2076        }
2077    }
2078}
2079
2080/// A symbol defined in a `MATCH_RECOGNIZE` operation.
2081///
2082/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#define-defining-symbols>.
2083#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2084#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2085#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2086/// A symbol defined in a `MATCH_RECOGNIZE` operation.
2087pub struct SymbolDefinition {
2088    /// The symbol identifier.
2089    pub symbol: Ident,
2090    /// The expression defining the symbol.
2091    pub definition: Expr,
2092}
2093
2094impl fmt::Display for SymbolDefinition {
2095    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2096        write!(f, "{} AS {}", self.symbol, self.definition)
2097    }
2098}
2099
2100/// A symbol in a `MATCH_RECOGNIZE` pattern.
2101#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2102#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2103#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2104pub enum MatchRecognizeSymbol {
2105    /// A named symbol, e.g. `S1`.
2106    Named(Ident),
2107    /// A virtual symbol representing the start of the of partition (`^`).
2108    Start,
2109    /// A virtual symbol representing the end of the partition (`$`).
2110    End,
2111}
2112
2113impl fmt::Display for MatchRecognizeSymbol {
2114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2115        match self {
2116            MatchRecognizeSymbol::Named(symbol) => write!(f, "{symbol}"),
2117            MatchRecognizeSymbol::Start => write!(f, "^"),
2118            MatchRecognizeSymbol::End => write!(f, "$"),
2119        }
2120    }
2121}
2122
2123/// The pattern in a `MATCH_RECOGNIZE` operation.
2124///
2125/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#pattern-specifying-the-pattern-to-match>.
2126#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2127#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2128#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2129pub enum MatchRecognizePattern {
2130    /// A named symbol such as `S1` or a virtual symbol such as `^`.
2131    Symbol(MatchRecognizeSymbol),
2132    /// {- symbol -}
2133    Exclude(MatchRecognizeSymbol),
2134    /// PERMUTE(symbol_1, ..., symbol_n)
2135    Permute(Vec<MatchRecognizeSymbol>),
2136    /// pattern_1 pattern_2 ... pattern_n
2137    Concat(Vec<MatchRecognizePattern>),
2138    /// ( pattern )
2139    Group(Box<MatchRecognizePattern>),
2140    /// pattern_1 | pattern_2 | ... | pattern_n
2141    Alternation(Vec<MatchRecognizePattern>),
2142    /// e.g. pattern*
2143    Repetition(Box<MatchRecognizePattern>, RepetitionQuantifier),
2144}
2145
2146impl fmt::Display for MatchRecognizePattern {
2147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2148        use MatchRecognizePattern::*;
2149        match self {
2150            Symbol(symbol) => write!(f, "{symbol}"),
2151            Exclude(symbol) => write!(f, "{{- {symbol} -}}"),
2152            Permute(symbols) => write!(f, "PERMUTE({})", display_comma_separated(symbols)),
2153            Concat(patterns) => write!(f, "{}", display_separated(patterns, " ")),
2154            Group(pattern) => write!(f, "( {pattern} )"),
2155            Alternation(patterns) => write!(f, "{}", display_separated(patterns, " | ")),
2156            Repetition(pattern, op) => write!(f, "{pattern}{op}"),
2157        }
2158    }
2159}
2160
2161/// Determines the minimum and maximum allowed occurrences of a pattern in a
2162/// `MATCH_RECOGNIZE` operation.
2163#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2164#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2165#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2166pub enum RepetitionQuantifier {
2167    /// `*`
2168    ZeroOrMore,
2169    /// `+`
2170    OneOrMore,
2171    /// `?`
2172    AtMostOne,
2173    /// `{n}`
2174    Exactly(u32),
2175    /// `{n,}`
2176    AtLeast(u32),
2177    /// `{,n}`
2178    AtMost(u32),
2179    /// `{n,m}
2180    Range(u32, u32),
2181}
2182
2183impl fmt::Display for RepetitionQuantifier {
2184    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2185        use RepetitionQuantifier::*;
2186        match self {
2187            ZeroOrMore => write!(f, "*"),
2188            OneOrMore => write!(f, "+"),
2189            AtMostOne => write!(f, "?"),
2190            Exactly(n) => write!(f, "{{{n}}}"),
2191            AtLeast(n) => write!(f, "{{{n},}}"),
2192            AtMost(n) => write!(f, "{{,{n}}}"),
2193            Range(n, m) => write!(f, "{{{n},{m}}}"),
2194        }
2195    }
2196}
2197
2198impl fmt::Display for TableFactor {
2199    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2200        match self {
2201            TableFactor::Table {
2202                name,
2203                alias,
2204                args,
2205                with_hints,
2206                version,
2207                partitions,
2208                with_ordinality,
2209                json_path,
2210                sample,
2211                index_hints,
2212            } => {
2213                name.fmt(f)?;
2214                if let Some(json_path) = json_path {
2215                    json_path.fmt(f)?;
2216                }
2217                if !partitions.is_empty() {
2218                    write!(f, "PARTITION ({})", display_comma_separated(partitions))?;
2219                }
2220                if let Some(args) = args {
2221                    write!(f, "(")?;
2222                    write!(f, "{}", display_comma_separated(&args.args))?;
2223                    if let Some(ref settings) = args.settings {
2224                        if !args.args.is_empty() {
2225                            write!(f, ", ")?;
2226                        }
2227                        write!(f, "SETTINGS {}", display_comma_separated(settings))?;
2228                    }
2229                    write!(f, ")")?;
2230                }
2231                if *with_ordinality {
2232                    write!(f, " WITH ORDINALITY")?;
2233                }
2234                if let Some(TableSampleKind::BeforeTableAlias(sample)) = sample {
2235                    write!(f, " {sample}")?;
2236                }
2237                if let Some(alias) = alias {
2238                    write!(f, " {alias}")?;
2239                }
2240                if !index_hints.is_empty() {
2241                    write!(f, " {}", display_separated(index_hints, " "))?;
2242                }
2243                if !with_hints.is_empty() {
2244                    write!(f, " WITH ({})", display_comma_separated(with_hints))?;
2245                }
2246                if let Some(version) = version {
2247                    write!(f, " {version}")?;
2248                }
2249                if let Some(TableSampleKind::AfterTableAlias(sample)) = sample {
2250                    write!(f, " {sample}")?;
2251                }
2252                Ok(())
2253            }
2254            TableFactor::Derived {
2255                lateral,
2256                subquery,
2257                alias,
2258                sample,
2259            } => {
2260                if *lateral {
2261                    write!(f, "LATERAL ")?;
2262                }
2263                f.write_str("(")?;
2264                NewLine.fmt(f)?;
2265                Indent(subquery).fmt(f)?;
2266                NewLine.fmt(f)?;
2267                f.write_str(")")?;
2268                if let Some(alias) = alias {
2269                    write!(f, " {alias}")?;
2270                }
2271                if let Some(TableSampleKind::AfterTableAlias(sample)) = sample {
2272                    write!(f, " {sample}")?;
2273                }
2274                Ok(())
2275            }
2276            TableFactor::Function {
2277                lateral,
2278                name,
2279                args,
2280                alias,
2281            } => {
2282                if *lateral {
2283                    write!(f, "LATERAL ")?;
2284                }
2285                write!(f, "{name}")?;
2286                write!(f, "({})", display_comma_separated(args))?;
2287                if let Some(alias) = alias {
2288                    write!(f, " {alias}")?;
2289                }
2290                Ok(())
2291            }
2292            TableFactor::TableFunction { expr, alias } => {
2293                write!(f, "TABLE({expr})")?;
2294                if let Some(alias) = alias {
2295                    write!(f, " {alias}")?;
2296                }
2297                Ok(())
2298            }
2299            TableFactor::UNNEST {
2300                alias,
2301                array_exprs,
2302                with_offset,
2303                with_offset_alias,
2304                with_ordinality,
2305            } => {
2306                write!(f, "UNNEST({})", display_comma_separated(array_exprs))?;
2307
2308                if *with_ordinality {
2309                    write!(f, " WITH ORDINALITY")?;
2310                }
2311
2312                if let Some(alias) = alias {
2313                    write!(f, " {alias}")?;
2314                }
2315                if *with_offset {
2316                    write!(f, " WITH OFFSET")?;
2317                }
2318                if let Some(alias) = with_offset_alias {
2319                    write!(f, " {alias}")?;
2320                }
2321                Ok(())
2322            }
2323            TableFactor::JsonTable {
2324                json_expr,
2325                json_path,
2326                columns,
2327                alias,
2328            } => {
2329                write!(
2330                    f,
2331                    "JSON_TABLE({json_expr}, {json_path} COLUMNS({columns}))",
2332                    columns = display_comma_separated(columns)
2333                )?;
2334                if let Some(alias) = alias {
2335                    write!(f, " {alias}")?;
2336                }
2337                Ok(())
2338            }
2339            TableFactor::OpenJsonTable {
2340                json_expr,
2341                json_path,
2342                columns,
2343                alias,
2344            } => {
2345                write!(f, "OPENJSON({json_expr}")?;
2346                if let Some(json_path) = json_path {
2347                    write!(f, ", {json_path}")?;
2348                }
2349                write!(f, ")")?;
2350                if !columns.is_empty() {
2351                    write!(f, " WITH ({})", display_comma_separated(columns))?;
2352                }
2353                if let Some(alias) = alias {
2354                    write!(f, " {alias}")?;
2355                }
2356                Ok(())
2357            }
2358            TableFactor::NestedJoin {
2359                table_with_joins,
2360                alias,
2361            } => {
2362                write!(f, "({table_with_joins})")?;
2363                if let Some(alias) = alias {
2364                    write!(f, " {alias}")?;
2365                }
2366                Ok(())
2367            }
2368            TableFactor::Pivot {
2369                table,
2370                aggregate_functions,
2371                value_column,
2372                value_source,
2373                default_on_null,
2374                alias,
2375            } => {
2376                write!(
2377                    f,
2378                    "{table} PIVOT({} FOR ",
2379                    display_comma_separated(aggregate_functions),
2380                )?;
2381                if value_column.len() == 1 {
2382                    write!(f, "{}", value_column[0])?;
2383                } else {
2384                    write!(f, "({})", display_comma_separated(value_column))?;
2385                }
2386                write!(f, " IN ({value_source})")?;
2387                if let Some(expr) = default_on_null {
2388                    write!(f, " DEFAULT ON NULL ({expr})")?;
2389                }
2390                write!(f, ")")?;
2391                if let Some(alias) = alias {
2392                    write!(f, " {alias}")?;
2393                }
2394                Ok(())
2395            }
2396            TableFactor::Unpivot {
2397                table,
2398                null_inclusion,
2399                value,
2400                name,
2401                columns,
2402                alias,
2403            } => {
2404                write!(f, "{table} UNPIVOT")?;
2405                if let Some(null_inclusion) = null_inclusion {
2406                    write!(f, " {null_inclusion} ")?;
2407                }
2408                write!(
2409                    f,
2410                    "({} FOR {} IN ({}))",
2411                    value,
2412                    name,
2413                    display_comma_separated(columns)
2414                )?;
2415                if let Some(alias) = alias {
2416                    write!(f, " {alias}")?;
2417                }
2418                Ok(())
2419            }
2420            TableFactor::MatchRecognize {
2421                table,
2422                partition_by,
2423                order_by,
2424                measures,
2425                rows_per_match,
2426                after_match_skip,
2427                pattern,
2428                symbols,
2429                alias,
2430            } => {
2431                write!(f, "{table} MATCH_RECOGNIZE(")?;
2432                if !partition_by.is_empty() {
2433                    write!(f, "PARTITION BY {} ", display_comma_separated(partition_by))?;
2434                }
2435                if !order_by.is_empty() {
2436                    write!(f, "ORDER BY {} ", display_comma_separated(order_by))?;
2437                }
2438                if !measures.is_empty() {
2439                    write!(f, "MEASURES {} ", display_comma_separated(measures))?;
2440                }
2441                if let Some(rows_per_match) = rows_per_match {
2442                    write!(f, "{rows_per_match} ")?;
2443                }
2444                if let Some(after_match_skip) = after_match_skip {
2445                    write!(f, "{after_match_skip} ")?;
2446                }
2447                write!(f, "PATTERN ({pattern}) ")?;
2448                write!(f, "DEFINE {})", display_comma_separated(symbols))?;
2449                if let Some(alias) = alias {
2450                    write!(f, " {alias}")?;
2451                }
2452                Ok(())
2453            }
2454            TableFactor::XmlTable {
2455                row_expression,
2456                passing,
2457                columns,
2458                alias,
2459                namespaces,
2460            } => {
2461                write!(f, "XMLTABLE(")?;
2462                if !namespaces.is_empty() {
2463                    write!(
2464                        f,
2465                        "XMLNAMESPACES({}), ",
2466                        display_comma_separated(namespaces)
2467                    )?;
2468                }
2469                write!(
2470                    f,
2471                    "{row_expression}{passing} COLUMNS {columns})",
2472                    columns = display_comma_separated(columns)
2473                )?;
2474                if let Some(alias) = alias {
2475                    write!(f, " {alias}")?;
2476                }
2477                Ok(())
2478            }
2479            TableFactor::SemanticView {
2480                name,
2481                dimensions,
2482                metrics,
2483                facts,
2484                where_clause,
2485                alias,
2486            } => {
2487                write!(f, "SEMANTIC_VIEW({name}")?;
2488
2489                if !dimensions.is_empty() {
2490                    write!(f, " DIMENSIONS {}", display_comma_separated(dimensions))?;
2491                }
2492
2493                if !metrics.is_empty() {
2494                    write!(f, " METRICS {}", display_comma_separated(metrics))?;
2495                }
2496
2497                if !facts.is_empty() {
2498                    write!(f, " FACTS {}", display_comma_separated(facts))?;
2499                }
2500
2501                if let Some(where_clause) = where_clause {
2502                    write!(f, " WHERE {where_clause}")?;
2503                }
2504
2505                write!(f, ")")?;
2506
2507                if let Some(alias) = alias {
2508                    write!(f, " {alias}")?;
2509                }
2510
2511                Ok(())
2512            }
2513        }
2514    }
2515}
2516
2517#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2518#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2519#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2520/// An alias for a table reference, optionally including an explicit `AS` and column names.
2521pub struct TableAlias {
2522    /// Tells whether the alias was introduced with an explicit, preceding "AS"
2523    /// keyword, e.g. `AS name`. Typically, the keyword is preceding the name
2524    /// (e.g. `.. FROM table AS t ..`).
2525    pub explicit: bool,
2526    /// Alias identifier for the table.
2527    pub name: Ident,
2528    /// Optional column aliases declared in parentheses after the table alias.
2529    pub columns: Vec<TableAliasColumnDef>,
2530}
2531
2532impl fmt::Display for TableAlias {
2533    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2534        write!(f, "{}{}", if self.explicit { "AS " } else { "" }, self.name)?;
2535        if !self.columns.is_empty() {
2536            write!(f, " ({})", display_comma_separated(&self.columns))?;
2537        }
2538        Ok(())
2539    }
2540}
2541
2542/// SQL column definition in a table expression alias.
2543/// Most of the time, the data type is not specified.
2544/// But some table-valued functions do require specifying the data type.
2545///
2546/// See <https://www.postgresql.org/docs/17/queries-table-expressions.html#QUERIES-TABLEFUNCTIONS>
2547#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2548#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2549#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2550pub struct TableAliasColumnDef {
2551    /// Column name alias
2552    pub name: Ident,
2553    /// Some table-valued functions require specifying the data type in the alias.
2554    pub data_type: Option<DataType>,
2555}
2556
2557impl TableAliasColumnDef {
2558    /// Create a new table alias column definition with only a name and no type
2559    pub fn from_name<S: Into<String>>(name: S) -> Self {
2560        TableAliasColumnDef {
2561            name: Ident::new(name),
2562            data_type: None,
2563        }
2564    }
2565}
2566
2567impl fmt::Display for TableAliasColumnDef {
2568    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2569        write!(f, "{}", self.name)?;
2570        if let Some(ref data_type) = self.data_type {
2571            write!(f, " {data_type}")?;
2572        }
2573        Ok(())
2574    }
2575}
2576
2577#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2578#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2579#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2580/// Specifies a table version selection, e.g. `FOR SYSTEM_TIME AS OF` or `AT(...)`.
2581pub enum TableVersion {
2582    /// When the table version is defined using `FOR SYSTEM_TIME AS OF`.
2583    /// For example: `SELECT * FROM tbl FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)`
2584    ForSystemTimeAsOf(Expr),
2585    /// When the table version is defined using `TIMESTAMP AS OF`.
2586    /// Databricks supports this syntax.
2587    /// For example: `SELECT * FROM tbl TIMESTAMP AS OF CURRENT_TIMESTAMP() - INTERVAL 1 HOUR`
2588    TimestampAsOf(Expr),
2589    /// When the table version is defined using `VERSION AS OF`.
2590    /// Databricks supports this syntax.
2591    /// For example: `SELECT * FROM tbl VERSION AS OF 2`
2592    VersionAsOf(Expr),
2593    /// When the table version is defined using a function.
2594    /// For example: `SELECT * FROM tbl AT(TIMESTAMP => '2020-08-14 09:30:00')`
2595    Function(Expr),
2596    /// Snowflake `CHANGES` clause for change tracking queries.
2597    /// For example:
2598    /// ```sql
2599    /// SELECT * FROM t
2600    ///   CHANGES(INFORMATION => DEFAULT)
2601    ///   AT(TIMESTAMP => TO_TIMESTAMP_TZ('...'))
2602    ///   END(TIMESTAMP => TO_TIMESTAMP_TZ('...'))
2603    /// ```
2604    /// <https://docs.snowflake.com/en/sql-reference/constructs/changes>
2605    Changes {
2606        /// The `CHANGES(INFORMATION => ...)` function-call expression.
2607        changes: Expr,
2608        /// The `AT(TIMESTAMP => ...)` function-call expression.
2609        at: Expr,
2610        /// The optional `END(TIMESTAMP => ...)` function-call expression.
2611        end: Option<Expr>,
2612    },
2613}
2614
2615impl Display for TableVersion {
2616    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2617        match self {
2618            TableVersion::ForSystemTimeAsOf(e) => write!(f, "FOR SYSTEM_TIME AS OF {e}")?,
2619            TableVersion::TimestampAsOf(e) => write!(f, "TIMESTAMP AS OF {e}")?,
2620            TableVersion::VersionAsOf(e) => write!(f, "VERSION AS OF {e}")?,
2621            TableVersion::Function(func) => write!(f, "{func}")?,
2622            TableVersion::Changes { changes, at, end } => {
2623                write!(f, "{changes} {at}")?;
2624                if let Some(end) = end {
2625                    write!(f, " {end}")?;
2626                }
2627            }
2628        }
2629        Ok(())
2630    }
2631}
2632
2633#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2634#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2635#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2636/// A single `JOIN` clause including relation and join operator/options.
2637pub struct Join {
2638    /// The joined table factor (table reference or derived table).
2639    pub relation: TableFactor,
2640    /// ClickHouse supports the optional `GLOBAL` keyword before the join operator.
2641    /// See [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/join)
2642    pub global: bool,
2643    /// The join operator and its constraint (INNER/LEFT/RIGHT/CROSS/ASOF/etc.).
2644    pub join_operator: JoinOperator,
2645}
2646
2647impl fmt::Display for Join {
2648    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2649        fn prefix(constraint: &JoinConstraint) -> &'static str {
2650            match constraint {
2651                JoinConstraint::Natural => "NATURAL ",
2652                _ => "",
2653            }
2654        }
2655        fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
2656            struct Suffix<'a>(&'a JoinConstraint);
2657            impl fmt::Display for Suffix<'_> {
2658                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2659                    match self.0 {
2660                        JoinConstraint::On(expr) => write!(f, " ON {expr}"),
2661                        JoinConstraint::Using(attrs) => {
2662                            write!(f, " USING({})", display_comma_separated(attrs))
2663                        }
2664                        _ => Ok(()),
2665                    }
2666                }
2667            }
2668            Suffix(constraint)
2669        }
2670        if self.global {
2671            write!(f, "GLOBAL ")?;
2672        }
2673
2674        match &self.join_operator {
2675            JoinOperator::Join(constraint) => f.write_fmt(format_args!(
2676                "{}JOIN {}{}",
2677                prefix(constraint),
2678                self.relation,
2679                suffix(constraint)
2680            )),
2681            JoinOperator::Inner(constraint) => f.write_fmt(format_args!(
2682                "{}INNER JOIN {}{}",
2683                prefix(constraint),
2684                self.relation,
2685                suffix(constraint)
2686            )),
2687            JoinOperator::Left(constraint) => f.write_fmt(format_args!(
2688                "{}LEFT JOIN {}{}",
2689                prefix(constraint),
2690                self.relation,
2691                suffix(constraint)
2692            )),
2693            JoinOperator::LeftOuter(constraint) => f.write_fmt(format_args!(
2694                "{}LEFT OUTER JOIN {}{}",
2695                prefix(constraint),
2696                self.relation,
2697                suffix(constraint)
2698            )),
2699            JoinOperator::Right(constraint) => f.write_fmt(format_args!(
2700                "{}RIGHT JOIN {}{}",
2701                prefix(constraint),
2702                self.relation,
2703                suffix(constraint)
2704            )),
2705            JoinOperator::RightOuter(constraint) => f.write_fmt(format_args!(
2706                "{}RIGHT OUTER JOIN {}{}",
2707                prefix(constraint),
2708                self.relation,
2709                suffix(constraint)
2710            )),
2711            JoinOperator::FullOuter(constraint) => f.write_fmt(format_args!(
2712                "{}FULL JOIN {}{}",
2713                prefix(constraint),
2714                self.relation,
2715                suffix(constraint)
2716            )),
2717            JoinOperator::CrossJoin(constraint) => f.write_fmt(format_args!(
2718                "CROSS JOIN {}{}",
2719                self.relation,
2720                suffix(constraint)
2721            )),
2722            JoinOperator::Semi(constraint) => f.write_fmt(format_args!(
2723                "{}SEMI JOIN {}{}",
2724                prefix(constraint),
2725                self.relation,
2726                suffix(constraint)
2727            )),
2728            JoinOperator::LeftSemi(constraint) => f.write_fmt(format_args!(
2729                "{}LEFT SEMI JOIN {}{}",
2730                prefix(constraint),
2731                self.relation,
2732                suffix(constraint)
2733            )),
2734            JoinOperator::RightSemi(constraint) => f.write_fmt(format_args!(
2735                "{}RIGHT SEMI JOIN {}{}",
2736                prefix(constraint),
2737                self.relation,
2738                suffix(constraint)
2739            )),
2740            JoinOperator::Anti(constraint) => f.write_fmt(format_args!(
2741                "{}ANTI JOIN {}{}",
2742                prefix(constraint),
2743                self.relation,
2744                suffix(constraint)
2745            )),
2746            JoinOperator::LeftAnti(constraint) => f.write_fmt(format_args!(
2747                "{}LEFT ANTI JOIN {}{}",
2748                prefix(constraint),
2749                self.relation,
2750                suffix(constraint)
2751            )),
2752            JoinOperator::RightAnti(constraint) => f.write_fmt(format_args!(
2753                "{}RIGHT ANTI JOIN {}{}",
2754                prefix(constraint),
2755                self.relation,
2756                suffix(constraint)
2757            )),
2758            JoinOperator::CrossApply => f.write_fmt(format_args!("CROSS APPLY {}", self.relation)),
2759            JoinOperator::OuterApply => f.write_fmt(format_args!("OUTER APPLY {}", self.relation)),
2760            JoinOperator::AsOf {
2761                match_condition,
2762                constraint,
2763            } => f.write_fmt(format_args!(
2764                "ASOF JOIN {} MATCH_CONDITION ({match_condition}){}",
2765                self.relation,
2766                suffix(constraint)
2767            )),
2768            JoinOperator::StraightJoin(constraint) => f.write_fmt(format_args!(
2769                "STRAIGHT_JOIN {}{}",
2770                self.relation,
2771                suffix(constraint)
2772            )),
2773        }
2774    }
2775}
2776
2777#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2778#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2779#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2780/// The operator used for joining two tables, e.g. `INNER`, `LEFT`, `CROSS`, `ASOF`, etc.
2781pub enum JoinOperator {
2782    /// Generic `JOIN` with an optional constraint.
2783    Join(JoinConstraint),
2784    /// `INNER JOIN` with an optional constraint.
2785    Inner(JoinConstraint),
2786    /// `LEFT JOIN` with an optional constraint.
2787    Left(JoinConstraint),
2788    /// `LEFT OUTER JOIN` with an optional constraint.
2789    LeftOuter(JoinConstraint),
2790    /// `RIGHT JOIN` with an optional constraint.
2791    Right(JoinConstraint),
2792    /// `RIGHT OUTER JOIN` with an optional constraint.
2793    RightOuter(JoinConstraint),
2794    /// `FULL OUTER JOIN` with an optional constraint.
2795    FullOuter(JoinConstraint),
2796    /// `CROSS JOIN` (constraint usage is non-standard).
2797    CrossJoin(JoinConstraint),
2798    /// `SEMI JOIN` (non-standard)
2799    Semi(JoinConstraint),
2800    /// `LEFT SEMI JOIN` (non-standard)
2801    LeftSemi(JoinConstraint),
2802    /// `RIGHT SEMI JOIN` (non-standard)
2803    RightSemi(JoinConstraint),
2804    /// `ANTI JOIN` (non-standard)
2805    Anti(JoinConstraint),
2806    /// `LEFT ANTI JOIN` (non-standard)
2807    LeftAnti(JoinConstraint),
2808    /// `RIGHT ANTI JOIN` (non-standard)
2809    RightAnti(JoinConstraint),
2810    /// `CROSS APPLY` (non-standard)
2811    CrossApply,
2812    /// `OUTER APPLY` (non-standard)
2813    OuterApply,
2814    /// `ASOF` joins are used for joining time-series tables whose timestamp columns do not match exactly.
2815    ///
2816    /// See <https://docs.snowflake.com/en/sql-reference/constructs/asof-join>.
2817    AsOf {
2818        /// Condition used to match records in the `ASOF` join.
2819        match_condition: Expr,
2820        /// Additional constraint applied to the `ASOF` join.
2821        constraint: JoinConstraint,
2822    },
2823    /// `STRAIGHT_JOIN` (MySQL non-standard behavior)
2824    ///
2825    /// See <https://dev.mysql.com/doc/refman/8.4/en/join.html>.
2826    StraightJoin(JoinConstraint),
2827}
2828
2829#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2830#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2831#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2832/// Represents how two tables are constrained in a join: `ON`, `USING`, `NATURAL`, or none.
2833pub enum JoinConstraint {
2834    /// `ON <expr>` join condition.
2835    On(Expr),
2836    /// `USING(...)` list of column names.
2837    Using(Vec<ObjectName>),
2838    /// `NATURAL` join (columns matched automatically).
2839    Natural,
2840    /// No constraint specified (e.g. `CROSS JOIN`).
2841    None,
2842}
2843
2844#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2845#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2846#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2847/// The kind of `ORDER BY` clause: either `ALL` with modifiers or a list of expressions.
2848pub enum OrderByKind {
2849    /// `GROUP BY ALL`/`ORDER BY ALL` syntax with optional modifiers.
2850    ///
2851    /// [DuckDB]:  <https://duckdb.org/docs/sql/query_syntax/orderby>
2852    /// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by>
2853    All(OrderByOptions),
2854
2855    /// A standard list of ordering expressions.
2856    Expressions(Vec<OrderByExpr>),
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 an `ORDER BY` clause with its kind and optional `INTERPOLATE`.
2863pub struct OrderBy {
2864    /// The kind of ordering (expressions or `ALL`).
2865    pub kind: OrderByKind,
2866
2867    /// Optional `INTERPOLATE` clause (ClickHouse extension).
2868    pub interpolate: Option<Interpolate>,
2869}
2870
2871impl fmt::Display for OrderBy {
2872    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2873        write!(f, "ORDER BY")?;
2874        match &self.kind {
2875            OrderByKind::Expressions(exprs) => {
2876                write!(f, " {}", display_comma_separated(exprs))?;
2877            }
2878            OrderByKind::All(all) => {
2879                write!(f, " ALL{all}")?;
2880            }
2881        }
2882
2883        if let Some(ref interpolate) = self.interpolate {
2884            match &interpolate.exprs {
2885                Some(exprs) => write!(f, " INTERPOLATE ({})", display_comma_separated(exprs))?,
2886                None => write!(f, " INTERPOLATE")?,
2887            }
2888        }
2889
2890        Ok(())
2891    }
2892}
2893
2894/// An `ORDER BY` expression
2895#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2896#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2897#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2898pub struct OrderByExpr {
2899    /// The expression to order by.
2900    pub expr: Expr,
2901    /// Ordering options such as `ASC`/`DESC` and `NULLS` behavior.
2902    pub options: OrderByOptions,
2903    /// Optional `WITH FILL` clause (ClickHouse extension) which specifies how to fill gaps.
2904    pub with_fill: Option<WithFill>,
2905}
2906
2907impl From<Ident> for OrderByExpr {
2908    fn from(ident: Ident) -> Self {
2909        OrderByExpr {
2910            expr: Expr::Identifier(ident),
2911            options: OrderByOptions::default(),
2912            with_fill: None,
2913        }
2914    }
2915}
2916
2917impl fmt::Display for OrderByExpr {
2918    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2919        write!(f, "{}{}", self.expr, self.options)?;
2920        if let Some(ref with_fill) = self.with_fill {
2921            write!(f, " {with_fill}")?
2922        }
2923        Ok(())
2924    }
2925}
2926
2927/// ClickHouse `WITH FILL` modifier for `ORDER BY` clause.
2928/// Supported by [ClickHouse syntax]
2929///
2930/// [ClickHouse syntax]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier>
2931#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2932#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2933#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2934/// `WITH FILL` options for ClickHouse `ORDER BY` expressions.
2935pub struct WithFill {
2936    /// Optional lower bound expression for the fill range (`FROM <expr>`).
2937    pub from: Option<Expr>,
2938    /// Optional upper bound expression for the fill range (`TO <expr>`).
2939    pub to: Option<Expr>,
2940    /// Optional step expression specifying interpolation step (`STEP <expr>`).
2941    pub step: Option<Expr>,
2942}
2943
2944impl fmt::Display for WithFill {
2945    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2946        write!(f, "WITH FILL")?;
2947        if let Some(ref from) = self.from {
2948            write!(f, " FROM {from}")?;
2949        }
2950        if let Some(ref to) = self.to {
2951            write!(f, " TO {to}")?;
2952        }
2953        if let Some(ref step) = self.step {
2954            write!(f, " STEP {step}")?;
2955        }
2956        Ok(())
2957    }
2958}
2959
2960/// ClickHouse `INTERPOLATE` clause for use in `ORDER BY` clause when using `WITH FILL` modifier.
2961/// Supported by [ClickHouse syntax]
2962///
2963/// [ClickHouse syntax]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier>
2964#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2965#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2966#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2967/// An expression used by `WITH FILL`/`INTERPOLATE` to specify interpolation for a column.
2968pub struct InterpolateExpr {
2969    /// The column to interpolate.
2970    pub column: Ident,
2971    /// Optional `AS <expr>` expression specifying how to compute interpolated values.
2972    pub expr: Option<Expr>,
2973}
2974
2975#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2976#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2977#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2978/// `INTERPOLATE` clause used with ClickHouse `WITH FILL` to compute missing values.
2979pub struct Interpolate {
2980    /// Optional list of interpolation expressions.
2981    pub exprs: Option<Vec<InterpolateExpr>>,
2982}
2983
2984impl fmt::Display for InterpolateExpr {
2985    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2986        write!(f, "{}", self.column)?;
2987        if let Some(ref expr) = self.expr {
2988            write!(f, " AS {expr}")?;
2989        }
2990        Ok(())
2991    }
2992}
2993
2994#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2995#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2996#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2997/// Options for an `ORDER BY` expression (ASC/DESC and NULLS FIRST/LAST).
2998pub struct OrderByOptions {
2999    /// Optional `ASC` (`Some(true)`) or `DESC` (`Some(false)`).
3000    pub asc: Option<bool>,
3001    /// Optional `NULLS FIRST` (`Some(true)`) or `NULLS LAST` (`Some(false)`).
3002    pub nulls_first: Option<bool>,
3003}
3004
3005impl fmt::Display for OrderByOptions {
3006    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3007        match self.asc {
3008            Some(true) => write!(f, " ASC")?,
3009            Some(false) => write!(f, " DESC")?,
3010            None => (),
3011        }
3012        match self.nulls_first {
3013            Some(true) => write!(f, " NULLS FIRST")?,
3014            Some(false) => write!(f, " NULLS LAST")?,
3015            None => (),
3016        }
3017        Ok(())
3018    }
3019}
3020
3021#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3022#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3023#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3024/// Represents the different syntactic forms of `LIMIT` clauses.
3025pub enum LimitClause {
3026    /// Standard SQL `LIMIT` syntax (optionally `BY` and `OFFSET`).
3027    ///
3028    /// `LIMIT <limit> [BY <expr>,<expr>,...] [OFFSET <offset>]`
3029    LimitOffset {
3030        /// `LIMIT { <N> | ALL }` expression.
3031        limit: Option<Expr>,
3032        /// Optional `OFFSET` expression with optional `ROW(S)` keyword.
3033        offset: Option<Offset>,
3034        /// Optional `BY { <expr>,... }` list used by some dialects (ClickHouse).
3035        limit_by: Vec<Expr>,
3036    },
3037    /// MySQL-specific syntax: `LIMIT <offset>, <limit>` (order reversed).
3038    OffsetCommaLimit {
3039        /// The offset expression.
3040        offset: Expr,
3041        /// The limit expression.
3042        limit: Expr,
3043    },
3044}
3045
3046impl fmt::Display for LimitClause {
3047    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3048        match self {
3049            LimitClause::LimitOffset {
3050                limit,
3051                limit_by,
3052                offset,
3053            } => {
3054                if let Some(ref limit) = limit {
3055                    write!(f, " LIMIT {limit}")?;
3056                }
3057                if let Some(ref offset) = offset {
3058                    write!(f, " {offset}")?;
3059                }
3060                if !limit_by.is_empty() {
3061                    debug_assert!(limit.is_some());
3062                    write!(f, " BY {}", display_separated(limit_by, ", "))?;
3063                }
3064                Ok(())
3065            }
3066            LimitClause::OffsetCommaLimit { offset, limit } => {
3067                write!(f, " LIMIT {offset}, {limit}")
3068            }
3069        }
3070    }
3071}
3072
3073#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3074#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3075#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3076/// `OFFSET` clause consisting of a value and a rows specifier.
3077pub struct Offset {
3078    /// The numeric expression following `OFFSET`.
3079    pub value: Expr,
3080    /// Whether the offset uses `ROW`/`ROWS` or omits it.
3081    pub rows: OffsetRows,
3082}
3083
3084impl fmt::Display for Offset {
3085    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3086        write!(f, "OFFSET {}{}", self.value, self.rows)
3087    }
3088}
3089
3090/// Stores the keyword after `OFFSET <number>`
3091#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3092#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3093#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3094pub enum OffsetRows {
3095    /// Omitting `ROW`/`ROWS` entirely (non-standard MySQL quirk).
3096    None,
3097    /// `ROW` keyword present.
3098    Row,
3099    /// `ROWS` keyword present.
3100    Rows,
3101}
3102
3103impl fmt::Display for OffsetRows {
3104    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3105        match self {
3106            OffsetRows::None => Ok(()),
3107            OffsetRows::Row => write!(f, " ROW"),
3108            OffsetRows::Rows => write!(f, " ROWS"),
3109        }
3110    }
3111}
3112
3113/// Pipe syntax, first introduced in Google BigQuery.
3114/// Example:
3115///
3116/// ```sql
3117/// FROM Produce
3118/// |> WHERE sales > 0
3119/// |> AGGREGATE SUM(sales) AS total_sales, COUNT(*) AS num_sales
3120///    GROUP BY item;
3121/// ```
3122///
3123/// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#pipe_syntax>
3124#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3125#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3126#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3127pub enum PipeOperator {
3128    /// Limits the number of rows to return in a query, with an optional OFFSET clause to skip over rows.
3129    ///
3130    /// Syntax: `|> LIMIT <n> [OFFSET <m>]`
3131    ///
3132    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#limit_pipe_operator>
3133    Limit {
3134        /// The expression specifying the number of rows to return.
3135        expr: Expr,
3136        /// Optional offset expression provided inline with `LIMIT`.
3137        offset: Option<Expr>,
3138    },
3139    /// Filters the results of the input table.
3140    ///
3141    /// Syntax: `|> WHERE <condition>`
3142    ///
3143    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#where_pipe_operator>
3144    Where {
3145        /// The filter expression.
3146        expr: Expr,
3147    },
3148    /// `ORDER BY <expr> [ASC|DESC], ...`
3149    OrderBy {
3150        /// The ordering expressions.
3151        exprs: Vec<OrderByExpr>,
3152    },
3153    /// Produces a new table with the listed columns, similar to the outermost SELECT clause in a table subquery in standard syntax.
3154    ///
3155    /// Syntax `|> SELECT <expr> [[AS] alias], ...`
3156    ///
3157    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#select_pipe_operator>
3158    Select {
3159        /// The select items to produce.
3160        exprs: Vec<SelectItem>,
3161    },
3162    /// Propagates the existing table and adds computed columns, similar to SELECT *, new_column in standard syntax.
3163    ///
3164    /// Syntax: `|> EXTEND <expr> [[AS] alias], ...`
3165    ///
3166    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#extend_pipe_operator>
3167    Extend {
3168        /// Expressions defining added columns.
3169        exprs: Vec<SelectItem>,
3170    },
3171    /// Replaces the value of a column in the current table, similar to SELECT * REPLACE (expression AS column) in standard syntax.
3172    ///
3173    /// Syntax: `|> SET <column> = <expression>, ...`
3174    ///
3175    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#set_pipe_operator>
3176    Set {
3177        /// Assignments to apply (`column = expr`).
3178        assignments: Vec<Assignment>,
3179    },
3180    /// Removes listed columns from the current table, similar to SELECT * EXCEPT (column) in standard syntax.
3181    ///
3182    /// Syntax: `|> DROP <column>, ...`
3183    ///
3184    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#drop_pipe_operator>
3185    Drop {
3186        /// Columns to drop.
3187        columns: Vec<Ident>,
3188    },
3189    /// Introduces a table alias for the input table, similar to applying the AS alias clause on a table subquery in standard syntax.
3190    ///
3191    /// Syntax: `|> AS <alias>`
3192    ///
3193    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#as_pipe_operator>
3194    As {
3195        /// Alias to assign to the input table.
3196        alias: Ident,
3197    },
3198    /// Performs aggregation on data across grouped rows or an entire table.
3199    ///
3200    /// Syntax: `|> AGGREGATE <agg_expr> [[AS] alias], ...`
3201    ///
3202    /// Syntax:
3203    /// ```norust
3204    /// |> AGGREGATE [<agg_expr> [[AS] alias], ...]
3205    /// GROUP BY <grouping_expr> [AS alias], ...
3206    /// ```
3207    ///
3208    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#aggregate_pipe_operator>
3209    Aggregate {
3210        /// Expressions computed for each row prior to grouping.
3211        full_table_exprs: Vec<ExprWithAliasAndOrderBy>,
3212        /// Grouping expressions for aggregation.
3213        group_by_expr: Vec<ExprWithAliasAndOrderBy>,
3214    },
3215    /// Selects a random sample of rows from the input table.
3216    /// Syntax: `|> TABLESAMPLE SYSTEM (10 PERCENT)
3217    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#tablesample_pipe_operator>
3218    TableSample {
3219        /// Sampling clause describing the sample.
3220        sample: Box<TableSample>,
3221    },
3222    /// Renames columns in the input table.
3223    ///
3224    /// Syntax: `|> RENAME old_name AS new_name, ...`
3225    ///
3226    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#rename_pipe_operator>
3227    Rename {
3228        /// Mappings of old to new identifiers.
3229        mappings: Vec<IdentWithAlias>,
3230    },
3231    /// Combines the input table with one or more tables using UNION.
3232    ///
3233    /// Syntax: `|> UNION [ALL|DISTINCT] (<query>), (<query>), ...`
3234    ///
3235    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#union_pipe_operator>
3236    Union {
3237        /// Set quantifier (`ALL` or `DISTINCT`).
3238        set_quantifier: SetQuantifier,
3239        /// The queries to combine with `UNION`.
3240        queries: Vec<Query>,
3241    },
3242    /// Returns only the rows that are present in both the input table and the specified tables.
3243    ///
3244    /// Syntax: `|> INTERSECT [DISTINCT] (<query>), (<query>), ...`
3245    ///
3246    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#intersect_pipe_operator>
3247    Intersect {
3248        /// Set quantifier for the `INTERSECT` operator.
3249        set_quantifier: SetQuantifier,
3250        /// The queries to intersect.
3251        queries: Vec<Query>,
3252    },
3253    /// Returns only the rows that are present in the input table but not in the specified tables.
3254    ///
3255    /// Syntax: `|> EXCEPT DISTINCT (<query>), (<query>), ...`
3256    ///
3257    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#except_pipe_operator>
3258    Except {
3259        /// Set quantifier for the `EXCEPT` operator.
3260        set_quantifier: SetQuantifier,
3261        /// The queries to exclude from the input set.
3262        queries: Vec<Query>,
3263    },
3264    /// Calls a table function or procedure that returns a table.
3265    ///
3266    /// Syntax: `|> CALL function_name(args) [AS alias]`
3267    ///
3268    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#call_pipe_operator>
3269    Call {
3270        /// The function or procedure to call which returns a table.
3271        function: Function,
3272        /// Optional alias for the result table.
3273        alias: Option<Ident>,
3274    },
3275    /// Pivots data from rows to columns.
3276    ///
3277    /// Syntax: `|> PIVOT(aggregate_function(column) FOR pivot_column IN (value1, value2, ...)) [AS alias]`
3278    ///
3279    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#pivot_pipe_operator>
3280    Pivot {
3281        /// Aggregate functions to compute during pivot.
3282        aggregate_functions: Vec<ExprWithAlias>,
3283        /// Column(s) that provide the pivot values.
3284        value_column: Vec<Ident>,
3285        /// The source of pivot values (literal list or subquery).
3286        value_source: PivotValueSource,
3287        /// Optional alias for the output.
3288        alias: Option<Ident>,
3289    },
3290    /// The `UNPIVOT` pipe operator transforms columns into rows.
3291    ///
3292    /// Syntax:
3293    /// ```sql
3294    /// |> UNPIVOT(value_column FOR name_column IN (column1, column2, ...)) [alias]
3295    /// ```
3296    ///
3297    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#unpivot_pipe_operator>
3298    Unpivot {
3299        /// Output column that will receive the unpivoted value.
3300        value_column: Ident,
3301        /// Column name holding the unpivoted column name.
3302        name_column: Ident,
3303        /// Columns to unpivot.
3304        unpivot_columns: Vec<Ident>,
3305        /// Optional alias for the unpivot result.
3306        alias: Option<Ident>,
3307    },
3308    /// Joins the input table with another table.
3309    ///
3310    /// Syntax: `|> [JOIN_TYPE] JOIN <table> [alias] ON <condition>` or `|> [JOIN_TYPE] JOIN <table> [alias] USING (<columns>)`
3311    ///
3312    /// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#join_pipe_operator>
3313    Join(Join),
3314}
3315
3316impl fmt::Display for PipeOperator {
3317    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3318        match self {
3319            PipeOperator::Select { exprs } => {
3320                write!(f, "SELECT {}", display_comma_separated(exprs.as_slice()))
3321            }
3322            PipeOperator::Extend { exprs } => {
3323                write!(f, "EXTEND {}", display_comma_separated(exprs.as_slice()))
3324            }
3325            PipeOperator::Set { assignments } => {
3326                write!(f, "SET {}", display_comma_separated(assignments.as_slice()))
3327            }
3328            PipeOperator::Drop { columns } => {
3329                write!(f, "DROP {}", display_comma_separated(columns.as_slice()))
3330            }
3331            PipeOperator::As { alias } => {
3332                write!(f, "AS {alias}")
3333            }
3334            PipeOperator::Limit { expr, offset } => {
3335                write!(f, "LIMIT {expr}")?;
3336                if let Some(offset) = offset {
3337                    write!(f, " OFFSET {offset}")?;
3338                }
3339                Ok(())
3340            }
3341            PipeOperator::Aggregate {
3342                full_table_exprs,
3343                group_by_expr,
3344            } => {
3345                write!(f, "AGGREGATE")?;
3346                if !full_table_exprs.is_empty() {
3347                    write!(
3348                        f,
3349                        " {}",
3350                        display_comma_separated(full_table_exprs.as_slice())
3351                    )?;
3352                }
3353                if !group_by_expr.is_empty() {
3354                    write!(f, " GROUP BY {}", display_comma_separated(group_by_expr))?;
3355                }
3356                Ok(())
3357            }
3358
3359            PipeOperator::Where { expr } => {
3360                write!(f, "WHERE {expr}")
3361            }
3362            PipeOperator::OrderBy { exprs } => {
3363                write!(f, "ORDER BY {}", display_comma_separated(exprs.as_slice()))
3364            }
3365
3366            PipeOperator::TableSample { sample } => {
3367                write!(f, "{sample}")
3368            }
3369            PipeOperator::Rename { mappings } => {
3370                write!(f, "RENAME {}", display_comma_separated(mappings))
3371            }
3372            PipeOperator::Union {
3373                set_quantifier,
3374                queries,
3375            } => Self::fmt_set_operation(f, "UNION", set_quantifier, queries),
3376            PipeOperator::Intersect {
3377                set_quantifier,
3378                queries,
3379            } => Self::fmt_set_operation(f, "INTERSECT", set_quantifier, queries),
3380            PipeOperator::Except {
3381                set_quantifier,
3382                queries,
3383            } => Self::fmt_set_operation(f, "EXCEPT", set_quantifier, queries),
3384            PipeOperator::Call { function, alias } => {
3385                write!(f, "CALL {function}")?;
3386                Self::fmt_optional_alias(f, alias)
3387            }
3388            PipeOperator::Pivot {
3389                aggregate_functions,
3390                value_column,
3391                value_source,
3392                alias,
3393            } => {
3394                write!(
3395                    f,
3396                    "PIVOT({} FOR {} IN ({}))",
3397                    display_comma_separated(aggregate_functions),
3398                    Expr::CompoundIdentifier(value_column.to_vec()),
3399                    value_source
3400                )?;
3401                Self::fmt_optional_alias(f, alias)
3402            }
3403            PipeOperator::Unpivot {
3404                value_column,
3405                name_column,
3406                unpivot_columns,
3407                alias,
3408            } => {
3409                write!(
3410                    f,
3411                    "UNPIVOT({} FOR {} IN ({}))",
3412                    value_column,
3413                    name_column,
3414                    display_comma_separated(unpivot_columns)
3415                )?;
3416                Self::fmt_optional_alias(f, alias)
3417            }
3418            PipeOperator::Join(join) => write!(f, "{join}"),
3419        }
3420    }
3421}
3422
3423impl PipeOperator {
3424    /// Helper function to format optional alias for pipe operators
3425    fn fmt_optional_alias(f: &mut fmt::Formatter<'_>, alias: &Option<Ident>) -> fmt::Result {
3426        if let Some(alias) = alias {
3427            write!(f, " AS {alias}")?;
3428        }
3429        Ok(())
3430    }
3431
3432    /// Helper function to format set operations (UNION, INTERSECT, EXCEPT) with queries
3433    fn fmt_set_operation(
3434        f: &mut fmt::Formatter<'_>,
3435        operation: &str,
3436        set_quantifier: &SetQuantifier,
3437        queries: &[Query],
3438    ) -> fmt::Result {
3439        write!(f, "{operation}")?;
3440        match set_quantifier {
3441            SetQuantifier::None => {}
3442            _ => {
3443                write!(f, " {set_quantifier}")?;
3444            }
3445        }
3446        write!(f, " ")?;
3447        let parenthesized_queries: Vec<String> =
3448            queries.iter().map(|query| format!("({query})")).collect();
3449        write!(f, "{}", display_comma_separated(&parenthesized_queries))
3450    }
3451}
3452
3453#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3454#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3455#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3456/// `FETCH` clause options.
3457pub struct Fetch {
3458    /// `WITH TIES` option is present.
3459    pub with_ties: bool,
3460    /// `PERCENT` modifier is present.
3461    pub percent: bool,
3462    /// Optional quantity expression (e.g. `FETCH FIRST 10 ROWS`).
3463    pub quantity: Option<Expr>,
3464}
3465
3466impl fmt::Display for Fetch {
3467    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3468        let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
3469        if let Some(ref quantity) = self.quantity {
3470            let percent = if self.percent { " PERCENT" } else { "" };
3471            write!(f, "FETCH FIRST {quantity}{percent} ROWS {extension}")
3472        } else {
3473            write!(f, "FETCH FIRST ROWS {extension}")
3474        }
3475    }
3476}
3477
3478#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3479#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3480#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3481/// `FOR ...` locking clause.
3482pub struct LockClause {
3483    /// The kind of lock requested (e.g. `SHARE`, `UPDATE`).
3484    pub lock_type: LockType,
3485    /// Optional object name after `OF` (e.g. `FOR UPDATE OF t1`).
3486    pub of: Option<ObjectName>,
3487    /// Optional non-blocking behavior (`NOWAIT` / `SKIP LOCKED`).
3488    pub nonblock: Option<NonBlock>,
3489}
3490
3491impl fmt::Display for LockClause {
3492    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3493        write!(f, "FOR {}", &self.lock_type)?;
3494        if let Some(ref of) = self.of {
3495            write!(f, " OF {of}")?;
3496        }
3497        if let Some(ref nb) = self.nonblock {
3498            write!(f, " {nb}")?;
3499        }
3500        Ok(())
3501    }
3502}
3503
3504#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3505#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3506#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3507/// The lock type used in `FOR <lock>` clauses (e.g. `FOR SHARE`, `FOR UPDATE`).
3508pub enum LockType {
3509    /// `SHARE` lock (shared lock).
3510    Share,
3511    /// `UPDATE` lock (exclusive/update lock).
3512    Update,
3513}
3514
3515impl fmt::Display for LockType {
3516    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3517        let select_lock = match self {
3518            LockType::Share => "SHARE",
3519            LockType::Update => "UPDATE",
3520        };
3521        write!(f, "{select_lock}")
3522    }
3523}
3524
3525#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3526#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3527#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3528/// Non-blocking lock options for `FOR ...` clauses.
3529pub enum NonBlock {
3530    /// `NOWAIT` — do not wait for the lock.
3531    Nowait,
3532    /// `SKIP LOCKED` — skip rows that are locked.
3533    SkipLocked,
3534}
3535
3536impl fmt::Display for NonBlock {
3537    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3538        let nonblock = match self {
3539            NonBlock::Nowait => "NOWAIT",
3540            NonBlock::SkipLocked => "SKIP LOCKED",
3541        };
3542        write!(f, "{nonblock}")
3543    }
3544}
3545
3546#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3547#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3548#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3549/// `ALL`, `DISTINCT`, or `DISTINCT ON (...)` modifiers for `SELECT` lists.
3550pub enum Distinct {
3551    /// `ALL` (keep duplicate rows)
3552    ///
3553    /// Generally this is the default if omitted, but omission should be represented as
3554    /// `None::<Option<Distinct>>`
3555    All,
3556
3557    /// `DISTINCT` (remove duplicate rows)
3558    Distinct,
3559
3560    /// `DISTINCT ON (...)` (Postgres extension)
3561    On(Vec<Expr>),
3562}
3563
3564impl fmt::Display for Distinct {
3565    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3566        match self {
3567            Distinct::All => write!(f, "ALL"),
3568            Distinct::Distinct => write!(f, "DISTINCT"),
3569            Distinct::On(col_names) => {
3570                let col_names = display_comma_separated(col_names);
3571                write!(f, "DISTINCT ON ({col_names})")
3572            }
3573        }
3574    }
3575}
3576
3577#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3578#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3579#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3580/// MSSQL `TOP` clause options.
3581pub struct Top {
3582    /// SQL semantic equivalent of LIMIT but with same structure as FETCH.
3583    /// MSSQL only.
3584    pub with_ties: bool,
3585    /// Apply `PERCENT` extension.
3586    pub percent: bool,
3587    /// The optional quantity (expression or constant) following `TOP`.
3588    pub quantity: Option<TopQuantity>,
3589}
3590
3591#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3592#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3593#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3594/// Quantity used in a `TOP` clause: either an expression or a constant.
3595pub enum TopQuantity {
3596    /// A parenthesized expression (MSSQL syntax: `TOP (expr)`).
3597    Expr(Expr),
3598    /// An unparenthesized integer constant: `TOP 10`.
3599    Constant(u64),
3600}
3601
3602impl fmt::Display for Top {
3603    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3604        let extension = if self.with_ties { " WITH TIES" } else { "" };
3605        if let Some(ref quantity) = self.quantity {
3606            let percent = if self.percent { " PERCENT" } else { "" };
3607            match quantity {
3608                TopQuantity::Expr(quantity) => write!(f, "TOP ({quantity}){percent}{extension}"),
3609                TopQuantity::Constant(quantity) => {
3610                    write!(f, "TOP {quantity}{percent}{extension}")
3611                }
3612            }
3613        } else {
3614            write!(f, "TOP{extension}")
3615        }
3616    }
3617}
3618
3619#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3620#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3621#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3622/// An explicit `VALUES` clause and its rows.
3623pub struct Values {
3624    /// Was there an explicit `ROW` keyword (MySQL)?
3625    /// <https://dev.mysql.com/doc/refman/8.0/en/values.html>
3626    pub explicit_row: bool,
3627    /// `true` if `VALUE` (singular) keyword was used instead of `VALUES`.
3628    /// <https://dev.mysql.com/doc/refman/9.2/en/insert.html>
3629    pub value_keyword: bool,
3630    /// The list of rows, each row is a list of expressions.
3631    pub rows: Vec<Vec<Expr>>,
3632}
3633
3634impl fmt::Display for Values {
3635    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3636        match self.value_keyword {
3637            true => f.write_str("VALUE")?,
3638            false => f.write_str("VALUES")?,
3639        };
3640        let prefix = if self.explicit_row { "ROW" } else { "" };
3641        let mut delim = "";
3642        for row in &self.rows {
3643            f.write_str(delim)?;
3644            delim = ",";
3645            SpaceOrNewline.fmt(f)?;
3646            Indent(format_args!("{prefix}({})", display_comma_separated(row))).fmt(f)?;
3647        }
3648        Ok(())
3649    }
3650}
3651
3652#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3653#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3654#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3655/// `SELECT INTO` clause options.
3656pub struct SelectInto {
3657    /// `TEMPORARY` modifier.
3658    pub temporary: bool,
3659    /// `UNLOGGED` modifier.
3660    pub unlogged: bool,
3661    /// `TABLE` keyword present.
3662    pub table: bool,
3663    /// Name of the target table.
3664    pub name: ObjectName,
3665}
3666
3667impl fmt::Display for SelectInto {
3668    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3669        let temporary = if self.temporary { " TEMPORARY" } else { "" };
3670        let unlogged = if self.unlogged { " UNLOGGED" } else { "" };
3671        let table = if self.table { " TABLE" } else { "" };
3672
3673        write!(f, "INTO{}{}{} {}", temporary, unlogged, table, self.name)
3674    }
3675}
3676
3677/// ClickHouse supports GROUP BY WITH modifiers(includes ROLLUP|CUBE|TOTALS).
3678/// e.g. GROUP BY year WITH ROLLUP WITH TOTALS
3679///
3680/// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#rollup-modifier>
3681#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3682#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3683#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3684/// Modifiers used with `GROUP BY` such as `WITH ROLLUP` or `WITH CUBE`.
3685pub enum GroupByWithModifier {
3686    /// `WITH ROLLUP` modifier.
3687    Rollup,
3688    /// `WITH CUBE` modifier.
3689    Cube,
3690    /// `WITH TOTALS` modifier (ClickHouse).
3691    Totals,
3692    /// Hive supports GROUPING SETS syntax, e.g. `GROUP BY GROUPING SETS(...)`.
3693    ///
3694    /// [Hive]: <https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=30151323#EnhancedAggregation,Cube,GroupingandRollup-GROUPINGSETSclause>
3695    GroupingSets(Expr),
3696}
3697
3698impl fmt::Display for GroupByWithModifier {
3699    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3700        match self {
3701            GroupByWithModifier::Rollup => write!(f, "WITH ROLLUP"),
3702            GroupByWithModifier::Cube => write!(f, "WITH CUBE"),
3703            GroupByWithModifier::Totals => write!(f, "WITH TOTALS"),
3704            GroupByWithModifier::GroupingSets(expr) => {
3705                write!(f, "{expr}")
3706            }
3707        }
3708    }
3709}
3710
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/// Represents the two syntactic forms that `GROUP BY` can take, including
3715/// `GROUP BY ALL` with optional modifiers and ordinary `GROUP BY <exprs>`.
3716pub enum GroupByExpr {
3717    /// ALL syntax of [Snowflake], [DuckDB] and [ClickHouse].
3718    ///
3719    /// [Snowflake]: <https://docs.snowflake.com/en/sql-reference/constructs/group-by#label-group-by-all-columns>
3720    /// [DuckDB]:  <https://duckdb.org/docs/sql/query_syntax/groupby.html>
3721    /// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#group-by-all>
3722    ///
3723    /// ClickHouse also supports WITH modifiers after GROUP BY ALL and expressions.
3724    ///
3725    /// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#rollup-modifier>
3726    All(Vec<GroupByWithModifier>),
3727    /// `GROUP BY <expressions>` with optional modifiers.
3728    Expressions(Vec<Expr>, Vec<GroupByWithModifier>),
3729}
3730
3731impl fmt::Display for GroupByExpr {
3732    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3733        match self {
3734            GroupByExpr::All(modifiers) => {
3735                write!(f, "GROUP BY ALL")?;
3736                if !modifiers.is_empty() {
3737                    write!(f, " {}", display_separated(modifiers, " "))?;
3738                }
3739                Ok(())
3740            }
3741            GroupByExpr::Expressions(col_names, modifiers) => {
3742                f.write_str("GROUP BY")?;
3743                SpaceOrNewline.fmt(f)?;
3744                Indent(display_comma_separated(col_names)).fmt(f)?;
3745                if !modifiers.is_empty() {
3746                    write!(f, " {}", display_separated(modifiers, " "))?;
3747                }
3748                Ok(())
3749            }
3750        }
3751    }
3752}
3753
3754/// `FORMAT` identifier or `FORMAT NULL` clause, specific to ClickHouse.
3755///
3756/// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/format>
3757#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3758#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3759#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3760pub enum FormatClause {
3761    /// The format identifier.
3762    Identifier(Ident),
3763    /// `FORMAT NULL` clause.
3764    Null,
3765}
3766
3767impl fmt::Display for FormatClause {
3768    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3769        match self {
3770            FormatClause::Identifier(ident) => write!(f, "FORMAT {ident}"),
3771            FormatClause::Null => write!(f, "FORMAT NULL"),
3772        }
3773    }
3774}
3775
3776/// FORMAT identifier in input context, specific to ClickHouse.
3777///
3778/// [ClickHouse]: <https://clickhouse.com/docs/en/interfaces/formats>
3779#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3780#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3781#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3782pub struct InputFormatClause {
3783    /// The format identifier.
3784    pub ident: Ident,
3785    /// Optional format parameters.
3786    pub values: Vec<Expr>,
3787}
3788
3789impl fmt::Display for InputFormatClause {
3790    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3791        write!(f, "FORMAT {}", self.ident)?;
3792
3793        if !self.values.is_empty() {
3794            write!(f, " {}", display_comma_separated(self.values.as_slice()))?;
3795        }
3796
3797        Ok(())
3798    }
3799}
3800
3801/// `FOR XML` or `FOR JSON` clause (MSSQL): formats the output of a query as XML or JSON.
3802#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3803#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3804#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3805pub enum ForClause {
3806    /// `FOR BROWSE` clause.
3807    Browse,
3808    /// `FOR JSON ...` clause and its options.
3809    Json {
3810        /// JSON mode (`AUTO` or `PATH`).
3811        for_json: ForJson,
3812        /// Optional `ROOT('...')` parameter.
3813        root: Option<String>,
3814        /// `INCLUDE_NULL_VALUES` flag.
3815        include_null_values: bool,
3816        /// `WITHOUT_ARRAY_WRAPPER` flag.
3817        without_array_wrapper: bool,
3818    },
3819    /// `FOR XML ...` clause and its options.
3820    Xml {
3821        /// XML mode (`RAW`, `AUTO`, `EXPLICIT`, `PATH`).
3822        for_xml: ForXml,
3823        /// `ELEMENTS` flag.
3824        elements: bool,
3825        /// `BINARY BASE64` flag.
3826        binary_base64: bool,
3827        /// Optional `ROOT('...')` parameter.
3828        root: Option<String>,
3829        /// `TYPE` flag.
3830        r#type: bool,
3831    },
3832}
3833
3834impl fmt::Display for ForClause {
3835    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3836        match self {
3837            ForClause::Browse => write!(f, "FOR BROWSE"),
3838            ForClause::Json {
3839                for_json,
3840                root,
3841                include_null_values,
3842                without_array_wrapper,
3843            } => {
3844                write!(f, "FOR JSON ")?;
3845                write!(f, "{for_json}")?;
3846                if let Some(root) = root {
3847                    write!(f, ", ROOT('{root}')")?;
3848                }
3849                if *include_null_values {
3850                    write!(f, ", INCLUDE_NULL_VALUES")?;
3851                }
3852                if *without_array_wrapper {
3853                    write!(f, ", WITHOUT_ARRAY_WRAPPER")?;
3854                }
3855                Ok(())
3856            }
3857            ForClause::Xml {
3858                for_xml,
3859                elements,
3860                binary_base64,
3861                root,
3862                r#type,
3863            } => {
3864                write!(f, "FOR XML ")?;
3865                write!(f, "{for_xml}")?;
3866                if *binary_base64 {
3867                    write!(f, ", BINARY BASE64")?;
3868                }
3869                if *r#type {
3870                    write!(f, ", TYPE")?;
3871                }
3872                if let Some(root) = root {
3873                    write!(f, ", ROOT('{root}')")?;
3874                }
3875                if *elements {
3876                    write!(f, ", ELEMENTS")?;
3877                }
3878                Ok(())
3879            }
3880        }
3881    }
3882}
3883
3884#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3885#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3886#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3887/// Modes for `FOR XML` clause.
3888pub enum ForXml {
3889    /// `RAW` mode with optional root name: `RAW('root')`.
3890    Raw(Option<String>),
3891    /// `AUTO` mode.
3892    Auto,
3893    /// `EXPLICIT` mode.
3894    Explicit,
3895    /// `PATH` mode with optional root: `PATH('root')`.
3896    Path(Option<String>),
3897}
3898
3899impl fmt::Display for ForXml {
3900    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3901        match self {
3902            ForXml::Raw(root) => {
3903                write!(f, "RAW")?;
3904                if let Some(root) = root {
3905                    write!(f, "('{root}')")?;
3906                }
3907                Ok(())
3908            }
3909            ForXml::Auto => write!(f, "AUTO"),
3910            ForXml::Explicit => write!(f, "EXPLICIT"),
3911            ForXml::Path(root) => {
3912                write!(f, "PATH")?;
3913                if let Some(root) = root {
3914                    write!(f, "('{root}')")?;
3915                }
3916                Ok(())
3917            }
3918        }
3919    }
3920}
3921
3922#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3923#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3924#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3925/// Modes for `FOR JSON` clause.
3926pub enum ForJson {
3927    /// `AUTO` mode.
3928    Auto,
3929    /// `PATH` mode.
3930    Path,
3931}
3932
3933impl fmt::Display for ForJson {
3934    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3935        match self {
3936            ForJson::Auto => write!(f, "AUTO"),
3937            ForJson::Path => write!(f, "PATH"),
3938        }
3939    }
3940}
3941
3942/// A single column definition in MySQL's `JSON_TABLE` table valued function.
3943///
3944/// See
3945/// - [MySQL's JSON_TABLE documentation](https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html#function_json-table)
3946/// - [Oracle's JSON_TABLE documentation](https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/JSON_TABLE.html)
3947/// - [MariaDB's JSON_TABLE documentation](https://mariadb.com/kb/en/json_table/)
3948///
3949/// ```sql
3950/// SELECT *
3951/// FROM JSON_TABLE(
3952///     '["a", "b"]',
3953///     '$[*]' COLUMNS (
3954///         name FOR ORDINALITY,
3955///         value VARCHAR(20) PATH '$',
3956///         NESTED PATH '$[*]' COLUMNS (
3957///             value VARCHAR(20) PATH '$'
3958///         )
3959///     )
3960/// ) AS jt;
3961/// ```
3962#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3963#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3964#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3965pub enum JsonTableColumn {
3966    /// A named column with a JSON path
3967    Named(JsonTableNamedColumn),
3968    /// The FOR ORDINALITY column, which is a special column that returns the index of the current row in a JSON array.
3969    ForOrdinality(Ident),
3970    /// A set of nested columns, which extracts data from a nested JSON array.
3971    Nested(JsonTableNestedColumn),
3972}
3973
3974impl fmt::Display for JsonTableColumn {
3975    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3976        match self {
3977            JsonTableColumn::Named(json_table_named_column) => {
3978                write!(f, "{json_table_named_column}")
3979            }
3980            JsonTableColumn::ForOrdinality(ident) => write!(f, "{ident} FOR ORDINALITY"),
3981            JsonTableColumn::Nested(json_table_nested_column) => {
3982                write!(f, "{json_table_nested_column}")
3983            }
3984        }
3985    }
3986}
3987
3988/// A nested column in a JSON_TABLE column list
3989///
3990/// See <https://mariadb.com/kb/en/json_table/#nested-paths>
3991#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3992#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3993#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3994/// A nested column in a `JSON_TABLE` column list.
3995pub struct JsonTableNestedColumn {
3996    /// JSON path expression (must be a literal `Value`).
3997    pub path: ValueWithSpan,
3998    /// Columns extracted from the matched nested array.
3999    pub columns: Vec<JsonTableColumn>,
4000}
4001
4002impl fmt::Display for JsonTableNestedColumn {
4003    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4004        write!(
4005            f,
4006            "NESTED PATH {} COLUMNS ({})",
4007            self.path,
4008            display_comma_separated(&self.columns)
4009        )
4010    }
4011}
4012
4013/// A single column definition in MySQL's `JSON_TABLE` table valued function.
4014///
4015/// See <https://mariadb.com/kb/en/json_table/#path-columns>
4016///
4017/// ```sql
4018///         value VARCHAR(20) PATH '$'
4019/// ```
4020#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4021#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4022#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4023pub struct JsonTableNamedColumn {
4024    /// The name of the column to be extracted.
4025    pub name: Ident,
4026    /// The type of the column to be extracted.
4027    pub r#type: DataType,
4028    /// The path to the column to be extracted. Must be a literal string.
4029    pub path: ValueWithSpan,
4030    /// true if the column is a boolean set to true if the given path exists
4031    pub exists: bool,
4032    /// The empty handling clause of the column
4033    pub on_empty: Option<JsonTableColumnErrorHandling>,
4034    /// The error handling clause of the column
4035    pub on_error: Option<JsonTableColumnErrorHandling>,
4036}
4037
4038impl fmt::Display for JsonTableNamedColumn {
4039    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4040        write!(
4041            f,
4042            "{} {}{} PATH {}",
4043            self.name,
4044            self.r#type,
4045            if self.exists { " EXISTS" } else { "" },
4046            self.path
4047        )?;
4048        if let Some(on_empty) = &self.on_empty {
4049            write!(f, " {on_empty} ON EMPTY")?;
4050        }
4051        if let Some(on_error) = &self.on_error {
4052            write!(f, " {on_error} ON ERROR")?;
4053        }
4054        Ok(())
4055    }
4056}
4057
4058/// Stores the error handling clause of a `JSON_TABLE` table valued function:
4059/// {NULL | DEFAULT json_string | ERROR} ON {ERROR | EMPTY }
4060#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4061#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4062#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4063/// Error/empty-value handling for `JSON_TABLE` columns.
4064pub enum JsonTableColumnErrorHandling {
4065    /// `NULL` — return NULL when the path does not match.
4066    Null,
4067    /// `DEFAULT <value>` — use the provided `Value` as a default.
4068    Default(ValueWithSpan),
4069    /// `ERROR` — raise an error.
4070    Error,
4071}
4072
4073impl fmt::Display for JsonTableColumnErrorHandling {
4074    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4075        match self {
4076            JsonTableColumnErrorHandling::Null => write!(f, "NULL"),
4077            JsonTableColumnErrorHandling::Default(json_string) => {
4078                write!(f, "DEFAULT {json_string}")
4079            }
4080            JsonTableColumnErrorHandling::Error => write!(f, "ERROR"),
4081        }
4082    }
4083}
4084
4085/// A single column definition in MSSQL's `OPENJSON WITH` clause.
4086///
4087/// ```sql
4088/// colName type [ column_path ] [ AS JSON ]
4089/// ```
4090///
4091/// Reference: <https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16#syntax>
4092#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4093#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4094#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4095pub struct OpenJsonTableColumn {
4096    /// The name of the column to be extracted.
4097    pub name: Ident,
4098    /// The type of the column to be extracted.
4099    pub r#type: DataType,
4100    /// The path to the column to be extracted. Must be a literal string.
4101    pub path: Option<String>,
4102    /// The `AS JSON` option.
4103    pub as_json: bool,
4104}
4105
4106impl fmt::Display for OpenJsonTableColumn {
4107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4108        write!(f, "{} {}", self.name, self.r#type)?;
4109        if let Some(path) = &self.path {
4110            write!(f, " '{}'", value::escape_single_quote_string(path))?;
4111        }
4112        if self.as_json {
4113            write!(f, " AS JSON")?;
4114        }
4115        Ok(())
4116    }
4117}
4118
4119/// BigQuery supports ValueTables which have 2 modes:
4120/// `SELECT [ALL | DISTINCT] AS STRUCT`
4121/// `SELECT [ALL | DISTINCT] AS VALUE`
4122///
4123/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#value_tables>
4124/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_list>
4125#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4126#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4127#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4128/// Mode of BigQuery value tables, e.g. `AS STRUCT` or `AS VALUE`.
4129pub enum ValueTableMode {
4130    /// `AS STRUCT`
4131    AsStruct,
4132    /// `AS VALUE`
4133    AsValue,
4134    /// `DISTINCT AS STRUCT`
4135    DistinctAsStruct,
4136    /// `DISTINCT AS VALUE`
4137    DistinctAsValue,
4138}
4139
4140impl fmt::Display for ValueTableMode {
4141    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4142        match self {
4143            ValueTableMode::AsStruct => write!(f, "AS STRUCT"),
4144            ValueTableMode::AsValue => write!(f, "AS VALUE"),
4145            ValueTableMode::DistinctAsStruct => write!(f, "DISTINCT AS STRUCT"),
4146            ValueTableMode::DistinctAsValue => write!(f, "DISTINCT AS VALUE"),
4147        }
4148    }
4149}
4150
4151/// The `FROM` clause of an `UPDATE TABLE` statement
4152#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4153#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4154#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4155pub enum UpdateTableFromKind {
4156    /// Update Statement where the 'FROM' clause is before the 'SET' keyword (Supported by Snowflake)
4157    /// For Example: `UPDATE FROM t1 SET t1.name='aaa'`
4158    BeforeSet(Vec<TableWithJoins>),
4159    /// Update Statement where the 'FROM' clause is after the 'SET' keyword (Which is the standard way)
4160    /// For Example: `UPDATE SET t1.name='aaa' FROM t1`
4161    AfterSet(Vec<TableWithJoins>),
4162}
4163
4164/// Defines the options for an XmlTable column: Named or ForOrdinality
4165#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4166#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4167#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4168pub enum XmlTableColumnOption {
4169    /// A named column with a type, optional path, and default value.
4170    NamedInfo {
4171        /// The type of the column to be extracted.
4172        r#type: DataType,
4173        /// The path to the column to be extracted. If None, defaults to the column name.
4174        path: Option<Expr>,
4175        /// Default value if path does not match
4176        default: Option<Expr>,
4177        /// Whether the column is nullable (NULL=true, NOT NULL=false)
4178        nullable: bool,
4179    },
4180    /// The FOR ORDINALITY marker
4181    ForOrdinality,
4182}
4183
4184/// A single column definition in XMLTABLE
4185///
4186/// ```sql
4187/// COLUMNS
4188///     id int PATH '@id',
4189///     ordinality FOR ORDINALITY,
4190///     "COUNTRY_NAME" text,
4191///     country_id text PATH 'COUNTRY_ID',
4192///     size_sq_km float PATH 'SIZE[@unit = "sq_km"]',
4193///     size_other text PATH 'concat(SIZE[@unit!="sq_km"], " ", SIZE[@unit!="sq_km"]/@unit)',
4194///     premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified'
4195/// ```
4196#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4197#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4198#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4199pub struct XmlTableColumn {
4200    /// The name of the column.
4201    pub name: Ident,
4202    /// Column options: type/path/default or FOR ORDINALITY
4203    pub option: XmlTableColumnOption,
4204}
4205
4206impl fmt::Display for XmlTableColumn {
4207    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4208        write!(f, "{}", self.name)?;
4209        match &self.option {
4210            XmlTableColumnOption::NamedInfo {
4211                r#type,
4212                path,
4213                default,
4214                nullable,
4215            } => {
4216                write!(f, " {type}")?;
4217                if let Some(p) = path {
4218                    write!(f, " PATH {p}")?;
4219                }
4220                if let Some(d) = default {
4221                    write!(f, " DEFAULT {d}")?;
4222                }
4223                if !*nullable {
4224                    write!(f, " NOT NULL")?;
4225                }
4226                Ok(())
4227            }
4228            XmlTableColumnOption::ForOrdinality => {
4229                write!(f, " FOR ORDINALITY")
4230            }
4231        }
4232    }
4233}
4234
4235/// Argument passed in the XMLTABLE PASSING clause
4236#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4237#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4238#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4239/// Argument passed in the `XMLTABLE PASSING` clause.
4240pub struct XmlPassingArgument {
4241    /// Expression to pass to the XML table.
4242    pub expr: Expr,
4243    /// Optional alias for the argument.
4244    pub alias: Option<Ident>,
4245    /// `true` if `BY VALUE` is specified for the argument.
4246    pub by_value: bool,
4247}
4248
4249impl fmt::Display for XmlPassingArgument {
4250    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4251        if self.by_value {
4252            write!(f, "BY VALUE ")?;
4253        }
4254        write!(f, "{}", self.expr)?;
4255        if let Some(alias) = &self.alias {
4256            write!(f, " AS {alias}")?;
4257        }
4258        Ok(())
4259    }
4260}
4261
4262/// The PASSING clause for XMLTABLE
4263#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4264#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4265#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4266/// The PASSING clause for `XMLTABLE`.
4267pub struct XmlPassingClause {
4268    /// The list of passed arguments.
4269    pub arguments: Vec<XmlPassingArgument>,
4270}
4271
4272impl fmt::Display for XmlPassingClause {
4273    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4274        if !self.arguments.is_empty() {
4275            write!(f, " PASSING {}", display_comma_separated(&self.arguments))?;
4276        }
4277        Ok(())
4278    }
4279}
4280
4281/// Represents a single XML namespace definition in the XMLNAMESPACES clause.
4282///
4283/// `namespace_uri AS namespace_name`
4284#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4285#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4286#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4287pub struct XmlNamespaceDefinition {
4288    /// The namespace URI (a text expression).
4289    pub uri: Expr,
4290    /// The alias for the namespace (a simple identifier).
4291    pub name: Ident,
4292}
4293
4294impl fmt::Display for XmlNamespaceDefinition {
4295    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4296        write!(f, "{} AS {}", self.uri, self.name)
4297    }
4298}