Skip to main content

mz_sql_parser/ast/defs/
query.rs

1// Copyright 2018 sqlparser-rs contributors. All rights reserved.
2// Copyright Materialize, Inc. and contributors. All rights reserved.
3//
4// This file is derived from the sqlparser-rs project, available at
5// https://github.com/andygrove/sqlparser-rs. It was incorporated
6// directly into Materialize on December 21, 2019.
7//
8// Licensed under the Apache License, Version 2.0 (the "License");
9// you may not use this file except in compliance with the License.
10// You may obtain a copy of the License in the LICENSE file at the
11// root of this repository, or online at
12//
13//     http://www.apache.org/licenses/LICENSE-2.0
14//
15// Unless required by applicable law or agreed to in writing, software
16// distributed under the License is distributed on an "AS IS" BASIS,
17// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18// See the License for the specific language governing permissions and
19// limitations under the License.
20
21use std::fmt::{self, Debug};
22use std::hash::Hash;
23use std::mem;
24
25use crate::ast::display::{self, AstDisplay, AstFormatter, WithOptionName};
26use crate::ast::{AstInfo, Expr, Function, Ident, ShowStatement, WithOptionValue};
27
28/// The most complete variant of a `SELECT` query expression, optionally
29/// including `WITH`, `UNION` / other set operations, and `ORDER BY`.
30#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
31pub struct Query<T: AstInfo> {
32    /// WITH (common table expressions, or CTEs)
33    pub ctes: CteBlock<T>,
34    /// SELECT or UNION / EXCEPT / INTERSECT
35    pub body: SetExpr<T>,
36    /// ORDER BY
37    pub order_by: Vec<OrderByExpr<T>>,
38    /// `LIMIT { <N> | ALL }`
39    /// `FETCH { FIRST | NEXT } <N> { ROW | ROWS } | { ONLY | WITH TIES }`
40    pub limit: Option<Limit<T>>,
41    /// `OFFSET <N> { ROW | ROWS }`
42    pub offset: Option<Expr<T>>,
43}
44
45impl<T: AstInfo> AstDisplay for Query<T> {
46    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
47        f.write_node(&self.ctes);
48        f.write_node(&self.body);
49        if !self.order_by.is_empty() {
50            f.write_str(" ORDER BY ");
51            f.write_node(&display::comma_separated(&self.order_by));
52        }
53
54        let write_offset = |f: &mut AstFormatter<W>| {
55            if let Some(offset) = &self.offset {
56                f.write_str(" OFFSET ");
57                f.write_node(offset);
58            }
59        };
60
61        if let Some(limit) = &self.limit {
62            if limit.with_ties {
63                write_offset(f);
64                f.write_str(" FETCH FIRST ");
65                f.write_node(&limit.quantity);
66                f.write_str(" ROWS WITH TIES");
67            } else {
68                f.write_str(" LIMIT ");
69                f.write_node(&limit.quantity);
70                write_offset(f);
71            }
72        } else {
73            write_offset(f);
74        }
75    }
76}
77impl_display_t!(Query);
78
79impl<T: AstInfo> Query<T> {
80    pub fn select(select: Select<T>) -> Query<T> {
81        Query {
82            ctes: CteBlock::empty(),
83            body: SetExpr::Select(Box::new(select)),
84            order_by: vec![],
85            limit: None,
86            offset: None,
87        }
88    }
89
90    pub fn query(query: Query<T>) -> Query<T> {
91        Query {
92            ctes: CteBlock::empty(),
93            body: SetExpr::Query(Box::new(query)),
94            order_by: vec![],
95            limit: None,
96            offset: None,
97        }
98    }
99
100    pub fn take(&mut self) -> Query<T> {
101        mem::replace(
102            self,
103            Query::<T> {
104                ctes: CteBlock::empty(),
105                order_by: vec![],
106                body: SetExpr::Values(Values(vec![])),
107                limit: None,
108                offset: None,
109            },
110        )
111    }
112}
113
114/// A node in a tree, representing a "query body" expression, roughly:
115/// `SELECT ... [ {UNION|EXCEPT|INTERSECT} SELECT ...]`
116#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
117pub enum SetExpr<T: AstInfo> {
118    /// Restricted SELECT .. FROM .. HAVING (no ORDER BY or set operations)
119    Select(Box<Select<T>>),
120    /// Parenthesized SELECT subquery, which may include more set operations
121    /// in its body and an optional ORDER BY / LIMIT.
122    Query(Box<Query<T>>),
123    /// UNION/EXCEPT/INTERSECT of two queries
124    SetOperation {
125        op: SetOperator,
126        all: bool,
127        left: Box<SetExpr<T>>,
128        right: Box<SetExpr<T>>,
129    },
130    Values(Values<T>),
131    Show(ShowStatement<T>),
132    Table(T::ItemName),
133}
134
135impl<T: AstInfo> SetExpr<T> {
136    /// Whether the rendered SQL for this body begins with `SHOW` (i.e. its
137    /// leftmost leaf is a `Show`). Such a body must be parenthesized when it is
138    /// a statement's query, because a top-level leading `SHOW` is dispatched as
139    /// a `Statement::Show` and would swallow any following set operator.
140    pub fn starts_with_show(&self) -> bool {
141        match self {
142            SetExpr::Show(_) => true,
143            SetExpr::SetOperation { left, .. } => left.starts_with_show(),
144            _ => false,
145        }
146    }
147}
148
149impl<T: AstInfo> AstDisplay for SetExpr<T> {
150    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
151        match self {
152            SetExpr::Select(s) => f.write_node(s),
153            SetExpr::Query(q) => {
154                f.write_str("(");
155                f.write_node(q);
156                f.write_str(")")
157            }
158            SetExpr::Values(v) => f.write_node(v),
159            SetExpr::Show(v) => f.write_node(v),
160            SetExpr::Table(t) => {
161                f.write_str("TABLE ");
162                f.write_node(t)
163            }
164            SetExpr::SetOperation {
165                left,
166                right,
167                op,
168                all,
169            } => {
170                f.write_node(left);
171                f.write_str(" ");
172                f.write_node(op);
173                f.write_str(" ");
174                if *all {
175                    f.write_str("ALL ");
176                }
177                f.write_node(right);
178            }
179        }
180    }
181}
182impl_display_t!(SetExpr);
183
184#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
185pub enum SetOperator {
186    Union,
187    Except,
188    Intersect,
189}
190
191impl AstDisplay for SetOperator {
192    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
193        f.write_str(match self {
194            SetOperator::Union => "UNION",
195            SetOperator::Except => "EXCEPT",
196            SetOperator::Intersect => "INTERSECT",
197        })
198    }
199}
200impl_display!(SetOperator);
201
202#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
203pub enum SelectOptionName {
204    ExpectedGroupSize,
205    AggregateInputGroupSize,
206    DistinctOnInputGroupSize,
207    LimitInputGroupSize,
208}
209
210impl AstDisplay for SelectOptionName {
211    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
212        f.write_str(match self {
213            SelectOptionName::ExpectedGroupSize => "EXPECTED GROUP SIZE",
214            SelectOptionName::AggregateInputGroupSize => "AGGREGATE INPUT GROUP SIZE",
215            SelectOptionName::DistinctOnInputGroupSize => "DISTINCT ON INPUT GROUP SIZE",
216            SelectOptionName::LimitInputGroupSize => "LIMIT INPUT GROUP SIZE",
217        })
218    }
219}
220impl_display!(SelectOptionName);
221
222impl WithOptionName for SelectOptionName {
223    /// # WARNING
224    ///
225    /// Whenever implementing this trait consider very carefully whether or not
226    /// this value could contain sensitive user data. If you're uncertain, err
227    /// on the conservative side and return `true`.
228    fn redact_value(&self) -> bool {
229        match self {
230            SelectOptionName::ExpectedGroupSize
231            | SelectOptionName::AggregateInputGroupSize
232            | SelectOptionName::DistinctOnInputGroupSize
233            | SelectOptionName::LimitInputGroupSize => false,
234        }
235    }
236}
237
238#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
239pub struct SelectOption<T: AstInfo> {
240    pub name: SelectOptionName,
241    pub value: Option<WithOptionValue<T>>,
242}
243impl_display_for_with_option!(SelectOption);
244
245/// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may
246/// appear either as the only body item of an `SQLQuery`, or as an operand
247/// to a set operation like `UNION`.
248#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
249pub struct Select<T: AstInfo> {
250    pub distinct: Option<Distinct<T>>,
251    /// projection expressions
252    pub projection: Vec<SelectItem<T>>,
253    /// FROM
254    pub from: Vec<TableWithJoins<T>>,
255    /// WHERE
256    pub selection: Option<Expr<T>>,
257    /// GROUP BY
258    pub group_by: Vec<Expr<T>>,
259    /// HAVING
260    pub having: Option<Expr<T>>,
261    /// QUALIFY
262    pub qualify: Option<Expr<T>>,
263    /// OPTION
264    pub options: Vec<SelectOption<T>>,
265}
266
267impl<T: AstInfo> AstDisplay for Select<T> {
268    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
269        f.write_str("SELECT");
270        if let Some(distinct) = &self.distinct {
271            f.write_str(" ");
272            f.write_node(distinct);
273        }
274        if !self.projection.is_empty() {
275            f.write_str(" ");
276            f.write_node(&display::comma_separated(&self.projection));
277        }
278        if !self.from.is_empty() {
279            f.write_str(" FROM ");
280            f.write_node(&display::comma_separated(&self.from));
281        }
282        if let Some(ref selection) = self.selection {
283            f.write_str(" WHERE ");
284            f.write_node(selection);
285        }
286        if !self.group_by.is_empty() {
287            f.write_str(" GROUP BY ");
288            f.write_node(&display::comma_separated(&self.group_by));
289        }
290        if let Some(ref having) = self.having {
291            f.write_str(" HAVING ");
292            f.write_node(having);
293        }
294        if let Some(ref qualify) = self.qualify {
295            f.write_str(" QUALIFY ");
296            f.write_node(qualify);
297        }
298        if !self.options.is_empty() {
299            f.write_str(" OPTIONS (");
300            f.write_node(&display::comma_separated(&self.options));
301            f.write_str(")");
302        }
303    }
304}
305impl_display_t!(Select);
306
307impl<T: AstInfo> Select<T> {
308    pub fn from(mut self, twj: TableWithJoins<T>) -> Select<T> {
309        self.from.push(twj);
310        self
311    }
312
313    pub fn project(mut self, select_item: SelectItem<T>) -> Select<T> {
314        self.projection.push(select_item);
315        self
316    }
317
318    pub fn selection(mut self, selection: Option<Expr<T>>) -> Select<T> {
319        self.selection = selection;
320        self
321    }
322}
323
324#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
325pub enum Distinct<T: AstInfo> {
326    EntireRow,
327    On(Vec<Expr<T>>),
328}
329impl_display_t!(Distinct);
330
331impl<T: AstInfo> AstDisplay for Distinct<T> {
332    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
333        match self {
334            Distinct::EntireRow => f.write_str("DISTINCT"),
335            Distinct::On(cols) => {
336                f.write_str("DISTINCT ON (");
337                f.write_node(&display::comma_separated(cols));
338                f.write_str(")");
339            }
340        }
341    }
342}
343
344/// A block of common table expressions (CTEs).
345///
346/// The block can either be entirely "simple" (traditional SQL `WITH` block),
347/// or "mutually recursive", which introduce their bindings before the block
348/// and may result in mutually recursive definitions.
349#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
350pub enum CteBlock<T: AstInfo> {
351    Simple(Vec<Cte<T>>),
352    MutuallyRecursive(MutRecBlock<T>),
353}
354
355#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
356pub struct MutRecBlock<T: AstInfo> {
357    pub options: Vec<MutRecBlockOption<T>>,
358    pub ctes: Vec<CteMutRec<T>>,
359}
360
361impl<T: AstInfo> CteBlock<T> {
362    /// Returns an empty (simple) CTE block.
363    pub fn empty() -> Self {
364        CteBlock::Simple(Vec::new())
365    }
366    /// True if there are no bindings in the block.
367    pub fn is_empty(&self) -> bool {
368        match self {
369            CteBlock::Simple(list) => list.is_empty(),
370            CteBlock::MutuallyRecursive(list) => list.ctes.is_empty(),
371        }
372    }
373    /// Iterates through the identifiers used in bindings.
374    pub fn bound_identifiers(&self) -> impl Iterator<Item = &Ident> {
375        let mut names = Vec::new();
376        match self {
377            CteBlock::Simple(list) => {
378                for cte in list.iter() {
379                    names.push(&cte.alias.name);
380                }
381            }
382            CteBlock::MutuallyRecursive(MutRecBlock { options: _, ctes }) => {
383                for cte in ctes.iter() {
384                    names.push(&cte.name);
385                }
386            }
387        }
388        names.into_iter()
389    }
390}
391
392impl<T: AstInfo> AstDisplay for CteBlock<T> {
393    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
394        if !self.is_empty() {
395            match self {
396                CteBlock::Simple(list) => {
397                    f.write_str("WITH ");
398                    f.write_node(&display::comma_separated(list));
399                }
400                CteBlock::MutuallyRecursive(MutRecBlock { options, ctes }) => {
401                    f.write_str("WITH MUTUALLY RECURSIVE ");
402                    if !options.is_empty() {
403                        f.write_str("(");
404                        f.write_node(&display::comma_separated(options));
405                        f.write_str(") ");
406                    }
407                    f.write_node(&display::comma_separated(ctes));
408                }
409            }
410            f.write_str(" ");
411        }
412    }
413}
414
415/// A single CTE (used after `WITH`): `alias [(col1, col2, ...)] AS ( query )`
416/// The names in the column list before `AS`, when specified, replace the names
417/// of the columns returned by the query. The parser does not validate that the
418/// number of columns in the query matches the number of columns in the query.
419#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
420pub struct Cte<T: AstInfo> {
421    pub alias: TableAlias,
422    pub id: T::CteId,
423    pub query: Query<T>,
424}
425
426impl<T: AstInfo> AstDisplay for Cte<T> {
427    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
428        f.write_node(&self.alias);
429        f.write_str(" AS (");
430        f.write_node(&self.query);
431        f.write_str(")");
432    }
433}
434impl_display_t!(Cte);
435
436#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
437pub struct CteMutRec<T: AstInfo> {
438    pub name: Ident,
439    pub columns: Vec<CteMutRecColumnDef<T>>,
440    pub id: T::CteId,
441    pub query: Query<T>,
442}
443
444impl<T: AstInfo> AstDisplay for CteMutRec<T> {
445    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
446        f.write_node(&self.name);
447        if !self.columns.is_empty() {
448            f.write_str(" (");
449            f.write_node(&display::comma_separated(&self.columns));
450            f.write_str(")");
451        }
452        f.write_str(" AS (");
453        f.write_node(&self.query);
454        f.write_str(")");
455    }
456}
457impl_display_t!(CteMutRec);
458
459/// A column definition in a [`CteMutRec`].
460#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
461pub struct CteMutRecColumnDef<T: AstInfo> {
462    pub name: Ident,
463    pub data_type: T::DataType,
464}
465
466impl<T: AstInfo> AstDisplay for CteMutRecColumnDef<T> {
467    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
468        f.write_node(&self.name);
469        f.write_str(" ");
470        f.write_node(&self.data_type);
471    }
472}
473impl_display_t!(CteMutRecColumnDef);
474
475#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
476pub enum MutRecBlockOptionName {
477    RecursionLimit,
478    ErrorAtRecursionLimit,
479    ReturnAtRecursionLimit,
480}
481
482impl AstDisplay for MutRecBlockOptionName {
483    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
484        f.write_str(match self {
485            MutRecBlockOptionName::RecursionLimit => "RECURSION LIMIT",
486            MutRecBlockOptionName::ErrorAtRecursionLimit => "ERROR AT RECURSION LIMIT",
487            MutRecBlockOptionName::ReturnAtRecursionLimit => "RETURN AT RECURSION LIMIT",
488        })
489    }
490}
491impl_display!(MutRecBlockOptionName);
492
493impl WithOptionName for MutRecBlockOptionName {
494    /// # WARNING
495    ///
496    /// Whenever implementing this trait consider very carefully whether or not
497    /// this value could contain sensitive user data. If you're uncertain, err
498    /// on the conservative side and return `true`.
499    fn redact_value(&self) -> bool {
500        match self {
501            MutRecBlockOptionName::RecursionLimit
502            | MutRecBlockOptionName::ErrorAtRecursionLimit
503            | MutRecBlockOptionName::ReturnAtRecursionLimit => false,
504        }
505    }
506}
507
508#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
509pub struct MutRecBlockOption<T: AstInfo> {
510    pub name: MutRecBlockOptionName,
511    pub value: Option<WithOptionValue<T>>,
512}
513impl_display_for_with_option!(MutRecBlockOption);
514
515/// One item of the comma-separated list following `SELECT`
516#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
517pub enum SelectItem<T: AstInfo> {
518    /// An expression, optionally followed by `[ AS ] alias`.
519    Expr { expr: Expr<T>, alias: Option<Ident> },
520    /// An unqualified `*`.
521    Wildcard,
522}
523
524impl<T: AstInfo> AstDisplay for SelectItem<T> {
525    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
526        match &self {
527            SelectItem::Expr { expr, alias } => {
528                f.write_node(expr);
529                if let Some(alias) = alias {
530                    f.write_str(" AS ");
531                    f.write_node(alias);
532                }
533            }
534            SelectItem::Wildcard => f.write_str("*"),
535        }
536    }
537}
538impl_display_t!(SelectItem);
539
540#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
541pub struct TableWithJoins<T: AstInfo> {
542    pub relation: TableFactor<T>,
543    pub joins: Vec<Join<T>>,
544}
545
546impl<T: AstInfo> AstDisplay for TableWithJoins<T> {
547    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
548        f.write_node(&self.relation);
549        for join in &self.joins {
550            f.write_node(join)
551        }
552    }
553}
554impl_display_t!(TableWithJoins);
555
556impl<T: AstInfo> TableWithJoins<T> {
557    pub fn subquery(query: Query<T>, alias: TableAlias) -> TableWithJoins<T> {
558        TableWithJoins {
559            relation: TableFactor::Derived {
560                lateral: false,
561                subquery: Box::new(query),
562                alias: Some(alias),
563            },
564            joins: vec![],
565        }
566    }
567}
568
569/// A table name or a parenthesized subquery with an optional alias
570#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
571pub enum TableFactor<T: AstInfo> {
572    Table {
573        name: T::ItemName,
574        alias: Option<TableAlias>,
575    },
576    Function {
577        function: Function<T>,
578        alias: Option<TableAlias>,
579        with_ordinality: bool,
580    },
581    RowsFrom {
582        functions: Vec<Function<T>>,
583        alias: Option<TableAlias>,
584        with_ordinality: bool,
585    },
586    Derived {
587        lateral: bool,
588        subquery: Box<Query<T>>,
589        alias: Option<TableAlias>,
590    },
591    /// Represents a parenthesized join expression, such as
592    /// `(foo <JOIN> bar [ <JOIN> baz ... ])`.
593    /// The inner `TableWithJoins` can have no joins only if its
594    /// `relation` is itself a `TableFactor::NestedJoin`.
595    NestedJoin {
596        join: Box<TableWithJoins<T>>,
597        alias: Option<TableAlias>,
598    },
599}
600
601impl<T: AstInfo> AstDisplay for TableFactor<T> {
602    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
603        match self {
604            TableFactor::Table { name, alias } => {
605                f.write_node(name);
606                if let Some(alias) = alias {
607                    f.write_str(" AS ");
608                    f.write_node(alias);
609                }
610            }
611            TableFactor::Function {
612                function,
613                alias,
614                with_ordinality,
615            } => {
616                function.fmt_table_call(f);
617                if *with_ordinality {
618                    f.write_str(" WITH ORDINALITY");
619                }
620                if let Some(alias) = &alias {
621                    f.write_str(" AS ");
622                    f.write_node(alias);
623                }
624            }
625            TableFactor::RowsFrom {
626                functions,
627                alias,
628                with_ordinality,
629            } => {
630                f.write_str("ROWS FROM (");
631                for (i, function) in functions.iter().enumerate() {
632                    if i > 0 {
633                        f.write_str(", ");
634                    }
635                    function.fmt_table_call(f);
636                }
637                f.write_str(")");
638                if *with_ordinality {
639                    f.write_str(" WITH ORDINALITY");
640                }
641                if let Some(alias) = alias {
642                    f.write_str(" AS ");
643                    f.write_node(alias);
644                }
645            }
646            TableFactor::Derived {
647                lateral,
648                subquery,
649                alias,
650            } => {
651                if *lateral {
652                    f.write_str("LATERAL ");
653                }
654                f.write_str("(");
655                f.write_node(subquery);
656                f.write_str(")");
657                if let Some(alias) = alias {
658                    f.write_str(" AS ");
659                    f.write_node(alias);
660                }
661            }
662            TableFactor::NestedJoin { join, alias } => {
663                f.write_str("(");
664                f.write_node(join);
665                f.write_str(")");
666                if let Some(alias) = alias {
667                    f.write_str(" AS ");
668                    f.write_node(alias);
669                }
670            }
671        }
672    }
673}
674impl_display_t!(TableFactor);
675
676#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
677pub struct TableAlias {
678    pub name: Ident,
679    pub columns: Vec<Ident>,
680    /// Whether the number of aliased columns must exactly match the number of
681    /// columns in the underlying table.
682    ///
683    /// TODO(benesch): this shouldn't really live in the AST (it's a HIR
684    /// concern), but it will have to do for now.
685    pub strict: bool,
686}
687
688impl AstDisplay for TableAlias {
689    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
690        f.write_node(&self.name);
691        if !self.columns.is_empty() {
692            f.write_str(" (");
693            f.write_node(&display::comma_separated(&self.columns));
694            f.write_str(")");
695        }
696    }
697}
698impl_display!(TableAlias);
699
700#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
701pub struct Join<T: AstInfo> {
702    pub relation: TableFactor<T>,
703    pub join_operator: JoinOperator<T>,
704}
705
706impl<T: AstInfo> AstDisplay for Join<T> {
707    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
708        fn prefix<T: AstInfo>(constraint: &JoinConstraint<T>) -> &'static str {
709            match constraint {
710                JoinConstraint::Natural => "NATURAL ",
711                _ => "",
712            }
713        }
714        fn suffix<'a, T: AstInfo>(constraint: &'a JoinConstraint<T>) -> impl AstDisplay + 'a {
715            struct Suffix<'a, T: AstInfo>(&'a JoinConstraint<T>);
716            impl<'a, T: AstInfo> AstDisplay for Suffix<'a, T> {
717                fn fmt<W>(&self, f: &mut AstFormatter<W>)
718                where
719                    W: fmt::Write,
720                {
721                    match self.0 {
722                        JoinConstraint::On(expr) => {
723                            f.write_str(" ON ");
724                            f.write_node(expr);
725                        }
726                        JoinConstraint::Using { columns, alias } => {
727                            f.write_str(" USING (");
728                            f.write_node(&display::comma_separated(columns));
729                            f.write_str(")");
730
731                            if let Some(join_using_alias) = alias {
732                                f.write_str(" AS ");
733                                f.write_node(join_using_alias);
734                            }
735                        }
736                        JoinConstraint::Natural => {}
737                    }
738                }
739            }
740            Suffix(constraint)
741        }
742        match &self.join_operator {
743            JoinOperator::Inner(constraint) => {
744                f.write_str(" ");
745                f.write_str(prefix(constraint));
746                f.write_str("JOIN ");
747                f.write_node(&self.relation);
748                f.write_node(&suffix(constraint));
749            }
750            JoinOperator::LeftOuter(constraint) => {
751                f.write_str(" ");
752                f.write_str(prefix(constraint));
753                f.write_str("LEFT JOIN ");
754                f.write_node(&self.relation);
755                f.write_node(&suffix(constraint));
756            }
757            JoinOperator::RightOuter(constraint) => {
758                f.write_str(" ");
759                f.write_str(prefix(constraint));
760                f.write_str("RIGHT JOIN ");
761                f.write_node(&self.relation);
762                f.write_node(&suffix(constraint));
763            }
764            JoinOperator::FullOuter(constraint) => {
765                f.write_str(" ");
766                f.write_str(prefix(constraint));
767                f.write_str("FULL JOIN ");
768                f.write_node(&self.relation);
769                f.write_node(&suffix(constraint));
770            }
771            JoinOperator::CrossJoin => {
772                f.write_str(" CROSS JOIN ");
773                f.write_node(&self.relation);
774            }
775        }
776    }
777}
778impl_display_t!(Join);
779
780#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
781pub enum JoinOperator<T: AstInfo> {
782    Inner(JoinConstraint<T>),
783    LeftOuter(JoinConstraint<T>),
784    RightOuter(JoinConstraint<T>),
785    FullOuter(JoinConstraint<T>),
786    CrossJoin,
787}
788
789#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
790pub enum JoinConstraint<T: AstInfo> {
791    On(Expr<T>),
792    Using {
793        columns: Vec<Ident>,
794        alias: Option<Ident>,
795    },
796    Natural,
797}
798
799/// SQL ORDER BY expression
800#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
801pub struct OrderByExpr<T: AstInfo> {
802    pub expr: Expr<T>,
803    pub asc: Option<bool>,
804    pub nulls_last: Option<bool>,
805}
806
807impl<T: AstInfo> AstDisplay for OrderByExpr<T> {
808    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
809        f.write_node(&self.expr);
810        match self.asc {
811            Some(true) => f.write_str(" ASC"),
812            Some(false) => f.write_str(" DESC"),
813            None => {}
814        }
815        match self.nulls_last {
816            Some(true) => f.write_str(" NULLS LAST"),
817            Some(false) => f.write_str(" NULLS FIRST"),
818            None => {}
819        }
820    }
821}
822impl_display_t!(OrderByExpr);
823
824#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
825pub struct Limit<T: AstInfo> {
826    pub with_ties: bool,
827    pub quantity: Expr<T>,
828}
829
830#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
831pub struct Values<T: AstInfo>(pub Vec<Vec<Expr<T>>>);
832
833impl<T: AstInfo> AstDisplay for Values<T> {
834    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
835        f.write_str("VALUES ");
836        let mut delim = "";
837
838        for (i, row) in self.0.iter().enumerate() {
839            if f.redacted() && i == 20 {
840                f.write_str("/* ");
841                f.write_str(&(self.0.len().saturating_sub(20)).to_string());
842                f.write_str(" more rows */");
843                break;
844            }
845
846            f.write_str(delim);
847            delim = ", ";
848            f.write_str("(");
849            f.write_node(&display::comma_separated(row));
850            f.write_str(")");
851        }
852    }
853}
854impl_display_t!(Values);