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