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