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