Skip to main content

risingwave_sqlparser/ast/
query.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5//     http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13use crate::ast::*;
14
15/// The most complete variant of a `SELECT` query expression, optionally
16/// including `WITH`, `UNION` / other set operations, and `ORDER BY`.
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub struct Query {
19    /// WITH (common table expressions, or CTEs)
20    pub with: Option<With>,
21    /// SELECT or UNION / EXCEPT / INTERSECT
22    pub body: SetExpr,
23    /// ORDER BY
24    pub order_by: Vec<OrderByExpr>,
25    /// `LIMIT { <N> | ALL }`
26    pub limit: Option<Expr>,
27    /// `OFFSET <N> [ { ROW | ROWS } ]`
28    ///
29    /// `ROW` and `ROWS` are noise words that don't influence the effect of the clause.
30    /// They are provided for ANSI compatibility.
31    pub offset: Option<String>,
32    /// `FETCH { FIRST | NEXT } <N> [ PERCENT ] { ROW | ROWS } | { ONLY | WITH TIES }`
33    ///
34    /// `ROW` and `ROWS` as well as `FIRST` and `NEXT` are noise words that don't influence the
35    /// effect of the clause. They are provided for ANSI compatibility.
36    pub fetch: Option<Fetch>,
37}
38
39impl Query {
40    /// Simple `VALUES` without other clauses.
41    pub fn as_simple_values(&self) -> Option<&Values> {
42        match &self {
43            Query {
44                with: None,
45                body: SetExpr::Values(values),
46                order_by,
47                limit: None,
48                offset: None,
49                fetch: None,
50            } if order_by.is_empty() => Some(values),
51            _ => None,
52        }
53    }
54
55    /// `SELECT <expr>` without other clauses.
56    pub fn as_single_select_item(&self) -> Option<&Expr> {
57        match &self {
58            Query {
59                with: None,
60                body: SetExpr::Select(select),
61                order_by,
62                limit: None,
63                offset: None,
64                fetch: None,
65            } if order_by.is_empty() => match select.as_ref() {
66                Select {
67                    distinct: Distinct::All,
68                    projection,
69                    from,
70                    lateral_views,
71                    selection: None,
72                    group_by,
73                    having: None,
74                    window,
75                } if projection.len() == 1
76                    && from.is_empty()
77                    && lateral_views.is_empty()
78                    && group_by.is_empty()
79                    && window.is_empty() =>
80                {
81                    match &projection[0] {
82                        SelectItem::UnnamedExpr(expr) => Some(expr),
83                        SelectItem::ExprWithAlias { expr, .. } => Some(expr),
84                        _ => None,
85                    }
86                }
87                _ => None,
88            },
89            _ => None,
90        }
91    }
92}
93
94impl fmt::Display for Query {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        if let Some(ref with) = self.with {
97            write!(f, "{} ", with)?;
98        }
99        write!(f, "{}", self.body)?;
100        if !self.order_by.is_empty() {
101            write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
102        }
103        if let Some(ref limit) = self.limit {
104            write!(f, " LIMIT {}", limit)?;
105        }
106        if let Some(ref offset) = self.offset {
107            write!(f, " OFFSET {}", offset)?;
108        }
109        if let Some(ref fetch) = self.fetch {
110            write!(f, " {}", fetch)?;
111        }
112        Ok(())
113    }
114}
115
116/// A node in a tree, representing a "query body" expression, roughly:
117/// `SELECT ... [ {UNION|EXCEPT|INTERSECT} SELECT ...]`
118
119#[derive(Debug, Clone, PartialEq, Eq, Hash)]
120pub enum SetExpr {
121    /// Restricted SELECT .. FROM .. HAVING (no ORDER BY or set operations)
122    Select(Box<Select>),
123    /// Parenthesized SELECT subquery, which may include more set operations
124    /// in its body and an optional ORDER BY / LIMIT.
125    Query(Box<Query>),
126    /// UNION/EXCEPT/INTERSECT of two queries
127    SetOperation {
128        op: SetOperator,
129        all: bool,
130        corresponding: Corresponding,
131        left: Box<SetExpr>,
132        right: Box<SetExpr>,
133    },
134    Values(Values),
135}
136
137impl fmt::Display for SetExpr {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        match self {
140            SetExpr::Select(s) => write!(f, "{}", s),
141            SetExpr::Query(q) => write!(f, "({})", q),
142            SetExpr::Values(v) => write!(f, "{}", v),
143            SetExpr::SetOperation {
144                left,
145                right,
146                op,
147                all,
148                corresponding,
149            } => {
150                let all_str = if *all { " ALL" } else { "" };
151                write!(f, "{} {}{}{} {}", left, op, all_str, corresponding, right)
152            }
153        }
154    }
155}
156
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
158pub enum SetOperator {
159    Union,
160    Except,
161    Intersect,
162}
163
164impl fmt::Display for SetOperator {
165    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166        f.write_str(match self {
167            SetOperator::Union => "UNION",
168            SetOperator::Except => "EXCEPT",
169            SetOperator::Intersect => "INTERSECT",
170        })
171    }
172}
173
174/// `CORRESPONDING [ BY <left paren> <corresponding column list> <right paren> ]`
175#[derive(Debug, Clone, PartialEq, Eq, Hash)]
176pub struct Corresponding {
177    pub corresponding: bool,
178    pub column_list: Option<Vec<Ident>>,
179}
180
181impl Corresponding {
182    pub fn with_column_list(column_list: Option<Vec<Ident>>) -> Self {
183        Self {
184            corresponding: true,
185            column_list,
186        }
187    }
188
189    pub fn none() -> Self {
190        Self {
191            corresponding: false,
192            column_list: None,
193        }
194    }
195
196    pub fn is_corresponding(&self) -> bool {
197        self.corresponding
198    }
199
200    pub fn column_list(&self) -> Option<&[Ident]> {
201        self.column_list.as_deref()
202    }
203}
204
205impl fmt::Display for Corresponding {
206    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207        if self.corresponding {
208            write!(f, " CORRESPONDING")?;
209            if let Some(column_list) = &self.column_list {
210                write!(f, " BY ({})", display_comma_separated(column_list))?;
211            }
212        }
213        Ok(())
214    }
215}
216
217/// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may
218/// appear either as the only body item of an `SQLQuery`, or as an operand
219/// to a set operation like `UNION`.
220#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
221pub struct Select {
222    pub distinct: Distinct,
223    /// projection expressions
224    pub projection: Vec<SelectItem>,
225    /// FROM
226    pub from: Vec<TableWithJoins>,
227    /// LATERAL VIEWs
228    pub lateral_views: Vec<LateralView>,
229    /// WHERE
230    pub selection: Option<Expr>,
231    /// GROUP BY
232    pub group_by: Vec<Expr>,
233    /// HAVING
234    pub having: Option<Expr>,
235    /// WINDOW
236    pub window: Vec<NamedWindow>,
237}
238
239impl fmt::Display for Select {
240    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        write!(f, "SELECT{}", self.distinct)?;
242        write!(f, " {}", display_comma_separated(&self.projection))?;
243        if !self.from.is_empty() {
244            write!(f, " FROM {}", display_comma_separated(&self.from))?;
245        }
246        if !self.lateral_views.is_empty() {
247            for lv in &self.lateral_views {
248                write!(f, "{}", lv)?;
249            }
250        }
251        if let Some(ref selection) = self.selection {
252            write!(f, " WHERE {}", selection)?;
253        }
254        if !self.group_by.is_empty() {
255            write!(f, " GROUP BY {}", display_comma_separated(&self.group_by))?;
256        }
257        if let Some(ref having) = self.having {
258            write!(f, " HAVING {}", having)?;
259        }
260        if !self.window.is_empty() {
261            write!(f, " WINDOW {}", display_comma_separated(&self.window))?;
262        }
263        Ok(())
264    }
265}
266
267/// An `ALL`, `DISTINCT` or `DISTINCT ON (expr, ...)` after `SELECT`.
268#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
269#[expect(clippy::enum_variant_names)]
270pub enum Distinct {
271    /// An optional parameter that returns all matching rows.
272    #[default]
273    All,
274    /// A parameter that removes duplicates from the result-set.
275    Distinct,
276    /// An optional parameter that eliminates duplicate data based on the expressions.
277    DistinctOn(Vec<Expr>),
278}
279
280impl Distinct {
281    pub const fn is_all(&self) -> bool {
282        matches!(self, Distinct::All)
283    }
284
285    pub const fn is_distinct(&self) -> bool {
286        matches!(self, Distinct::Distinct)
287    }
288}
289
290impl fmt::Display for Distinct {
291    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292        match self {
293            Distinct::All => write!(f, ""),
294            Distinct::Distinct => write!(f, " DISTINCT"),
295            Distinct::DistinctOn(exprs) => {
296                write!(f, " DISTINCT ON ({})", display_comma_separated(exprs))
297            }
298        }
299    }
300}
301
302/// A hive LATERAL VIEW with potential column aliases
303#[derive(Debug, Clone, PartialEq, Eq, Hash)]
304pub struct LateralView {
305    /// LATERAL VIEW
306    pub lateral_view: Expr,
307    /// LATERAL VIEW table name
308    pub lateral_view_name: ObjectName,
309    /// LATERAL VIEW optional column aliases
310    pub lateral_col_alias: Vec<Ident>,
311    /// LATERAL VIEW OUTER
312    pub outer: bool,
313}
314
315impl fmt::Display for LateralView {
316    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317        write!(
318            f,
319            " LATERAL VIEW{outer} {} {}",
320            self.lateral_view,
321            self.lateral_view_name,
322            outer = if self.outer { " OUTER" } else { "" }
323        )?;
324        if !self.lateral_col_alias.is_empty() {
325            write!(
326                f,
327                " AS {}",
328                display_comma_separated(&self.lateral_col_alias)
329            )?;
330        }
331        Ok(())
332    }
333}
334
335#[derive(Debug, Clone, PartialEq, Eq, Hash)]
336pub struct With {
337    pub recursive: bool,
338    pub cte_tables: Vec<Cte>,
339}
340
341impl fmt::Display for With {
342    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343        write!(
344            f,
345            "WITH {}{}",
346            if self.recursive { "RECURSIVE " } else { "" },
347            display_comma_separated(&self.cte_tables)
348        )
349    }
350}
351
352/// A single CTE (used after `WITH`): `alias [(col1, col2, ...)] AS ( query )`
353///
354/// The names in the column list before `AS`, when specified, replace the names
355/// of the columns returned by the query. The parser does not validate that the
356/// number of columns in the query matches the number of columns in the query.
357#[derive(Debug, Clone, PartialEq, Eq, Hash)]
358pub struct Cte {
359    pub alias: TableAlias,
360    pub cte_inner: CteInner,
361}
362
363impl fmt::Display for Cte {
364    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365        match &self.cte_inner {
366            CteInner::Query(query) => write!(f, "{} AS ({})", self.alias, query)?,
367            CteInner::ChangeLog(obj_name) => {
368                write!(f, "{} AS changelog from {}", self.alias, obj_name)?
369            }
370        }
371        Ok(())
372    }
373}
374
375#[derive(Debug, Clone, PartialEq, Eq, Hash)]
376pub enum CteInner {
377    Query(Box<Query>),
378    ChangeLog(ObjectName),
379}
380
381/// One item of the comma-separated list following `SELECT`
382#[derive(Debug, Clone, PartialEq, Eq, Hash)]
383pub enum SelectItem {
384    /// Any expression, not followed by `[ AS ] alias`
385    UnnamedExpr(Expr),
386    /// Expr is an arbitrary expression, returning either a table or a column.
387    /// Idents are the prefix of `*`, which are consecutive field accesses.
388    /// e.g. `(table.v1).*` or `(table).v1.*`
389    ExprQualifiedWildcard(Expr, Vec<Ident>),
390    /// An expression, followed by `[ AS ] alias`
391    ExprWithAlias { expr: Expr, alias: Ident },
392    /// `alias.*` or even `schema.table.*` followed by optional except
393    QualifiedWildcard(ObjectName, Option<Vec<Expr>>),
394    /// An unqualified `*`, or `* except (exprs)`
395    Wildcard(Option<Vec<Expr>>),
396}
397
398impl fmt::Display for SelectItem {
399    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400        match &self {
401            SelectItem::UnnamedExpr(expr) => write!(f, "{}", expr),
402            SelectItem::ExprWithAlias { expr, alias } => write!(f, "{} AS {}", expr, alias),
403            SelectItem::ExprQualifiedWildcard(expr, prefix) => write!(
404                f,
405                "({}){}.*",
406                expr,
407                prefix
408                    .iter()
409                    .format_with("", |i, f| f(&format_args!(".{i}")))
410            ),
411            SelectItem::QualifiedWildcard(prefix, except) => match except {
412                Some(cols) => write!(
413                    f,
414                    "{}.* EXCEPT ({})",
415                    prefix,
416                    cols.iter()
417                        .map(|v| v.to_string())
418                        .collect::<Vec<String>>()
419                        .as_slice()
420                        .join(", ")
421                ),
422                None => write!(f, "{}.*", prefix),
423            },
424            SelectItem::Wildcard(except) => match except {
425                Some(cols) => write!(
426                    f,
427                    "* EXCEPT ({})",
428                    cols.iter()
429                        .map(|v| v.to_string())
430                        .collect::<Vec<String>>()
431                        .as_slice()
432                        .join(", ")
433                ),
434                None => write!(f, "*"),
435            },
436        }
437    }
438}
439
440#[derive(Debug, Clone, PartialEq, Eq, Hash)]
441pub struct TableWithJoins {
442    pub relation: TableFactor,
443    pub joins: Vec<Join>,
444}
445
446impl fmt::Display for TableWithJoins {
447    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448        write!(f, "{}", self.relation)?;
449        for join in &self.joins {
450            write!(f, "{}", join)?;
451        }
452        Ok(())
453    }
454}
455
456/// A table name or a parenthesized subquery with an optional alias
457#[derive(Debug, Clone, PartialEq, Eq, Hash)]
458pub enum TableFactor {
459    Table {
460        name: ObjectName,
461        alias: Option<TableAlias>,
462        as_of: Option<AsOf>,
463    },
464    Derived {
465        lateral: bool,
466        subquery: Box<Query>,
467        alias: Option<TableAlias>,
468    },
469    /// `<expr>(args)[ AS <alias> ]`
470    ///
471    /// Note that scalar functions can also be used in this way.
472    TableFunction {
473        name: ObjectName,
474        alias: Option<TableAlias>,
475        args: Vec<FunctionArg>,
476        with_ordinality: bool,
477    },
478    /// Represents a parenthesized table factor. The SQL spec only allows a
479    /// join expression (`(foo <JOIN> bar [ <JOIN> baz ... ])`) to be nested,
480    /// possibly several times.
481    ///
482    /// The parser may also accept non-standard nesting of bare tables for some
483    /// dialects, but the information about such nesting is stripped from AST.
484    NestedJoin(Box<TableWithJoins>),
485    /// `<table> MATCH_RECOGNIZE (...)`: SQL:2016 row pattern recognition applied
486    /// to an input table factor.
487    MatchRecognize {
488        /// The input the pattern is matched over.
489        table: Box<TableFactor>,
490        /// `PARTITION BY <expr>, ...` — empty when omitted.
491        partition_by: Vec<Expr>,
492        /// `ORDER BY <expr> [ASC|DESC], ...` — empty when omitted.
493        order_by: Vec<OrderByExpr>,
494        /// `MEASURES <expr> AS <alias>, ...` — empty when omitted.
495        measures: Vec<Measure>,
496        /// `ONE ROW PER MATCH` | `ALL ROWS PER MATCH` — `None` when omitted.
497        rows_per_match: Option<RowsPerMatch>,
498        /// `AFTER MATCH SKIP ...` — `None` when omitted.
499        after_match_skip: Option<AfterMatchSkip>,
500        /// `PATTERN ( <pattern> )` — required.
501        pattern: MatchRecognizePattern,
502        /// `WITHIN <interval>` — bounds a match's time span; `None` when omitted.
503        within: Option<Expr>,
504        /// `SUBSET <name> = (<vars>), ...` — empty when omitted.
505        subsets: Vec<SubsetDefinition>,
506        /// `DEFINE <symbol> AS <condition>, ...` — required.
507        symbols: Vec<SymbolDefinition>,
508        /// Optional alias for the row-pattern output.
509        alias: Option<TableAlias>,
510    },
511}
512
513/// A single `MEASURES` item: `<expr> AS <alias>`.
514#[derive(Debug, Clone, PartialEq, Eq, Hash)]
515pub struct Measure {
516    pub expr: Expr,
517    pub alias: Ident,
518}
519
520impl fmt::Display for Measure {
521    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522        write!(f, "{} AS {}", self.expr, self.alias)
523    }
524}
525
526/// The output mode of a `MATCH_RECOGNIZE` clause.
527#[derive(Debug, Clone, PartialEq, Eq, Hash)]
528pub enum RowsPerMatch {
529    /// `ONE ROW PER MATCH`
530    OneRow,
531    /// `ALL ROWS PER MATCH`
532    AllRows,
533}
534
535impl fmt::Display for RowsPerMatch {
536    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
537        match self {
538            RowsPerMatch::OneRow => write!(f, "ONE ROW PER MATCH"),
539            RowsPerMatch::AllRows => write!(f, "ALL ROWS PER MATCH"),
540        }
541    }
542}
543
544/// The `AFTER MATCH SKIP` strategy of a `MATCH_RECOGNIZE` clause.
545#[derive(Debug, Clone, PartialEq, Eq, Hash)]
546pub enum AfterMatchSkip {
547    /// `AFTER MATCH SKIP PAST LAST ROW`
548    PastLastRow,
549    /// `AFTER MATCH SKIP TO NEXT ROW`
550    ToNextRow,
551    /// `AFTER MATCH SKIP TO FIRST <symbol>`
552    ToFirst(Ident),
553    /// `AFTER MATCH SKIP TO LAST <symbol>`
554    ToLast(Ident),
555}
556
557impl fmt::Display for AfterMatchSkip {
558    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
559        write!(f, "AFTER MATCH SKIP ")?;
560        match self {
561            AfterMatchSkip::PastLastRow => write!(f, "PAST LAST ROW"),
562            AfterMatchSkip::ToNextRow => write!(f, "TO NEXT ROW"),
563            AfterMatchSkip::ToFirst(symbol) => write!(f, "TO FIRST {}", symbol),
564            AfterMatchSkip::ToLast(symbol) => write!(f, "TO LAST {}", symbol),
565        }
566    }
567}
568
569/// A single `DEFINE` item: `<symbol> AS <condition>`.
570#[derive(Debug, Clone, PartialEq, Eq, Hash)]
571pub struct SymbolDefinition {
572    pub symbol: Ident,
573    pub definition: Expr,
574}
575
576impl fmt::Display for SymbolDefinition {
577    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
578        write!(f, "{} AS {}", self.symbol, self.definition)
579    }
580}
581
582/// A single `SUBSET` item: `<name> = (<pattern variable>, ...)` — a union variable.
583#[derive(Debug, Clone, PartialEq, Eq, Hash)]
584pub struct SubsetDefinition {
585    pub name: Ident,
586    pub members: Vec<Ident>,
587}
588
589impl fmt::Display for SubsetDefinition {
590    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
591        write!(
592            f,
593            "{} = ({})",
594            self.name,
595            display_comma_separated(&self.members)
596        )
597    }
598}
599
600/// A row-pattern variable, or one of the row-pattern anchors.
601#[derive(Debug, Clone, PartialEq, Eq, Hash)]
602pub enum MatchRecognizeSymbol {
603    /// A named pattern variable, defined (or referenced) in `DEFINE`.
604    Named(Ident),
605    /// The start anchor `^`.
606    Start,
607    /// The end anchor `$`.
608    End,
609}
610
611impl fmt::Display for MatchRecognizeSymbol {
612    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613        match self {
614            MatchRecognizeSymbol::Named(symbol) => write!(f, "{}", symbol),
615            MatchRecognizeSymbol::Start => write!(f, "^"),
616            MatchRecognizeSymbol::End => write!(f, "$"),
617        }
618    }
619}
620
621/// A row-pattern expression inside `PATTERN ( ... )`.
622#[derive(Debug, Clone, PartialEq, Eq, Hash)]
623pub enum MatchRecognizePattern {
624    /// A single symbol, e.g. `A`, `^`, `$`.
625    Symbol(MatchRecognizeSymbol),
626    /// An exclusion `{- <pattern> -}`.
627    Exclude(MatchRecognizeSymbol),
628    /// `PERMUTE(<symbol>, ...)`.
629    Permute(Vec<MatchRecognizeSymbol>),
630    /// Concatenation, e.g. `A B C`.
631    Concat(Vec<MatchRecognizePattern>),
632    /// A parenthesized sub-pattern `( <pattern> )`.
633    Group(Box<MatchRecognizePattern>),
634    /// Alternation, e.g. `A | B | C`.
635    Alternation(Vec<MatchRecognizePattern>),
636    /// A quantified sub-pattern, e.g. `A*`, `A+`, `A?`, `A{1,3}`. The bool is `reluctant` (a trailing
637    /// `?`, e.g. `A*?`, which prefers the fewest matches).
638    Repetition(Box<MatchRecognizePattern>, RepetitionQuantifier, bool),
639}
640
641impl fmt::Display for MatchRecognizePattern {
642    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
643        use MatchRecognizePattern::*;
644        match self {
645            Symbol(symbol) => write!(f, "{}", symbol),
646            Exclude(symbol) => write!(f, "{{- {} -}}", symbol),
647            Permute(symbols) => write!(f, "PERMUTE({})", display_comma_separated(symbols)),
648            Concat(patterns) => write!(f, "{}", display_separated(patterns, " ")),
649            Group(pattern) => write!(f, "({})", pattern),
650            Alternation(patterns) => write!(f, "{}", display_separated(patterns, " | ")),
651            Repetition(pattern, quantifier, reluctant) => {
652                write!(
653                    f,
654                    "{}{}{}",
655                    pattern,
656                    quantifier,
657                    if *reluctant { "?" } else { "" }
658                )
659            }
660        }
661    }
662}
663
664/// A quantifier applied to a row-pattern, e.g. `*`, `+`, `?`, `{n,m}`.
665#[derive(Debug, Clone, PartialEq, Eq, Hash)]
666pub enum RepetitionQuantifier {
667    /// `*`
668    ZeroOrMore,
669    /// `+`
670    OneOrMore,
671    /// `?`
672    AtMostOne,
673    /// `{n}`
674    Exactly(u32),
675    /// `{n,}`
676    AtLeast(u32),
677    /// `{,m}`
678    AtMost(u32),
679    /// `{n,m}`
680    Range(u32, u32),
681}
682
683impl fmt::Display for RepetitionQuantifier {
684    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
685        use RepetitionQuantifier::*;
686        match self {
687            ZeroOrMore => write!(f, "*"),
688            OneOrMore => write!(f, "+"),
689            AtMostOne => write!(f, "?"),
690            Exactly(n) => write!(f, "{{{}}}", n),
691            AtLeast(n) => write!(f, "{{{},}}", n),
692            AtMost(m) => write!(f, "{{,{}}}", m),
693            Range(n, m) => write!(f, "{{{},{}}}", n, m),
694        }
695    }
696}
697
698impl fmt::Display for TableFactor {
699    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
700        match self {
701            TableFactor::Table { name, alias, as_of } => {
702                write!(f, "{}", name)?;
703                if let Some(as_of) = as_of {
704                    write!(f, "{}", as_of)?
705                }
706                if let Some(alias) = alias {
707                    write!(f, " AS {}", alias)?;
708                }
709                Ok(())
710            }
711            TableFactor::Derived {
712                lateral,
713                subquery,
714                alias,
715            } => {
716                if *lateral {
717                    write!(f, "LATERAL ")?;
718                }
719                write!(f, "({})", subquery)?;
720                if let Some(alias) = alias {
721                    write!(f, " AS {}", alias)?;
722                }
723                Ok(())
724            }
725            TableFactor::TableFunction {
726                name,
727                alias,
728                args,
729                with_ordinality,
730            } => {
731                write!(f, "{}({})", name, display_comma_separated(args))?;
732                if *with_ordinality {
733                    write!(f, " WITH ORDINALITY")?;
734                }
735                if let Some(alias) = alias {
736                    write!(f, " AS {}", alias)?;
737                }
738                Ok(())
739            }
740            TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference),
741            TableFactor::MatchRecognize {
742                table,
743                partition_by,
744                order_by,
745                measures,
746                rows_per_match,
747                after_match_skip,
748                pattern,
749                within,
750                subsets,
751                symbols,
752                alias,
753            } => {
754                write!(f, "{} MATCH_RECOGNIZE (", table)?;
755                if !partition_by.is_empty() {
756                    write!(f, "PARTITION BY {} ", display_comma_separated(partition_by))?;
757                }
758                if !order_by.is_empty() {
759                    write!(f, "ORDER BY {} ", display_comma_separated(order_by))?;
760                }
761                if !measures.is_empty() {
762                    write!(f, "MEASURES {} ", display_comma_separated(measures))?;
763                }
764                if let Some(rows_per_match) = rows_per_match {
765                    write!(f, "{} ", rows_per_match)?;
766                }
767                if let Some(after_match_skip) = after_match_skip {
768                    write!(f, "{} ", after_match_skip)?;
769                }
770                write!(f, "PATTERN ({}) ", pattern)?;
771                if let Some(within) = within {
772                    write!(f, "WITHIN {} ", within)?;
773                }
774                if !subsets.is_empty() {
775                    write!(f, "SUBSET {} ", display_comma_separated(subsets))?;
776                }
777                write!(f, "DEFINE {})", display_comma_separated(symbols))?;
778                if let Some(alias) = alias {
779                    write!(f, " AS {}", alias)?;
780                }
781                Ok(())
782            }
783        }
784    }
785}
786
787#[derive(Debug, Clone, PartialEq, Eq, Hash)]
788pub struct TableAlias {
789    pub name: Ident,
790    pub columns: Vec<Ident>,
791}
792
793impl fmt::Display for TableAlias {
794    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
795        write!(f, "{}", self.name)?;
796        if !self.columns.is_empty() {
797            write!(f, " ({})", display_comma_separated(&self.columns))?;
798        }
799        Ok(())
800    }
801}
802
803#[derive(Debug, Clone, PartialEq, Eq, Hash)]
804pub struct Join {
805    pub relation: TableFactor,
806    pub join_operator: JoinOperator,
807}
808
809impl fmt::Display for Join {
810    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
811        fn prefix(constraint: &JoinConstraint) -> &'static str {
812            match constraint {
813                JoinConstraint::Natural => "NATURAL ",
814                _ => "",
815            }
816        }
817        fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
818            struct Suffix<'a>(&'a JoinConstraint);
819            impl fmt::Display for Suffix<'_> {
820                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
821                    match self.0 {
822                        JoinConstraint::On(expr) => write!(f, " ON {}", expr),
823                        JoinConstraint::Using(attrs) => {
824                            write!(f, " USING({})", display_comma_separated(attrs))
825                        }
826                        _ => Ok(()),
827                    }
828                }
829            }
830            Suffix(constraint)
831        }
832        let broadcast = if matches!(
833            self.relation,
834            TableFactor::Table {
835                as_of: Some(AsOf::ProcessTimeBroadcast),
836                ..
837            }
838        ) {
839            "BROADCAST "
840        } else {
841            ""
842        };
843        match &self.join_operator {
844            JoinOperator::Inner(constraint) => write!(
845                f,
846                " {}{}JOIN {}{}",
847                prefix(constraint),
848                broadcast,
849                self.relation,
850                suffix(constraint)
851            ),
852            JoinOperator::LeftOuter(constraint) => write!(
853                f,
854                " {}{}LEFT JOIN {}{}",
855                prefix(constraint),
856                broadcast,
857                self.relation,
858                suffix(constraint)
859            ),
860            JoinOperator::RightOuter(constraint) => write!(
861                f,
862                " {}RIGHT JOIN {}{}",
863                prefix(constraint),
864                self.relation,
865                suffix(constraint)
866            ),
867            JoinOperator::FullOuter(constraint) => write!(
868                f,
869                " {}FULL JOIN {}{}",
870                prefix(constraint),
871                self.relation,
872                suffix(constraint)
873            ),
874            JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
875            JoinOperator::AsOfInner(constraint) => write!(
876                f,
877                " {}ASOF JOIN {}{}",
878                prefix(constraint),
879                self.relation,
880                suffix(constraint)
881            ),
882            JoinOperator::AsOfLeft(constraint) => write!(
883                f,
884                " {}ASOF LEFT JOIN {}{}",
885                prefix(constraint),
886                self.relation,
887                suffix(constraint)
888            ),
889        }
890    }
891}
892
893#[derive(Debug, Clone, PartialEq, Eq, Hash)]
894pub enum JoinOperator {
895    Inner(JoinConstraint),
896    LeftOuter(JoinConstraint),
897    RightOuter(JoinConstraint),
898    FullOuter(JoinConstraint),
899    CrossJoin,
900    AsOfInner(JoinConstraint),
901    AsOfLeft(JoinConstraint),
902}
903
904#[derive(Debug, Clone, PartialEq, Eq, Hash)]
905pub enum JoinConstraint {
906    On(Expr),
907    Using(Vec<Ident>),
908    Natural,
909    None,
910}
911
912/// An `ORDER BY` expression
913#[derive(Debug, Clone, PartialEq, Eq, Hash)]
914pub struct OrderByExpr {
915    pub expr: Expr,
916    /// Optional `ASC` or `DESC`
917    pub asc: Option<bool>,
918    /// Optional `NULLS FIRST` or `NULLS LAST`
919    pub nulls_first: Option<bool>,
920}
921
922impl fmt::Display for OrderByExpr {
923    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
924        write!(f, "{}", self.expr)?;
925        match self.asc {
926            Some(true) => write!(f, " ASC")?,
927            Some(false) => write!(f, " DESC")?,
928            None => (),
929        }
930        match self.nulls_first {
931            Some(true) => write!(f, " NULLS FIRST")?,
932            Some(false) => write!(f, " NULLS LAST")?,
933            None => (),
934        }
935        Ok(())
936    }
937}
938
939#[derive(Debug, Clone, PartialEq, Eq, Hash)]
940pub struct Fetch {
941    pub with_ties: bool,
942    pub quantity: Option<String>,
943}
944
945impl fmt::Display for Fetch {
946    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
947        let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
948        if let Some(ref quantity) = self.quantity {
949            write!(f, "FETCH FIRST {} ROWS {}", quantity, extension)
950        } else {
951            write!(f, "FETCH FIRST ROWS {}", extension)
952        }
953    }
954}
955
956#[derive(Debug, Clone, PartialEq, Eq, Hash)]
957pub struct Top {
958    /// SQL semantic equivalent of LIMIT but with same structure as FETCH.
959    pub with_ties: bool,
960    pub percent: bool,
961    pub quantity: Option<Expr>,
962}
963
964impl fmt::Display for Top {
965    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
966        let extension = if self.with_ties { " WITH TIES" } else { "" };
967        if let Some(ref quantity) = self.quantity {
968            let percent = if self.percent { " PERCENT" } else { "" };
969            write!(f, "TOP ({}){}{}", quantity, percent, extension)
970        } else {
971            write!(f, "TOP{}", extension)
972        }
973    }
974}
975
976#[derive(Debug, Clone, PartialEq, Eq, Hash)]
977pub struct Values(pub Vec<Vec<Expr>>);
978
979impl fmt::Display for Values {
980    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
981        write!(f, "VALUES ")?;
982        let mut delim = "";
983        for row in &self.0 {
984            write!(f, "{}", delim)?;
985            delim = ", ";
986            write!(f, "({})", display_comma_separated(row))?;
987        }
988        Ok(())
989    }
990}
991
992/// A named window definition in the WINDOW clause
993#[derive(Debug, Clone, PartialEq, Eq, Hash)]
994pub struct NamedWindow {
995    pub name: Ident,
996    pub window_spec: WindowSpec,
997}
998
999impl fmt::Display for NamedWindow {
1000    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1001        write!(f, "{} AS ({})", self.name, self.window_spec)
1002    }
1003}