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
13#[cfg(not(feature = "std"))]
14use alloc::{boxed::Box, vec::Vec};
15
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19use crate::ast::*;
20
21/// The most complete variant of a `SELECT` query expression, optionally
22/// including `WITH`, `UNION` / other set operations, and `ORDER BY`.
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub struct Query {
26    /// WITH (common table expressions, or CTEs)
27    pub with: Option<With>,
28    /// SELECT or UNION / EXCEPT / INTERSECT
29    pub body: SetExpr,
30    /// ORDER BY
31    pub order_by: Vec<OrderByExpr>,
32    /// `LIMIT { <N> | ALL }`
33    pub limit: Option<Expr>,
34    /// `OFFSET <N> [ { ROW | ROWS } ]`
35    ///
36    /// `ROW` and `ROWS` are noise words that don't influence the effect of the clause.
37    /// They are provided for ANSI compatibility.
38    pub offset: Option<String>,
39    /// `FETCH { FIRST | NEXT } <N> [ PERCENT ] { ROW | ROWS } | { ONLY | WITH TIES }`
40    ///
41    /// `ROW` and `ROWS` as well as `FIRST` and `NEXT` are noise words that don't influence the
42    /// effect of the clause. They are provided for ANSI compatibility.
43    pub fetch: Option<Fetch>,
44}
45
46impl Query {
47    /// Simple `VALUES` without other clauses.
48    pub fn as_simple_values(&self) -> Option<&Values> {
49        match &self {
50            Query {
51                with: None,
52                body: SetExpr::Values(values),
53                order_by,
54                limit: None,
55                offset: None,
56                fetch: None,
57            } if order_by.is_empty() => Some(values),
58            _ => None,
59        }
60    }
61
62    /// `SELECT <expr>` without other clauses.
63    pub fn as_single_select_item(&self) -> Option<&Expr> {
64        match &self {
65            Query {
66                with: None,
67                body: SetExpr::Select(select),
68                order_by,
69                limit: None,
70                offset: None,
71                fetch: None,
72            } if order_by.is_empty() => match select.as_ref() {
73                Select {
74                    distinct: Distinct::All,
75                    projection,
76                    from,
77                    lateral_views,
78                    selection: None,
79                    group_by,
80                    having: None,
81                    window,
82                } if projection.len() == 1
83                    && from.is_empty()
84                    && lateral_views.is_empty()
85                    && group_by.is_empty()
86                    && window.is_empty() =>
87                {
88                    match &projection[0] {
89                        SelectItem::UnnamedExpr(expr) => Some(expr),
90                        SelectItem::ExprWithAlias { expr, .. } => Some(expr),
91                        _ => None,
92                    }
93                }
94                _ => None,
95            },
96            _ => None,
97        }
98    }
99}
100
101impl fmt::Display for Query {
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        if let Some(ref with) = self.with {
104            write!(f, "{} ", with)?;
105        }
106        write!(f, "{}", self.body)?;
107        if !self.order_by.is_empty() {
108            write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
109        }
110        if let Some(ref limit) = self.limit {
111            write!(f, " LIMIT {}", limit)?;
112        }
113        if let Some(ref offset) = self.offset {
114            write!(f, " OFFSET {}", offset)?;
115        }
116        if let Some(ref fetch) = self.fetch {
117            write!(f, " {}", fetch)?;
118        }
119        Ok(())
120    }
121}
122
123/// A node in a tree, representing a "query body" expression, roughly:
124/// `SELECT ... [ {UNION|EXCEPT|INTERSECT} SELECT ...]`
125#[allow(clippy::large_enum_variant)]
126#[derive(Debug, Clone, PartialEq, Eq, Hash)]
127#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
128pub enum SetExpr {
129    /// Restricted SELECT .. FROM .. HAVING (no ORDER BY or set operations)
130    Select(Box<Select>),
131    /// Parenthesized SELECT subquery, which may include more set operations
132    /// in its body and an optional ORDER BY / LIMIT.
133    Query(Box<Query>),
134    /// UNION/EXCEPT/INTERSECT of two queries
135    SetOperation {
136        op: SetOperator,
137        all: bool,
138        corresponding: Corresponding,
139        left: Box<SetExpr>,
140        right: Box<SetExpr>,
141    },
142    Values(Values),
143}
144
145impl fmt::Display for SetExpr {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        match self {
148            SetExpr::Select(s) => write!(f, "{}", s),
149            SetExpr::Query(q) => write!(f, "({})", q),
150            SetExpr::Values(v) => write!(f, "{}", v),
151            SetExpr::SetOperation {
152                left,
153                right,
154                op,
155                all,
156                corresponding,
157            } => {
158                let all_str = if *all { " ALL" } else { "" };
159                write!(f, "{} {}{}{} {}", left, op, all_str, corresponding, right)
160            }
161        }
162    }
163}
164
165#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
166#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
167pub enum SetOperator {
168    Union,
169    Except,
170    Intersect,
171}
172
173impl fmt::Display for SetOperator {
174    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175        f.write_str(match self {
176            SetOperator::Union => "UNION",
177            SetOperator::Except => "EXCEPT",
178            SetOperator::Intersect => "INTERSECT",
179        })
180    }
181}
182
183#[derive(Debug, Clone, PartialEq, Eq, Hash)]
184#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
185/// `CORRESPONDING [ BY <left paren> <corresponding column list> <right paren> ]`
186pub struct Corresponding {
187    pub corresponding: bool,
188    pub column_list: Option<Vec<Ident>>,
189}
190
191impl Corresponding {
192    pub fn with_column_list(column_list: Option<Vec<Ident>>) -> Self {
193        Self {
194            corresponding: true,
195            column_list,
196        }
197    }
198
199    pub fn none() -> Self {
200        Self {
201            corresponding: false,
202            column_list: None,
203        }
204    }
205
206    pub fn is_corresponding(&self) -> bool {
207        self.corresponding
208    }
209
210    pub fn column_list(&self) -> Option<&[Ident]> {
211        self.column_list.as_deref()
212    }
213}
214
215impl fmt::Display for Corresponding {
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        if self.corresponding {
218            write!(f, " CORRESPONDING")?;
219            if let Some(column_list) = &self.column_list {
220                write!(f, " BY ({})", display_comma_separated(column_list))?;
221            }
222        }
223        Ok(())
224    }
225}
226
227/// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may
228/// appear either as the only body item of an `SQLQuery`, or as an operand
229/// to a set operation like `UNION`.
230#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
231#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
232pub struct Select {
233    pub distinct: Distinct,
234    /// projection expressions
235    pub projection: Vec<SelectItem>,
236    /// FROM
237    pub from: Vec<TableWithJoins>,
238    /// LATERAL VIEWs
239    pub lateral_views: Vec<LateralView>,
240    /// WHERE
241    pub selection: Option<Expr>,
242    /// GROUP BY
243    pub group_by: Vec<Expr>,
244    /// HAVING
245    pub having: Option<Expr>,
246    /// WINDOW
247    pub window: Vec<NamedWindow>,
248}
249
250impl fmt::Display for Select {
251    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252        write!(f, "SELECT{}", &self.distinct)?;
253        write!(f, " {}", display_comma_separated(&self.projection))?;
254        if !self.from.is_empty() {
255            write!(f, " FROM {}", display_comma_separated(&self.from))?;
256        }
257        if !self.lateral_views.is_empty() {
258            for lv in &self.lateral_views {
259                write!(f, "{}", lv)?;
260            }
261        }
262        if let Some(ref selection) = self.selection {
263            write!(f, " WHERE {}", selection)?;
264        }
265        if !self.group_by.is_empty() {
266            write!(f, " GROUP BY {}", display_comma_separated(&self.group_by))?;
267        }
268        if let Some(ref having) = self.having {
269            write!(f, " HAVING {}", having)?;
270        }
271        if !self.window.is_empty() {
272            write!(f, " WINDOW {}", display_comma_separated(&self.window))?;
273        }
274        Ok(())
275    }
276}
277
278/// An `ALL`, `DISTINCT` or `DISTINCT ON (expr, ...)` after `SELECT`.
279#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
280#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
281#[expect(clippy::enum_variant_names)]
282pub enum Distinct {
283    /// An optional parameter that returns all matching rows.
284    #[default]
285    All,
286    /// A parameter that removes duplicates from the result-set.
287    Distinct,
288    /// An optional parameter that eliminates duplicate data based on the expressions.
289    DistinctOn(Vec<Expr>),
290}
291
292impl Distinct {
293    pub const fn is_all(&self) -> bool {
294        matches!(self, Distinct::All)
295    }
296
297    pub const fn is_distinct(&self) -> bool {
298        matches!(self, Distinct::Distinct)
299    }
300}
301
302impl fmt::Display for Distinct {
303    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304        match self {
305            Distinct::All => write!(f, ""),
306            Distinct::Distinct => write!(f, " DISTINCT"),
307            Distinct::DistinctOn(exprs) => {
308                write!(f, " DISTINCT ON ({})", display_comma_separated(exprs))
309            }
310        }
311    }
312}
313
314/// A hive LATERAL VIEW with potential column aliases
315#[derive(Debug, Clone, PartialEq, Eq, Hash)]
316#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
317pub struct LateralView {
318    /// LATERAL VIEW
319    pub lateral_view: Expr,
320    /// LATERAL VIEW table name
321    pub lateral_view_name: ObjectName,
322    /// LATERAL VIEW optional column aliases
323    pub lateral_col_alias: Vec<Ident>,
324    /// LATERAL VIEW OUTER
325    pub outer: bool,
326}
327
328impl fmt::Display for LateralView {
329    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
330        write!(
331            f,
332            " LATERAL VIEW{outer} {} {}",
333            self.lateral_view,
334            self.lateral_view_name,
335            outer = if self.outer { " OUTER" } else { "" }
336        )?;
337        if !self.lateral_col_alias.is_empty() {
338            write!(
339                f,
340                " AS {}",
341                display_comma_separated(&self.lateral_col_alias)
342            )?;
343        }
344        Ok(())
345    }
346}
347
348#[derive(Debug, Clone, PartialEq, Eq, Hash)]
349#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
350pub struct With {
351    pub recursive: bool,
352    pub cte_tables: Vec<Cte>,
353}
354
355impl fmt::Display for With {
356    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
357        write!(
358            f,
359            "WITH {}{}",
360            if self.recursive { "RECURSIVE " } else { "" },
361            display_comma_separated(&self.cte_tables)
362        )
363    }
364}
365
366/// A single CTE (used after `WITH`): `alias [(col1, col2, ...)] AS ( query )`
367///
368/// The names in the column list before `AS`, when specified, replace the names
369/// of the columns returned by the query. The parser does not validate that the
370/// number of columns in the query matches the number of columns in the query.
371#[derive(Debug, Clone, PartialEq, Eq, Hash)]
372#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
373pub struct Cte {
374    pub alias: TableAlias,
375    pub cte_inner: CteInner,
376}
377
378impl fmt::Display for Cte {
379    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380        match &self.cte_inner {
381            CteInner::Query(query) => write!(f, "{} AS ({})", self.alias, query)?,
382            CteInner::ChangeLog(obj_name) => {
383                write!(f, "{} AS changelog from {}", self.alias, obj_name)?
384            }
385        }
386        Ok(())
387    }
388}
389
390#[derive(Debug, Clone, PartialEq, Eq, Hash)]
391#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
392pub enum CteInner {
393    Query(Box<Query>),
394    ChangeLog(ObjectName),
395}
396
397/// One item of the comma-separated list following `SELECT`
398#[derive(Debug, Clone, PartialEq, Eq, Hash)]
399#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
400pub enum SelectItem {
401    /// Any expression, not followed by `[ AS ] alias`
402    UnnamedExpr(Expr),
403    /// Expr is an arbitrary expression, returning either a table or a column.
404    /// Idents are the prefix of `*`, which are consecutive field accesses.
405    /// e.g. `(table.v1).*` or `(table).v1.*`
406    ExprQualifiedWildcard(Expr, Vec<Ident>),
407    /// An expression, followed by `[ AS ] alias`
408    ExprWithAlias { expr: Expr, alias: Ident },
409    /// `alias.*` or even `schema.table.*` followed by optional except
410    QualifiedWildcard(ObjectName, Option<Vec<Expr>>),
411    /// An unqualified `*`, or `* except (exprs)`
412    Wildcard(Option<Vec<Expr>>),
413}
414
415impl fmt::Display for SelectItem {
416    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
417        match &self {
418            SelectItem::UnnamedExpr(expr) => write!(f, "{}", expr),
419            SelectItem::ExprWithAlias { expr, alias } => write!(f, "{} AS {}", expr, alias),
420            SelectItem::ExprQualifiedWildcard(expr, prefix) => write!(
421                f,
422                "({}){}.*",
423                expr,
424                prefix
425                    .iter()
426                    .format_with("", |i, f| f(&format_args!(".{i}")))
427            ),
428            SelectItem::QualifiedWildcard(prefix, except) => match except {
429                Some(cols) => write!(
430                    f,
431                    "{}.* EXCEPT ({})",
432                    prefix,
433                    cols.iter()
434                        .map(|v| v.to_string())
435                        .collect::<Vec<String>>()
436                        .as_slice()
437                        .join(", ")
438                ),
439                None => write!(f, "{}.*", prefix),
440            },
441            SelectItem::Wildcard(except) => match except {
442                Some(cols) => write!(
443                    f,
444                    "* EXCEPT ({})",
445                    cols.iter()
446                        .map(|v| v.to_string())
447                        .collect::<Vec<String>>()
448                        .as_slice()
449                        .join(", ")
450                ),
451                None => write!(f, "*"),
452            },
453        }
454    }
455}
456
457#[derive(Debug, Clone, PartialEq, Eq, Hash)]
458#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
459pub struct TableWithJoins {
460    pub relation: TableFactor,
461    pub joins: Vec<Join>,
462}
463
464impl fmt::Display for TableWithJoins {
465    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
466        write!(f, "{}", self.relation)?;
467        for join in &self.joins {
468            write!(f, "{}", join)?;
469        }
470        Ok(())
471    }
472}
473
474/// A table name or a parenthesized subquery with an optional alias
475#[derive(Debug, Clone, PartialEq, Eq, Hash)]
476#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
477pub enum TableFactor {
478    Table {
479        name: ObjectName,
480        alias: Option<TableAlias>,
481        as_of: Option<AsOf>,
482    },
483    Derived {
484        lateral: bool,
485        subquery: Box<Query>,
486        alias: Option<TableAlias>,
487    },
488    /// `<expr>(args)[ AS <alias> ]`
489    ///
490    /// Note that scalar functions can also be used in this way.
491    TableFunction {
492        name: ObjectName,
493        alias: Option<TableAlias>,
494        args: Vec<FunctionArg>,
495        with_ordinality: bool,
496    },
497    /// Represents a parenthesized table factor. The SQL spec only allows a
498    /// join expression (`(foo <JOIN> bar [ <JOIN> baz ... ])`) to be nested,
499    /// possibly several times.
500    ///
501    /// The parser may also accept non-standard nesting of bare tables for some
502    /// dialects, but the information about such nesting is stripped from AST.
503    NestedJoin(Box<TableWithJoins>),
504}
505
506impl fmt::Display for TableFactor {
507    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
508        match self {
509            TableFactor::Table { name, alias, as_of } => {
510                write!(f, "{}", name)?;
511                if let Some(as_of) = as_of {
512                    write!(f, "{}", as_of)?
513                }
514                if let Some(alias) = alias {
515                    write!(f, " AS {}", alias)?;
516                }
517                Ok(())
518            }
519            TableFactor::Derived {
520                lateral,
521                subquery,
522                alias,
523            } => {
524                if *lateral {
525                    write!(f, "LATERAL ")?;
526                }
527                write!(f, "({})", subquery)?;
528                if let Some(alias) = alias {
529                    write!(f, " AS {}", alias)?;
530                }
531                Ok(())
532            }
533            TableFactor::TableFunction {
534                name,
535                alias,
536                args,
537                with_ordinality,
538            } => {
539                write!(f, "{}({})", name, display_comma_separated(args))?;
540                if *with_ordinality {
541                    write!(f, " WITH ORDINALITY")?;
542                }
543                if let Some(alias) = alias {
544                    write!(f, " AS {}", alias)?;
545                }
546                Ok(())
547            }
548            TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference),
549        }
550    }
551}
552
553#[derive(Debug, Clone, PartialEq, Eq, Hash)]
554#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
555pub struct TableAlias {
556    pub name: Ident,
557    pub columns: Vec<Ident>,
558}
559
560impl fmt::Display for TableAlias {
561    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
562        write!(f, "{}", self.name)?;
563        if !self.columns.is_empty() {
564            write!(f, " ({})", display_comma_separated(&self.columns))?;
565        }
566        Ok(())
567    }
568}
569
570#[derive(Debug, Clone, PartialEq, Eq, Hash)]
571#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
572pub struct Join {
573    pub relation: TableFactor,
574    pub join_operator: JoinOperator,
575}
576
577impl fmt::Display for Join {
578    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
579        fn prefix(constraint: &JoinConstraint) -> &'static str {
580            match constraint {
581                JoinConstraint::Natural => "NATURAL ",
582                _ => "",
583            }
584        }
585        fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
586            struct Suffix<'a>(&'a JoinConstraint);
587            impl fmt::Display for Suffix<'_> {
588                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
589                    match self.0 {
590                        JoinConstraint::On(expr) => write!(f, " ON {}", expr),
591                        JoinConstraint::Using(attrs) => {
592                            write!(f, " USING({})", display_comma_separated(attrs))
593                        }
594                        _ => Ok(()),
595                    }
596                }
597            }
598            Suffix(constraint)
599        }
600        match &self.join_operator {
601            JoinOperator::Inner(constraint) => write!(
602                f,
603                " {}JOIN {}{}",
604                prefix(constraint),
605                self.relation,
606                suffix(constraint)
607            ),
608            JoinOperator::LeftOuter(constraint) => write!(
609                f,
610                " {}LEFT JOIN {}{}",
611                prefix(constraint),
612                self.relation,
613                suffix(constraint)
614            ),
615            JoinOperator::RightOuter(constraint) => write!(
616                f,
617                " {}RIGHT JOIN {}{}",
618                prefix(constraint),
619                self.relation,
620                suffix(constraint)
621            ),
622            JoinOperator::FullOuter(constraint) => write!(
623                f,
624                " {}FULL JOIN {}{}",
625                prefix(constraint),
626                self.relation,
627                suffix(constraint)
628            ),
629            JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
630            JoinOperator::AsOfInner(constraint) => write!(
631                f,
632                " {}ASOF JOIN {}{}",
633                prefix(constraint),
634                self.relation,
635                suffix(constraint)
636            ),
637            JoinOperator::AsOfLeft(constraint) => write!(
638                f,
639                " {}ASOF LEFT JOIN {}{}",
640                prefix(constraint),
641                self.relation,
642                suffix(constraint)
643            ),
644        }
645    }
646}
647
648#[derive(Debug, Clone, PartialEq, Eq, Hash)]
649#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
650pub enum JoinOperator {
651    Inner(JoinConstraint),
652    LeftOuter(JoinConstraint),
653    RightOuter(JoinConstraint),
654    FullOuter(JoinConstraint),
655    CrossJoin,
656    AsOfInner(JoinConstraint),
657    AsOfLeft(JoinConstraint),
658}
659
660#[derive(Debug, Clone, PartialEq, Eq, Hash)]
661#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
662pub enum JoinConstraint {
663    On(Expr),
664    Using(Vec<Ident>),
665    Natural,
666    None,
667}
668
669/// An `ORDER BY` expression
670#[derive(Debug, Clone, PartialEq, Eq, Hash)]
671#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
672pub struct OrderByExpr {
673    pub expr: Expr,
674    /// Optional `ASC` or `DESC`
675    pub asc: Option<bool>,
676    /// Optional `NULLS FIRST` or `NULLS LAST`
677    pub nulls_first: Option<bool>,
678}
679
680impl fmt::Display for OrderByExpr {
681    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
682        write!(f, "{}", self.expr)?;
683        match self.asc {
684            Some(true) => write!(f, " ASC")?,
685            Some(false) => write!(f, " DESC")?,
686            None => (),
687        }
688        match self.nulls_first {
689            Some(true) => write!(f, " NULLS FIRST")?,
690            Some(false) => write!(f, " NULLS LAST")?,
691            None => (),
692        }
693        Ok(())
694    }
695}
696
697#[derive(Debug, Clone, PartialEq, Eq, Hash)]
698#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
699pub struct Fetch {
700    pub with_ties: bool,
701    pub quantity: Option<String>,
702}
703
704impl fmt::Display for Fetch {
705    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
706        let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
707        if let Some(ref quantity) = self.quantity {
708            write!(f, "FETCH FIRST {} ROWS {}", quantity, extension)
709        } else {
710            write!(f, "FETCH FIRST ROWS {}", extension)
711        }
712    }
713}
714
715#[derive(Debug, Clone, PartialEq, Eq, Hash)]
716#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
717pub struct Top {
718    /// SQL semantic equivalent of LIMIT but with same structure as FETCH.
719    pub with_ties: bool,
720    pub percent: bool,
721    pub quantity: Option<Expr>,
722}
723
724impl fmt::Display for Top {
725    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
726        let extension = if self.with_ties { " WITH TIES" } else { "" };
727        if let Some(ref quantity) = self.quantity {
728            let percent = if self.percent { " PERCENT" } else { "" };
729            write!(f, "TOP ({}){}{}", quantity, percent, extension)
730        } else {
731            write!(f, "TOP{}", extension)
732        }
733    }
734}
735
736#[derive(Debug, Clone, PartialEq, Eq, Hash)]
737#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
738pub struct Values(pub Vec<Vec<Expr>>);
739
740impl fmt::Display for Values {
741    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
742        write!(f, "VALUES ")?;
743        let mut delim = "";
744        for row in &self.0 {
745            write!(f, "{}", delim)?;
746            delim = ", ";
747            write!(f, "({})", display_comma_separated(row))?;
748        }
749        Ok(())
750    }
751}
752
753/// A named window definition in the WINDOW clause
754#[derive(Debug, Clone, PartialEq, Eq, Hash)]
755#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
756pub struct NamedWindow {
757    pub name: Ident,
758    pub window_spec: WindowSpec,
759}
760
761impl fmt::Display for NamedWindow {
762    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
763        write!(f, "{} AS ({})", self.name, self.window_spec)
764    }
765}