sqlparser/ast/
query.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13#[cfg(not(feature = "std"))]
14use alloc::{boxed::Box, vec::Vec};
15
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19#[cfg(feature = "visitor")]
20use sqlparser_derive::{Visit, VisitMut};
21
22use crate::ast::*;
23
24/// The most complete variant of a `SELECT` query expression, optionally
25/// including `WITH`, `UNION` / other set operations, and `ORDER BY`.
26#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
27#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
28#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
29pub struct Query {
30    /// WITH (common table expressions, or CTEs)
31    pub with: Option<With>,
32    /// SELECT or UNION / EXCEPT / INTERSECT
33    pub body: Box<SetExpr>,
34    /// ORDER BY
35    pub order_by: Vec<OrderByExpr>,
36    /// `LIMIT { <N> | ALL }`
37    pub limit: Option<Expr>,
38
39    /// `LIMIT { <N> } BY { <expr>,<expr>,... } }`
40    pub limit_by: Vec<Expr>,
41
42    /// `OFFSET <N> [ { ROW | ROWS } ]`
43    pub offset: Option<Offset>,
44    /// `FETCH { FIRST | NEXT } <N> [ PERCENT ] { ROW | ROWS } | { ONLY | WITH TIES }`
45    pub fetch: Option<Fetch>,
46    /// `FOR { UPDATE | SHARE } [ OF table_name ] [ SKIP LOCKED | NOWAIT ]`
47    pub locks: Vec<LockClause>,
48}
49
50impl fmt::Display for Query {
51    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52        if let Some(ref with) = self.with {
53            write!(f, "{with} ")?;
54        }
55        write!(f, "{}", self.body)?;
56        if !self.order_by.is_empty() {
57            write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
58        }
59        if let Some(ref limit) = self.limit {
60            write!(f, " LIMIT {limit}")?;
61        }
62        if let Some(ref offset) = self.offset {
63            write!(f, " {offset}")?;
64        }
65        if !self.limit_by.is_empty() {
66            write!(f, " BY {}", display_separated(&self.limit_by, ", "))?;
67        }
68        if let Some(ref fetch) = self.fetch {
69            write!(f, " {fetch}")?;
70        }
71        if !self.locks.is_empty() {
72            write!(f, " {}", display_separated(&self.locks, " "))?;
73        }
74        Ok(())
75    }
76}
77
78/// A node in a tree, representing a "query body" expression, roughly:
79/// `SELECT ... [ {UNION|EXCEPT|INTERSECT} SELECT ...]`
80#[allow(clippy::large_enum_variant)]
81#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
82#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
83#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
84pub enum SetExpr {
85    /// Restricted SELECT .. FROM .. HAVING (no ORDER BY or set operations)
86    Select(Box<Select>),
87    /// Parenthesized SELECT subquery, which may include more set operations
88    /// in its body and an optional ORDER BY / LIMIT.
89    Query(Box<Query>),
90    /// UNION/EXCEPT/INTERSECT of two queries
91    SetOperation {
92        op: SetOperator,
93        set_quantifier: SetQuantifier,
94        left: Box<SetExpr>,
95        right: Box<SetExpr>,
96    },
97    Values(Values),
98    Insert(Statement),
99    Update(Statement),
100    Table(Box<Table>),
101}
102
103impl fmt::Display for SetExpr {
104    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105        match self {
106            SetExpr::Select(s) => write!(f, "{s}"),
107            SetExpr::Query(q) => write!(f, "({q})"),
108            SetExpr::Values(v) => write!(f, "{v}"),
109            SetExpr::Insert(v) => write!(f, "{v}"),
110            SetExpr::Update(v) => write!(f, "{v}"),
111            SetExpr::Table(t) => write!(f, "{t}"),
112            SetExpr::SetOperation {
113                left,
114                right,
115                op,
116                set_quantifier,
117            } => {
118                write!(f, "{left} {op}")?;
119                match set_quantifier {
120                    SetQuantifier::All
121                    | SetQuantifier::Distinct
122                    | SetQuantifier::ByName
123                    | SetQuantifier::AllByName
124                    | SetQuantifier::DistinctByName => write!(f, " {set_quantifier}")?,
125                    SetQuantifier::None => write!(f, "{set_quantifier}")?,
126                }
127                write!(f, " {right}")?;
128                Ok(())
129            }
130        }
131    }
132}
133
134#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
135#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
136#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
137pub enum SetOperator {
138    Union,
139    Except,
140    Intersect,
141}
142
143impl fmt::Display for SetOperator {
144    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145        f.write_str(match self {
146            SetOperator::Union => "UNION",
147            SetOperator::Except => "EXCEPT",
148            SetOperator::Intersect => "INTERSECT",
149        })
150    }
151}
152
153/// A quantifier for [SetOperator].
154// TODO: Restrict parsing specific SetQuantifier in some specific dialects.
155// For example, BigQuery does not support `DISTINCT` for `EXCEPT` and `INTERSECT`
156#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
157#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
158#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
159pub enum SetQuantifier {
160    All,
161    Distinct,
162    ByName,
163    AllByName,
164    DistinctByName,
165    None,
166}
167
168impl fmt::Display for SetQuantifier {
169    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
170        match self {
171            SetQuantifier::All => write!(f, "ALL"),
172            SetQuantifier::Distinct => write!(f, "DISTINCT"),
173            SetQuantifier::ByName => write!(f, "BY NAME"),
174            SetQuantifier::AllByName => write!(f, "ALL BY NAME"),
175            SetQuantifier::DistinctByName => write!(f, "DISTINCT BY NAME"),
176            SetQuantifier::None => write!(f, ""),
177        }
178    }
179}
180
181#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
182#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
183/// A [`TABLE` command]( https://www.postgresql.org/docs/current/sql-select.html#SQL-TABLE)
184#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
185pub struct Table {
186    pub table_name: Option<String>,
187    pub schema_name: Option<String>,
188}
189
190impl fmt::Display for Table {
191    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192        if let Some(ref schema_name) = self.schema_name {
193            write!(
194                f,
195                "TABLE {}.{}",
196                schema_name,
197                self.table_name.as_ref().unwrap(),
198            )?;
199        } else {
200            write!(f, "TABLE {}", self.table_name.as_ref().unwrap(),)?;
201        }
202        Ok(())
203    }
204}
205
206/// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may
207/// appear either as the only body item of a `Query`, or as an operand
208/// to a set operation like `UNION`.
209#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
210#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
211#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
212pub struct Select {
213    pub distinct: Option<Distinct>,
214    /// MSSQL syntax: `TOP (<N>) [ PERCENT ] [ WITH TIES ]`
215    pub top: Option<Top>,
216    /// projection expressions
217    pub projection: Vec<SelectItem>,
218    /// INTO
219    pub into: Option<SelectInto>,
220    /// FROM
221    pub from: Vec<TableWithJoins>,
222    /// LATERAL VIEWs
223    pub lateral_views: Vec<LateralView>,
224    /// WHERE
225    pub selection: Option<Expr>,
226    /// GROUP BY
227    pub group_by: GroupByExpr,
228    /// CLUSTER BY (Hive)
229    pub cluster_by: Vec<Expr>,
230    /// DISTRIBUTE BY (Hive)
231    pub distribute_by: Vec<Expr>,
232    /// SORT BY (Hive)
233    pub sort_by: Vec<Expr>,
234    /// HAVING
235    pub having: Option<Expr>,
236    /// WINDOW AS
237    pub named_window: Vec<NamedWindowDefinition>,
238    /// QUALIFY (Snowflake)
239    pub qualify: Option<Expr>,
240}
241
242impl fmt::Display for Select {
243    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
244        write!(f, "SELECT")?;
245        if let Some(ref distinct) = self.distinct {
246            write!(f, " {distinct}")?;
247        }
248        if let Some(ref top) = self.top {
249            write!(f, " {top}")?;
250        }
251        write!(f, " {}", display_comma_separated(&self.projection))?;
252
253        if let Some(ref into) = self.into {
254            write!(f, " {into}")?;
255        }
256
257        if !self.from.is_empty() {
258            write!(f, " FROM {}", display_comma_separated(&self.from))?;
259        }
260        if !self.lateral_views.is_empty() {
261            for lv in &self.lateral_views {
262                write!(f, "{lv}")?;
263            }
264        }
265        if let Some(ref selection) = self.selection {
266            write!(f, " WHERE {selection}")?;
267        }
268        match &self.group_by {
269            GroupByExpr::All => write!(f, " GROUP BY ALL")?,
270            GroupByExpr::Expressions(exprs) => {
271                if !exprs.is_empty() {
272                    write!(f, " GROUP BY {}", display_comma_separated(exprs))?;
273                }
274            }
275        }
276        if !self.cluster_by.is_empty() {
277            write!(
278                f,
279                " CLUSTER BY {}",
280                display_comma_separated(&self.cluster_by)
281            )?;
282        }
283        if !self.distribute_by.is_empty() {
284            write!(
285                f,
286                " DISTRIBUTE BY {}",
287                display_comma_separated(&self.distribute_by)
288            )?;
289        }
290        if !self.sort_by.is_empty() {
291            write!(f, " SORT BY {}", display_comma_separated(&self.sort_by))?;
292        }
293        if let Some(ref having) = self.having {
294            write!(f, " HAVING {having}")?;
295        }
296        if !self.named_window.is_empty() {
297            write!(f, " WINDOW {}", display_comma_separated(&self.named_window))?;
298        }
299        if let Some(ref qualify) = self.qualify {
300            write!(f, " QUALIFY {qualify}")?;
301        }
302        Ok(())
303    }
304}
305
306/// A hive LATERAL VIEW with potential column aliases
307#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
308#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
309#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
310pub struct LateralView {
311    /// LATERAL VIEW
312    pub lateral_view: Expr,
313    /// LATERAL VIEW table name
314    pub lateral_view_name: ObjectName,
315    /// LATERAL VIEW optional column aliases
316    pub lateral_col_alias: Vec<Ident>,
317    /// LATERAL VIEW OUTER
318    pub outer: bool,
319}
320
321impl fmt::Display for LateralView {
322    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
323        write!(
324            f,
325            " LATERAL VIEW{outer} {} {}",
326            self.lateral_view,
327            self.lateral_view_name,
328            outer = if self.outer { " OUTER" } else { "" }
329        )?;
330        if !self.lateral_col_alias.is_empty() {
331            write!(
332                f,
333                " AS {}",
334                display_comma_separated(&self.lateral_col_alias)
335            )?;
336        }
337        Ok(())
338    }
339}
340
341#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
342#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
343#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
344pub struct NamedWindowDefinition(pub Ident, pub WindowSpec);
345
346impl fmt::Display for NamedWindowDefinition {
347    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
348        write!(f, "{} AS ({})", self.0, self.1)
349    }
350}
351
352#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
353#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
354#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
355pub struct With {
356    pub recursive: bool,
357    pub cte_tables: Vec<Cte>,
358}
359
360impl fmt::Display for With {
361    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
362        write!(
363            f,
364            "WITH {}{}",
365            if self.recursive { "RECURSIVE " } else { "" },
366            display_comma_separated(&self.cte_tables)
367        )
368    }
369}
370
371/// A single CTE (used after `WITH`): `alias [(col1, col2, ...)] AS ( query )`
372/// The names in the column list before `AS`, when specified, replace the names
373/// of the columns returned by the query. The parser does not validate that the
374/// number of columns in the query matches the number of columns in the query.
375#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
376#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
377#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
378pub struct Cte {
379    pub alias: TableAlias,
380    pub query: Box<Query>,
381    pub from: Option<Ident>,
382}
383
384impl fmt::Display for Cte {
385    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
386        write!(f, "{} AS ({})", self.alias, self.query)?;
387        if let Some(ref fr) = self.from {
388            write!(f, " FROM {fr}")?;
389        }
390        Ok(())
391    }
392}
393
394/// One item of the comma-separated list following `SELECT`
395#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
396#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
397#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
398pub enum SelectItem {
399    /// Any expression, not followed by `[ AS ] alias`
400    UnnamedExpr(Expr),
401    /// An expression, followed by `[ AS ] alias`
402    ExprWithAlias { expr: Expr, alias: Ident },
403    /// `alias.*` or even `schema.table.*`
404    QualifiedWildcard(ObjectName, WildcardAdditionalOptions),
405    /// An unqualified `*`
406    Wildcard(WildcardAdditionalOptions),
407}
408
409/// Single aliased identifier
410///
411/// # Syntax
412/// ```plaintext
413/// <ident> AS <alias>
414/// ```
415#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
416#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
417#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
418pub struct IdentWithAlias {
419    pub ident: Ident,
420    pub alias: Ident,
421}
422
423impl fmt::Display for IdentWithAlias {
424    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
425        write!(f, "{} AS {}", self.ident, self.alias)
426    }
427}
428
429/// Additional options for wildcards, e.g. Snowflake `EXCLUDE`/`RENAME` and Bigquery `EXCEPT`.
430#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
431#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
432#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
433pub struct WildcardAdditionalOptions {
434    /// `[EXCLUDE...]`.
435    pub opt_exclude: Option<ExcludeSelectItem>,
436    /// `[EXCEPT...]`.
437    ///  Clickhouse syntax: <https://clickhouse.com/docs/en/sql-reference/statements/select#except>
438    pub opt_except: Option<ExceptSelectItem>,
439    /// `[RENAME ...]`.
440    pub opt_rename: Option<RenameSelectItem>,
441    /// `[REPLACE]`
442    ///  BigQuery syntax: <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_replace>
443    ///  Clickhouse syntax: <https://clickhouse.com/docs/en/sql-reference/statements/select#replace>
444    pub opt_replace: Option<ReplaceSelectItem>,
445}
446
447impl fmt::Display for WildcardAdditionalOptions {
448    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
449        if let Some(exclude) = &self.opt_exclude {
450            write!(f, " {exclude}")?;
451        }
452        if let Some(except) = &self.opt_except {
453            write!(f, " {except}")?;
454        }
455        if let Some(rename) = &self.opt_rename {
456            write!(f, " {rename}")?;
457        }
458        if let Some(replace) = &self.opt_replace {
459            write!(f, " {replace}")?;
460        }
461        Ok(())
462    }
463}
464
465/// Snowflake `EXCLUDE` information.
466///
467/// # Syntax
468/// ```plaintext
469/// <col_name>
470/// | (<col_name>, <col_name>, ...)
471/// ```
472#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
473#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
474#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
475pub enum ExcludeSelectItem {
476    /// Single column name without parenthesis.
477    ///
478    /// # Syntax
479    /// ```plaintext
480    /// <col_name>
481    /// ```
482    Single(Ident),
483    /// Multiple column names inside parenthesis.
484    /// # Syntax
485    /// ```plaintext
486    /// (<col_name>, <col_name>, ...)
487    /// ```
488    Multiple(Vec<Ident>),
489}
490
491impl fmt::Display for ExcludeSelectItem {
492    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
493        write!(f, "EXCLUDE")?;
494        match self {
495            Self::Single(column) => {
496                write!(f, " {column}")?;
497            }
498            Self::Multiple(columns) => {
499                write!(f, " ({})", display_comma_separated(columns))?;
500            }
501        }
502        Ok(())
503    }
504}
505
506/// Snowflake `RENAME` information.
507///
508/// # Syntax
509/// ```plaintext
510/// <col_name> AS <col_alias>
511/// | (<col_name> AS <col_alias>, <col_name> AS <col_alias>, ...)
512/// ```
513#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
514#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
515#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
516pub enum RenameSelectItem {
517    /// Single column name with alias without parenthesis.
518    ///
519    /// # Syntax
520    /// ```plaintext
521    /// <col_name> AS <col_alias>
522    /// ```
523    Single(IdentWithAlias),
524    /// Multiple column names with aliases inside parenthesis.
525    /// # Syntax
526    /// ```plaintext
527    /// (<col_name> AS <col_alias>, <col_name> AS <col_alias>, ...)
528    /// ```
529    Multiple(Vec<IdentWithAlias>),
530}
531
532impl fmt::Display for RenameSelectItem {
533    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
534        write!(f, "RENAME")?;
535        match self {
536            Self::Single(column) => {
537                write!(f, " {column}")?;
538            }
539            Self::Multiple(columns) => {
540                write!(f, " ({})", display_comma_separated(columns))?;
541            }
542        }
543        Ok(())
544    }
545}
546
547/// Bigquery `EXCEPT` information, with at least one column.
548///
549/// # Syntax
550/// ```plaintext
551/// EXCEPT (<col_name> [, ...])
552/// ```
553#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
554#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
555#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
556pub struct ExceptSelectItem {
557    /// First guaranteed column.
558    pub first_element: Ident,
559    /// Additional columns. This list can be empty.
560    pub additional_elements: Vec<Ident>,
561}
562
563impl fmt::Display for ExceptSelectItem {
564    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
565        write!(f, "EXCEPT ")?;
566        if self.additional_elements.is_empty() {
567            write!(f, "({})", self.first_element)?;
568        } else {
569            write!(
570                f,
571                "({}, {})",
572                self.first_element,
573                display_comma_separated(&self.additional_elements)
574            )?;
575        }
576        Ok(())
577    }
578}
579
580/// Bigquery `REPLACE` information.
581///
582/// # Syntax
583/// ```plaintext
584/// REPLACE (<new_expr> [AS] <col_name>)
585/// REPLACE (<col_name> [AS] <col_alias>, <col_name> [AS] <col_alias>, ...)
586/// ```
587#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
588#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
589#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
590pub struct ReplaceSelectItem {
591    pub items: Vec<Box<ReplaceSelectElement>>,
592}
593
594impl fmt::Display for ReplaceSelectItem {
595    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
596        write!(f, "REPLACE")?;
597        write!(f, " ({})", display_comma_separated(&self.items))?;
598        Ok(())
599    }
600}
601
602/// # Syntax
603/// ```plaintext
604/// <expr> [AS] <column_name>
605/// ```
606#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
607#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
608#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
609pub struct ReplaceSelectElement {
610    pub expr: Expr,
611    pub column_name: Ident,
612    pub as_keyword: bool,
613}
614
615impl fmt::Display for ReplaceSelectElement {
616    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
617        if self.as_keyword {
618            write!(f, "{} AS {}", self.expr, self.column_name)
619        } else {
620            write!(f, "{} {}", self.expr, self.column_name)
621        }
622    }
623}
624
625impl fmt::Display for SelectItem {
626    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
627        match &self {
628            SelectItem::UnnamedExpr(expr) => write!(f, "{expr}"),
629            SelectItem::ExprWithAlias { expr, alias } => write!(f, "{expr} AS {alias}"),
630            SelectItem::QualifiedWildcard(prefix, additional_options) => {
631                write!(f, "{prefix}.*")?;
632                write!(f, "{additional_options}")?;
633                Ok(())
634            }
635            SelectItem::Wildcard(additional_options) => {
636                write!(f, "*")?;
637                write!(f, "{additional_options}")?;
638                Ok(())
639            }
640        }
641    }
642}
643
644#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
645#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
646#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
647pub struct TableWithJoins {
648    pub relation: TableFactor,
649    pub joins: Vec<Join>,
650}
651
652impl fmt::Display for TableWithJoins {
653    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
654        write!(f, "{}", self.relation)?;
655        for join in &self.joins {
656            write!(f, "{join}")?;
657        }
658        Ok(())
659    }
660}
661
662/// A table name or a parenthesized subquery with an optional alias
663#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
664#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
665#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
666#[cfg_attr(feature = "visitor", visit(with = "visit_table_factor"))]
667pub enum TableFactor {
668    Table {
669        #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
670        name: ObjectName,
671        alias: Option<TableAlias>,
672        /// Arguments of a table-valued function, as supported by Postgres
673        /// and MSSQL. Note that deprecated MSSQL `FROM foo (NOLOCK)` syntax
674        /// will also be parsed as `args`.
675        ///
676        /// This field's value is `Some(v)`, where `v` is a (possibly empty)
677        /// vector of arguments, in the case of a table-valued function call,
678        /// whereas it's `None` in the case of a regular table name.
679        args: Option<Vec<FunctionArg>>,
680        /// MSSQL-specific `WITH (...)` hints such as NOLOCK.
681        with_hints: Vec<Expr>,
682        /// Optional version qualifier to facilitate table time-travel, as
683        /// supported by BigQuery and MSSQL.
684        version: Option<TableVersion>,
685        /// [Partition selection](https://dev.mysql.com/doc/refman/8.0/en/partitioning-selection.html), supported by MySQL.
686        partitions: Vec<Ident>,
687    },
688    Derived {
689        lateral: bool,
690        subquery: Box<Query>,
691        alias: Option<TableAlias>,
692    },
693    /// `TABLE(<expr>)[ AS <alias> ]`
694    TableFunction {
695        expr: Expr,
696        alias: Option<TableAlias>,
697    },
698    /// `e.g. LATERAL FLATTEN(<args>)[ AS <alias> ]`
699    Function {
700        lateral: bool,
701        name: ObjectName,
702        args: Vec<FunctionArg>,
703        alias: Option<TableAlias>,
704    },
705    /// ```sql
706    /// SELECT * FROM UNNEST ([10,20,30]) as numbers WITH OFFSET;
707    /// +---------+--------+
708    /// | numbers | offset |
709    /// +---------+--------+
710    /// | 10      | 0      |
711    /// | 20      | 1      |
712    /// | 30      | 2      |
713    /// +---------+--------+
714    /// ```
715    UNNEST {
716        alias: Option<TableAlias>,
717        array_exprs: Vec<Expr>,
718        with_offset: bool,
719        with_offset_alias: Option<Ident>,
720    },
721    /// Represents a parenthesized table factor. The SQL spec only allows a
722    /// join expression (`(foo <JOIN> bar [ <JOIN> baz ... ])`) to be nested,
723    /// possibly several times.
724    ///
725    /// The parser may also accept non-standard nesting of bare tables for some
726    /// dialects, but the information about such nesting is stripped from AST.
727    NestedJoin {
728        table_with_joins: Box<TableWithJoins>,
729        alias: Option<TableAlias>,
730    },
731    /// Represents PIVOT operation on a table.
732    /// For example `FROM monthly_sales PIVOT(sum(amount) FOR MONTH IN ('JAN', 'FEB'))`
733    /// See <https://docs.snowflake.com/en/sql-reference/constructs/pivot>
734    Pivot {
735        #[cfg_attr(feature = "visitor", visit(with = "visit_table_factor"))]
736        table: Box<TableFactor>,
737        aggregate_function: Expr, // Function expression
738        value_column: Vec<Ident>,
739        pivot_values: Vec<Value>,
740        alias: Option<TableAlias>,
741    },
742    /// An UNPIVOT operation on a table.
743    ///
744    /// Syntax:
745    /// ```sql
746    /// table UNPIVOT(value FOR name IN (column1, [ column2, ... ])) [ alias ]
747    /// ```
748    ///
749    /// See <https://docs.snowflake.com/en/sql-reference/constructs/unpivot>.
750    Unpivot {
751        #[cfg_attr(feature = "visitor", visit(with = "visit_table_factor"))]
752        table: Box<TableFactor>,
753        value: Ident,
754        name: Ident,
755        columns: Vec<Ident>,
756        alias: Option<TableAlias>,
757    },
758}
759
760impl fmt::Display for TableFactor {
761    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
762        match self {
763            TableFactor::Table {
764                name,
765                alias,
766                args,
767                with_hints,
768                version,
769                partitions,
770            } => {
771                write!(f, "{name}")?;
772                if !partitions.is_empty() {
773                    write!(f, "PARTITION ({})", display_comma_separated(partitions))?;
774                }
775                if let Some(args) = args {
776                    write!(f, "({})", display_comma_separated(args))?;
777                }
778                if let Some(alias) = alias {
779                    write!(f, " AS {alias}")?;
780                }
781                if !with_hints.is_empty() {
782                    write!(f, " WITH ({})", display_comma_separated(with_hints))?;
783                }
784                if let Some(version) = version {
785                    write!(f, "{version}")?;
786                }
787                Ok(())
788            }
789            TableFactor::Derived {
790                lateral,
791                subquery,
792                alias,
793            } => {
794                if *lateral {
795                    write!(f, "LATERAL ")?;
796                }
797                write!(f, "({subquery})")?;
798                if let Some(alias) = alias {
799                    write!(f, " AS {alias}")?;
800                }
801                Ok(())
802            }
803            TableFactor::Function {
804                lateral,
805                name,
806                args,
807                alias,
808            } => {
809                if *lateral {
810                    write!(f, "LATERAL ")?;
811                }
812                write!(f, "{name}")?;
813                write!(f, "({})", display_comma_separated(args))?;
814                if let Some(alias) = alias {
815                    write!(f, " AS {alias}")?;
816                }
817                Ok(())
818            }
819            TableFactor::TableFunction { expr, alias } => {
820                write!(f, "TABLE({expr})")?;
821                if let Some(alias) = alias {
822                    write!(f, " AS {alias}")?;
823                }
824                Ok(())
825            }
826            TableFactor::UNNEST {
827                alias,
828                array_exprs,
829                with_offset,
830                with_offset_alias,
831            } => {
832                write!(f, "UNNEST({})", display_comma_separated(array_exprs))?;
833
834                if let Some(alias) = alias {
835                    write!(f, " AS {alias}")?;
836                }
837                if *with_offset {
838                    write!(f, " WITH OFFSET")?;
839                }
840                if let Some(alias) = with_offset_alias {
841                    write!(f, " AS {alias}")?;
842                }
843                Ok(())
844            }
845            TableFactor::NestedJoin {
846                table_with_joins,
847                alias,
848            } => {
849                write!(f, "({table_with_joins})")?;
850                if let Some(alias) = alias {
851                    write!(f, " AS {alias}")?;
852                }
853                Ok(())
854            }
855            TableFactor::Pivot {
856                table,
857                aggregate_function,
858                value_column,
859                pivot_values,
860                alias,
861            } => {
862                write!(
863                    f,
864                    "{} PIVOT({} FOR {} IN ({}))",
865                    table,
866                    aggregate_function,
867                    Expr::CompoundIdentifier(value_column.to_vec()),
868                    display_comma_separated(pivot_values)
869                )?;
870                if alias.is_some() {
871                    write!(f, " AS {}", alias.as_ref().unwrap())?;
872                }
873                Ok(())
874            }
875            TableFactor::Unpivot {
876                table,
877                value,
878                name,
879                columns,
880                alias,
881            } => {
882                write!(
883                    f,
884                    "{} UNPIVOT({} FOR {} IN ({}))",
885                    table,
886                    value,
887                    name,
888                    display_comma_separated(columns)
889                )?;
890                if alias.is_some() {
891                    write!(f, " AS {}", alias.as_ref().unwrap())?;
892                }
893                Ok(())
894            }
895        }
896    }
897}
898
899#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
900#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
901#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
902pub struct TableAlias {
903    pub name: Ident,
904    pub columns: Vec<Ident>,
905}
906
907impl fmt::Display for TableAlias {
908    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
909        write!(f, "{}", self.name)?;
910        if !self.columns.is_empty() {
911            write!(f, " ({})", display_comma_separated(&self.columns))?;
912        }
913        Ok(())
914    }
915}
916
917#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
918#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
919#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
920pub enum TableVersion {
921    ForSystemTimeAsOf(Expr),
922}
923
924impl Display for TableVersion {
925    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
926        match self {
927            TableVersion::ForSystemTimeAsOf(e) => write!(f, " FOR SYSTEM_TIME AS OF {e}")?,
928        }
929        Ok(())
930    }
931}
932
933#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
934#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
935#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
936pub struct Join {
937    pub relation: TableFactor,
938    pub join_operator: JoinOperator,
939}
940
941impl fmt::Display for Join {
942    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
943        fn prefix(constraint: &JoinConstraint) -> &'static str {
944            match constraint {
945                JoinConstraint::Natural => "NATURAL ",
946                _ => "",
947            }
948        }
949        fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
950            struct Suffix<'a>(&'a JoinConstraint);
951            impl<'a> fmt::Display for Suffix<'a> {
952                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
953                    match self.0 {
954                        JoinConstraint::On(expr) => write!(f, " ON {expr}"),
955                        JoinConstraint::Using(attrs) => {
956                            write!(f, " USING({})", display_comma_separated(attrs))
957                        }
958                        _ => Ok(()),
959                    }
960                }
961            }
962            Suffix(constraint)
963        }
964        match &self.join_operator {
965            JoinOperator::Inner(constraint) => write!(
966                f,
967                " {}JOIN {}{}",
968                prefix(constraint),
969                self.relation,
970                suffix(constraint)
971            ),
972            JoinOperator::LeftOuter(constraint) => write!(
973                f,
974                " {}LEFT JOIN {}{}",
975                prefix(constraint),
976                self.relation,
977                suffix(constraint)
978            ),
979            JoinOperator::RightOuter(constraint) => write!(
980                f,
981                " {}RIGHT JOIN {}{}",
982                prefix(constraint),
983                self.relation,
984                suffix(constraint)
985            ),
986            JoinOperator::FullOuter(constraint) => write!(
987                f,
988                " {}FULL JOIN {}{}",
989                prefix(constraint),
990                self.relation,
991                suffix(constraint)
992            ),
993            JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
994            JoinOperator::LeftSemi(constraint) => write!(
995                f,
996                " {}LEFT SEMI JOIN {}{}",
997                prefix(constraint),
998                self.relation,
999                suffix(constraint)
1000            ),
1001            JoinOperator::RightSemi(constraint) => write!(
1002                f,
1003                " {}RIGHT SEMI JOIN {}{}",
1004                prefix(constraint),
1005                self.relation,
1006                suffix(constraint)
1007            ),
1008            JoinOperator::LeftAnti(constraint) => write!(
1009                f,
1010                " {}LEFT ANTI JOIN {}{}",
1011                prefix(constraint),
1012                self.relation,
1013                suffix(constraint)
1014            ),
1015            JoinOperator::RightAnti(constraint) => write!(
1016                f,
1017                " {}RIGHT ANTI JOIN {}{}",
1018                prefix(constraint),
1019                self.relation,
1020                suffix(constraint)
1021            ),
1022            JoinOperator::CrossApply => write!(f, " CROSS APPLY {}", self.relation),
1023            JoinOperator::OuterApply => write!(f, " OUTER APPLY {}", self.relation),
1024        }
1025    }
1026}
1027
1028#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1029#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1030#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1031pub enum JoinOperator {
1032    Inner(JoinConstraint),
1033    LeftOuter(JoinConstraint),
1034    RightOuter(JoinConstraint),
1035    FullOuter(JoinConstraint),
1036    CrossJoin,
1037    /// LEFT SEMI (non-standard)
1038    LeftSemi(JoinConstraint),
1039    /// RIGHT SEMI (non-standard)
1040    RightSemi(JoinConstraint),
1041    /// LEFT ANTI (non-standard)
1042    LeftAnti(JoinConstraint),
1043    /// RIGHT ANTI (non-standard)
1044    RightAnti(JoinConstraint),
1045    /// CROSS APPLY (non-standard)
1046    CrossApply,
1047    /// OUTER APPLY (non-standard)
1048    OuterApply,
1049}
1050
1051#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1052#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1053#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1054pub enum JoinConstraint {
1055    On(Expr),
1056    Using(Vec<Ident>),
1057    Natural,
1058    None,
1059}
1060
1061/// An `ORDER BY` expression
1062#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1063#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1064#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1065pub struct OrderByExpr {
1066    pub expr: Expr,
1067    /// Optional `ASC` or `DESC`
1068    pub asc: Option<bool>,
1069    /// Optional `NULLS FIRST` or `NULLS LAST`
1070    pub nulls_first: Option<bool>,
1071}
1072
1073impl fmt::Display for OrderByExpr {
1074    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1075        write!(f, "{}", self.expr)?;
1076        match self.asc {
1077            Some(true) => write!(f, " ASC")?,
1078            Some(false) => write!(f, " DESC")?,
1079            None => (),
1080        }
1081        match self.nulls_first {
1082            Some(true) => write!(f, " NULLS FIRST")?,
1083            Some(false) => write!(f, " NULLS LAST")?,
1084            None => (),
1085        }
1086        Ok(())
1087    }
1088}
1089
1090#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1091#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1092#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1093pub struct Offset {
1094    pub value: Expr,
1095    pub rows: OffsetRows,
1096}
1097
1098impl fmt::Display for Offset {
1099    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1100        write!(f, "OFFSET {}{}", self.value, self.rows)
1101    }
1102}
1103
1104/// Stores the keyword after `OFFSET <number>`
1105#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1106#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1107#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1108pub enum OffsetRows {
1109    /// Omitting ROW/ROWS is non-standard MySQL quirk.
1110    None,
1111    Row,
1112    Rows,
1113}
1114
1115impl fmt::Display for OffsetRows {
1116    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1117        match self {
1118            OffsetRows::None => Ok(()),
1119            OffsetRows::Row => write!(f, " ROW"),
1120            OffsetRows::Rows => write!(f, " ROWS"),
1121        }
1122    }
1123}
1124
1125#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1126#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1127#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1128pub struct Fetch {
1129    pub with_ties: bool,
1130    pub percent: bool,
1131    pub quantity: Option<Expr>,
1132}
1133
1134impl fmt::Display for Fetch {
1135    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1136        let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
1137        if let Some(ref quantity) = self.quantity {
1138            let percent = if self.percent { " PERCENT" } else { "" };
1139            write!(f, "FETCH FIRST {quantity}{percent} ROWS {extension}")
1140        } else {
1141            write!(f, "FETCH FIRST ROWS {extension}")
1142        }
1143    }
1144}
1145
1146#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1147#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1148#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1149pub struct LockClause {
1150    pub lock_type: LockType,
1151    pub of: Option<ObjectName>,
1152    pub nonblock: Option<NonBlock>,
1153}
1154
1155impl fmt::Display for LockClause {
1156    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1157        write!(f, "FOR {}", &self.lock_type)?;
1158        if let Some(ref of) = self.of {
1159            write!(f, " OF {of}")?;
1160        }
1161        if let Some(ref nb) = self.nonblock {
1162            write!(f, " {nb}")?;
1163        }
1164        Ok(())
1165    }
1166}
1167
1168#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1169#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1170#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1171pub enum LockType {
1172    Share,
1173    Update,
1174}
1175
1176impl fmt::Display for LockType {
1177    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1178        let select_lock = match self {
1179            LockType::Share => "SHARE",
1180            LockType::Update => "UPDATE",
1181        };
1182        write!(f, "{select_lock}")
1183    }
1184}
1185
1186#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1187#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1188#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1189pub enum NonBlock {
1190    Nowait,
1191    SkipLocked,
1192}
1193
1194impl fmt::Display for NonBlock {
1195    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1196        let nonblock = match self {
1197            NonBlock::Nowait => "NOWAIT",
1198            NonBlock::SkipLocked => "SKIP LOCKED",
1199        };
1200        write!(f, "{nonblock}")
1201    }
1202}
1203
1204#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1205#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1206#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1207pub enum Distinct {
1208    /// DISTINCT
1209    Distinct,
1210
1211    /// DISTINCT ON({column names})
1212    On(Vec<Expr>),
1213}
1214
1215impl fmt::Display for Distinct {
1216    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1217        match self {
1218            Distinct::Distinct => write!(f, "DISTINCT"),
1219            Distinct::On(col_names) => {
1220                let col_names = display_comma_separated(col_names);
1221                write!(f, "DISTINCT ON ({col_names})")
1222            }
1223        }
1224    }
1225}
1226
1227#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1228#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1229#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1230pub struct Top {
1231    /// SQL semantic equivalent of LIMIT but with same structure as FETCH.
1232    pub with_ties: bool,
1233    pub percent: bool,
1234    pub quantity: Option<Expr>,
1235}
1236
1237impl fmt::Display for Top {
1238    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1239        let extension = if self.with_ties { " WITH TIES" } else { "" };
1240        if let Some(ref quantity) = self.quantity {
1241            let percent = if self.percent { " PERCENT" } else { "" };
1242            write!(f, "TOP ({quantity}){percent}{extension}")
1243        } else {
1244            write!(f, "TOP{extension}")
1245        }
1246    }
1247}
1248
1249#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1250#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1251#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1252pub struct Values {
1253    /// Was there an explicit ROWs keyword (MySQL)?
1254    /// <https://dev.mysql.com/doc/refman/8.0/en/values.html>
1255    pub explicit_row: bool,
1256    pub rows: Vec<Vec<Expr>>,
1257}
1258
1259impl fmt::Display for Values {
1260    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1261        write!(f, "VALUES ")?;
1262        let prefix = if self.explicit_row { "ROW" } else { "" };
1263        let mut delim = "";
1264        for row in &self.rows {
1265            write!(f, "{delim}")?;
1266            delim = ", ";
1267            write!(f, "{prefix}({})", display_comma_separated(row))?;
1268        }
1269        Ok(())
1270    }
1271}
1272
1273#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1274#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1275#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1276pub struct SelectInto {
1277    pub temporary: bool,
1278    pub unlogged: bool,
1279    pub table: bool,
1280    pub name: ObjectName,
1281}
1282
1283impl fmt::Display for SelectInto {
1284    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1285        let temporary = if self.temporary { " TEMPORARY" } else { "" };
1286        let unlogged = if self.unlogged { " UNLOGGED" } else { "" };
1287        let table = if self.table { " TABLE" } else { "" };
1288
1289        write!(f, "INTO{}{}{} {}", temporary, unlogged, table, self.name)
1290    }
1291}
1292
1293#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1294#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1295#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1296pub enum GroupByExpr {
1297    /// ALL syntax of [Snowflake], and [DuckDB]
1298    ///
1299    /// [Snowflake]: <https://docs.snowflake.com/en/sql-reference/constructs/group-by#label-group-by-all-columns>
1300    /// [DuckDB]:  <https://duckdb.org/docs/sql/query_syntax/groupby.html>
1301    All,
1302
1303    /// Expressions
1304    Expressions(Vec<Expr>),
1305}
1306
1307impl fmt::Display for GroupByExpr {
1308    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1309        match self {
1310            GroupByExpr::All => write!(f, "GROUP BY ALL"),
1311            GroupByExpr::Expressions(col_names) => {
1312                let col_names = display_comma_separated(col_names);
1313                write!(f, "GROUP BY ({col_names})")
1314            }
1315        }
1316    }
1317}