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