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> AstDisplay for SetExpr<T> {
136    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
137        match self {
138            SetExpr::Select(s) => f.write_node(s),
139            SetExpr::Query(q) => {
140                f.write_str("(");
141                f.write_node(q);
142                f.write_str(")")
143            }
144            SetExpr::Values(v) => f.write_node(v),
145            SetExpr::Show(v) => f.write_node(v),
146            SetExpr::Table(t) => {
147                f.write_str("TABLE ");
148                f.write_node(t)
149            }
150            SetExpr::SetOperation {
151                left,
152                right,
153                op,
154                all,
155            } => {
156                f.write_node(left);
157                f.write_str(" ");
158                f.write_node(op);
159                f.write_str(" ");
160                if *all {
161                    f.write_str("ALL ");
162                }
163                f.write_node(right);
164            }
165        }
166    }
167}
168impl_display_t!(SetExpr);
169
170#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
171pub enum SetOperator {
172    Union,
173    Except,
174    Intersect,
175}
176
177impl AstDisplay for SetOperator {
178    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
179        f.write_str(match self {
180            SetOperator::Union => "UNION",
181            SetOperator::Except => "EXCEPT",
182            SetOperator::Intersect => "INTERSECT",
183        })
184    }
185}
186impl_display!(SetOperator);
187
188#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
189pub enum SelectOptionName {
190    ExpectedGroupSize,
191    AggregateInputGroupSize,
192    DistinctOnInputGroupSize,
193    LimitInputGroupSize,
194}
195
196impl AstDisplay for SelectOptionName {
197    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
198        f.write_str(match self {
199            SelectOptionName::ExpectedGroupSize => "EXPECTED GROUP SIZE",
200            SelectOptionName::AggregateInputGroupSize => "AGGREGATE INPUT GROUP SIZE",
201            SelectOptionName::DistinctOnInputGroupSize => "DISTINCT ON INPUT GROUP SIZE",
202            SelectOptionName::LimitInputGroupSize => "LIMIT INPUT GROUP SIZE",
203        })
204    }
205}
206impl_display!(SelectOptionName);
207
208impl WithOptionName for SelectOptionName {
209    /// # WARNING
210    ///
211    /// Whenever implementing this trait consider very carefully whether or not
212    /// this value could contain sensitive user data. If you're uncertain, err
213    /// on the conservative side and return `true`.
214    fn redact_value(&self) -> bool {
215        match self {
216            SelectOptionName::ExpectedGroupSize
217            | SelectOptionName::AggregateInputGroupSize
218            | SelectOptionName::DistinctOnInputGroupSize
219            | SelectOptionName::LimitInputGroupSize => false,
220        }
221    }
222}
223
224#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
225pub struct SelectOption<T: AstInfo> {
226    pub name: SelectOptionName,
227    pub value: Option<WithOptionValue<T>>,
228}
229impl_display_for_with_option!(SelectOption);
230
231/// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may
232/// appear either as the only body item of an `SQLQuery`, or as an operand
233/// to a set operation like `UNION`.
234#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
235pub struct Select<T: AstInfo> {
236    pub distinct: Option<Distinct<T>>,
237    /// projection expressions
238    pub projection: Vec<SelectItem<T>>,
239    /// FROM
240    pub from: Vec<TableWithJoins<T>>,
241    /// WHERE
242    pub selection: Option<Expr<T>>,
243    /// GROUP BY
244    pub group_by: Vec<Expr<T>>,
245    /// HAVING
246    pub having: Option<Expr<T>>,
247    /// QUALIFY
248    pub qualify: Option<Expr<T>>,
249    /// OPTION
250    pub options: Vec<SelectOption<T>>,
251}
252
253impl<T: AstInfo> AstDisplay for Select<T> {
254    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
255        f.write_str("SELECT");
256        if let Some(distinct) = &self.distinct {
257            f.write_str(" ");
258            f.write_node(distinct);
259        }
260        if !self.projection.is_empty() {
261            f.write_str(" ");
262            f.write_node(&display::comma_separated(&self.projection));
263        }
264        if !self.from.is_empty() {
265            f.write_str(" FROM ");
266            f.write_node(&display::comma_separated(&self.from));
267        }
268        if let Some(ref selection) = self.selection {
269            f.write_str(" WHERE ");
270            f.write_node(selection);
271        }
272        if !self.group_by.is_empty() {
273            f.write_str(" GROUP BY ");
274            f.write_node(&display::comma_separated(&self.group_by));
275        }
276        if let Some(ref having) = self.having {
277            f.write_str(" HAVING ");
278            f.write_node(having);
279        }
280        if let Some(ref qualify) = self.qualify {
281            f.write_str(" QUALIFY ");
282            f.write_node(qualify);
283        }
284        if !self.options.is_empty() {
285            f.write_str(" OPTIONS (");
286            f.write_node(&display::comma_separated(&self.options));
287            f.write_str(")");
288        }
289    }
290}
291impl_display_t!(Select);
292
293impl<T: AstInfo> Select<T> {
294    pub fn from(mut self, twj: TableWithJoins<T>) -> Select<T> {
295        self.from.push(twj);
296        self
297    }
298
299    pub fn project(mut self, select_item: SelectItem<T>) -> Select<T> {
300        self.projection.push(select_item);
301        self
302    }
303
304    pub fn selection(mut self, selection: Option<Expr<T>>) -> Select<T> {
305        self.selection = selection;
306        self
307    }
308}
309
310#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
311pub enum Distinct<T: AstInfo> {
312    EntireRow,
313    On(Vec<Expr<T>>),
314}
315impl_display_t!(Distinct);
316
317impl<T: AstInfo> AstDisplay for Distinct<T> {
318    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
319        match self {
320            Distinct::EntireRow => f.write_str("DISTINCT"),
321            Distinct::On(cols) => {
322                f.write_str("DISTINCT ON (");
323                f.write_node(&display::comma_separated(cols));
324                f.write_str(")");
325            }
326        }
327    }
328}
329
330/// A block of common table expressions (CTEs).
331///
332/// The block can either be entirely "simple" (traditional SQL `WITH` block),
333/// or "mutually recursive", which introduce their bindings before the block
334/// and may result in mutually recursive definitions.
335#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
336pub enum CteBlock<T: AstInfo> {
337    Simple(Vec<Cte<T>>),
338    MutuallyRecursive(MutRecBlock<T>),
339}
340
341#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
342pub struct MutRecBlock<T: AstInfo> {
343    pub options: Vec<MutRecBlockOption<T>>,
344    pub ctes: Vec<CteMutRec<T>>,
345}
346
347impl<T: AstInfo> CteBlock<T> {
348    /// Returns an empty (simple) CTE block.
349    pub fn empty() -> Self {
350        CteBlock::Simple(Vec::new())
351    }
352    /// True if there are no bindings in the block.
353    pub fn is_empty(&self) -> bool {
354        match self {
355            CteBlock::Simple(list) => list.is_empty(),
356            CteBlock::MutuallyRecursive(list) => list.ctes.is_empty(),
357        }
358    }
359    /// Iterates through the identifiers used in bindings.
360    pub fn bound_identifiers(&self) -> impl Iterator<Item = &Ident> {
361        let mut names = Vec::new();
362        match self {
363            CteBlock::Simple(list) => {
364                for cte in list.iter() {
365                    names.push(&cte.alias.name);
366                }
367            }
368            CteBlock::MutuallyRecursive(MutRecBlock { options: _, ctes }) => {
369                for cte in ctes.iter() {
370                    names.push(&cte.name);
371                }
372            }
373        }
374        names.into_iter()
375    }
376}
377
378impl<T: AstInfo> AstDisplay for CteBlock<T> {
379    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
380        if !self.is_empty() {
381            match self {
382                CteBlock::Simple(list) => {
383                    f.write_str("WITH ");
384                    f.write_node(&display::comma_separated(list));
385                }
386                CteBlock::MutuallyRecursive(MutRecBlock { options, ctes }) => {
387                    f.write_str("WITH MUTUALLY RECURSIVE ");
388                    if !options.is_empty() {
389                        f.write_str("(");
390                        f.write_node(&display::comma_separated(options));
391                        f.write_str(") ");
392                    }
393                    f.write_node(&display::comma_separated(ctes));
394                }
395            }
396            f.write_str(" ");
397        }
398    }
399}
400
401/// A single CTE (used after `WITH`): `alias [(col1, col2, ...)] AS ( query )`
402/// The names in the column list before `AS`, when specified, replace the names
403/// of the columns returned by the query. The parser does not validate that the
404/// number of columns in the query matches the number of columns in the query.
405#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
406pub struct Cte<T: AstInfo> {
407    pub alias: TableAlias,
408    pub id: T::CteId,
409    pub query: Query<T>,
410}
411
412impl<T: AstInfo> AstDisplay for Cte<T> {
413    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
414        f.write_node(&self.alias);
415        f.write_str(" AS (");
416        f.write_node(&self.query);
417        f.write_str(")");
418    }
419}
420impl_display_t!(Cte);
421
422#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
423pub struct CteMutRec<T: AstInfo> {
424    pub name: Ident,
425    pub columns: Vec<CteMutRecColumnDef<T>>,
426    pub id: T::CteId,
427    pub query: Query<T>,
428}
429
430impl<T: AstInfo> AstDisplay for CteMutRec<T> {
431    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
432        f.write_node(&self.name);
433        if !self.columns.is_empty() {
434            f.write_str(" (");
435            f.write_node(&display::comma_separated(&self.columns));
436            f.write_str(")");
437        }
438        f.write_str(" AS (");
439        f.write_node(&self.query);
440        f.write_str(")");
441    }
442}
443impl_display_t!(CteMutRec);
444
445/// A column definition in a [`CteMutRec`].
446#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
447pub struct CteMutRecColumnDef<T: AstInfo> {
448    pub name: Ident,
449    pub data_type: T::DataType,
450}
451
452impl<T: AstInfo> AstDisplay for CteMutRecColumnDef<T> {
453    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
454        f.write_node(&self.name);
455        f.write_str(" ");
456        f.write_node(&self.data_type);
457    }
458}
459impl_display_t!(CteMutRecColumnDef);
460
461#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
462pub enum MutRecBlockOptionName {
463    RecursionLimit,
464    ErrorAtRecursionLimit,
465    ReturnAtRecursionLimit,
466}
467
468impl AstDisplay for MutRecBlockOptionName {
469    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
470        f.write_str(match self {
471            MutRecBlockOptionName::RecursionLimit => "RECURSION LIMIT",
472            MutRecBlockOptionName::ErrorAtRecursionLimit => "ERROR AT RECURSION LIMIT",
473            MutRecBlockOptionName::ReturnAtRecursionLimit => "RETURN AT RECURSION LIMIT",
474        })
475    }
476}
477impl_display!(MutRecBlockOptionName);
478
479impl WithOptionName for MutRecBlockOptionName {
480    /// # WARNING
481    ///
482    /// Whenever implementing this trait consider very carefully whether or not
483    /// this value could contain sensitive user data. If you're uncertain, err
484    /// on the conservative side and return `true`.
485    fn redact_value(&self) -> bool {
486        match self {
487            MutRecBlockOptionName::RecursionLimit
488            | MutRecBlockOptionName::ErrorAtRecursionLimit
489            | MutRecBlockOptionName::ReturnAtRecursionLimit => false,
490        }
491    }
492}
493
494#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
495pub struct MutRecBlockOption<T: AstInfo> {
496    pub name: MutRecBlockOptionName,
497    pub value: Option<WithOptionValue<T>>,
498}
499impl_display_for_with_option!(MutRecBlockOption);
500
501/// One item of the comma-separated list following `SELECT`
502#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
503pub enum SelectItem<T: AstInfo> {
504    /// An expression, optionally followed by `[ AS ] alias`.
505    Expr { expr: Expr<T>, alias: Option<Ident> },
506    /// An unqualified `*`.
507    Wildcard,
508}
509
510impl<T: AstInfo> AstDisplay for SelectItem<T> {
511    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
512        match &self {
513            SelectItem::Expr { expr, alias } => {
514                f.write_node(expr);
515                if let Some(alias) = alias {
516                    f.write_str(" AS ");
517                    f.write_node(alias);
518                }
519            }
520            SelectItem::Wildcard => f.write_str("*"),
521        }
522    }
523}
524impl_display_t!(SelectItem);
525
526#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
527pub struct TableWithJoins<T: AstInfo> {
528    pub relation: TableFactor<T>,
529    pub joins: Vec<Join<T>>,
530}
531
532impl<T: AstInfo> AstDisplay for TableWithJoins<T> {
533    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
534        f.write_node(&self.relation);
535        for join in &self.joins {
536            f.write_node(join)
537        }
538    }
539}
540impl_display_t!(TableWithJoins);
541
542impl<T: AstInfo> TableWithJoins<T> {
543    pub fn subquery(query: Query<T>, alias: TableAlias) -> TableWithJoins<T> {
544        TableWithJoins {
545            relation: TableFactor::Derived {
546                lateral: false,
547                subquery: Box::new(query),
548                alias: Some(alias),
549            },
550            joins: vec![],
551        }
552    }
553}
554
555/// A table name or a parenthesized subquery with an optional alias
556#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
557pub enum TableFactor<T: AstInfo> {
558    Table {
559        name: T::ItemName,
560        alias: Option<TableAlias>,
561    },
562    Function {
563        function: Function<T>,
564        alias: Option<TableAlias>,
565        with_ordinality: bool,
566    },
567    RowsFrom {
568        functions: Vec<Function<T>>,
569        alias: Option<TableAlias>,
570        with_ordinality: bool,
571    },
572    Derived {
573        lateral: bool,
574        subquery: Box<Query<T>>,
575        alias: Option<TableAlias>,
576    },
577    /// Represents a parenthesized join expression, such as
578    /// `(foo <JOIN> bar [ <JOIN> baz ... ])`.
579    /// The inner `TableWithJoins` can have no joins only if its
580    /// `relation` is itself a `TableFactor::NestedJoin`.
581    NestedJoin {
582        join: Box<TableWithJoins<T>>,
583        alias: Option<TableAlias>,
584    },
585}
586
587impl<T: AstInfo> AstDisplay for TableFactor<T> {
588    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
589        match self {
590            TableFactor::Table { name, alias } => {
591                f.write_node(name);
592                if let Some(alias) = alias {
593                    f.write_str(" AS ");
594                    f.write_node(alias);
595                }
596            }
597            TableFactor::Function {
598                function,
599                alias,
600                with_ordinality,
601            } => {
602                f.write_node(function);
603                if let Some(alias) = &alias {
604                    f.write_str(" AS ");
605                    f.write_node(alias);
606                }
607                if *with_ordinality {
608                    f.write_str(" WITH ORDINALITY");
609                }
610            }
611            TableFactor::RowsFrom {
612                functions,
613                alias,
614                with_ordinality,
615            } => {
616                f.write_str("ROWS FROM (");
617                f.write_node(&display::comma_separated(functions));
618                f.write_str(")");
619                if let Some(alias) = alias {
620                    f.write_str(" AS ");
621                    f.write_node(alias);
622                }
623                if *with_ordinality {
624                    f.write_str(" WITH ORDINALITY");
625                }
626            }
627            TableFactor::Derived {
628                lateral,
629                subquery,
630                alias,
631            } => {
632                if *lateral {
633                    f.write_str("LATERAL ");
634                }
635                f.write_str("(");
636                f.write_node(subquery);
637                f.write_str(")");
638                if let Some(alias) = alias {
639                    f.write_str(" AS ");
640                    f.write_node(alias);
641                }
642            }
643            TableFactor::NestedJoin { join, alias } => {
644                f.write_str("(");
645                f.write_node(join);
646                f.write_str(")");
647                if let Some(alias) = alias {
648                    f.write_str(" AS ");
649                    f.write_node(alias);
650                }
651            }
652        }
653    }
654}
655impl_display_t!(TableFactor);
656
657#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
658pub struct TableAlias {
659    pub name: Ident,
660    pub columns: Vec<Ident>,
661    /// Whether the number of aliased columns must exactly match the number of
662    /// columns in the underlying table.
663    ///
664    /// TODO(benesch): this shouldn't really live in the AST (it's a HIR
665    /// concern), but it will have to do for now.
666    pub strict: bool,
667}
668
669impl AstDisplay for TableAlias {
670    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
671        f.write_node(&self.name);
672        if !self.columns.is_empty() {
673            f.write_str(" (");
674            f.write_node(&display::comma_separated(&self.columns));
675            f.write_str(")");
676        }
677    }
678}
679impl_display!(TableAlias);
680
681#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
682pub struct Join<T: AstInfo> {
683    pub relation: TableFactor<T>,
684    pub join_operator: JoinOperator<T>,
685}
686
687impl<T: AstInfo> AstDisplay for Join<T> {
688    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
689        fn prefix<T: AstInfo>(constraint: &JoinConstraint<T>) -> &'static str {
690            match constraint {
691                JoinConstraint::Natural => "NATURAL ",
692                _ => "",
693            }
694        }
695        fn suffix<'a, T: AstInfo>(constraint: &'a JoinConstraint<T>) -> impl AstDisplay + 'a {
696            struct Suffix<'a, T: AstInfo>(&'a JoinConstraint<T>);
697            impl<'a, T: AstInfo> AstDisplay for Suffix<'a, T> {
698                fn fmt<W>(&self, f: &mut AstFormatter<W>)
699                where
700                    W: fmt::Write,
701                {
702                    match self.0 {
703                        JoinConstraint::On(expr) => {
704                            f.write_str(" ON ");
705                            f.write_node(expr);
706                        }
707                        JoinConstraint::Using { columns, alias } => {
708                            f.write_str(" USING (");
709                            f.write_node(&display::comma_separated(columns));
710                            f.write_str(")");
711
712                            if let Some(join_using_alias) = alias {
713                                f.write_str(" AS ");
714                                f.write_node(join_using_alias);
715                            }
716                        }
717                        _ => {}
718                    }
719                }
720            }
721            Suffix(constraint)
722        }
723        match &self.join_operator {
724            JoinOperator::Inner(constraint) => {
725                f.write_str(" ");
726                f.write_str(prefix(constraint));
727                f.write_str("JOIN ");
728                f.write_node(&self.relation);
729                f.write_node(&suffix(constraint));
730            }
731            JoinOperator::LeftOuter(constraint) => {
732                f.write_str(" ");
733                f.write_str(prefix(constraint));
734                f.write_str("LEFT JOIN ");
735                f.write_node(&self.relation);
736                f.write_node(&suffix(constraint));
737            }
738            JoinOperator::RightOuter(constraint) => {
739                f.write_str(" ");
740                f.write_str(prefix(constraint));
741                f.write_str("RIGHT JOIN ");
742                f.write_node(&self.relation);
743                f.write_node(&suffix(constraint));
744            }
745            JoinOperator::FullOuter(constraint) => {
746                f.write_str(" ");
747                f.write_str(prefix(constraint));
748                f.write_str("FULL JOIN ");
749                f.write_node(&self.relation);
750                f.write_node(&suffix(constraint));
751            }
752            JoinOperator::CrossJoin => {
753                f.write_str(" CROSS JOIN ");
754                f.write_node(&self.relation);
755            }
756        }
757    }
758}
759impl_display_t!(Join);
760
761#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
762pub enum JoinOperator<T: AstInfo> {
763    Inner(JoinConstraint<T>),
764    LeftOuter(JoinConstraint<T>),
765    RightOuter(JoinConstraint<T>),
766    FullOuter(JoinConstraint<T>),
767    CrossJoin,
768}
769
770#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
771pub enum JoinConstraint<T: AstInfo> {
772    On(Expr<T>),
773    Using {
774        columns: Vec<Ident>,
775        alias: Option<Ident>,
776    },
777    Natural,
778}
779
780/// SQL ORDER BY expression
781#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
782pub struct OrderByExpr<T: AstInfo> {
783    pub expr: Expr<T>,
784    pub asc: Option<bool>,
785    pub nulls_last: Option<bool>,
786}
787
788impl<T: AstInfo> AstDisplay for OrderByExpr<T> {
789    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
790        f.write_node(&self.expr);
791        match self.asc {
792            Some(true) => f.write_str(" ASC"),
793            Some(false) => f.write_str(" DESC"),
794            None => {}
795        }
796        match self.nulls_last {
797            Some(true) => f.write_str(" NULLS LAST"),
798            Some(false) => f.write_str(" NULLS FIRST"),
799            None => {}
800        }
801    }
802}
803impl_display_t!(OrderByExpr);
804
805#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
806pub struct Limit<T: AstInfo> {
807    pub with_ties: bool,
808    pub quantity: Expr<T>,
809}
810
811#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
812pub struct Values<T: AstInfo>(pub Vec<Vec<Expr<T>>>);
813
814impl<T: AstInfo> AstDisplay for Values<T> {
815    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
816        f.write_str("VALUES ");
817        let mut delim = "";
818
819        for (i, row) in self.0.iter().enumerate() {
820            if f.redacted() && i == 20 {
821                f.write_str("/* ");
822                f.write_str(&(self.0.len().saturating_sub(20)).to_string());
823                f.write_str(" more rows */");
824                break;
825            }
826
827            f.write_str(delim);
828            delim = ", ";
829            f.write_str("(");
830            f.write_node(&display::comma_separated(row));
831            f.write_str(")");
832        }
833    }
834}
835impl_display_t!(Values);