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 { from, key } => {
368                write!(f, "{} AS changelog from {}", self.alias, from)?;
369
370                if let Some(key) = key {
371                    write!(f, " KEY ({})", display_comma_separated(key))?;
372                }
373            }
374        }
375        Ok(())
376    }
377}
378
379#[derive(Debug, Clone, PartialEq, Eq, Hash)]
380pub enum CteInner {
381    Query(Box<Query>),
382    ChangeLog {
383        from: ObjectName,
384        key: Option<Vec<Ident>>,
385    },
386}
387
388/// One item of the comma-separated list following `SELECT`
389#[derive(Debug, Clone, PartialEq, Eq, Hash)]
390pub enum SelectItem {
391    /// Any expression, not followed by `[ AS ] alias`
392    UnnamedExpr(Expr),
393    /// Expr is an arbitrary expression, returning either a table or a column.
394    /// Idents are the prefix of `*`, which are consecutive field accesses.
395    /// e.g. `(table.v1).*` or `(table).v1.*`
396    ExprQualifiedWildcard(Expr, Vec<Ident>),
397    /// An expression, followed by `[ AS ] alias`
398    ExprWithAlias { expr: Expr, alias: Ident },
399    /// `alias.*` or even `schema.table.*` followed by optional except
400    QualifiedWildcard(ObjectName, Option<Vec<Expr>>),
401    /// An unqualified `*`, or `* except (exprs)`
402    Wildcard(Option<Vec<Expr>>),
403}
404
405impl fmt::Display for SelectItem {
406    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
407        match &self {
408            SelectItem::UnnamedExpr(expr) => write!(f, "{}", expr),
409            SelectItem::ExprWithAlias { expr, alias } => write!(f, "{} AS {}", expr, alias),
410            SelectItem::ExprQualifiedWildcard(expr, prefix) => write!(
411                f,
412                "({}){}.*",
413                expr,
414                prefix
415                    .iter()
416                    .format_with("", |i, f| f(&format_args!(".{i}")))
417            ),
418            SelectItem::QualifiedWildcard(prefix, except) => match except {
419                Some(cols) => write!(
420                    f,
421                    "{}.* EXCEPT ({})",
422                    prefix,
423                    cols.iter()
424                        .map(|v| v.to_string())
425                        .collect::<Vec<String>>()
426                        .as_slice()
427                        .join(", ")
428                ),
429                None => write!(f, "{}.*", prefix),
430            },
431            SelectItem::Wildcard(except) => match except {
432                Some(cols) => write!(
433                    f,
434                    "* EXCEPT ({})",
435                    cols.iter()
436                        .map(|v| v.to_string())
437                        .collect::<Vec<String>>()
438                        .as_slice()
439                        .join(", ")
440                ),
441                None => write!(f, "*"),
442            },
443        }
444    }
445}
446
447#[derive(Debug, Clone, PartialEq, Eq, Hash)]
448pub struct TableWithJoins {
449    pub relation: TableFactor,
450    pub joins: Vec<Join>,
451}
452
453impl fmt::Display for TableWithJoins {
454    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455        write!(f, "{}", self.relation)?;
456        for join in &self.joins {
457            write!(f, "{}", join)?;
458        }
459        Ok(())
460    }
461}
462
463/// A table name or a parenthesized subquery with an optional alias
464#[derive(Debug, Clone, PartialEq, Eq, Hash)]
465pub enum TableFactor {
466    Table {
467        name: ObjectName,
468        alias: Option<TableAlias>,
469        as_of: Option<AsOf>,
470    },
471    Derived {
472        lateral: bool,
473        subquery: Box<Query>,
474        alias: Option<TableAlias>,
475    },
476    /// `<expr>(args)[ AS <alias> ]`
477    ///
478    /// Note that scalar functions can also be used in this way.
479    TableFunction {
480        name: ObjectName,
481        alias: Option<TableAlias>,
482        args: Vec<FunctionArg>,
483        with_ordinality: bool,
484    },
485    /// Represents a parenthesized table factor. The SQL spec only allows a
486    /// join expression (`(foo <JOIN> bar [ <JOIN> baz ... ])`) to be nested,
487    /// possibly several times.
488    ///
489    /// The parser may also accept non-standard nesting of bare tables for some
490    /// dialects, but the information about such nesting is stripped from AST.
491    NestedJoin(Box<TableWithJoins>),
492    /// `<table> MATCH_RECOGNIZE (...)`: SQL:2016 row pattern recognition applied
493    /// to an input table factor.
494    MatchRecognize {
495        /// The input the pattern is matched over.
496        table: Box<TableFactor>,
497        /// `PARTITION BY <expr>, ...` — empty when omitted.
498        partition_by: Vec<Expr>,
499        /// `ORDER BY <expr> [ASC|DESC], ...` — empty when omitted.
500        order_by: Vec<OrderByExpr>,
501        /// `MEASURES <expr> AS <alias>, ...` — empty when omitted.
502        measures: Vec<Measure>,
503        /// `ONE ROW PER MATCH` | `ALL ROWS PER MATCH` — `None` when omitted.
504        rows_per_match: Option<RowsPerMatch>,
505        /// `AFTER MATCH SKIP ...` — `None` when omitted.
506        after_match_skip: Option<AfterMatchSkip>,
507        /// `PATTERN ( <pattern> )` — required.
508        pattern: MatchRecognizePattern,
509        /// `WITHIN <interval>` — bounds a match's time span; `None` when omitted.
510        within: Option<Expr>,
511        /// `SUBSET <name> = (<vars>), ...` — empty when omitted.
512        subsets: Vec<SubsetDefinition>,
513        /// `DEFINE <symbol> AS <condition>, ...` — required.
514        symbols: Vec<SymbolDefinition>,
515        /// Optional alias for the row-pattern output.
516        alias: Option<TableAlias>,
517    },
518}
519
520/// A single `MEASURES` item: `<expr> AS <alias>`.
521#[derive(Debug, Clone, PartialEq, Eq, Hash)]
522pub struct Measure {
523    pub expr: Expr,
524    pub alias: Ident,
525}
526
527impl fmt::Display for Measure {
528    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
529        write!(f, "{} AS {}", self.expr, self.alias)
530    }
531}
532
533/// The output mode of a `MATCH_RECOGNIZE` clause.
534#[derive(Debug, Clone, PartialEq, Eq, Hash)]
535pub enum RowsPerMatch {
536    /// `ONE ROW PER MATCH`
537    OneRow,
538    /// `ALL ROWS PER MATCH`
539    AllRows,
540}
541
542impl fmt::Display for RowsPerMatch {
543    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
544        match self {
545            RowsPerMatch::OneRow => write!(f, "ONE ROW PER MATCH"),
546            RowsPerMatch::AllRows => write!(f, "ALL ROWS PER MATCH"),
547        }
548    }
549}
550
551/// The `AFTER MATCH SKIP` strategy of a `MATCH_RECOGNIZE` clause.
552#[derive(Debug, Clone, PartialEq, Eq, Hash)]
553pub enum AfterMatchSkip {
554    /// `AFTER MATCH SKIP PAST LAST ROW`
555    PastLastRow,
556    /// `AFTER MATCH SKIP TO NEXT ROW`
557    ToNextRow,
558    /// `AFTER MATCH SKIP TO FIRST <symbol>`
559    ToFirst(Ident),
560    /// `AFTER MATCH SKIP TO LAST <symbol>`
561    ToLast(Ident),
562}
563
564impl fmt::Display for AfterMatchSkip {
565    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
566        write!(f, "AFTER MATCH SKIP ")?;
567        match self {
568            AfterMatchSkip::PastLastRow => write!(f, "PAST LAST ROW"),
569            AfterMatchSkip::ToNextRow => write!(f, "TO NEXT ROW"),
570            AfterMatchSkip::ToFirst(symbol) => write!(f, "TO FIRST {}", symbol),
571            AfterMatchSkip::ToLast(symbol) => write!(f, "TO LAST {}", symbol),
572        }
573    }
574}
575
576/// A single `DEFINE` item: `<symbol> AS <condition>`.
577#[derive(Debug, Clone, PartialEq, Eq, Hash)]
578pub struct SymbolDefinition {
579    pub symbol: Ident,
580    pub definition: Expr,
581}
582
583impl fmt::Display for SymbolDefinition {
584    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
585        write!(f, "{} AS {}", self.symbol, self.definition)
586    }
587}
588
589/// A single `SUBSET` item: `<name> = (<pattern variable>, ...)` — a union variable.
590#[derive(Debug, Clone, PartialEq, Eq, Hash)]
591pub struct SubsetDefinition {
592    pub name: Ident,
593    pub members: Vec<Ident>,
594}
595
596impl fmt::Display for SubsetDefinition {
597    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
598        write!(
599            f,
600            "{} = ({})",
601            self.name,
602            display_comma_separated(&self.members)
603        )
604    }
605}
606
607/// A row-pattern variable, or one of the row-pattern anchors.
608#[derive(Debug, Clone, PartialEq, Eq, Hash)]
609pub enum MatchRecognizeSymbol {
610    /// A named pattern variable, defined (or referenced) in `DEFINE`.
611    Named(Ident),
612    /// The start anchor `^`.
613    Start,
614    /// The end anchor `$`.
615    End,
616}
617
618impl fmt::Display for MatchRecognizeSymbol {
619    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
620        match self {
621            MatchRecognizeSymbol::Named(symbol) => write!(f, "{}", symbol),
622            MatchRecognizeSymbol::Start => write!(f, "^"),
623            MatchRecognizeSymbol::End => write!(f, "$"),
624        }
625    }
626}
627
628/// A row-pattern expression inside `PATTERN ( ... )`.
629#[derive(Debug, Clone, PartialEq, Eq, Hash)]
630pub enum MatchRecognizePattern {
631    /// A single symbol, e.g. `A`, `^`, `$`.
632    Symbol(MatchRecognizeSymbol),
633    /// An exclusion `{- <pattern> -}`.
634    Exclude(MatchRecognizeSymbol),
635    /// `PERMUTE(<symbol>, ...)`.
636    Permute(Vec<MatchRecognizeSymbol>),
637    /// Concatenation, e.g. `A B C`.
638    Concat(Vec<MatchRecognizePattern>),
639    /// A parenthesized sub-pattern `( <pattern> )`.
640    Group(Box<MatchRecognizePattern>),
641    /// Alternation, e.g. `A | B | C`.
642    Alternation(Vec<MatchRecognizePattern>),
643    /// A quantified sub-pattern, e.g. `A*`, `A+`, `A?`, `A{1,3}`. The bool is `reluctant` (a trailing
644    /// `?`, e.g. `A*?`, which prefers the fewest matches).
645    Repetition(Box<MatchRecognizePattern>, RepetitionQuantifier, bool),
646}
647
648impl fmt::Display for MatchRecognizePattern {
649    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
650        use MatchRecognizePattern::*;
651        match self {
652            Symbol(symbol) => write!(f, "{}", symbol),
653            Exclude(symbol) => write!(f, "{{- {} -}}", symbol),
654            Permute(symbols) => write!(f, "PERMUTE({})", display_comma_separated(symbols)),
655            Concat(patterns) => write!(f, "{}", display_separated(patterns, " ")),
656            Group(pattern) => write!(f, "({})", pattern),
657            Alternation(patterns) => write!(f, "{}", display_separated(patterns, " | ")),
658            Repetition(pattern, quantifier, reluctant) => {
659                write!(
660                    f,
661                    "{}{}{}",
662                    pattern,
663                    quantifier,
664                    if *reluctant { "?" } else { "" }
665                )
666            }
667        }
668    }
669}
670
671/// A quantifier applied to a row-pattern, e.g. `*`, `+`, `?`, `{n,m}`.
672#[derive(Debug, Clone, PartialEq, Eq, Hash)]
673pub enum RepetitionQuantifier {
674    /// `*`
675    ZeroOrMore,
676    /// `+`
677    OneOrMore,
678    /// `?`
679    AtMostOne,
680    /// `{n}`
681    Exactly(u32),
682    /// `{n,}`
683    AtLeast(u32),
684    /// `{,m}`
685    AtMost(u32),
686    /// `{n,m}`
687    Range(u32, u32),
688}
689
690impl fmt::Display for RepetitionQuantifier {
691    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
692        use RepetitionQuantifier::*;
693        match self {
694            ZeroOrMore => write!(f, "*"),
695            OneOrMore => write!(f, "+"),
696            AtMostOne => write!(f, "?"),
697            Exactly(n) => write!(f, "{{{}}}", n),
698            AtLeast(n) => write!(f, "{{{},}}", n),
699            AtMost(m) => write!(f, "{{,{}}}", m),
700            Range(n, m) => write!(f, "{{{},{}}}", n, m),
701        }
702    }
703}
704
705impl fmt::Display for TableFactor {
706    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
707        match self {
708            TableFactor::Table { name, alias, as_of } => {
709                write!(f, "{}", name)?;
710                if let Some(as_of) = as_of {
711                    write!(f, "{}", as_of)?
712                }
713                if let Some(alias) = alias {
714                    write!(f, " AS {}", alias)?;
715                }
716                Ok(())
717            }
718            TableFactor::Derived {
719                lateral,
720                subquery,
721                alias,
722            } => {
723                if *lateral {
724                    write!(f, "LATERAL ")?;
725                }
726                write!(f, "({})", subquery)?;
727                if let Some(alias) = alias {
728                    write!(f, " AS {}", alias)?;
729                }
730                Ok(())
731            }
732            TableFactor::TableFunction {
733                name,
734                alias,
735                args,
736                with_ordinality,
737            } => {
738                write!(f, "{}({})", name, display_comma_separated(args))?;
739                if *with_ordinality {
740                    write!(f, " WITH ORDINALITY")?;
741                }
742                if let Some(alias) = alias {
743                    write!(f, " AS {}", alias)?;
744                }
745                Ok(())
746            }
747            TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference),
748            TableFactor::MatchRecognize {
749                table,
750                partition_by,
751                order_by,
752                measures,
753                rows_per_match,
754                after_match_skip,
755                pattern,
756                within,
757                subsets,
758                symbols,
759                alias,
760            } => {
761                write!(f, "{} MATCH_RECOGNIZE (", table)?;
762                if !partition_by.is_empty() {
763                    write!(f, "PARTITION BY {} ", display_comma_separated(partition_by))?;
764                }
765                if !order_by.is_empty() {
766                    write!(f, "ORDER BY {} ", display_comma_separated(order_by))?;
767                }
768                if !measures.is_empty() {
769                    write!(f, "MEASURES {} ", display_comma_separated(measures))?;
770                }
771                if let Some(rows_per_match) = rows_per_match {
772                    write!(f, "{} ", rows_per_match)?;
773                }
774                if let Some(after_match_skip) = after_match_skip {
775                    write!(f, "{} ", after_match_skip)?;
776                }
777                write!(f, "PATTERN ({}) ", pattern)?;
778                if let Some(within) = within {
779                    write!(f, "WITHIN {} ", within)?;
780                }
781                if !subsets.is_empty() {
782                    write!(f, "SUBSET {} ", display_comma_separated(subsets))?;
783                }
784                write!(f, "DEFINE {})", display_comma_separated(symbols))?;
785                if let Some(alias) = alias {
786                    write!(f, " AS {}", alias)?;
787                }
788                Ok(())
789            }
790        }
791    }
792}
793
794#[derive(Debug, Clone, PartialEq, Eq, Hash)]
795pub struct TableAlias {
796    pub name: Ident,
797    pub columns: Vec<Ident>,
798}
799
800impl fmt::Display for TableAlias {
801    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
802        write!(f, "{}", self.name)?;
803        if !self.columns.is_empty() {
804            write!(f, " ({})", display_comma_separated(&self.columns))?;
805        }
806        Ok(())
807    }
808}
809
810#[derive(Debug, Clone, PartialEq, Eq, Hash)]
811pub struct Join {
812    pub relation: TableFactor,
813    pub join_operator: JoinOperator,
814}
815
816impl fmt::Display for Join {
817    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
818        fn prefix(constraint: &JoinConstraint) -> &'static str {
819            match constraint {
820                JoinConstraint::Natural => "NATURAL ",
821                _ => "",
822            }
823        }
824        fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
825            struct Suffix<'a>(&'a JoinConstraint);
826            impl fmt::Display for Suffix<'_> {
827                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
828                    match self.0 {
829                        JoinConstraint::On(expr) => write!(f, " ON {}", expr),
830                        JoinConstraint::Using(attrs) => {
831                            write!(f, " USING({})", display_comma_separated(attrs))
832                        }
833                        _ => Ok(()),
834                    }
835                }
836            }
837            Suffix(constraint)
838        }
839        let broadcast = if matches!(
840            self.relation,
841            TableFactor::Table {
842                as_of: Some(AsOf::ProcessTimeBroadcast),
843                ..
844            }
845        ) {
846            "BROADCAST "
847        } else {
848            ""
849        };
850        match &self.join_operator {
851            JoinOperator::Inner(constraint) => write!(
852                f,
853                " {}{}JOIN {}{}",
854                prefix(constraint),
855                broadcast,
856                self.relation,
857                suffix(constraint)
858            ),
859            JoinOperator::LeftOuter(constraint) => write!(
860                f,
861                " {}{}LEFT JOIN {}{}",
862                prefix(constraint),
863                broadcast,
864                self.relation,
865                suffix(constraint)
866            ),
867            JoinOperator::RightOuter(constraint) => write!(
868                f,
869                " {}RIGHT JOIN {}{}",
870                prefix(constraint),
871                self.relation,
872                suffix(constraint)
873            ),
874            JoinOperator::FullOuter(constraint) => write!(
875                f,
876                " {}FULL JOIN {}{}",
877                prefix(constraint),
878                self.relation,
879                suffix(constraint)
880            ),
881            JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
882            JoinOperator::AsOfInner(constraint) => write!(
883                f,
884                " {}ASOF JOIN {}{}",
885                prefix(constraint),
886                self.relation,
887                suffix(constraint)
888            ),
889            JoinOperator::AsOfLeft(constraint) => write!(
890                f,
891                " {}ASOF LEFT JOIN {}{}",
892                prefix(constraint),
893                self.relation,
894                suffix(constraint)
895            ),
896        }
897    }
898}
899
900#[derive(Debug, Clone, PartialEq, Eq, Hash)]
901pub enum JoinOperator {
902    Inner(JoinConstraint),
903    LeftOuter(JoinConstraint),
904    RightOuter(JoinConstraint),
905    FullOuter(JoinConstraint),
906    CrossJoin,
907    AsOfInner(JoinConstraint),
908    AsOfLeft(JoinConstraint),
909}
910
911#[derive(Debug, Clone, PartialEq, Eq, Hash)]
912pub enum JoinConstraint {
913    On(Expr),
914    Using(Vec<Ident>),
915    Natural,
916    None,
917}
918
919/// An `ORDER BY` expression
920#[derive(Debug, Clone, PartialEq, Eq, Hash)]
921pub struct OrderByExpr {
922    pub expr: Expr,
923    /// Optional `ASC` or `DESC`
924    pub asc: Option<bool>,
925    /// Optional `NULLS FIRST` or `NULLS LAST`
926    pub nulls_first: Option<bool>,
927}
928
929impl fmt::Display for OrderByExpr {
930    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
931        write!(f, "{}", self.expr)?;
932        match self.asc {
933            Some(true) => write!(f, " ASC")?,
934            Some(false) => write!(f, " DESC")?,
935            None => (),
936        }
937        match self.nulls_first {
938            Some(true) => write!(f, " NULLS FIRST")?,
939            Some(false) => write!(f, " NULLS LAST")?,
940            None => (),
941        }
942        Ok(())
943    }
944}
945
946#[derive(Debug, Clone, PartialEq, Eq, Hash)]
947pub struct Fetch {
948    pub with_ties: bool,
949    pub quantity: Option<String>,
950}
951
952impl fmt::Display for Fetch {
953    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
954        let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
955        if let Some(ref quantity) = self.quantity {
956            write!(f, "FETCH FIRST {} ROWS {}", quantity, extension)
957        } else {
958            write!(f, "FETCH FIRST ROWS {}", extension)
959        }
960    }
961}
962
963#[derive(Debug, Clone, PartialEq, Eq, Hash)]
964pub struct Top {
965    /// SQL semantic equivalent of LIMIT but with same structure as FETCH.
966    pub with_ties: bool,
967    pub percent: bool,
968    pub quantity: Option<Expr>,
969}
970
971impl fmt::Display for Top {
972    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
973        let extension = if self.with_ties { " WITH TIES" } else { "" };
974        if let Some(ref quantity) = self.quantity {
975            let percent = if self.percent { " PERCENT" } else { "" };
976            write!(f, "TOP ({}){}{}", quantity, percent, extension)
977        } else {
978            write!(f, "TOP{}", extension)
979        }
980    }
981}
982
983#[derive(Debug, Clone, PartialEq, Eq, Hash)]
984pub struct Values(pub Vec<Vec<Expr>>);
985
986impl fmt::Display for Values {
987    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
988        write!(f, "VALUES ")?;
989        let mut delim = "";
990        for row in &self.0 {
991            write!(f, "{}", delim)?;
992            delim = ", ";
993            write!(f, "({})", display_comma_separated(row))?;
994        }
995        Ok(())
996    }
997}
998
999/// A named window definition in the WINDOW clause
1000#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1001pub struct NamedWindow {
1002    pub name: Ident,
1003    pub window_spec: WindowSpec,
1004}
1005
1006impl fmt::Display for NamedWindow {
1007    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1008        write!(f, "{} AS ({})", self.name, self.window_spec)
1009    }
1010}