wing_sqlparser/ast/
mod.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//! SQL Abstract Syntax Tree (AST) types
14mod data_type;
15mod ddl;
16mod operator;
17mod query;
18mod value;
19
20#[cfg(not(feature = "std"))]
21use alloc::{
22    boxed::Box,
23    string::{String, ToString},
24    vec::Vec,
25};
26use core::fmt;
27
28#[cfg(feature = "serde")]
29use serde::{Deserialize, Serialize};
30
31pub use self::data_type::DataType;
32pub use self::ddl::{
33    AlterColumnOperation, AlterTableOperation, ColumnDef, ColumnOption, ColumnOptionDef,
34    ReferentialAction, TableConstraint,
35};
36pub use self::operator::{BinaryOperator, UnaryOperator};
37pub use self::query::{
38    Cte, Fetch, Join, JoinConstraint, JoinOperator, LateralView, LockType, Offset, OffsetRows,
39    OrderByExpr, Query, Select, SelectItem, SetExpr, SetOperator, TableAlias, TableFactor,
40    TableWithJoins, Top, Values, With,
41};
42pub use self::value::{DateTimeField, TrimWhereField, Value};
43
44struct DisplaySeparated<'a, T>
45where
46    T: fmt::Display,
47{
48    slice: &'a [T],
49    sep: &'static str,
50}
51
52impl<'a, T> fmt::Display for DisplaySeparated<'a, T>
53where
54    T: fmt::Display,
55{
56    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57        let mut delim = "";
58        for t in self.slice {
59            write!(f, "{}", delim)?;
60            delim = self.sep;
61            write!(f, "{}", t)?;
62        }
63        Ok(())
64    }
65}
66
67fn display_separated<'a, T>(slice: &'a [T], sep: &'static str) -> DisplaySeparated<'a, T>
68where
69    T: fmt::Display,
70{
71    DisplaySeparated { slice, sep }
72}
73
74fn display_comma_separated<T>(slice: &[T]) -> DisplaySeparated<'_, T>
75where
76    T: fmt::Display,
77{
78    DisplaySeparated { slice, sep: ", " }
79}
80
81/// An identifier, decomposed into its value or character data and the quote style.
82#[derive(Debug, Clone, PartialEq, Eq, Hash)]
83#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
84pub struct Ident {
85    /// The value of the identifier without quotes.
86    pub value: String,
87    /// The starting quote if any. Valid quote characters are the single quote,
88    /// double quote, backtick, and opening square bracket.
89    pub quote_style: Option<char>,
90}
91
92impl Ident {
93    /// Create a new identifier with the given value and no quotes.
94    pub fn new<S>(value: S) -> Self
95    where
96        S: Into<String>,
97    {
98        Ident {
99            value: value.into(),
100            quote_style: None,
101        }
102    }
103
104    /// Create a new quoted identifier with the given quote and value. This function
105    /// panics if the given quote is not a valid quote character.
106    pub fn with_quote<S>(quote: char, value: S) -> Self
107    where
108        S: Into<String>,
109    {
110        assert!(quote == '\'' || quote == '"' || quote == '`' || quote == '[');
111        Ident {
112            value: value.into(),
113            quote_style: Some(quote),
114        }
115    }
116}
117
118impl From<&str> for Ident {
119    fn from(value: &str) -> Self {
120        Ident {
121            value: value.to_string(),
122            quote_style: None,
123        }
124    }
125}
126
127impl fmt::Display for Ident {
128    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129        match self.quote_style {
130            Some(q) if q == '"' || q == '\'' || q == '`' => write!(f, "{}{}{}", q, self.value, q),
131            Some(q) if q == '[' => write!(f, "[{}]", self.value),
132            None => f.write_str(&self.value),
133            _ => panic!("unexpected quote style"),
134        }
135    }
136}
137
138/// A name of a table, view, custom type, etc., possibly multi-part, i.e. db.schema.obj
139#[derive(Debug, Clone, PartialEq, Eq, Hash)]
140#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
141pub struct ObjectName(pub Vec<Ident>);
142
143impl fmt::Display for ObjectName {
144    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145        write!(f, "{}", display_separated(&self.0, "."))
146    }
147}
148
149/// An SQL expression of any type.
150///
151/// The parser does not distinguish between expressions of different types
152/// (e.g. boolean vs string), so the caller must handle expressions of
153/// inappropriate type, like `WHERE 1` or `SELECT 1=1`, as necessary.
154#[derive(Debug, Clone, PartialEq, Eq, Hash)]
155#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
156pub enum Expr {
157    /// Identifier e.g. table name or column name
158    Identifier(Ident),
159    /// Multi-part identifier, e.g. `table_alias.column` or `schema.table.col`
160    CompoundIdentifier(Vec<Ident>),
161    /// `IS NULL` operator
162    IsNull(Box<Expr>),
163    /// `IS NOT NULL` operator
164    IsNotNull(Box<Expr>),
165    /// `IS DISTINCT FROM` operator
166    IsDistinctFrom(Box<Expr>, Box<Expr>),
167    /// `IS NOT DISTINCT FROM` operator
168    IsNotDistinctFrom(Box<Expr>, Box<Expr>),
169    /// `[ NOT ] IN (val1, val2, ...)`
170    InList {
171        expr: Box<Expr>,
172        list: Vec<Expr>,
173        negated: bool,
174    },
175    /// `[ NOT ] IN (SELECT ...)`
176    InSubquery {
177        expr: Box<Expr>,
178        subquery: Box<Query>,
179        negated: bool,
180    },
181    /// `<expr> [ NOT ] BETWEEN <low> AND <high>`
182    Between {
183        expr: Box<Expr>,
184        negated: bool,
185        low: Box<Expr>,
186        high: Box<Expr>,
187    },
188    /// Binary operation e.g. `1 + 1` or `foo > bar`
189    BinaryOp {
190        left: Box<Expr>,
191        op: BinaryOperator,
192        right: Box<Expr>,
193    },
194    /// Unary operation e.g. `NOT foo`
195    UnaryOp {
196        op: UnaryOperator,
197        expr: Box<Expr>,
198    },
199    /// CAST an expression to a different data type e.g. `CAST(foo AS VARCHAR(123))`
200    Cast {
201        expr: Box<Expr>,
202        data_type: DataType,
203    },
204    /// TRY_CAST an expression to a different data type e.g. `TRY_CAST(foo AS VARCHAR(123))`
205    //  this differs from CAST in the choice of how to implement invalid conversions
206    TryCast {
207        expr: Box<Expr>,
208        data_type: DataType,
209    },
210    /// EXTRACT(DateTimeField FROM <expr>)
211    Extract {
212        field: DateTimeField,
213        expr: Box<Expr>,
214    },
215    /// SUBSTRING(<expr> [FROM <expr>] [FOR <expr>])
216    Substring {
217        expr: Box<Expr>,
218        substring_from: Option<Box<Expr>>,
219        substring_for: Option<Box<Expr>>,
220    },
221    /// TRIM([BOTH | LEADING | TRAILING] <expr> [FROM <expr>])\
222    /// Or\
223    /// TRIM(<expr>)
224    Trim {
225        expr: Box<Expr>,
226        // ([BOTH | LEADING | TRAILING], <expr>)
227        trim_where: Option<(TrimWhereField, Box<Expr>)>,
228    },
229    /// `expr COLLATE collation`
230    Collate {
231        expr: Box<Expr>,
232        collation: ObjectName,
233    },
234    /// Nested expression e.g. `(foo > bar)` or `(1)`
235    Nested(Box<Expr>),
236    /// A literal value, such as string, number, date or NULL
237    Value(Value),
238    /// A constant of form `<data_type> 'value'`.
239    /// This can represent ANSI SQL `DATE`, `TIME`, and `TIMESTAMP` literals (such as `DATE '2020-01-01'`),
240    /// as well as constants of other types (a non-standard PostgreSQL extension).
241    TypedString {
242        data_type: DataType,
243        value: String,
244    },
245    MapAccess {
246        column: Box<Expr>,
247        keys: Vec<Expr>,
248    },
249    /// Scalar function call e.g. `LEFT(foo, 5)`
250    Function(Function),
251    /// `CASE [<operand>] WHEN <condition> THEN <result> ... [ELSE <result>] END`
252    ///
253    /// Note we only recognize a complete single expression as `<condition>`,
254    /// not `< 0` nor `1, 2, 3` as allowed in a `<simple when clause>` per
255    /// <https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#simple-when-clause>
256    Case {
257        operand: Option<Box<Expr>>,
258        conditions: Vec<Expr>,
259        results: Vec<Expr>,
260        else_result: Option<Box<Expr>>,
261    },
262    /// An exists expression `EXISTS(SELECT ...)`, used in expressions like
263    /// `WHERE EXISTS (SELECT ...)`.
264    Exists(Box<Query>),
265    /// A parenthesized subquery `(SELECT ...)`, used in expression like
266    /// `SELECT (subquery) AS x` or `WHERE (subquery) = x`
267    Subquery(Box<Query>),
268    /// The `LISTAGG` function `SELECT LISTAGG(...) WITHIN GROUP (ORDER BY ...)`
269    ListAgg(ListAgg),
270    /// The `GROUPING SETS` expr.
271    GroupingSets(Vec<Vec<Expr>>),
272    /// The `CUBE` expr.
273    Cube(Vec<Vec<Expr>>),
274    /// The `ROLLUP` expr.
275    Rollup(Vec<Vec<Expr>>),
276}
277
278impl fmt::Display for Expr {
279    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
280        match self {
281            Expr::Identifier(s) => write!(f, "{}", s),
282            Expr::MapAccess { column, keys } => {
283                write!(f, "{}", column)?;
284                for k in keys {
285                    match k {
286                        k @ Expr::Value(Value::Number(_, _)) => write!(f, "[{}]", k)?,
287                        Expr::Value(Value::SingleQuotedString(s)) => write!(f, "[\"{}\"]", s)?,
288                        _ => write!(f, "[{}]", k)?,
289                    }
290                }
291                Ok(())
292            }
293            Expr::CompoundIdentifier(s) => write!(f, "{}", display_separated(s, ".")),
294            Expr::IsNull(ast) => write!(f, "{} IS NULL", ast),
295            Expr::IsNotNull(ast) => write!(f, "{} IS NOT NULL", ast),
296            Expr::InList {
297                expr,
298                list,
299                negated,
300            } => write!(
301                f,
302                "{} {}IN ({})",
303                expr,
304                if *negated { "NOT " } else { "" },
305                display_comma_separated(list)
306            ),
307            Expr::InSubquery {
308                expr,
309                subquery,
310                negated,
311            } => write!(
312                f,
313                "{} {}IN ({})",
314                expr,
315                if *negated { "NOT " } else { "" },
316                subquery
317            ),
318            Expr::Between {
319                expr,
320                negated,
321                low,
322                high,
323            } => write!(
324                f,
325                "{} {}BETWEEN {} AND {}",
326                expr,
327                if *negated { "NOT " } else { "" },
328                low,
329                high
330            ),
331            Expr::BinaryOp { left, op, right } => write!(f, "{} {} {}", left, op, right),
332            Expr::UnaryOp { op, expr } => {
333                if op == &UnaryOperator::PGPostfixFactorial {
334                    write!(f, "{}{}", expr, op)
335                } else {
336                    write!(f, "{} {}", op, expr)
337                }
338            }
339            Expr::Cast { expr, data_type } => write!(f, "CAST({} AS {})", expr, data_type),
340            Expr::TryCast { expr, data_type } => write!(f, "TRY_CAST({} AS {})", expr, data_type),
341            Expr::Extract { field, expr } => write!(f, "EXTRACT({} FROM {})", field, expr),
342            Expr::Collate { expr, collation } => write!(f, "{} COLLATE {}", expr, collation),
343            Expr::Nested(ast) => write!(f, "({})", ast),
344            Expr::Value(v) => write!(f, "{}", v),
345            Expr::TypedString { data_type, value } => {
346                write!(f, "{}", data_type)?;
347                write!(f, " '{}'", &value::escape_single_quote_string(value))
348            }
349            Expr::Function(fun) => write!(f, "{}", fun),
350            Expr::Case {
351                operand,
352                conditions,
353                results,
354                else_result,
355            } => {
356                write!(f, "CASE")?;
357                if let Some(operand) = operand {
358                    write!(f, " {}", operand)?;
359                }
360                for (c, r) in conditions.iter().zip(results) {
361                    write!(f, " WHEN {} THEN {}", c, r)?;
362                }
363
364                if let Some(else_result) = else_result {
365                    write!(f, " ELSE {}", else_result)?;
366                }
367                write!(f, " END")
368            }
369            Expr::Exists(s) => write!(f, "EXISTS ({})", s),
370            Expr::Subquery(s) => write!(f, "({})", s),
371            Expr::ListAgg(listagg) => write!(f, "{}", listagg),
372            Expr::GroupingSets(sets) => {
373                write!(f, "GROUPING SETS (")?;
374                let mut sep = "";
375                for set in sets {
376                    write!(f, "{}", sep)?;
377                    sep = ", ";
378                    write!(f, "({})", display_comma_separated(set))?;
379                }
380                write!(f, ")")
381            }
382            Expr::Cube(sets) => {
383                write!(f, "CUBE (")?;
384                let mut sep = "";
385                for set in sets {
386                    write!(f, "{}", sep)?;
387                    sep = ", ";
388                    if set.len() == 1 {
389                        write!(f, "{}", set[0])?;
390                    } else {
391                        write!(f, "({})", display_comma_separated(set))?;
392                    }
393                }
394                write!(f, ")")
395            }
396            Expr::Rollup(sets) => {
397                write!(f, "ROLLUP (")?;
398                let mut sep = "";
399                for set in sets {
400                    write!(f, "{}", sep)?;
401                    sep = ", ";
402                    if set.len() == 1 {
403                        write!(f, "{}", set[0])?;
404                    } else {
405                        write!(f, "({})", display_comma_separated(set))?;
406                    }
407                }
408                write!(f, ")")
409            }
410            Expr::Substring {
411                expr,
412                substring_from,
413                substring_for,
414            } => {
415                write!(f, "SUBSTRING({}", expr)?;
416                if let Some(from_part) = substring_from {
417                    write!(f, " FROM {}", from_part)?;
418                }
419                if let Some(from_part) = substring_for {
420                    write!(f, " FOR {}", from_part)?;
421                }
422
423                write!(f, ")")
424            }
425            Expr::IsDistinctFrom(a, b) => write!(f, "{} IS DISTINCT FROM {}", a, b),
426            Expr::IsNotDistinctFrom(a, b) => write!(f, "{} IS NOT DISTINCT FROM {}", a, b),
427            Expr::Trim { expr, trim_where } => {
428                write!(f, "TRIM(")?;
429                if let Some((ident, trim_char)) = trim_where {
430                    write!(f, "{} {} FROM {}", ident, trim_char, expr)?;
431                } else {
432                    write!(f, "{}", expr)?;
433                }
434
435                write!(f, ")")
436            }
437        }
438    }
439}
440
441/// A window specification (i.e. `OVER (PARTITION BY .. ORDER BY .. etc.)`)
442#[derive(Debug, Clone, PartialEq, Eq, Hash)]
443#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
444pub struct WindowSpec {
445    pub partition_by: Vec<Expr>,
446    pub order_by: Vec<OrderByExpr>,
447    pub window_frame: Option<WindowFrame>,
448}
449
450impl fmt::Display for WindowSpec {
451    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
452        let mut delim = "";
453        if !self.partition_by.is_empty() {
454            delim = " ";
455            write!(
456                f,
457                "PARTITION BY {}",
458                display_comma_separated(&self.partition_by)
459            )?;
460        }
461        if !self.order_by.is_empty() {
462            f.write_str(delim)?;
463            delim = " ";
464            write!(f, "ORDER BY {}", display_comma_separated(&self.order_by))?;
465        }
466        if let Some(window_frame) = &self.window_frame {
467            f.write_str(delim)?;
468            if let Some(end_bound) = &window_frame.end_bound {
469                write!(
470                    f,
471                    "{} BETWEEN {} AND {}",
472                    window_frame.units, window_frame.start_bound, end_bound
473                )?;
474            } else {
475                write!(f, "{} {}", window_frame.units, window_frame.start_bound)?;
476            }
477        }
478        Ok(())
479    }
480}
481
482/// Specifies the data processed by a window function, e.g.
483/// `RANGE UNBOUNDED PRECEDING` or `ROWS BETWEEN 5 PRECEDING AND CURRENT ROW`.
484///
485/// Note: The parser does not validate the specified bounds; the caller should
486/// reject invalid bounds like `ROWS UNBOUNDED FOLLOWING` before execution.
487#[derive(Debug, Clone, PartialEq, Eq, Hash)]
488#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
489pub struct WindowFrame {
490    pub units: WindowFrameUnits,
491    pub start_bound: WindowFrameBound,
492    /// The right bound of the `BETWEEN .. AND` clause. The end bound of `None`
493    /// indicates the shorthand form (e.g. `ROWS 1 PRECEDING`), which must
494    /// behave the same as `end_bound = WindowFrameBound::CurrentRow`.
495    pub end_bound: Option<WindowFrameBound>,
496    // TBD: EXCLUDE
497}
498
499impl Default for WindowFrame {
500    /// returns default value for window frame
501    ///
502    /// see https://www.sqlite.org/windowfunctions.html#frame_specifications
503    fn default() -> Self {
504        Self {
505            units: WindowFrameUnits::Range,
506            start_bound: WindowFrameBound::Preceding(None),
507            end_bound: None,
508        }
509    }
510}
511
512#[derive(Debug, Clone, PartialEq, Eq, Hash)]
513#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
514pub enum WindowFrameUnits {
515    Rows,
516    Range,
517    Groups,
518}
519
520impl fmt::Display for WindowFrameUnits {
521    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
522        f.write_str(match self {
523            WindowFrameUnits::Rows => "ROWS",
524            WindowFrameUnits::Range => "RANGE",
525            WindowFrameUnits::Groups => "GROUPS",
526        })
527    }
528}
529
530/// Specifies [WindowFrame]'s `start_bound` and `end_bound`
531#[derive(Debug, Clone, PartialEq, Eq, Hash)]
532#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
533pub enum WindowFrameBound {
534    /// `CURRENT ROW`
535    CurrentRow,
536    /// `<N> PRECEDING` or `UNBOUNDED PRECEDING`
537    Preceding(Option<u64>),
538    /// `<N> FOLLOWING` or `UNBOUNDED FOLLOWING`.
539    Following(Option<u64>),
540}
541
542impl fmt::Display for WindowFrameBound {
543    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
544        match self {
545            WindowFrameBound::CurrentRow => f.write_str("CURRENT ROW"),
546            WindowFrameBound::Preceding(None) => f.write_str("UNBOUNDED PRECEDING"),
547            WindowFrameBound::Following(None) => f.write_str("UNBOUNDED FOLLOWING"),
548            WindowFrameBound::Preceding(Some(n)) => write!(f, "{} PRECEDING", n),
549            WindowFrameBound::Following(Some(n)) => write!(f, "{} FOLLOWING", n),
550        }
551    }
552}
553
554#[derive(Debug, Clone, PartialEq, Eq, Hash)]
555#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
556pub enum AddDropSync {
557    ADD,
558    DROP,
559    SYNC,
560}
561
562impl fmt::Display for AddDropSync {
563    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
564        match self {
565            AddDropSync::SYNC => f.write_str("SYNC PARTITIONS"),
566            AddDropSync::DROP => f.write_str("DROP PARTITIONS"),
567            AddDropSync::ADD => f.write_str("ADD PARTITIONS"),
568        }
569    }
570}
571
572#[derive(Debug, Clone, PartialEq, Eq, Hash)]
573#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
574pub enum ShowCreateObject {
575    Event,
576    Function,
577    Procedure,
578    Table,
579    Trigger,
580}
581
582impl fmt::Display for ShowCreateObject {
583    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
584        match self {
585            ShowCreateObject::Event => f.write_str("EVENT"),
586            ShowCreateObject::Function => f.write_str("FUNCTION"),
587            ShowCreateObject::Procedure => f.write_str("PROCEDURE"),
588            ShowCreateObject::Table => f.write_str("TABLE"),
589            ShowCreateObject::Trigger => f.write_str("TRIGGER"),
590        }
591    }
592}
593
594#[derive(Debug, Clone, PartialEq, Eq, Hash)]
595#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
596pub enum CommentObject {
597    Column,
598    Table,
599}
600
601impl fmt::Display for CommentObject {
602    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
603        match self {
604            CommentObject::Column => f.write_str("COLUMN"),
605            CommentObject::Table => f.write_str("TABLE"),
606        }
607    }
608}
609
610/// A top-level statement (SELECT, INSERT, CREATE, etc.)
611#[allow(clippy::large_enum_variant)]
612#[derive(Debug, Clone, PartialEq, Eq, Hash)]
613#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
614pub enum Statement {
615    /// Analyze (Hive)
616    Analyze {
617        table_name: ObjectName,
618        partitions: Option<Vec<Expr>>,
619        for_columns: bool,
620        columns: Vec<Ident>,
621        cache_metadata: bool,
622        noscan: bool,
623        compute_statistics: bool,
624    },
625    /// Truncate (Hive)
626    Truncate {
627        table_name: ObjectName,
628        partitions: Option<Vec<Expr>>,
629    },
630    /// Msck (Hive)
631    Msck {
632        table_name: ObjectName,
633        repair: bool,
634        partition_action: Option<AddDropSync>,
635    },
636    /// SELECT
637    Query(Box<Query>),
638    /// INSERT
639    Insert {
640        /// Only for Sqlite
641        or: Option<SqliteOnConflict>,
642        /// TABLE
643        table_name: ObjectName,
644        /// COLUMNS
645        columns: Vec<Ident>,
646        /// Overwrite (Hive)
647        overwrite: bool,
648        /// A SQL query that specifies what to insert
649        source: Box<Query>,
650        /// partitioned insert (Hive)
651        partitioned: Option<Vec<Expr>>,
652        /// Columns defined after PARTITION
653        after_columns: Vec<Ident>,
654        /// whether the insert has the table keyword (Hive)
655        table: bool,
656        on: Option<OnInsert>,
657    },
658    // TODO: Support ROW FORMAT
659    Directory {
660        overwrite: bool,
661        local: bool,
662        path: String,
663        file_format: Option<FileFormat>,
664        source: Box<Query>,
665    },
666    Copy {
667        /// TABLE
668        table_name: ObjectName,
669        /// COLUMNS
670        columns: Vec<Ident>,
671        /// VALUES a vector of values to be copied
672        values: Vec<Option<String>>,
673    },
674    /// UPDATE
675    Update {
676        /// TABLE
677        table: TableWithJoins,
678        /// Column assignments
679        assignments: Vec<Assignment>,
680        /// WHERE
681        selection: Option<Expr>,
682    },
683    /// DELETE
684    Delete {
685        /// FROM
686        table_name: ObjectName,
687        /// WHERE
688        selection: Option<Expr>,
689    },
690    /// CREATE VIEW
691    CreateView {
692        or_replace: bool,
693        materialized: bool,
694        /// View name
695        name: ObjectName,
696        columns: Vec<Ident>,
697        query: Box<Query>,
698        with_options: Vec<SqlOption>,
699    },
700    /// CREATE TABLE
701    CreateTable {
702        or_replace: bool,
703        temporary: bool,
704        external: bool,
705        if_not_exists: bool,
706        /// Table name
707        name: ObjectName,
708        /// Optional schema
709        columns: Vec<ColumnDef>,
710        constraints: Vec<TableConstraint>,
711        hive_distribution: HiveDistributionStyle,
712        hive_formats: Option<HiveFormat>,
713        table_properties: Vec<SqlOption>,
714        with_options: Vec<SqlOption>,
715        file_format: Option<FileFormat>,
716        location: Option<String>,
717        query: Option<Box<Query>>,
718        without_rowid: bool,
719        like: Option<ObjectName>,
720    },
721    /// SQLite's `CREATE VIRTUAL TABLE .. USING <module_name> (<module_args>)`
722    CreateVirtualTable {
723        name: ObjectName,
724        if_not_exists: bool,
725        module_name: Ident,
726        module_args: Vec<Ident>,
727    },
728    /// CREATE INDEX
729    CreateIndex {
730        /// index name
731        name: ObjectName,
732        table_name: ObjectName,
733        columns: Vec<OrderByExpr>,
734        unique: bool,
735        if_not_exists: bool,
736    },
737    /// ALTER TABLE
738    AlterTable {
739        /// Table name
740        name: ObjectName,
741        operation: AlterTableOperation,
742    },
743    /// DROP
744    Drop {
745        /// The type of the object to drop: TABLE, VIEW, etc.
746        object_type: ObjectType,
747        /// An optional `IF EXISTS` clause. (Non-standard.)
748        if_exists: bool,
749        /// One or more objects to drop. (ANSI SQL requires exactly one.)
750        names: Vec<ObjectName>,
751        /// Whether `CASCADE` was specified. This will be `false` when
752        /// `RESTRICT` or no drop behavior at all was specified.
753        cascade: bool,
754        /// Hive allows you specify whether the table's stored data will be
755        /// deleted along with the dropped table
756        purge: bool,
757    },
758    /// SET <variable>
759    ///
760    /// Note: this is not a standard SQL statement, but it is supported by at
761    /// least MySQL and PostgreSQL. Not all MySQL-specific syntatic forms are
762    /// supported yet.
763    SetVariable {
764        local: bool,
765        hivevar: bool,
766        variable: Ident,
767        value: Vec<SetVariableValue>,
768    },
769    /// SHOW <variable>
770    ///
771    /// Note: this is a PostgreSQL-specific statement.
772    ShowVariable { variable: Vec<Ident> },
773    /// SHOW CREATE TABLE
774    ///
775    /// Note: this is a MySQL-specific statement.
776    ShowCreate {
777        obj_type: ShowCreateObject,
778        obj_name: ObjectName,
779    },
780    /// SHOW COLUMNS
781    ///
782    /// Note: this is a MySQL-specific statement.
783    ShowColumns {
784        extended: bool,
785        full: bool,
786        table_name: ObjectName,
787        filter: Option<ShowStatementFilter>,
788    },
789    /// `{ BEGIN [ TRANSACTION | WORK ] | START TRANSACTION } ...`
790    StartTransaction { modes: Vec<TransactionMode> },
791    /// `SET TRANSACTION ...`
792    SetTransaction {
793        modes: Vec<TransactionMode>,
794        snapshot: Option<Value>,
795        session: bool,
796    },
797    /// `COMMENT ON ...`
798    ///
799    /// Note: this is a PostgreSQL-specific statement.
800    Comment {
801        object_type: CommentObject,
802        object_name: ObjectName,
803        comment: Option<String>,
804    },
805    /// `COMMIT [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
806    Commit { chain: bool },
807    /// `ROLLBACK [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
808    Rollback { chain: bool },
809    /// CREATE SCHEMA
810    CreateSchema {
811        schema_name: ObjectName,
812        if_not_exists: bool,
813    },
814    /// CREATE DATABASE
815    CreateDatabase {
816        db_name: ObjectName,
817        if_not_exists: bool,
818        location: Option<String>,
819        managed_location: Option<String>,
820    },
821    /// `ASSERT <condition> [AS <message>]`
822    Assert {
823        condition: Expr,
824        message: Option<Expr>,
825    },
826    /// GRANT privileges ON objects TO grantees
827    Grant {
828        privileges: Privileges,
829        objects: GrantObjects,
830        grantees: Vec<Ident>,
831        with_grant_option: bool,
832        granted_by: Option<Ident>,
833    },
834    /// REVOKE privileges ON objects FROM grantees
835    Revoke {
836        privileges: Privileges,
837        objects: GrantObjects,
838        grantees: Vec<Ident>,
839        granted_by: Option<Ident>,
840        cascade: bool,
841    },
842    /// `DEALLOCATE [ PREPARE ] { name | ALL }`
843    ///
844    /// Note: this is a PostgreSQL-specific statement.
845    Deallocate { name: Ident, prepare: bool },
846    /// `EXECUTE name [ ( parameter [, ...] ) ]`
847    ///
848    /// Note: this is a PostgreSQL-specific statement.
849    Execute { name: Ident, parameters: Vec<Expr> },
850    /// `PREPARE name [ ( data_type [, ...] ) ] AS statement`
851    ///
852    /// Note: this is a PostgreSQL-specific statement.
853    Prepare {
854        name: Ident,
855        data_types: Vec<DataType>,
856        statement: Box<Statement>,
857    },
858    /// EXPLAIN TABLE
859    /// Note: this is a MySQL-specific statement. See <https://dev.mysql.com/doc/refman/8.0/en/explain.html>
860    ExplainTable {
861        // If true, query used the MySQL `DESCRIBE` alias for explain
862        describe_alias: bool,
863        // Table name
864        table_name: ObjectName,
865    },
866    /// EXPLAIN / DESCRIBE for select_statement
867    Explain {
868        // If true, query used the MySQL `DESCRIBE` alias for explain
869        describe_alias: bool,
870        /// Carry out the command and show actual run times and other statistics.
871        analyze: bool,
872        // Display additional information regarding the plan.
873        verbose: bool,
874        /// A SQL query that specifies what to explain
875        statement: Box<Statement>,
876    },
877}
878
879impl fmt::Display for Statement {
880    // Clippy thinks this function is too complicated, but it is painful to
881    // split up without extracting structs for each `Statement` variant.
882    #[allow(clippy::cognitive_complexity)]
883    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
884        match self {
885            Statement::ExplainTable {
886                describe_alias,
887                table_name,
888            } => {
889                if *describe_alias {
890                    write!(f, "DESCRIBE ")?;
891                } else {
892                    write!(f, "EXPLAIN ")?;
893                }
894
895                write!(f, "{}", table_name)
896            }
897            Statement::Explain {
898                describe_alias,
899                verbose,
900                analyze,
901                statement,
902            } => {
903                if *describe_alias {
904                    write!(f, "DESCRIBE ")?;
905                } else {
906                    write!(f, "EXPLAIN ")?;
907                }
908
909                if *analyze {
910                    write!(f, "ANALYZE ")?;
911                }
912
913                if *verbose {
914                    write!(f, "VERBOSE ")?;
915                }
916
917                write!(f, "{}", statement)
918            }
919            Statement::Query(s) => write!(f, "{}", s),
920            Statement::Directory {
921                overwrite,
922                local,
923                path,
924                file_format,
925                source,
926            } => {
927                write!(
928                    f,
929                    "INSERT{overwrite}{local} DIRECTORY '{path}'",
930                    overwrite = if *overwrite { " OVERWRITE" } else { "" },
931                    local = if *local { " LOCAL" } else { "" },
932                    path = path
933                )?;
934                if let Some(ref ff) = file_format {
935                    write!(f, " STORED AS {}", ff)?
936                }
937                write!(f, " {}", source)
938            }
939            Statement::Msck {
940                table_name,
941                repair,
942                partition_action,
943            } => {
944                write!(
945                    f,
946                    "MSCK {repair}TABLE {table}",
947                    repair = if *repair { "REPAIR " } else { "" },
948                    table = table_name
949                )?;
950                if let Some(pa) = partition_action {
951                    write!(f, " {}", pa)?;
952                }
953                Ok(())
954            }
955            Statement::Truncate {
956                table_name,
957                partitions,
958            } => {
959                write!(f, "TRUNCATE TABLE {}", table_name)?;
960                if let Some(ref parts) = partitions {
961                    if !parts.is_empty() {
962                        write!(f, " PARTITION ({})", display_comma_separated(parts))?;
963                    }
964                }
965                Ok(())
966            }
967            Statement::Analyze {
968                table_name,
969                partitions,
970                for_columns,
971                columns,
972                cache_metadata,
973                noscan,
974                compute_statistics,
975            } => {
976                write!(f, "ANALYZE TABLE {}", table_name)?;
977                if let Some(ref parts) = partitions {
978                    if !parts.is_empty() {
979                        write!(f, " PARTITION ({})", display_comma_separated(parts))?;
980                    }
981                }
982
983                if *compute_statistics {
984                    write!(f, " COMPUTE STATISTICS")?;
985                }
986                if *noscan {
987                    write!(f, " NOSCAN")?;
988                }
989                if *cache_metadata {
990                    write!(f, " CACHE METADATA")?;
991                }
992                if *for_columns {
993                    write!(f, " FOR COLUMNS")?;
994                    if !columns.is_empty() {
995                        write!(f, " {}", display_comma_separated(columns))?;
996                    }
997                }
998                Ok(())
999            }
1000            Statement::Insert {
1001                or,
1002                table_name,
1003                overwrite,
1004                partitioned,
1005                columns,
1006                after_columns,
1007                source,
1008                table,
1009                on,
1010            } => {
1011                if let Some(action) = or {
1012                    write!(f, "INSERT OR {} INTO {} ", action, table_name)?;
1013                } else {
1014                    write!(
1015                        f,
1016                        "INSERT {act}{tbl} {table_name} ",
1017                        table_name = table_name,
1018                        act = if *overwrite { "OVERWRITE" } else { "INTO" },
1019                        tbl = if *table { " TABLE" } else { "" }
1020                    )?;
1021                }
1022                if !columns.is_empty() {
1023                    write!(f, "({}) ", display_comma_separated(columns))?;
1024                }
1025                if let Some(ref parts) = partitioned {
1026                    if !parts.is_empty() {
1027                        write!(f, "PARTITION ({}) ", display_comma_separated(parts))?;
1028                    }
1029                }
1030                if !after_columns.is_empty() {
1031                    write!(f, "({}) ", display_comma_separated(after_columns))?;
1032                }
1033                write!(f, "{}", source)?;
1034
1035                if let Some(on) = on {
1036                    write!(f, "{}", on)
1037                } else {
1038                    Ok(())
1039                }
1040            }
1041
1042            Statement::Copy {
1043                table_name,
1044                columns,
1045                values,
1046            } => {
1047                write!(f, "COPY {}", table_name)?;
1048                if !columns.is_empty() {
1049                    write!(f, " ({})", display_comma_separated(columns))?;
1050                }
1051                write!(f, " FROM stdin; ")?;
1052                if !values.is_empty() {
1053                    writeln!(f)?;
1054                    let mut delim = "";
1055                    for v in values {
1056                        write!(f, "{}", delim)?;
1057                        delim = "\t";
1058                        if let Some(v) = v {
1059                            write!(f, "{}", v)?;
1060                        } else {
1061                            write!(f, "\\N")?;
1062                        }
1063                    }
1064                }
1065                write!(f, "\n\\.")
1066            }
1067            Statement::Update {
1068                table,
1069                assignments,
1070                selection,
1071            } => {
1072                write!(f, "UPDATE {}", table)?;
1073                if !assignments.is_empty() {
1074                    write!(f, " SET {}", display_comma_separated(assignments))?;
1075                }
1076                if let Some(selection) = selection {
1077                    write!(f, " WHERE {}", selection)?;
1078                }
1079                Ok(())
1080            }
1081            Statement::Delete {
1082                table_name,
1083                selection,
1084            } => {
1085                write!(f, "DELETE FROM {}", table_name)?;
1086                if let Some(selection) = selection {
1087                    write!(f, " WHERE {}", selection)?;
1088                }
1089                Ok(())
1090            }
1091            Statement::CreateDatabase {
1092                db_name,
1093                if_not_exists,
1094                location,
1095                managed_location,
1096            } => {
1097                write!(f, "CREATE")?;
1098                if *if_not_exists {
1099                    write!(f, " IF NOT EXISTS")?;
1100                }
1101                write!(f, " {}", db_name)?;
1102                if let Some(l) = location {
1103                    write!(f, " LOCATION '{}'", l)?;
1104                }
1105                if let Some(ml) = managed_location {
1106                    write!(f, " MANAGEDLOCATION '{}'", ml)?;
1107                }
1108                Ok(())
1109            }
1110            Statement::CreateView {
1111                name,
1112                or_replace,
1113                columns,
1114                query,
1115                materialized,
1116                with_options,
1117            } => {
1118                write!(
1119                    f,
1120                    "CREATE {or_replace}{materialized}VIEW {name}",
1121                    or_replace = if *or_replace { "OR REPLACE " } else { "" },
1122                    materialized = if *materialized { "MATERIALIZED " } else { "" },
1123                    name = name
1124                )?;
1125                if !with_options.is_empty() {
1126                    write!(f, " WITH ({})", display_comma_separated(with_options))?;
1127                }
1128                if !columns.is_empty() {
1129                    write!(f, " ({})", display_comma_separated(columns))?;
1130                }
1131                write!(f, " AS {}", query)
1132            }
1133            Statement::CreateTable {
1134                name,
1135                columns,
1136                constraints,
1137                table_properties,
1138                with_options,
1139                or_replace,
1140                if_not_exists,
1141                hive_distribution,
1142                hive_formats,
1143                external,
1144                temporary,
1145                file_format,
1146                location,
1147                query,
1148                without_rowid,
1149                like,
1150            } => {
1151                // We want to allow the following options
1152                // Empty column list, allowed by PostgreSQL:
1153                //   `CREATE TABLE t ()`
1154                // No columns provided for CREATE TABLE AS:
1155                //   `CREATE TABLE t AS SELECT a from t2`
1156                // Columns provided for CREATE TABLE AS:
1157                //   `CREATE TABLE t (a INT) AS SELECT a from t2`
1158                write!(
1159                    f,
1160                    "CREATE {or_replace}{external}{temporary}TABLE {if_not_exists}{name}",
1161                    or_replace = if *or_replace { "OR REPLACE " } else { "" },
1162                    external = if *external { "EXTERNAL " } else { "" },
1163                    if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
1164                    temporary = if *temporary { "TEMPORARY " } else { "" },
1165                    name = name,
1166                )?;
1167                if !columns.is_empty() || !constraints.is_empty() {
1168                    write!(f, " ({}", display_comma_separated(columns))?;
1169                    if !columns.is_empty() && !constraints.is_empty() {
1170                        write!(f, ", ")?;
1171                    }
1172                    write!(f, "{})", display_comma_separated(constraints))?;
1173                } else if query.is_none() && like.is_none() {
1174                    // PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
1175                    write!(f, " ()")?;
1176                }
1177                // Only for SQLite
1178                if *without_rowid {
1179                    write!(f, " WITHOUT ROWID")?;
1180                }
1181
1182                // Only for Hive
1183                if let Some(l) = like {
1184                    write!(f, " LIKE {}", l)?;
1185                }
1186                match hive_distribution {
1187                    HiveDistributionStyle::PARTITIONED { columns } => {
1188                        write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
1189                    }
1190                    HiveDistributionStyle::CLUSTERED {
1191                        columns,
1192                        sorted_by,
1193                        num_buckets,
1194                    } => {
1195                        write!(f, " CLUSTERED BY ({})", display_comma_separated(columns))?;
1196                        if !sorted_by.is_empty() {
1197                            write!(f, " SORTED BY ({})", display_comma_separated(sorted_by))?;
1198                        }
1199                        if *num_buckets > 0 {
1200                            write!(f, " INTO {} BUCKETS", num_buckets)?;
1201                        }
1202                    }
1203                    HiveDistributionStyle::SKEWED {
1204                        columns,
1205                        on,
1206                        stored_as_directories,
1207                    } => {
1208                        write!(
1209                            f,
1210                            " SKEWED BY ({})) ON ({})",
1211                            display_comma_separated(columns),
1212                            display_comma_separated(on)
1213                        )?;
1214                        if *stored_as_directories {
1215                            write!(f, " STORED AS DIRECTORIES")?;
1216                        }
1217                    }
1218                    _ => (),
1219                }
1220
1221                if let Some(HiveFormat {
1222                    row_format,
1223                    storage,
1224                    location,
1225                }) = hive_formats
1226                {
1227                    match row_format {
1228                        Some(HiveRowFormat::SERDE { class }) => {
1229                            write!(f, " ROW FORMAT SERDE '{}'", class)?
1230                        }
1231                        Some(HiveRowFormat::DELIMITED) => write!(f, " ROW FORMAT DELIMITED")?,
1232                        None => (),
1233                    }
1234                    match storage {
1235                        Some(HiveIOFormat::IOF {
1236                            input_format,
1237                            output_format,
1238                        }) => write!(
1239                            f,
1240                            " STORED AS INPUTFORMAT {} OUTPUTFORMAT {}",
1241                            input_format, output_format
1242                        )?,
1243                        Some(HiveIOFormat::FileFormat { format }) if !*external => {
1244                            write!(f, " STORED AS {}", format)?
1245                        }
1246                        _ => (),
1247                    }
1248                    if !*external {
1249                        if let Some(loc) = location {
1250                            write!(f, " LOCATION '{}'", loc)?;
1251                        }
1252                    }
1253                }
1254                if *external {
1255                    write!(
1256                        f,
1257                        " STORED AS {} LOCATION '{}'",
1258                        file_format.as_ref().unwrap(),
1259                        location.as_ref().unwrap()
1260                    )?;
1261                }
1262                if !table_properties.is_empty() {
1263                    write!(
1264                        f,
1265                        " TBLPROPERTIES ({})",
1266                        display_comma_separated(table_properties)
1267                    )?;
1268                }
1269                if !with_options.is_empty() {
1270                    write!(f, " WITH ({})", display_comma_separated(with_options))?;
1271                }
1272                if let Some(query) = query {
1273                    write!(f, " AS {}", query)?;
1274                }
1275                Ok(())
1276            }
1277            Statement::CreateVirtualTable {
1278                name,
1279                if_not_exists,
1280                module_name,
1281                module_args,
1282            } => {
1283                write!(
1284                    f,
1285                    "CREATE VIRTUAL TABLE {if_not_exists}{name} USING {module_name}",
1286                    if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
1287                    name = name,
1288                    module_name = module_name
1289                )?;
1290                if !module_args.is_empty() {
1291                    write!(f, " ({})", display_comma_separated(module_args))?;
1292                }
1293                Ok(())
1294            }
1295            Statement::CreateIndex {
1296                name,
1297                table_name,
1298                columns,
1299                unique,
1300                if_not_exists,
1301            } => write!(
1302                f,
1303                "CREATE {unique}INDEX {if_not_exists}{name} ON {table_name}({columns})",
1304                unique = if *unique { "UNIQUE " } else { "" },
1305                if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
1306                name = name,
1307                table_name = table_name,
1308                columns = display_separated(columns, ",")
1309            ),
1310            Statement::AlterTable { name, operation } => {
1311                write!(f, "ALTER TABLE {} {}", name, operation)
1312            }
1313            Statement::Drop {
1314                object_type,
1315                if_exists,
1316                names,
1317                cascade,
1318                purge,
1319            } => write!(
1320                f,
1321                "DROP {}{} {}{}{}",
1322                object_type,
1323                if *if_exists { " IF EXISTS" } else { "" },
1324                display_comma_separated(names),
1325                if *cascade { " CASCADE" } else { "" },
1326                if *purge { " PURGE" } else { "" }
1327            ),
1328            Statement::SetVariable {
1329                local,
1330                variable,
1331                hivevar,
1332                value,
1333            } => {
1334                f.write_str("SET ")?;
1335                if *local {
1336                    f.write_str("LOCAL ")?;
1337                }
1338                write!(
1339                    f,
1340                    "{hivevar}{name} = {value}",
1341                    hivevar = if *hivevar { "HIVEVAR:" } else { "" },
1342                    name = variable,
1343                    value = display_comma_separated(value)
1344                )
1345            }
1346            Statement::ShowVariable { variable } => {
1347                write!(f, "SHOW")?;
1348                if !variable.is_empty() {
1349                    write!(f, " {}", display_separated(variable, " "))?;
1350                }
1351                Ok(())
1352            }
1353            Statement::ShowCreate { obj_type, obj_name } => {
1354                write!(
1355                    f,
1356                    "SHOW CREATE {obj_type} {obj_name}",
1357                    obj_type = obj_type,
1358                    obj_name = obj_name,
1359                )?;
1360                Ok(())
1361            }
1362            Statement::ShowColumns {
1363                extended,
1364                full,
1365                table_name,
1366                filter,
1367            } => {
1368                write!(
1369                    f,
1370                    "SHOW {extended}{full}COLUMNS FROM {table_name}",
1371                    extended = if *extended { "EXTENDED " } else { "" },
1372                    full = if *full { "FULL " } else { "" },
1373                    table_name = table_name,
1374                )?;
1375                if let Some(filter) = filter {
1376                    write!(f, " {}", filter)?;
1377                }
1378                Ok(())
1379            }
1380            Statement::StartTransaction { modes } => {
1381                write!(f, "START TRANSACTION")?;
1382                if !modes.is_empty() {
1383                    write!(f, " {}", display_comma_separated(modes))?;
1384                }
1385                Ok(())
1386            }
1387            Statement::SetTransaction {
1388                modes,
1389                snapshot,
1390                session,
1391            } => {
1392                if *session {
1393                    write!(f, "SET SESSION CHARACTERISTICS AS TRANSACTION")?;
1394                } else {
1395                    write!(f, "SET TRANSACTION")?;
1396                }
1397                if !modes.is_empty() {
1398                    write!(f, " {}", display_comma_separated(modes))?;
1399                }
1400                if let Some(snapshot_id) = snapshot {
1401                    write!(f, " SNAPSHOT {}", snapshot_id)?;
1402                }
1403                Ok(())
1404            }
1405            Statement::Commit { chain } => {
1406                write!(f, "COMMIT{}", if *chain { " AND CHAIN" } else { "" },)
1407            }
1408            Statement::Rollback { chain } => {
1409                write!(f, "ROLLBACK{}", if *chain { " AND CHAIN" } else { "" },)
1410            }
1411            Statement::CreateSchema {
1412                schema_name,
1413                if_not_exists,
1414            } => write!(
1415                f,
1416                "CREATE SCHEMA {if_not_exists}{name}",
1417                if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
1418                name = schema_name
1419            ),
1420            Statement::Assert { condition, message } => {
1421                write!(f, "ASSERT {}", condition)?;
1422                if let Some(m) = message {
1423                    write!(f, " AS {}", m)?;
1424                }
1425                Ok(())
1426            }
1427            Statement::Grant {
1428                privileges,
1429                objects,
1430                grantees,
1431                with_grant_option,
1432                granted_by,
1433            } => {
1434                write!(f, "GRANT {} ", privileges)?;
1435                write!(f, "ON {} ", objects)?;
1436                write!(f, "TO {}", display_comma_separated(grantees))?;
1437                if *with_grant_option {
1438                    write!(f, " WITH GRANT OPTION")?;
1439                }
1440                if let Some(grantor) = granted_by {
1441                    write!(f, " GRANTED BY {}", grantor)?;
1442                }
1443                Ok(())
1444            }
1445            Statement::Revoke {
1446                privileges,
1447                objects,
1448                grantees,
1449                granted_by,
1450                cascade,
1451            } => {
1452                write!(f, "REVOKE {} ", privileges)?;
1453                write!(f, "ON {} ", objects)?;
1454                write!(f, "FROM {}", display_comma_separated(grantees))?;
1455                if let Some(grantor) = granted_by {
1456                    write!(f, " GRANTED BY {}", grantor)?;
1457                }
1458                write!(f, " {}", if *cascade { "CASCADE" } else { "RESTRICT" })?;
1459                Ok(())
1460            }
1461            Statement::Deallocate { name, prepare } => write!(
1462                f,
1463                "DEALLOCATE {prepare}{name}",
1464                prepare = if *prepare { "PREPARE " } else { "" },
1465                name = name,
1466            ),
1467            Statement::Execute { name, parameters } => {
1468                write!(f, "EXECUTE {}", name)?;
1469                if !parameters.is_empty() {
1470                    write!(f, "({})", display_comma_separated(parameters))?;
1471                }
1472                Ok(())
1473            }
1474            Statement::Prepare {
1475                name,
1476                data_types,
1477                statement,
1478            } => {
1479                write!(f, "PREPARE {} ", name)?;
1480                if !data_types.is_empty() {
1481                    write!(f, "({}) ", display_comma_separated(data_types))?;
1482                }
1483                write!(f, "AS {}", statement)
1484            }
1485            Statement::Comment {
1486                object_type,
1487                object_name,
1488                comment,
1489            } => {
1490                write!(f, "COMMENT ON {} {} IS ", object_type, object_name)?;
1491                if let Some(c) = comment {
1492                    write!(f, "'{}'", c)
1493                } else {
1494                    write!(f, "NULL")
1495                }
1496            }
1497        }
1498    }
1499}
1500
1501#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1502#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1503#[non_exhaustive]
1504pub enum OnInsert {
1505    /// ON DUPLICATE KEY UPDATE (MySQL when the key already exists, then execute an update instead)
1506    DuplicateKeyUpdate(Vec<Assignment>),
1507}
1508
1509impl fmt::Display for OnInsert {
1510    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1511        match self {
1512            Self::DuplicateKeyUpdate(expr) => write!(
1513                f,
1514                " ON DUPLICATE KEY UPDATE {}",
1515                display_comma_separated(expr)
1516            ),
1517        }
1518    }
1519}
1520
1521/// Privileges granted in a GRANT statement or revoked in a REVOKE statement.
1522#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1523#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1524pub enum Privileges {
1525    /// All privileges applicable to the object type
1526    All {
1527        /// Optional keyword from the spec, ignored in practice
1528        with_privileges_keyword: bool,
1529    },
1530    /// Specific privileges (e.g. `SELECT`, `INSERT`)
1531    Actions(Vec<Action>),
1532}
1533
1534impl fmt::Display for Privileges {
1535    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1536        match self {
1537            Privileges::All {
1538                with_privileges_keyword,
1539            } => {
1540                write!(
1541                    f,
1542                    "ALL{}",
1543                    if *with_privileges_keyword {
1544                        " PRIVILEGES"
1545                    } else {
1546                        ""
1547                    }
1548                )
1549            }
1550            Privileges::Actions(actions) => {
1551                write!(f, "{}", display_comma_separated(actions).to_string())
1552            }
1553        }
1554    }
1555}
1556
1557/// A privilege on a database object (table, sequence, etc.).
1558#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1559#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1560pub enum Action {
1561    Connect,
1562    Create,
1563    Delete,
1564    Execute,
1565    Insert { columns: Option<Vec<Ident>> },
1566    References { columns: Option<Vec<Ident>> },
1567    Select { columns: Option<Vec<Ident>> },
1568    Temporary,
1569    Trigger,
1570    Truncate,
1571    Update { columns: Option<Vec<Ident>> },
1572    Usage,
1573}
1574
1575impl fmt::Display for Action {
1576    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1577        match self {
1578            Action::Connect => f.write_str("CONNECT")?,
1579            Action::Create => f.write_str("CREATE")?,
1580            Action::Delete => f.write_str("DELETE")?,
1581            Action::Execute => f.write_str("EXECUTE")?,
1582            Action::Insert { .. } => f.write_str("INSERT")?,
1583            Action::References { .. } => f.write_str("REFERENCES")?,
1584            Action::Select { .. } => f.write_str("SELECT")?,
1585            Action::Temporary => f.write_str("TEMPORARY")?,
1586            Action::Trigger => f.write_str("TRIGGER")?,
1587            Action::Truncate => f.write_str("TRUNCATE")?,
1588            Action::Update { .. } => f.write_str("UPDATE")?,
1589            Action::Usage => f.write_str("USAGE")?,
1590        };
1591        match self {
1592            Action::Insert { columns }
1593            | Action::References { columns }
1594            | Action::Select { columns }
1595            | Action::Update { columns } => {
1596                if let Some(columns) = columns {
1597                    write!(f, " ({})", display_comma_separated(columns))?;
1598                }
1599            }
1600            _ => (),
1601        };
1602        Ok(())
1603    }
1604}
1605
1606/// Objects on which privileges are granted in a GRANT statement.
1607#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1608#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1609pub enum GrantObjects {
1610    /// Grant privileges on `ALL SEQUENCES IN SCHEMA <schema_name> [, ...]`
1611    AllSequencesInSchema { schemas: Vec<ObjectName> },
1612    /// Grant privileges on `ALL TABLES IN SCHEMA <schema_name> [, ...]`
1613    AllTablesInSchema { schemas: Vec<ObjectName> },
1614    /// Grant privileges on specific schemas
1615    Schemas(Vec<ObjectName>),
1616    /// Grant privileges on specific sequences
1617    Sequences(Vec<ObjectName>),
1618    /// Grant privileges on specific tables
1619    Tables(Vec<ObjectName>),
1620}
1621
1622impl fmt::Display for GrantObjects {
1623    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1624        match self {
1625            GrantObjects::Sequences(sequences) => {
1626                write!(f, "SEQUENCE {}", display_comma_separated(sequences))
1627            }
1628            GrantObjects::Schemas(schemas) => {
1629                write!(f, "SCHEMA {}", display_comma_separated(schemas))
1630            }
1631            GrantObjects::Tables(tables) => {
1632                write!(f, "{}", display_comma_separated(tables))
1633            }
1634            GrantObjects::AllSequencesInSchema { schemas } => {
1635                write!(
1636                    f,
1637                    "ALL SEQUENCES IN SCHEMA {}",
1638                    display_comma_separated(schemas)
1639                )
1640            }
1641            GrantObjects::AllTablesInSchema { schemas } => {
1642                write!(
1643                    f,
1644                    "ALL TABLES IN SCHEMA {}",
1645                    display_comma_separated(schemas)
1646                )
1647            }
1648        }
1649    }
1650}
1651
1652/// SQL assignment `foo = expr` as used in SQLUpdate
1653#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1654#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1655pub struct Assignment {
1656    pub id: Vec<Ident>,
1657    pub value: Expr,
1658}
1659
1660impl fmt::Display for Assignment {
1661    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1662        write!(f, "{} = {}", display_separated(&self.id, "."), self.value)
1663    }
1664}
1665
1666#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1667#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1668pub enum FunctionArgExpr {
1669    Expr(Expr),
1670    /// Qualified wildcard, e.g. `alias.*` or `schema.table.*`.
1671    QualifiedWildcard(ObjectName),
1672    /// An unqualified `*`
1673    Wildcard,
1674}
1675
1676impl fmt::Display for FunctionArgExpr {
1677    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1678        match self {
1679            FunctionArgExpr::Expr(expr) => write!(f, "{}", expr),
1680            FunctionArgExpr::QualifiedWildcard(prefix) => write!(f, "{}.*", prefix),
1681            FunctionArgExpr::Wildcard => f.write_str("*"),
1682        }
1683    }
1684}
1685
1686#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1687#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1688pub enum FunctionArg {
1689    Named { name: Ident, arg: FunctionArgExpr },
1690    Unnamed(FunctionArgExpr),
1691}
1692
1693impl fmt::Display for FunctionArg {
1694    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1695        match self {
1696            FunctionArg::Named { name, arg } => write!(f, "{} => {}", name, arg),
1697            FunctionArg::Unnamed(unnamed_arg) => write!(f, "{}", unnamed_arg),
1698        }
1699    }
1700}
1701
1702/// A function call
1703#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1704#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1705pub struct Function {
1706    pub name: ObjectName,
1707    pub args: Vec<FunctionArg>,
1708    pub over: Option<WindowSpec>,
1709    // aggregate functions may specify eg `COUNT(DISTINCT x)`
1710    pub distinct: bool,
1711}
1712
1713impl fmt::Display for Function {
1714    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1715        write!(
1716            f,
1717            "{}({}{})",
1718            self.name,
1719            if self.distinct { "DISTINCT " } else { "" },
1720            display_comma_separated(&self.args),
1721        )?;
1722        if let Some(o) = &self.over {
1723            write!(f, " OVER ({})", o)?;
1724        }
1725        Ok(())
1726    }
1727}
1728
1729/// External table's available file format
1730#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1731#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1732pub enum FileFormat {
1733    TEXTFILE,
1734    SEQUENCEFILE,
1735    ORC,
1736    PARQUET,
1737    AVRO,
1738    RCFILE,
1739    JSONFILE,
1740}
1741
1742impl fmt::Display for FileFormat {
1743    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1744        use self::FileFormat::*;
1745        f.write_str(match self {
1746            TEXTFILE => "TEXTFILE",
1747            SEQUENCEFILE => "SEQUENCEFILE",
1748            ORC => "ORC",
1749            PARQUET => "PARQUET",
1750            AVRO => "AVRO",
1751            RCFILE => "RCFILE",
1752            JSONFILE => "JSONFILE",
1753        })
1754    }
1755}
1756
1757/// A `LISTAGG` invocation `LISTAGG( [ DISTINCT ] <expr>[, <separator> ] [ON OVERFLOW <on_overflow>] ) )
1758/// [ WITHIN GROUP (ORDER BY <within_group1>[, ...] ) ]`
1759#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1760#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1761pub struct ListAgg {
1762    pub distinct: bool,
1763    pub expr: Box<Expr>,
1764    pub separator: Option<Box<Expr>>,
1765    pub on_overflow: Option<ListAggOnOverflow>,
1766    pub within_group: Vec<OrderByExpr>,
1767}
1768
1769impl fmt::Display for ListAgg {
1770    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1771        write!(
1772            f,
1773            "LISTAGG({}{}",
1774            if self.distinct { "DISTINCT " } else { "" },
1775            self.expr
1776        )?;
1777        if let Some(separator) = &self.separator {
1778            write!(f, ", {}", separator)?;
1779        }
1780        if let Some(on_overflow) = &self.on_overflow {
1781            write!(f, "{}", on_overflow)?;
1782        }
1783        write!(f, ")")?;
1784        if !self.within_group.is_empty() {
1785            write!(
1786                f,
1787                " WITHIN GROUP (ORDER BY {})",
1788                display_comma_separated(&self.within_group)
1789            )?;
1790        }
1791        Ok(())
1792    }
1793}
1794
1795/// The `ON OVERFLOW` clause of a LISTAGG invocation
1796#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1797#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1798pub enum ListAggOnOverflow {
1799    /// `ON OVERFLOW ERROR`
1800    Error,
1801
1802    /// `ON OVERFLOW TRUNCATE [ <filler> ] WITH[OUT] COUNT`
1803    Truncate {
1804        filler: Option<Box<Expr>>,
1805        with_count: bool,
1806    },
1807}
1808
1809impl fmt::Display for ListAggOnOverflow {
1810    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1811        write!(f, " ON OVERFLOW")?;
1812        match self {
1813            ListAggOnOverflow::Error => write!(f, " ERROR"),
1814            ListAggOnOverflow::Truncate { filler, with_count } => {
1815                write!(f, " TRUNCATE")?;
1816                if let Some(filler) = filler {
1817                    write!(f, " {}", filler)?;
1818                }
1819                if *with_count {
1820                    write!(f, " WITH")?;
1821                } else {
1822                    write!(f, " WITHOUT")?;
1823                }
1824                write!(f, " COUNT")
1825            }
1826        }
1827    }
1828}
1829
1830#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1831#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1832pub enum ObjectType {
1833    Table,
1834    View,
1835    Index,
1836    Schema,
1837}
1838
1839impl fmt::Display for ObjectType {
1840    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1841        f.write_str(match self {
1842            ObjectType::Table => "TABLE",
1843            ObjectType::View => "VIEW",
1844            ObjectType::Index => "INDEX",
1845            ObjectType::Schema => "SCHEMA",
1846        })
1847    }
1848}
1849
1850#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1851#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1852pub enum HiveDistributionStyle {
1853    PARTITIONED {
1854        columns: Vec<ColumnDef>,
1855    },
1856    CLUSTERED {
1857        columns: Vec<Ident>,
1858        sorted_by: Vec<ColumnDef>,
1859        num_buckets: i32,
1860    },
1861    SKEWED {
1862        columns: Vec<ColumnDef>,
1863        on: Vec<ColumnDef>,
1864        stored_as_directories: bool,
1865    },
1866    NONE,
1867}
1868
1869#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1870#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1871pub enum HiveRowFormat {
1872    SERDE { class: String },
1873    DELIMITED,
1874}
1875
1876#[allow(clippy::large_enum_variant)]
1877#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1878#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1879#[allow(clippy::large_enum_variant)]
1880pub enum HiveIOFormat {
1881    IOF {
1882        input_format: Expr,
1883        output_format: Expr,
1884    },
1885    FileFormat {
1886        format: FileFormat,
1887    },
1888}
1889
1890#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
1891#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1892pub struct HiveFormat {
1893    pub row_format: Option<HiveRowFormat>,
1894    pub storage: Option<HiveIOFormat>,
1895    pub location: Option<String>,
1896}
1897
1898#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1899#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1900pub struct SqlOption {
1901    pub name: Ident,
1902    pub value: Value,
1903}
1904
1905impl fmt::Display for SqlOption {
1906    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1907        write!(f, "{} = {}", self.name, self.value)
1908    }
1909}
1910
1911#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1912#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1913pub enum TransactionMode {
1914    AccessMode(TransactionAccessMode),
1915    IsolationLevel(TransactionIsolationLevel),
1916}
1917
1918impl fmt::Display for TransactionMode {
1919    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1920        use TransactionMode::*;
1921        match self {
1922            AccessMode(access_mode) => write!(f, "{}", access_mode),
1923            IsolationLevel(iso_level) => write!(f, "ISOLATION LEVEL {}", iso_level),
1924        }
1925    }
1926}
1927
1928#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1929#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1930pub enum TransactionAccessMode {
1931    ReadOnly,
1932    ReadWrite,
1933}
1934
1935impl fmt::Display for TransactionAccessMode {
1936    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1937        use TransactionAccessMode::*;
1938        f.write_str(match self {
1939            ReadOnly => "READ ONLY",
1940            ReadWrite => "READ WRITE",
1941        })
1942    }
1943}
1944
1945#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1946#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1947pub enum TransactionIsolationLevel {
1948    ReadUncommitted,
1949    ReadCommitted,
1950    RepeatableRead,
1951    Serializable,
1952}
1953
1954impl fmt::Display for TransactionIsolationLevel {
1955    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1956        use TransactionIsolationLevel::*;
1957        f.write_str(match self {
1958            ReadUncommitted => "READ UNCOMMITTED",
1959            ReadCommitted => "READ COMMITTED",
1960            RepeatableRead => "REPEATABLE READ",
1961            Serializable => "SERIALIZABLE",
1962        })
1963    }
1964}
1965
1966#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1967#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1968pub enum ShowStatementFilter {
1969    Like(String),
1970    ILike(String),
1971    Where(Expr),
1972}
1973
1974impl fmt::Display for ShowStatementFilter {
1975    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1976        use ShowStatementFilter::*;
1977        match self {
1978            Like(pattern) => write!(f, "LIKE '{}'", value::escape_single_quote_string(pattern)),
1979            ILike(pattern) => write!(f, "ILIKE {}", value::escape_single_quote_string(pattern)),
1980            Where(expr) => write!(f, "WHERE {}", expr),
1981        }
1982    }
1983}
1984
1985#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1986#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1987pub enum SetVariableValue {
1988    Ident(Ident),
1989    Literal(Value),
1990}
1991
1992impl fmt::Display for SetVariableValue {
1993    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1994        use SetVariableValue::*;
1995        match self {
1996            Ident(ident) => write!(f, "{}", ident),
1997            Literal(literal) => write!(f, "{}", literal),
1998        }
1999    }
2000}
2001
2002/// Sqlite specific syntax
2003///
2004/// https://sqlite.org/lang_conflict.html
2005#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2006#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2007pub enum SqliteOnConflict {
2008    Rollback,
2009    Abort,
2010    Fail,
2011    Ignore,
2012    Replace,
2013}
2014
2015impl fmt::Display for SqliteOnConflict {
2016    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2017        use SqliteOnConflict::*;
2018        match self {
2019            Rollback => write!(f, "ROLLBACK"),
2020            Abort => write!(f, "ABORT"),
2021            Fail => write!(f, "FAIL"),
2022            Ignore => write!(f, "IGNORE"),
2023            Replace => write!(f, "REPLACE"),
2024        }
2025    }
2026}
2027
2028#[cfg(test)]
2029mod tests {
2030    use super::*;
2031
2032    #[test]
2033    fn test_window_frame_default() {
2034        let window_frame = WindowFrame::default();
2035        assert_eq!(WindowFrameBound::Preceding(None), window_frame.start_bound);
2036    }
2037
2038    #[test]
2039    fn test_grouping_sets_display() {
2040        // a and b in different group
2041        let grouping_sets = Expr::GroupingSets(vec![
2042            vec![Expr::Identifier(Ident::new("a"))],
2043            vec![Expr::Identifier(Ident::new("b"))],
2044        ]);
2045        assert_eq!("GROUPING SETS ((a), (b))", format!("{}", grouping_sets));
2046
2047        // a and b in the same group
2048        let grouping_sets = Expr::GroupingSets(vec![vec![
2049            Expr::Identifier(Ident::new("a")),
2050            Expr::Identifier(Ident::new("b")),
2051        ]]);
2052        assert_eq!("GROUPING SETS ((a, b))", format!("{}", grouping_sets));
2053
2054        // (a, b) and (c, d) in different group
2055        let grouping_sets = Expr::GroupingSets(vec![
2056            vec![
2057                Expr::Identifier(Ident::new("a")),
2058                Expr::Identifier(Ident::new("b")),
2059            ],
2060            vec![
2061                Expr::Identifier(Ident::new("c")),
2062                Expr::Identifier(Ident::new("d")),
2063            ],
2064        ]);
2065        assert_eq!(
2066            "GROUPING SETS ((a, b), (c, d))",
2067            format!("{}", grouping_sets)
2068        );
2069    }
2070
2071    #[test]
2072    fn test_rollup_display() {
2073        let rollup = Expr::Rollup(vec![vec![Expr::Identifier(Ident::new("a"))]]);
2074        assert_eq!("ROLLUP (a)", format!("{}", rollup));
2075
2076        let rollup = Expr::Rollup(vec![vec![
2077            Expr::Identifier(Ident::new("a")),
2078            Expr::Identifier(Ident::new("b")),
2079        ]]);
2080        assert_eq!("ROLLUP ((a, b))", format!("{}", rollup));
2081
2082        let rollup = Expr::Rollup(vec![
2083            vec![Expr::Identifier(Ident::new("a"))],
2084            vec![Expr::Identifier(Ident::new("b"))],
2085        ]);
2086        assert_eq!("ROLLUP (a, b)", format!("{}", rollup));
2087
2088        let rollup = Expr::Rollup(vec![
2089            vec![Expr::Identifier(Ident::new("a"))],
2090            vec![
2091                Expr::Identifier(Ident::new("b")),
2092                Expr::Identifier(Ident::new("c")),
2093            ],
2094            vec![Expr::Identifier(Ident::new("d"))],
2095        ]);
2096        assert_eq!("ROLLUP (a, (b, c), d)", format!("{}", rollup));
2097    }
2098
2099    #[test]
2100    fn test_cube_display() {
2101        let cube = Expr::Cube(vec![vec![Expr::Identifier(Ident::new("a"))]]);
2102        assert_eq!("CUBE (a)", format!("{}", cube));
2103
2104        let cube = Expr::Cube(vec![vec![
2105            Expr::Identifier(Ident::new("a")),
2106            Expr::Identifier(Ident::new("b")),
2107        ]]);
2108        assert_eq!("CUBE ((a, b))", format!("{}", cube));
2109
2110        let cube = Expr::Cube(vec![
2111            vec![Expr::Identifier(Ident::new("a"))],
2112            vec![Expr::Identifier(Ident::new("b"))],
2113        ]);
2114        assert_eq!("CUBE (a, b)", format!("{}", cube));
2115
2116        let cube = Expr::Cube(vec![
2117            vec![Expr::Identifier(Ident::new("a"))],
2118            vec![
2119                Expr::Identifier(Ident::new("b")),
2120                Expr::Identifier(Ident::new("c")),
2121            ],
2122            vec![Expr::Identifier(Ident::new("d"))],
2123        ]);
2124        assert_eq!("CUBE (a, (b, c), d)", format!("{}", cube));
2125    }
2126}