Skip to main content

risingwave_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 analyze;
15mod data_type;
16pub(crate) mod ddl;
17mod legacy_source;
18mod operator;
19mod query;
20mod statement;
21mod value;
22
23use std::collections::HashSet;
24use std::fmt::{self, Display};
25use std::sync::Arc;
26
27use itertools::Itertools;
28use winnow::ModalResult;
29
30pub use self::data_type::{DataType, StructField};
31pub use self::ddl::{
32    AlterColumnOperation, AlterCompactionGroupOperation, AlterConnectionOperation,
33    AlterDatabaseOperation, AlterFragmentOperation, AlterFunctionOperation, AlterSchemaOperation,
34    AlterSecretOperation, AlterTableOperation, ColumnDef, ColumnOption, ColumnOptionDef,
35    ReferentialAction, SourceWatermark, TableConstraint, WebhookSourceInfo,
36};
37pub use self::legacy_source::{CompatibleFormatEncode, get_delimiter};
38pub use self::operator::{BinaryOperator, QualifiedOperator, UnaryOperator};
39pub use self::query::{
40    Corresponding, Cte, CteInner, Distinct, Fetch, Join, JoinConstraint, JoinOperator, LateralView,
41    NamedWindow, OrderByExpr, Query, Select, SelectItem, SetExpr, SetOperator, TableAlias,
42    TableFactor, TableWithJoins, Top, Values, With,
43};
44pub use self::statement::*;
45pub use self::value::{
46    ConnectionRefValue, CstyleEscapedString, DateTimeField, DollarQuotedString, JsonPredicateType,
47    SecretRefAsType, SecretRefValue, TrimWhereField, Value,
48};
49pub use crate::ast::analyze::AnalyzeTarget;
50pub use crate::ast::ddl::{
51    AlterIndexOperation, AlterSinkOperation, AlterSourceOperation, AlterSubscriptionOperation,
52    AlterViewOperation,
53};
54use crate::keywords::Keyword;
55use crate::parser::{IncludeOption, IncludeOptionItem, Parser, ParserError, StrError};
56pub use crate::quote_ident::QuoteIdent;
57use crate::tokenizer::Tokenizer;
58
59pub type RedactSqlOptionKeywordsRef = Arc<HashSet<String>>;
60
61task_local::task_local! {
62    pub static REDACT_SQL_OPTION_KEYWORDS: RedactSqlOptionKeywordsRef;
63}
64
65pub struct DisplaySeparated<'a, T>
66where
67    T: fmt::Display,
68{
69    slice: &'a [T],
70    sep: &'static str,
71}
72
73impl<T> fmt::Display for DisplaySeparated<'_, T>
74where
75    T: fmt::Display,
76{
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        let mut delim = "";
79        for t in self.slice {
80            write!(f, "{}", delim)?;
81            delim = self.sep;
82            write!(f, "{}", t)?;
83        }
84        Ok(())
85    }
86}
87
88pub fn display_separated<'a, T>(slice: &'a [T], sep: &'static str) -> DisplaySeparated<'a, T>
89where
90    T: fmt::Display,
91{
92    DisplaySeparated { slice, sep }
93}
94
95pub fn display_comma_separated<T>(slice: &[T]) -> DisplaySeparated<'_, T>
96where
97    T: fmt::Display,
98{
99    DisplaySeparated { slice, sep: ", " }
100}
101
102/// An identifier, decomposed into its value or character data and the quote style.
103#[derive(Debug, Clone, PartialEq, Eq, Hash)]
104pub struct Ident {
105    /// The value of the identifier without quotes.
106    pub(crate) value: String,
107    /// The starting quote if any. Valid quote characters are the single quote,
108    /// double quote, backtick, and opening square bracket.
109    pub(crate) quote_style: Option<char>,
110}
111
112impl Ident {
113    /// Create a new identifier with the given value and no quotes.
114    /// the given value must not be a empty string.
115    // FIXME: should avoid using this function unless it's a literal or for testing.
116    pub fn new_unchecked<S>(value: S) -> Self
117    where
118        S: Into<String>,
119    {
120        Ident {
121            value: value.into(),
122            quote_style: None,
123        }
124    }
125
126    /// Create a new quoted identifier with the given quote and value.
127    /// the given value must not be a empty string and the given quote must be in ['\'', '"', '`',
128    /// '['].
129    pub fn with_quote_unchecked<S>(quote: char, value: S) -> Self
130    where
131        S: Into<String>,
132    {
133        Ident {
134            value: value.into(),
135            quote_style: Some(quote),
136        }
137    }
138
139    /// Create a new quoted identifier with the given quote and value.
140    /// returns ParserError when the given string is empty or the given quote is illegal.
141    pub fn with_quote_check<S>(quote: char, value: S) -> Result<Ident, ParserError>
142    where
143        S: Into<String>,
144    {
145        let value_str = value.into();
146        if value_str.is_empty() {
147            return Err(ParserError::ParserError(format!(
148                "zero-length delimited identifier at or near \"{value_str}\""
149            )));
150        }
151
152        if !(quote == '\'' || quote == '"' || quote == '`' || quote == '[') {
153            return Err(ParserError::ParserError(
154                "unexpected quote style".to_owned(),
155            ));
156        }
157
158        Ok(Ident {
159            value: value_str,
160            quote_style: Some(quote),
161        })
162    }
163
164    /// Returns the identifier value used for name lookup and comparison.
165    ///
166    /// Unquoted identifiers are folded to lowercase, while double-quoted identifiers preserve
167    /// their case and unescaped contents. For example, `Foo` becomes `foo`, while `"Foo"` remains
168    /// `Foo` and `"a""b"` becomes `a"b`.
169    pub fn real_value(&self) -> String {
170        match self.quote_style {
171            Some('"') => self.value.clone(),
172            _ => self.value.to_lowercase(),
173        }
174    }
175
176    /// Creates an identifier from a name used internally by the database.
177    ///
178    /// The input is stored as its unescaped value. Double quotes are selected when needed to
179    /// preserve the name in SQL; escaping embedded quotes is left to the [`Display`] implementation.
180    /// This behaves like the SQL `quote_ident` function and the [`QuoteIdent`] wrapper.
181    pub fn from_real_value(value: &str) -> Self {
182        let needs_quotes = QuoteIdent::needs_quotes(value);
183
184        if needs_quotes {
185            Self::with_quote_unchecked('"', value)
186        } else {
187            Self::new_unchecked(value)
188        }
189    }
190
191    pub fn quote_style(&self) -> Option<char> {
192        self.quote_style
193    }
194}
195
196impl From<&str> for Ident {
197    fn from(value: &str) -> Self {
198        Self::from_real_value(value)
199    }
200}
201
202impl ParseTo for Ident {
203    fn parse_to(parser: &mut Parser<'_>) -> ModalResult<Self> {
204        parser.parse_identifier()
205    }
206}
207
208impl fmt::Display for Ident {
209    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210        match self.quote_style {
211            Some(q) if q == '\'' || q == '`' => write!(f, "{}{}{}", q, self.value, q),
212            Some('"') => write!(f, "\"{}\"", self.value.replace('"', "\"\"")),
213            Some('[') => write!(f, "[{}]", self.value),
214            None => f.write_str(&self.value),
215            _ => panic!("unexpected quote style"),
216        }
217    }
218}
219
220/// A name of a table, view, custom type, etc., possibly multi-part, i.e. db.schema.obj
221///
222/// Is is ensured to be non-empty.
223#[derive(Debug, Clone, PartialEq, Eq, Hash)]
224pub struct ObjectName(pub Vec<Ident>);
225
226impl ObjectName {
227    pub fn real_value(&self) -> String {
228        self.0
229            .iter()
230            .map(|ident| ident.real_value())
231            .collect::<Vec<_>>()
232            .join(".")
233    }
234
235    pub fn from_test_str(s: &str) -> Self {
236        ObjectName::from(vec![s.into()])
237    }
238
239    pub fn base_name(&self) -> String {
240        self.0
241            .iter()
242            .last()
243            .expect("should have base name")
244            .real_value()
245    }
246}
247
248impl fmt::Display for ObjectName {
249    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250        write!(f, "{}", display_separated(&self.0, "."))
251    }
252}
253
254impl ParseTo for ObjectName {
255    fn parse_to(p: &mut Parser<'_>) -> ModalResult<Self> {
256        p.parse_object_name()
257    }
258}
259
260impl From<Vec<Ident>> for ObjectName {
261    fn from(value: Vec<Ident>) -> Self {
262        Self(value)
263    }
264}
265
266/// For array type `ARRAY[..]` or `[..]`
267#[derive(Debug, Clone, PartialEq, Eq, Hash)]
268pub struct Array {
269    /// The list of expressions between brackets
270    pub elem: Vec<Expr>,
271
272    /// `true` for  `ARRAY[..]`, `false` for `[..]`
273    pub named: bool,
274}
275
276impl fmt::Display for Array {
277    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278        write!(
279            f,
280            "{}[{}]",
281            if self.named { "ARRAY" } else { "" },
282            display_comma_separated(&self.elem)
283        )
284    }
285}
286
287/// An escape character, to represent '' or a single character.
288#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
289pub struct EscapeChar(Option<char>);
290
291impl EscapeChar {
292    pub fn escape(ch: char) -> Self {
293        Self(Some(ch))
294    }
295
296    pub fn empty() -> Self {
297        Self(None)
298    }
299}
300
301impl fmt::Display for EscapeChar {
302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        match self.0 {
304            Some(ch) => write!(f, "{}", ch),
305            None => f.write_str(""),
306        }
307    }
308}
309
310/// An SQL expression of any type.
311///
312/// The parser does not distinguish between expressions of different types
313/// (e.g. boolean vs string), so the caller must handle expressions of
314/// inappropriate type, like `WHERE 1` or `SELECT 1=1`, as necessary.
315#[derive(Debug, Clone, PartialEq, Eq, Hash)]
316pub enum Expr {
317    /// Identifier e.g. table name or column name
318    Identifier(Ident),
319    /// Multi-part identifier, e.g. `table_alias.column` or `schema.table.col`
320    CompoundIdentifier(Vec<Ident>),
321    /// Struct-field identifier.
322    /// Expr is an arbitrary expression, returning either a table or a column.
323    /// Idents are consecutive field accesses.
324    /// e.g. `(table.v1).v2` or `(table).v1.v2`
325    ///
326    /// It must contain parentheses to be distinguished from a [`Expr::CompoundIdentifier`].
327    /// See also <https://www.postgresql.org/docs/current/rowtypes.html#ROWTYPES-ACCESSING>
328    ///
329    /// The left parentheses must be put at the beginning of the expression.
330    /// The first parenthesized part is the `expr` part, and the rest are flattened into `idents`.
331    /// e.g., `((v1).v2.v3).v4` is equivalent to `(v1).v2.v3.v4`.
332    FieldIdentifier(Box<Expr>, Vec<Ident>),
333    /// `IS NULL` operator
334    IsNull(Box<Expr>),
335    /// `IS NOT NULL` operator
336    IsNotNull(Box<Expr>),
337    /// `IS TRUE` operator
338    IsTrue(Box<Expr>),
339    /// `IS NOT TRUE` operator
340    IsNotTrue(Box<Expr>),
341    /// `IS FALSE` operator
342    IsFalse(Box<Expr>),
343    /// `IS NOT FALSE` operator
344    IsNotFalse(Box<Expr>),
345    /// `IS UNKNOWN` operator
346    IsUnknown(Box<Expr>),
347    /// `IS NOT UNKNOWN` operator
348    IsNotUnknown(Box<Expr>),
349    /// `IS DISTINCT FROM` operator
350    IsDistinctFrom(Box<Expr>, Box<Expr>),
351    /// `IS NOT DISTINCT FROM` operator
352    IsNotDistinctFrom(Box<Expr>, Box<Expr>),
353    /// ```text
354    /// IS [ NOT ] JSON [ VALUE | ARRAY | OBJECT | SCALAR ]
355    /// [ { WITH | WITHOUT } UNIQUE [ KEYS ] ]
356    /// ```
357    IsJson {
358        expr: Box<Expr>,
359        negated: bool,
360        item_type: JsonPredicateType,
361        unique_keys: bool,
362    },
363    /// `[ NOT ] IN (val1, val2, ...)`
364    InList {
365        expr: Box<Expr>,
366        list: Vec<Expr>,
367        negated: bool,
368    },
369    /// `[ NOT ] IN (SELECT ...)`
370    InSubquery {
371        expr: Box<Expr>,
372        subquery: Box<Query>,
373        negated: bool,
374    },
375    /// `<expr> [ NOT ] BETWEEN <low> AND <high>`
376    Between {
377        expr: Box<Expr>,
378        negated: bool,
379        low: Box<Expr>,
380        high: Box<Expr>,
381    },
382    /// LIKE
383    Like {
384        negated: bool,
385        expr: Box<Expr>,
386        pattern: Box<Expr>,
387        escape_char: Option<EscapeChar>,
388    },
389    /// ILIKE (case-insensitive LIKE)
390    ILike {
391        negated: bool,
392        expr: Box<Expr>,
393        pattern: Box<Expr>,
394        escape_char: Option<EscapeChar>,
395    },
396    /// `<expr> [ NOT ] SIMILAR TO <pat> ESCAPE <esc_text>`
397    SimilarTo {
398        negated: bool,
399        expr: Box<Expr>,
400        pattern: Box<Expr>,
401        escape_char: Option<EscapeChar>,
402    },
403    /// Binary operation e.g. `1 + 1` or `foo > bar`
404    BinaryOp {
405        left: Box<Expr>,
406        op: BinaryOperator,
407        right: Box<Expr>,
408    },
409    /// Some operation e.g. `foo > Some(bar)`, It will be wrapped in the right side of BinaryExpr
410    SomeOp(Box<Expr>),
411    /// ALL operation e.g. `foo > ALL(bar)`, It will be wrapped in the right side of BinaryExpr
412    AllOp(Box<Expr>),
413    /// Unary operation e.g. `NOT foo`
414    UnaryOp {
415        op: UnaryOperator,
416        expr: Box<Expr>,
417    },
418    /// CAST an expression to a different data type e.g. `CAST(foo AS VARCHAR)`
419    Cast {
420        expr: Box<Expr>,
421        data_type: DataType,
422    },
423    /// TRY_CAST an expression to a different data type e.g. `TRY_CAST(foo AS VARCHAR)`
424    //  this differs from CAST in the choice of how to implement invalid conversions
425    TryCast {
426        expr: Box<Expr>,
427        data_type: DataType,
428    },
429    /// AT TIME ZONE converts `timestamp without time zone` to/from `timestamp with time zone` with
430    /// explicitly specified zone
431    AtTimeZone {
432        timestamp: Box<Expr>,
433        time_zone: Box<Expr>,
434    },
435    /// `EXTRACT(DateTimeField FROM <expr>)`
436    Extract {
437        field: String,
438        expr: Box<Expr>,
439    },
440    /// `SUBSTRING(<expr> [FROM <expr>] [FOR <expr>])`
441    Substring {
442        expr: Box<Expr>,
443        substring_from: Option<Box<Expr>>,
444        substring_for: Option<Box<Expr>>,
445    },
446    /// `POSITION(<expr> IN <expr>)`
447    Position {
448        substring: Box<Expr>,
449        string: Box<Expr>,
450    },
451    /// `OVERLAY(<expr> PLACING <expr> FROM <expr> [ FOR <expr> ])`
452    Overlay {
453        expr: Box<Expr>,
454        new_substring: Box<Expr>,
455        start: Box<Expr>,
456        count: Option<Box<Expr>>,
457    },
458    /// `TRIM([BOTH | LEADING | TRAILING] [<expr>] FROM <expr>)`\
459    /// Or\
460    /// `TRIM([BOTH | LEADING | TRAILING] [FROM] <expr> [, <expr>])`
461    Trim {
462        expr: Box<Expr>,
463        // ([BOTH | LEADING | TRAILING], <expr>)
464        trim_where: Option<TrimWhereField>,
465        trim_what: Option<Box<Expr>>,
466    },
467    /// `expr COLLATE collation`
468    Collate {
469        expr: Box<Expr>,
470        collation: ObjectName,
471    },
472    /// Nested expression e.g. `(foo > bar)` or `(1)`
473    Nested(Box<Expr>),
474    /// A literal value, such as string, number, date or NULL
475    Value(Value),
476    /// Parameter Symbol e.g. `$1`, `$1::int`
477    Parameter {
478        index: u64,
479    },
480    /// A constant of form `<data_type> 'value'`.
481    /// This can represent ANSI SQL `DATE`, `TIME`, and `TIMESTAMP` literals (such as `DATE
482    /// '2020-01-01'`), as well as constants of other types (a non-standard PostgreSQL extension).
483    TypedString {
484        data_type: DataType,
485        value: String,
486    },
487    /// Scalar function call e.g. `LEFT(foo, 5)`
488    Function(Function),
489    /// `CASE [<operand>] WHEN <condition> THEN <result> ... [ELSE <result>] END`
490    ///
491    /// Note we only recognize a complete single expression as `<condition>`,
492    /// not `< 0` nor `1, 2, 3` as allowed in a `<simple when clause>` per
493    /// <https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#simple-when-clause>
494    Case {
495        operand: Option<Box<Expr>>,
496        conditions: Vec<Expr>,
497        results: Vec<Expr>,
498        else_result: Option<Box<Expr>>,
499    },
500    /// An exists expression `EXISTS(SELECT ...)`, used in expressions like
501    /// `WHERE EXISTS (SELECT ...)`.
502    Exists(Box<Query>),
503    /// A parenthesized subquery `(SELECT ...)`, used in expression like
504    /// `SELECT (subquery) AS x` or `WHERE (subquery) = x`
505    Subquery(Box<Query>),
506    /// The `GROUPING SETS` expr.
507    GroupingSets(Vec<Vec<Expr>>),
508    /// The `CUBE` expr.
509    Cube(Vec<Vec<Expr>>),
510    /// The `ROLLUP` expr.
511    Rollup(Vec<Vec<Expr>>),
512    /// The `ROW` expr. The `ROW` keyword can be omitted,
513    Row(Vec<Expr>),
514    /// An array constructor `ARRAY[[2,3,4],[5,6,7]]`
515    Array(Array),
516    /// An array constructing subquery `ARRAY(SELECT 2 UNION SELECT 3)`
517    ArraySubquery(Box<Query>),
518    /// A subscript expression `arr[1]` or `map['a']`
519    Index {
520        obj: Box<Expr>,
521        index: Box<Expr>,
522    },
523    /// A slice expression `arr[1:3]`
524    ArrayRangeIndex {
525        obj: Box<Expr>,
526        start: Option<Box<Expr>>,
527        end: Option<Box<Expr>>,
528    },
529    LambdaFunction {
530        args: Vec<Ident>,
531        body: Box<Expr>,
532    },
533    Map {
534        entries: Vec<(Expr, Expr)>,
535    },
536}
537
538impl fmt::Display for Expr {
539    #[expect(clippy::disallowed_methods, reason = "use zip_eq")]
540    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541        match self {
542            Expr::Identifier(s) => write!(f, "{}", s),
543            Expr::CompoundIdentifier(s) => write!(f, "{}", display_separated(s, ".")),
544            Expr::FieldIdentifier(ast, s) => write!(f, "({}).{}", ast, display_separated(s, ".")),
545            Expr::IsNull(ast) => write!(f, "{} IS NULL", ast),
546            Expr::IsNotNull(ast) => write!(f, "{} IS NOT NULL", ast),
547            Expr::IsTrue(ast) => write!(f, "{} IS TRUE", ast),
548            Expr::IsNotTrue(ast) => write!(f, "{} IS NOT TRUE", ast),
549            Expr::IsFalse(ast) => write!(f, "{} IS FALSE", ast),
550            Expr::IsNotFalse(ast) => write!(f, "{} IS NOT FALSE", ast),
551            Expr::IsUnknown(ast) => write!(f, "{} IS UNKNOWN", ast),
552            Expr::IsNotUnknown(ast) => write!(f, "{} IS NOT UNKNOWN", ast),
553            Expr::IsJson {
554                expr,
555                negated,
556                item_type,
557                unique_keys,
558            } => write!(
559                f,
560                "{} IS {}JSON{}{}",
561                expr,
562                if *negated { "NOT " } else { "" },
563                item_type,
564                if *unique_keys {
565                    " WITH UNIQUE KEYS"
566                } else {
567                    ""
568                },
569            ),
570            Expr::InList {
571                expr,
572                list,
573                negated,
574            } => write!(
575                f,
576                "{} {}IN ({})",
577                expr,
578                if *negated { "NOT " } else { "" },
579                display_comma_separated(list)
580            ),
581            Expr::InSubquery {
582                expr,
583                subquery,
584                negated,
585            } => write!(
586                f,
587                "{} {}IN ({})",
588                expr,
589                if *negated { "NOT " } else { "" },
590                subquery
591            ),
592            Expr::Between {
593                expr,
594                negated,
595                low,
596                high,
597            } => write!(
598                f,
599                "{} {}BETWEEN {} AND {}",
600                expr,
601                if *negated { "NOT " } else { "" },
602                low,
603                high
604            ),
605            Expr::Like {
606                negated,
607                expr,
608                pattern,
609                escape_char,
610            } => match escape_char {
611                Some(ch) => write!(
612                    f,
613                    "{} {}LIKE {} ESCAPE '{}'",
614                    expr,
615                    if *negated { "NOT " } else { "" },
616                    pattern,
617                    ch
618                ),
619                _ => write!(
620                    f,
621                    "{} {}LIKE {}",
622                    expr,
623                    if *negated { "NOT " } else { "" },
624                    pattern
625                ),
626            },
627            Expr::ILike {
628                negated,
629                expr,
630                pattern,
631                escape_char,
632            } => match escape_char {
633                Some(ch) => write!(
634                    f,
635                    "{} {}ILIKE {} ESCAPE '{}'",
636                    expr,
637                    if *negated { "NOT " } else { "" },
638                    pattern,
639                    ch
640                ),
641                _ => write!(
642                    f,
643                    "{} {}ILIKE {}",
644                    expr,
645                    if *negated { "NOT " } else { "" },
646                    pattern
647                ),
648            },
649            Expr::SimilarTo {
650                negated,
651                expr,
652                pattern,
653                escape_char,
654            } => match escape_char {
655                Some(ch) => write!(
656                    f,
657                    "{} {}SIMILAR TO {} ESCAPE '{}'",
658                    expr,
659                    if *negated { "NOT " } else { "" },
660                    pattern,
661                    ch
662                ),
663                _ => write!(
664                    f,
665                    "{} {}SIMILAR TO {}",
666                    expr,
667                    if *negated { "NOT " } else { "" },
668                    pattern
669                ),
670            },
671            Expr::BinaryOp { left, op, right } => write!(f, "{} {} {}", left, op, right),
672            Expr::SomeOp(expr) => write!(f, "SOME({})", expr),
673            Expr::AllOp(expr) => write!(f, "ALL({})", expr),
674            Expr::UnaryOp { op, expr } => {
675                write!(f, "{} {}", op, expr)
676            }
677            Expr::Cast { expr, data_type } => write!(f, "CAST({} AS {})", expr, data_type),
678            Expr::TryCast { expr, data_type } => write!(f, "TRY_CAST({} AS {})", expr, data_type),
679            Expr::AtTimeZone {
680                timestamp,
681                time_zone,
682            } => write!(f, "{} AT TIME ZONE {}", timestamp, time_zone),
683            Expr::Extract { field, expr } => write!(f, "EXTRACT({} FROM {})", field, expr),
684            Expr::Collate { expr, collation } => write!(f, "{} COLLATE {}", expr, collation),
685            Expr::Nested(ast) => write!(f, "({})", ast),
686            Expr::Value(v) => write!(f, "{}", v),
687            Expr::Parameter { index } => write!(f, "${}", index),
688            Expr::TypedString { data_type, value } => {
689                write!(f, "{}", data_type)?;
690                write!(f, " '{}'", value::escape_single_quote_string(value))
691            }
692            Expr::Function(fun) => write!(f, "{}", fun),
693            Expr::Case {
694                operand,
695                conditions,
696                results,
697                else_result,
698            } => {
699                write!(f, "CASE")?;
700                if let Some(operand) = operand {
701                    write!(f, " {}", operand)?;
702                }
703                for (c, r) in conditions.iter().zip_eq(results) {
704                    write!(f, " WHEN {} THEN {}", c, r)?;
705                }
706
707                if let Some(else_result) = else_result {
708                    write!(f, " ELSE {}", else_result)?;
709                }
710                write!(f, " END")
711            }
712            Expr::Exists(s) => write!(f, "EXISTS ({})", s),
713            Expr::Subquery(s) => write!(f, "({})", s),
714            Expr::GroupingSets(sets) => {
715                write!(f, "GROUPING SETS (")?;
716                let mut sep = "";
717                for set in sets {
718                    write!(f, "{}", sep)?;
719                    sep = ", ";
720                    write!(f, "({})", display_comma_separated(set))?;
721                }
722                write!(f, ")")
723            }
724            Expr::Cube(sets) => {
725                write!(f, "CUBE (")?;
726                let mut sep = "";
727                for set in sets {
728                    write!(f, "{}", sep)?;
729                    sep = ", ";
730                    if set.len() == 1 {
731                        write!(f, "{}", set[0])?;
732                    } else {
733                        write!(f, "({})", display_comma_separated(set))?;
734                    }
735                }
736                write!(f, ")")
737            }
738            Expr::Rollup(sets) => {
739                write!(f, "ROLLUP (")?;
740                let mut sep = "";
741                for set in sets {
742                    write!(f, "{}", sep)?;
743                    sep = ", ";
744                    if set.len() == 1 {
745                        write!(f, "{}", set[0])?;
746                    } else {
747                        write!(f, "({})", display_comma_separated(set))?;
748                    }
749                }
750                write!(f, ")")
751            }
752            Expr::Substring {
753                expr,
754                substring_from,
755                substring_for,
756            } => {
757                write!(f, "SUBSTRING({}", expr)?;
758                if let Some(from_part) = substring_from {
759                    write!(f, " FROM {}", from_part)?;
760                }
761                if let Some(from_part) = substring_for {
762                    write!(f, " FOR {}", from_part)?;
763                }
764
765                write!(f, ")")
766            }
767            Expr::Position { substring, string } => {
768                write!(f, "POSITION({} IN {})", substring, string)
769            }
770            Expr::Overlay {
771                expr,
772                new_substring,
773                start,
774                count,
775            } => {
776                write!(f, "OVERLAY({}", expr)?;
777                write!(f, " PLACING {}", new_substring)?;
778                write!(f, " FROM {}", start)?;
779
780                if let Some(count_expr) = count {
781                    write!(f, " FOR {}", count_expr)?;
782                }
783
784                write!(f, ")")
785            }
786            Expr::IsDistinctFrom(a, b) => write!(f, "{} IS DISTINCT FROM {}", a, b),
787            Expr::IsNotDistinctFrom(a, b) => write!(f, "{} IS NOT DISTINCT FROM {}", a, b),
788            Expr::Trim {
789                expr,
790                trim_where,
791                trim_what,
792            } => {
793                write!(f, "TRIM(")?;
794                if let Some(ident) = trim_where {
795                    write!(f, "{} ", ident)?;
796                }
797                if let Some(trim_char) = trim_what {
798                    write!(f, "{} ", trim_char)?;
799                }
800                write!(f, "FROM {})", expr)
801            }
802            Expr::Row(exprs) => write!(
803                f,
804                "ROW({})",
805                exprs
806                    .iter()
807                    .map(|v| v.to_string())
808                    .collect::<Vec<String>>()
809                    .as_slice()
810                    .join(", ")
811            ),
812            Expr::Index { obj, index } => {
813                write!(f, "{}[{}]", obj, index)?;
814                Ok(())
815            }
816            Expr::ArrayRangeIndex { obj, start, end } => {
817                let start_str = match start {
818                    None => "".to_owned(),
819                    Some(start) => format!("{}", start),
820                };
821                let end_str = match end {
822                    None => "".to_owned(),
823                    Some(end) => format!("{}", end),
824                };
825                write!(f, "{}[{}:{}]", obj, start_str, end_str)?;
826                Ok(())
827            }
828            Expr::Array(exprs) => write!(f, "{}", exprs),
829            Expr::ArraySubquery(s) => write!(f, "ARRAY ({})", s),
830            Expr::LambdaFunction { args, body } => {
831                write!(
832                    f,
833                    "|{}| {}",
834                    args.iter().map(ToString::to_string).join(", "),
835                    body
836                )
837            }
838            Expr::Map { entries } => {
839                write!(
840                    f,
841                    "MAP {{{}}}",
842                    entries
843                        .iter()
844                        .map(|(k, v)| format!("{}: {}", k, v))
845                        .join(", ")
846                )
847            }
848        }
849    }
850}
851
852/// A window specification (i.e. `OVER (PARTITION BY .. ORDER BY .. etc.)`).
853/// This is used both for named window definitions and inline window specifications.
854#[derive(Debug, Clone, PartialEq, Eq, Hash)]
855pub struct WindowSpec {
856    pub partition_by: Vec<Expr>,
857    pub order_by: Vec<OrderByExpr>,
858    pub window_frame: Option<WindowFrame>,
859}
860
861/// A window definition that can appear in the OVER clause of a window function.
862/// This can be either an inline window specification or a reference to a named window.
863#[derive(Debug, Clone, PartialEq, Eq, Hash)]
864pub enum Window {
865    /// Inline window specification: `OVER (PARTITION BY ... ORDER BY ...)`
866    Spec(WindowSpec),
867    /// Named window reference: `OVER window_name`
868    Name(Ident),
869}
870
871impl fmt::Display for WindowSpec {
872    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
873        let mut delim = "";
874        if !self.partition_by.is_empty() {
875            delim = " ";
876            write!(
877                f,
878                "PARTITION BY {}",
879                display_comma_separated(&self.partition_by)
880            )?;
881        }
882        if !self.order_by.is_empty() {
883            f.write_str(delim)?;
884            delim = " ";
885            write!(f, "ORDER BY {}", display_comma_separated(&self.order_by))?;
886        }
887        if let Some(window_frame) = &self.window_frame {
888            f.write_str(delim)?;
889            window_frame.fmt(f)?;
890        }
891        Ok(())
892    }
893}
894
895impl fmt::Display for Window {
896    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
897        match self {
898            Window::Spec(spec) => write!(f, "({})", spec),
899            Window::Name(name) => write!(f, "{}", name),
900        }
901    }
902}
903
904/// Specifies the data processed by a window function, e.g.
905/// `RANGE UNBOUNDED PRECEDING` or `ROWS BETWEEN 5 PRECEDING AND CURRENT ROW`.
906///
907/// Note: The parser does not validate the specified bounds; the caller should
908/// reject invalid bounds like `ROWS UNBOUNDED FOLLOWING` before execution.
909#[derive(Debug, Clone, PartialEq, Eq, Hash)]
910pub struct WindowFrame {
911    pub units: WindowFrameUnits,
912    pub bounds: WindowFrameBounds,
913    pub exclusion: Option<WindowFrameExclusion>,
914}
915
916#[derive(Debug, Clone, PartialEq, Eq, Hash)]
917pub enum WindowFrameUnits {
918    Rows,
919    Range,
920    Groups,
921    Session,
922}
923
924#[derive(Debug, Clone, PartialEq, Eq, Hash)]
925pub enum WindowFrameBounds {
926    Bounds {
927        start: WindowFrameBound,
928        /// The right bound of the `BETWEEN .. AND` clause. The end bound of `None`
929        /// indicates the shorthand form (e.g. `ROWS 1 PRECEDING`), which must
930        /// behave the same as `end_bound = WindowFrameBound::CurrentRow`.
931        end: Option<WindowFrameBound>,
932    },
933    Gap(Box<Expr>),
934}
935
936impl fmt::Display for WindowFrame {
937    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
938        write!(f, "{} ", self.units)?;
939        match &self.bounds {
940            WindowFrameBounds::Bounds { start, end } => {
941                if let Some(end) = end {
942                    write!(f, "BETWEEN {} AND {}", start, end)
943                } else {
944                    write!(f, "{}", start)
945                }
946            }
947            WindowFrameBounds::Gap(gap) => {
948                write!(f, "WITH GAP {}", gap)
949            }
950        }
951    }
952}
953
954impl fmt::Display for WindowFrameUnits {
955    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
956        f.write_str(match self {
957            WindowFrameUnits::Rows => "ROWS",
958            WindowFrameUnits::Range => "RANGE",
959            WindowFrameUnits::Groups => "GROUPS",
960            WindowFrameUnits::Session => "SESSION",
961        })
962    }
963}
964
965/// Specifies [WindowFrame]'s `start_bound` and `end_bound`
966#[derive(Debug, Clone, PartialEq, Eq, Hash)]
967pub enum WindowFrameBound {
968    /// `CURRENT ROW`
969    CurrentRow,
970    /// `<offset> PRECEDING` or `UNBOUNDED PRECEDING`
971    Preceding(Option<Box<Expr>>),
972    /// `<offset> FOLLOWING` or `UNBOUNDED FOLLOWING`.
973    Following(Option<Box<Expr>>),
974}
975
976impl fmt::Display for WindowFrameBound {
977    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
978        match self {
979            WindowFrameBound::CurrentRow => f.write_str("CURRENT ROW"),
980            WindowFrameBound::Preceding(None) => f.write_str("UNBOUNDED PRECEDING"),
981            WindowFrameBound::Following(None) => f.write_str("UNBOUNDED FOLLOWING"),
982            WindowFrameBound::Preceding(Some(n)) => write!(f, "{} PRECEDING", n),
983            WindowFrameBound::Following(Some(n)) => write!(f, "{} FOLLOWING", n),
984        }
985    }
986}
987
988/// Frame exclusion option of [WindowFrame].
989#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
990pub enum WindowFrameExclusion {
991    CurrentRow,
992    Group,
993    Ties,
994    NoOthers,
995}
996
997impl fmt::Display for WindowFrameExclusion {
998    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
999        match self {
1000            WindowFrameExclusion::CurrentRow => f.write_str("EXCLUDE CURRENT ROW"),
1001            WindowFrameExclusion::Group => f.write_str("EXCLUDE GROUP"),
1002            WindowFrameExclusion::Ties => f.write_str("EXCLUDE TIES"),
1003            WindowFrameExclusion::NoOthers => f.write_str("EXCLUDE NO OTHERS"),
1004        }
1005    }
1006}
1007
1008#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1009pub enum AddDropSync {
1010    ADD,
1011    DROP,
1012    SYNC,
1013}
1014
1015impl fmt::Display for AddDropSync {
1016    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1017        match self {
1018            AddDropSync::SYNC => f.write_str("SYNC PARTITIONS"),
1019            AddDropSync::DROP => f.write_str("DROP PARTITIONS"),
1020            AddDropSync::ADD => f.write_str("ADD PARTITIONS"),
1021        }
1022    }
1023}
1024
1025#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1026pub enum ShowObject {
1027    Table { schema: Option<Ident> },
1028    InternalTable { schema: Option<Ident> },
1029    Database,
1030    Schema,
1031    View { schema: Option<Ident> },
1032    MaterializedView { schema: Option<Ident> },
1033    Source { schema: Option<Ident> },
1034    Sink { schema: Option<Ident> },
1035    Subscription { schema: Option<Ident> },
1036    Columns { table: ObjectName },
1037    Connection { schema: Option<Ident> },
1038    Secret { schema: Option<Ident> },
1039    Function { schema: Option<Ident> },
1040    Indexes { table: ObjectName },
1041    Cluster,
1042    Jobs,
1043    ProcessList,
1044    Cursor,
1045    SubscriptionCursor,
1046}
1047
1048#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1049pub struct JobIdents(pub Vec<u32>);
1050
1051impl fmt::Display for ShowObject {
1052    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1053        fn fmt_schema(schema: &Option<Ident>) -> String {
1054            if let Some(schema) = schema {
1055                format!(" FROM {}", schema.value)
1056            } else {
1057                "".to_owned()
1058            }
1059        }
1060
1061        match self {
1062            ShowObject::Database => f.write_str("DATABASES"),
1063            ShowObject::Schema => f.write_str("SCHEMAS"),
1064            ShowObject::Table { schema } => {
1065                write!(f, "TABLES{}", fmt_schema(schema))
1066            }
1067            ShowObject::InternalTable { schema } => {
1068                write!(f, "INTERNAL TABLES{}", fmt_schema(schema))
1069            }
1070            ShowObject::View { schema } => {
1071                write!(f, "VIEWS{}", fmt_schema(schema))
1072            }
1073            ShowObject::MaterializedView { schema } => {
1074                write!(f, "MATERIALIZED VIEWS{}", fmt_schema(schema))
1075            }
1076            ShowObject::Source { schema } => write!(f, "SOURCES{}", fmt_schema(schema)),
1077            ShowObject::Sink { schema } => write!(f, "SINKS{}", fmt_schema(schema)),
1078            ShowObject::Columns { table } => write!(f, "COLUMNS FROM {}", table),
1079            ShowObject::Connection { schema } => write!(f, "CONNECTIONS{}", fmt_schema(schema)),
1080            ShowObject::Function { schema } => write!(f, "FUNCTIONS{}", fmt_schema(schema)),
1081            ShowObject::Indexes { table } => write!(f, "INDEXES FROM {}", table),
1082            ShowObject::Cluster => {
1083                write!(f, "CLUSTER")
1084            }
1085            ShowObject::Jobs => write!(f, "JOBS"),
1086            ShowObject::ProcessList => write!(f, "PROCESSLIST"),
1087            ShowObject::Subscription { schema } => write!(f, "SUBSCRIPTIONS{}", fmt_schema(schema)),
1088            ShowObject::Secret { schema } => write!(f, "SECRETS{}", fmt_schema(schema)),
1089            ShowObject::Cursor => write!(f, "CURSORS"),
1090            ShowObject::SubscriptionCursor => write!(f, "SUBSCRIPTION CURSORS"),
1091        }
1092    }
1093}
1094
1095#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1096pub enum ShowCreateType {
1097    Table,
1098    MaterializedView,
1099    View,
1100    Index,
1101    Source,
1102    Sink,
1103    Function,
1104    Subscription,
1105}
1106
1107impl fmt::Display for ShowCreateType {
1108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1109        match self {
1110            ShowCreateType::Table => f.write_str("TABLE"),
1111            ShowCreateType::MaterializedView => f.write_str("MATERIALIZED VIEW"),
1112            ShowCreateType::View => f.write_str("VIEW"),
1113            ShowCreateType::Index => f.write_str("INDEX"),
1114            ShowCreateType::Source => f.write_str("SOURCE"),
1115            ShowCreateType::Sink => f.write_str("SINK"),
1116            ShowCreateType::Function => f.write_str("FUNCTION"),
1117            ShowCreateType::Subscription => f.write_str("SUBSCRIPTION"),
1118        }
1119    }
1120}
1121
1122#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1123pub enum CommentObject {
1124    Column,
1125    Table,
1126}
1127
1128impl fmt::Display for CommentObject {
1129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1130        match self {
1131            CommentObject::Column => f.write_str("COLUMN"),
1132            CommentObject::Table => f.write_str("TABLE"),
1133        }
1134    }
1135}
1136
1137#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1138pub enum ExplainType {
1139    Logical,
1140    Physical,
1141    DistSql,
1142}
1143
1144impl fmt::Display for ExplainType {
1145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1146        match self {
1147            ExplainType::Logical => f.write_str("Logical"),
1148            ExplainType::Physical => f.write_str("Physical"),
1149            ExplainType::DistSql => f.write_str("DistSQL"),
1150        }
1151    }
1152}
1153
1154#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1155pub enum ExplainFormat {
1156    Text,
1157    Json,
1158    Xml,
1159    Yaml,
1160    Dot,
1161}
1162
1163impl fmt::Display for ExplainFormat {
1164    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1165        match self {
1166            ExplainFormat::Text => f.write_str("TEXT"),
1167            ExplainFormat::Json => f.write_str("JSON"),
1168            ExplainFormat::Xml => f.write_str("XML"),
1169            ExplainFormat::Yaml => f.write_str("YAML"),
1170            ExplainFormat::Dot => f.write_str("DOT"),
1171        }
1172    }
1173}
1174
1175#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1176pub struct ExplainOptions {
1177    /// Display additional information regarding the plan.
1178    pub verbose: bool,
1179    // Trace plan transformation of the optimizer step by step
1180    pub trace: bool,
1181    // Display backfill order
1182    pub backfill: bool,
1183    // explain's plan type
1184    pub explain_type: ExplainType,
1185    // explain's plan format
1186    pub explain_format: ExplainFormat,
1187}
1188
1189impl Default for ExplainOptions {
1190    fn default() -> Self {
1191        Self {
1192            verbose: false,
1193            trace: false,
1194            backfill: false,
1195            explain_type: ExplainType::Physical,
1196            explain_format: ExplainFormat::Text,
1197        }
1198    }
1199}
1200
1201impl fmt::Display for ExplainOptions {
1202    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1203        let default = Self::default();
1204        if *self == default {
1205            Ok(())
1206        } else {
1207            let mut option_strs = vec![];
1208            if self.verbose {
1209                option_strs.push("VERBOSE".to_owned());
1210            }
1211            if self.trace {
1212                option_strs.push("TRACE".to_owned());
1213            }
1214            if self.backfill {
1215                option_strs.push("BACKFILL".to_owned());
1216            }
1217            if self.explain_type == default.explain_type {
1218                option_strs.push(self.explain_type.to_string());
1219            }
1220            if self.explain_format == default.explain_format {
1221                option_strs.push(self.explain_format.to_string());
1222            }
1223            write!(f, "{}", option_strs.iter().format(","))
1224        }
1225    }
1226}
1227
1228#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1229pub struct CdcTableInfo {
1230    pub source_name: ObjectName,
1231    pub external_table_name: String,
1232}
1233
1234#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1235pub enum CopyEntity {
1236    Query(Box<Query>),
1237    Table {
1238        /// TABLE
1239        table_name: ObjectName,
1240        /// COLUMNS
1241        columns: Vec<Ident>,
1242    },
1243}
1244
1245#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1246pub enum CopyTarget {
1247    Stdin {
1248        /// VALUES a vector of values to be copied
1249        values: Vec<Option<String>>,
1250    },
1251    Stdout,
1252}
1253
1254#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1255pub enum WaitTarget {
1256    All,
1257    Table(ObjectName),
1258    MaterializedView(ObjectName),
1259    Sink(ObjectName),
1260    Index(ObjectName),
1261}
1262
1263/// A top-level statement (SELECT, INSERT, CREATE, etc.)
1264
1265#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1266pub enum Statement {
1267    /// Analyze (Hive)
1268    Analyze {
1269        table_name: ObjectName,
1270    },
1271    /// Truncate (Hive)
1272    Truncate {
1273        table_name: ObjectName,
1274    },
1275    /// Refresh table
1276    Refresh {
1277        table_name: ObjectName,
1278    },
1279    /// SELECT
1280    Query(Box<Query>),
1281    /// INSERT
1282    Insert {
1283        /// TABLE
1284        table_name: ObjectName,
1285        /// COLUMNS
1286        columns: Vec<Ident>,
1287        /// A SQL query that specifies what to insert
1288        source: Box<Query>,
1289        /// Define output of this insert statement
1290        returning: Vec<SelectItem>,
1291    },
1292    Copy {
1293        entity: CopyEntity,
1294        target: CopyTarget,
1295    },
1296    /// UPDATE
1297    Update {
1298        /// TABLE
1299        table_name: ObjectName,
1300        /// Column assignments
1301        assignments: Vec<Assignment>,
1302        /// WHERE
1303        selection: Option<Expr>,
1304        /// RETURNING
1305        returning: Vec<SelectItem>,
1306    },
1307    /// DELETE
1308    Delete {
1309        /// FROM
1310        table_name: ObjectName,
1311        /// WHERE
1312        selection: Option<Expr>,
1313        /// RETURNING
1314        returning: Vec<SelectItem>,
1315    },
1316    /// DELETE META SNAPSHOT(S)
1317    DeleteMetaSnapshots {
1318        snapshot_ids: Vec<u64>,
1319    },
1320    /// DISCARD
1321    Discard(DiscardType),
1322    /// CREATE VIEW
1323    CreateView {
1324        or_replace: bool,
1325        materialized: bool,
1326        if_not_exists: bool,
1327        /// View name
1328        name: ObjectName,
1329        columns: Vec<Ident>,
1330        query: Box<Query>,
1331        emit_mode: Option<EmitMode>,
1332        with_options: Vec<SqlOption>,
1333    },
1334    /// CREATE TABLE
1335    CreateTable {
1336        or_replace: bool,
1337        temporary: bool,
1338        if_not_exists: bool,
1339        /// Table name
1340        name: ObjectName,
1341        /// Optional schema
1342        columns: Vec<ColumnDef>,
1343        // The wildchar position in columns defined in sql. Only exist when using external schema.
1344        wildcard_idx: Option<usize>,
1345        constraints: Vec<TableConstraint>,
1346        with_options: Vec<SqlOption>,
1347        /// `FORMAT ... ENCODE ...` for table with connector
1348        format_encode: Option<CompatibleFormatEncode>,
1349        /// The watermark defined on source.
1350        source_watermarks: Vec<SourceWatermark>,
1351        /// Append only table.
1352        append_only: bool,
1353        /// On conflict behavior
1354        on_conflict: Option<OnConflict>,
1355        /// with_version_columns behind on conflict - supports multiple version columns
1356        with_version_columns: Vec<Ident>,
1357        /// `AS ( query )`
1358        query: Option<Box<Query>>,
1359        /// `FROM cdc_source TABLE database_name.table_name`
1360        cdc_table_info: Option<CdcTableInfo>,
1361        /// `INCLUDE a AS b INCLUDE c`
1362        include_column_options: IncludeOption,
1363        /// `VALIDATE SECRET secure_secret_name AS secure_compare ()`
1364        webhook_info: Option<WebhookSourceInfo>,
1365        /// `Engine = [hummock | iceberg]`
1366        engine: Engine,
1367    },
1368    /// CREATE INDEX
1369    CreateIndex {
1370        /// index name
1371        name: ObjectName,
1372        table_name: ObjectName,
1373        columns: Vec<OrderByExpr>,
1374        method: Option<Ident>,
1375        include: Vec<Ident>,
1376        distributed_by: Vec<Expr>,
1377        unique: bool,
1378        if_not_exists: bool,
1379        with_properties: WithProperties,
1380    },
1381    /// CREATE SOURCE
1382    CreateSource {
1383        stmt: CreateSourceStatement,
1384    },
1385    /// CREATE SINK
1386    CreateSink {
1387        stmt: CreateSinkStatement,
1388    },
1389    /// CREATE SUBSCRIPTION
1390    CreateSubscription {
1391        stmt: CreateSubscriptionStatement,
1392    },
1393    /// CREATE CONNECTION
1394    CreateConnection {
1395        stmt: CreateConnectionStatement,
1396    },
1397    CreateSecret {
1398        stmt: CreateSecretStatement,
1399    },
1400    /// CREATE FUNCTION
1401    ///
1402    /// Postgres: <https://www.postgresql.org/docs/15/sql-createfunction.html>
1403    CreateFunction {
1404        or_replace: bool,
1405        temporary: bool,
1406        if_not_exists: bool,
1407        name: ObjectName,
1408        args: Option<Vec<OperateFunctionArg>>,
1409        returns: Option<CreateFunctionReturns>,
1410        /// Optional parameters.
1411        params: CreateFunctionBody,
1412        with_options: CreateFunctionWithOptions, // FIXME(eric): use Option<>
1413    },
1414    /// CREATE AGGREGATE
1415    ///
1416    /// Postgres: <https://www.postgresql.org/docs/15/sql-createaggregate.html>
1417    CreateAggregate {
1418        or_replace: bool,
1419        if_not_exists: bool,
1420        name: ObjectName,
1421        args: Vec<OperateFunctionArg>,
1422        returns: DataType,
1423        /// Optional parameters.
1424        append_only: bool,
1425        params: CreateFunctionBody,
1426    },
1427
1428    /// DECLARE CURSOR
1429    DeclareCursor {
1430        stmt: DeclareCursorStatement,
1431    },
1432
1433    // FETCH CURSOR
1434    FetchCursor {
1435        stmt: FetchCursorStatement,
1436    },
1437
1438    // CLOSE CURSOR
1439    CloseCursor {
1440        stmt: CloseCursorStatement,
1441    },
1442
1443    /// ALTER DATABASE
1444    AlterDatabase {
1445        name: ObjectName,
1446        operation: AlterDatabaseOperation,
1447    },
1448    /// ALTER SCHEMA
1449    AlterSchema {
1450        name: ObjectName,
1451        operation: AlterSchemaOperation,
1452    },
1453    /// ALTER TABLE
1454    AlterTable {
1455        /// Table name
1456        name: ObjectName,
1457        operation: AlterTableOperation,
1458    },
1459    /// ALTER INDEX
1460    AlterIndex {
1461        /// Index name
1462        name: ObjectName,
1463        operation: AlterIndexOperation,
1464    },
1465    /// ALTER VIEW
1466    AlterView {
1467        /// View name
1468        name: ObjectName,
1469        materialized: bool,
1470        operation: AlterViewOperation,
1471    },
1472    /// ALTER SINK
1473    AlterSink {
1474        /// Sink name
1475        name: ObjectName,
1476        operation: AlterSinkOperation,
1477    },
1478    AlterSubscription {
1479        name: ObjectName,
1480        operation: AlterSubscriptionOperation,
1481    },
1482    /// ALTER SOURCE
1483    AlterSource {
1484        /// Source name
1485        name: ObjectName,
1486        operation: AlterSourceOperation,
1487    },
1488    /// ALTER FUNCTION
1489    AlterFunction {
1490        /// Function name
1491        name: ObjectName,
1492        args: Option<Vec<OperateFunctionArg>>,
1493        operation: AlterFunctionOperation,
1494    },
1495    /// ALTER CONNECTION
1496    AlterConnection {
1497        /// Connection name
1498        name: ObjectName,
1499        operation: AlterConnectionOperation,
1500    },
1501    /// ALTER SECRET
1502    AlterSecret {
1503        /// Secret name
1504        name: ObjectName,
1505        operation: AlterSecretOperation,
1506    },
1507    /// ALTER FRAGMENT
1508    AlterFragment {
1509        fragment_ids: Vec<u32>,
1510        operation: AlterFragmentOperation,
1511    },
1512    /// ALTER COMPACTION GROUP
1513    AlterCompactionGroup {
1514        group_ids: Vec<u64>,
1515        operation: AlterCompactionGroupOperation,
1516    },
1517    /// DESCRIBE relation
1518    /// ALTER DEFAULT PRIVILEGES
1519    AlterDefaultPrivileges {
1520        target_users: Option<Vec<Ident>>,
1521        schema_names: Option<Vec<ObjectName>>,
1522        operation: DefaultPrivilegeOperation,
1523    },
1524    /// DESCRIBE relation
1525    Describe {
1526        /// relation name
1527        name: ObjectName,
1528        kind: DescribeKind,
1529    },
1530    /// DESCRIBE FRAGMENT <fragment_id>
1531    DescribeFragment {
1532        fragment_id: u32,
1533    },
1534    /// SHOW OBJECT COMMAND
1535    ShowObjects {
1536        object: ShowObject,
1537        filter: Option<ShowStatementFilter>,
1538    },
1539    /// SHOW CREATE COMMAND
1540    ShowCreateObject {
1541        /// Show create object type
1542        create_type: ShowCreateType,
1543        /// Show create object name
1544        name: ObjectName,
1545    },
1546    ShowTransactionIsolationLevel,
1547    /// CANCEL JOBS COMMAND
1548    CancelJobs(JobIdents),
1549    /// KILL COMMAND
1550    /// Kill process in the show processlist.
1551    Kill(String),
1552    /// DROP
1553    Drop(DropStatement),
1554    /// DROP FUNCTION
1555    DropFunction {
1556        if_exists: bool,
1557        /// One or more function to drop
1558        func_desc: Vec<FunctionDesc>,
1559        /// `CASCADE` or `RESTRICT`
1560        option: Option<ReferentialAction>,
1561    },
1562    /// DROP AGGREGATE
1563    DropAggregate {
1564        if_exists: bool,
1565        /// One or more function to drop
1566        func_desc: Vec<FunctionDesc>,
1567        /// `CASCADE` or `RESTRICT`
1568        option: Option<ReferentialAction>,
1569    },
1570    /// `SET <variable>`
1571    ///
1572    /// Note: this is not a standard SQL statement, but it is supported by at
1573    /// least MySQL and PostgreSQL. Not all MySQL-specific syntactic forms are
1574    /// supported yet.
1575    SetVariable {
1576        local: bool,
1577        variable: Ident,
1578        value: SetVariableValue,
1579    },
1580    /// `SHOW <variable>`
1581    ///
1582    /// Note: this is a PostgreSQL-specific statement.
1583    ShowVariable {
1584        variable: Vec<Ident>,
1585    },
1586    /// `START TRANSACTION ...`
1587    StartTransaction {
1588        modes: Vec<TransactionMode>,
1589    },
1590    /// `BEGIN [ TRANSACTION | WORK ]`
1591    Begin {
1592        modes: Vec<TransactionMode>,
1593    },
1594    /// ABORT
1595    Abort,
1596    /// `SET TRANSACTION ...`
1597    SetTransaction {
1598        modes: Vec<TransactionMode>,
1599        snapshot: Option<Value>,
1600        session: bool,
1601    },
1602    /// `SET [ SESSION | LOCAL ] TIME ZONE { value | 'value' | LOCAL | DEFAULT }`
1603    SetTimeZone {
1604        local: bool,
1605        value: SetTimeZoneValue,
1606    },
1607    /// `COMMENT ON ...`
1608    ///
1609    /// Note: this is a PostgreSQL-specific statement.
1610    Comment {
1611        object_type: CommentObject,
1612        object_name: ObjectName,
1613        comment: Option<String>,
1614    },
1615    /// `COMMIT [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
1616    Commit {
1617        chain: bool,
1618    },
1619    /// `ROLLBACK [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
1620    Rollback {
1621        chain: bool,
1622    },
1623    /// CREATE SCHEMA
1624    CreateSchema {
1625        schema_name: ObjectName,
1626        if_not_exists: bool,
1627        owner: Option<ObjectName>,
1628    },
1629    /// CREATE DATABASE
1630    CreateDatabase {
1631        db_name: ObjectName,
1632        if_not_exists: bool,
1633        owner: Option<ObjectName>,
1634        resource_group: Option<SetVariableValue>,
1635        barrier_interval_ms: Option<u32>,
1636        checkpoint_frequency: Option<u64>,
1637    },
1638    /// GRANT privileges ON objects TO grantees
1639    Grant {
1640        privileges: Privileges,
1641        objects: GrantObjects,
1642        grantees: Vec<Ident>,
1643        with_grant_option: bool,
1644        granted_by: Option<Ident>,
1645    },
1646    /// REVOKE privileges ON objects FROM grantees
1647    Revoke {
1648        privileges: Privileges,
1649        objects: GrantObjects,
1650        grantees: Vec<Ident>,
1651        granted_by: Option<Ident>,
1652        revoke_grant_option: bool,
1653        cascade: bool,
1654    },
1655    /// `DEALLOCATE [ PREPARE ] { name | ALL }`
1656    ///
1657    /// Note: this is a PostgreSQL-specific statement.
1658    Deallocate {
1659        name: Option<Ident>,
1660        prepare: bool,
1661    },
1662    /// `EXECUTE name [ ( parameter [, ...] ) ]`
1663    ///
1664    /// Note: this is a PostgreSQL-specific statement.
1665    Execute {
1666        name: Ident,
1667        parameters: Vec<Expr>,
1668    },
1669    /// `PREPARE name [ ( data_type [, ...] ) ] AS statement`
1670    ///
1671    /// Note: this is a PostgreSQL-specific statement.
1672    Prepare {
1673        name: Ident,
1674        data_types: Vec<DataType>,
1675        statement: Box<Statement>,
1676    },
1677    /// EXPLAIN / DESCRIBE for select_statement
1678    Explain {
1679        /// Carry out the command and show actual run times and other statistics.
1680        analyze: bool,
1681        /// A SQL query that specifies what to explain
1682        statement: Box<Statement>,
1683        /// options of the explain statement
1684        options: ExplainOptions,
1685    },
1686    /// EXPLAIN ANALYZE for stream job
1687    /// We introduce a new statement rather than reuse `EXPLAIN` because
1688    /// the body of the statement is not an SQL query.
1689    /// TODO(kwannoel): Make profiling duration configurable: EXPLAIN ANALYZE (DURATION 1s) ...
1690    ExplainAnalyzeStreamJob {
1691        target: AnalyzeTarget,
1692        duration_secs: Option<u64>,
1693    },
1694    /// CREATE USER
1695    CreateUser(CreateUserStatement),
1696    /// ALTER USER
1697    AlterUser(AlterUserStatement),
1698    /// ALTER SYSTEM SET configuration_parameter { TO | = } { value | 'value' | DEFAULT }
1699    AlterSystem {
1700        param: Ident,
1701        value: SetVariableValue,
1702    },
1703    /// FLUSH the current barrier.
1704    ///
1705    /// Note: RisingWave specific statement.
1706    Flush,
1707    /// WAIT for background stream jobs to finish.
1708    /// It will block the current session until the condition is met.
1709    Wait(WaitTarget),
1710    /// Trigger meta backup.
1711    Backup,
1712    /// Trigger stream job recover
1713    Recover,
1714    /// `USE <db_name>`
1715    ///
1716    /// Note: this is a RisingWave specific statement and used to switch the current database.
1717    Use {
1718        db_name: ObjectName,
1719    },
1720    /// `VACUUM [FULL] [database_name][schema_name][object_name]`
1721    ///
1722    /// Note: this is a RisingWave specific statement for iceberg table/sink compaction.
1723    Vacuum {
1724        object_name: ObjectName,
1725        full: bool,
1726    },
1727}
1728
1729#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1730pub enum DescribeKind {
1731    /// `DESCRIBE <name>`
1732    Plain,
1733
1734    /// `DESCRIBE FRAGMENTS <name>`
1735    Fragments,
1736}
1737
1738impl fmt::Display for Statement {
1739    /// Converts(unparses) the statement to a SQL string.
1740    ///
1741    /// If the resulting SQL is not valid, this function will panic. Use
1742    /// [`Statement::try_to_string`] to get a `Result` instead.
1743    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1744        // Note: we ignore formatting options here.
1745        let sql = self
1746            .try_to_string()
1747            .expect("normalized SQL should be parsable");
1748        f.write_str(&sql)
1749    }
1750}
1751
1752impl Statement {
1753    /// Converts(unparses) the statement to a SQL string.
1754    ///
1755    /// If the resulting SQL is not valid, returns an error.
1756    pub fn try_to_string(&self) -> Result<String, ParserError> {
1757        let sql = self.to_string_unchecked();
1758
1759        // TODO(#20713): expand this check to all statements
1760        if matches!(
1761            self,
1762            Statement::CreateTable { .. } | Statement::CreateSource { .. }
1763        ) {
1764            let _ = Parser::parse_sql(&sql)?;
1765        }
1766        Ok(sql)
1767    }
1768
1769    /// Converts(unparses) the statement to a SQL string.
1770    ///
1771    /// The result may not be valid SQL if there's an implementation bug in the `Display`
1772    /// trait of any AST node. To avoid this, always prefer [`Statement::try_to_string`]
1773    /// to get a `Result`, or `to_string` which panics if the SQL is invalid.
1774    pub fn to_string_unchecked(&self) -> String {
1775        let mut buf = String::new();
1776        self.fmt_unchecked(&mut buf).unwrap();
1777        buf
1778    }
1779
1780    // NOTE: This function should not check the validity of the unparsed SQL (and panic).
1781    //       Thus, do not directly format a statement with `write!` or `format!`. Recursively
1782    //       call `fmt_unchecked` on the inner statements instead.
1783    //
1784    // Clippy thinks this function is too complicated, but it is painful to
1785    // split up without extracting structs for each `Statement` variant.
1786    #[expect(clippy::cognitive_complexity)]
1787    fn fmt_unchecked(&self, mut f: impl std::fmt::Write) -> fmt::Result {
1788        match self {
1789            Statement::Explain {
1790                analyze,
1791                statement,
1792                options,
1793            } => {
1794                write!(f, "EXPLAIN ")?;
1795
1796                if *analyze {
1797                    write!(f, "ANALYZE ")?;
1798                }
1799                write!(f, "{}", options)?;
1800
1801                statement.fmt_unchecked(f)
1802            }
1803            Statement::ExplainAnalyzeStreamJob {
1804                target,
1805                duration_secs,
1806            } => {
1807                write!(f, "EXPLAIN ANALYZE {}", target)?;
1808                if let Some(duration_secs) = duration_secs {
1809                    write!(f, " (DURATION_SECS {})", duration_secs)?;
1810                }
1811                Ok(())
1812            }
1813            Statement::Query(s) => write!(f, "{}", s),
1814            Statement::Truncate { table_name } => {
1815                write!(f, "TRUNCATE TABLE {}", table_name)?;
1816                Ok(())
1817            }
1818            Statement::Refresh { table_name } => {
1819                write!(f, "REFRESH TABLE {}", table_name)?;
1820                Ok(())
1821            }
1822            Statement::Analyze { table_name } => {
1823                write!(f, "ANALYZE TABLE {}", table_name)?;
1824                Ok(())
1825            }
1826            Statement::Describe { name, kind } => {
1827                write!(f, "DESCRIBE {}", name)?;
1828                match kind {
1829                    DescribeKind::Plain => {}
1830
1831                    DescribeKind::Fragments => {
1832                        write!(f, " FRAGMENTS")?;
1833                    }
1834                }
1835                Ok(())
1836            }
1837            Statement::DescribeFragment { fragment_id } => {
1838                write!(f, "DESCRIBE FRAGMENT {}", fragment_id)?;
1839                Ok(())
1840            }
1841            Statement::ShowObjects {
1842                object: show_object,
1843                filter,
1844            } => {
1845                write!(f, "SHOW {}", show_object)?;
1846                if let Some(filter) = filter {
1847                    write!(f, " {}", filter)?;
1848                }
1849                Ok(())
1850            }
1851            Statement::ShowCreateObject {
1852                create_type: show_type,
1853                name,
1854            } => {
1855                write!(f, "SHOW CREATE {} {}", show_type, name)?;
1856                Ok(())
1857            }
1858            Statement::ShowTransactionIsolationLevel => {
1859                write!(f, "SHOW TRANSACTION ISOLATION LEVEL")?;
1860                Ok(())
1861            }
1862            Statement::Insert {
1863                table_name,
1864                columns,
1865                source,
1866                returning,
1867            } => {
1868                write!(f, "INSERT INTO {table_name} ", table_name = table_name,)?;
1869                if !columns.is_empty() {
1870                    write!(f, "({}) ", display_comma_separated(columns))?;
1871                }
1872                write!(f, "{}", source)?;
1873                if !returning.is_empty() {
1874                    write!(f, " RETURNING ({})", display_comma_separated(returning))?;
1875                }
1876                Ok(())
1877            }
1878            Statement::Copy { entity, target } => {
1879                write!(f, "COPY ",)?;
1880                match entity {
1881                    CopyEntity::Query(query) => {
1882                        write!(f, "({})", query)?;
1883                    }
1884                    CopyEntity::Table {
1885                        table_name,
1886                        columns,
1887                    } => {
1888                        write!(f, "{}", table_name)?;
1889                        if !columns.is_empty() {
1890                            write!(f, " ({})", display_comma_separated(columns))?;
1891                        }
1892                    }
1893                }
1894
1895                match target {
1896                    CopyTarget::Stdin { values } => {
1897                        write!(f, " FROM STDIN; ")?;
1898                        if !values.is_empty() {
1899                            writeln!(f)?;
1900                            let mut delim = "";
1901                            for v in values {
1902                                write!(f, "{}", delim)?;
1903                                delim = "\t";
1904                                if let Some(v) = v {
1905                                    write!(f, "{}", v)?;
1906                                } else {
1907                                    write!(f, "\\N")?;
1908                                }
1909                            }
1910                        }
1911                        write!(f, "\n\\.")
1912                    }
1913                    CopyTarget::Stdout => {
1914                        write!(f, " TO STDOUT")
1915                    }
1916                }
1917            }
1918            Statement::Update {
1919                table_name,
1920                assignments,
1921                selection,
1922                returning,
1923            } => {
1924                write!(f, "UPDATE {}", table_name)?;
1925                if !assignments.is_empty() {
1926                    write!(f, " SET {}", display_comma_separated(assignments))?;
1927                }
1928                if let Some(selection) = selection {
1929                    write!(f, " WHERE {}", selection)?;
1930                }
1931                if !returning.is_empty() {
1932                    write!(f, " RETURNING ({})", display_comma_separated(returning))?;
1933                }
1934                Ok(())
1935            }
1936            Statement::Delete {
1937                table_name,
1938                selection,
1939                returning,
1940            } => {
1941                write!(f, "DELETE FROM {}", table_name)?;
1942                if let Some(selection) = selection {
1943                    write!(f, " WHERE {}", selection)?;
1944                }
1945                if !returning.is_empty() {
1946                    write!(f, " RETURNING {}", display_comma_separated(returning))?;
1947                }
1948                Ok(())
1949            }
1950            Statement::DeleteMetaSnapshots { snapshot_ids } => {
1951                write!(
1952                    f,
1953                    "DELETE META SNAPSHOTS {}",
1954                    display_comma_separated(snapshot_ids)
1955                )?;
1956                Ok(())
1957            }
1958            Statement::CreateDatabase {
1959                db_name,
1960                if_not_exists,
1961                owner,
1962                resource_group,
1963                barrier_interval_ms,
1964                checkpoint_frequency,
1965            } => {
1966                write!(f, "CREATE DATABASE")?;
1967                if *if_not_exists {
1968                    write!(f, " IF NOT EXISTS")?;
1969                }
1970                write!(f, " {}", db_name)?;
1971                if let Some(owner) = owner {
1972                    write!(f, " WITH OWNER = {}", owner)?;
1973                }
1974                if let Some(resource_group) = resource_group {
1975                    write!(f, " RESOURCE_GROUP = {}", resource_group)?;
1976                }
1977                if let Some(barrier_interval_ms) = barrier_interval_ms {
1978                    write!(f, " BARRIER_INTERVAL_MS = {}", barrier_interval_ms)?;
1979                }
1980                if let Some(checkpoint_frequency) = checkpoint_frequency {
1981                    write!(f, " CHECKPOINT_FREQUENCY = {}", checkpoint_frequency)?;
1982                }
1983
1984                Ok(())
1985            }
1986            Statement::CreateFunction {
1987                or_replace,
1988                temporary,
1989                if_not_exists,
1990                name,
1991                args,
1992                returns,
1993                params,
1994                with_options,
1995            } => {
1996                write!(
1997                    f,
1998                    "CREATE {or_replace}{temp}FUNCTION {if_not_exists}{name}",
1999                    temp = if *temporary { "TEMPORARY " } else { "" },
2000                    or_replace = if *or_replace { "OR REPLACE " } else { "" },
2001                    if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
2002                )?;
2003                if let Some(args) = args {
2004                    write!(f, "({})", display_comma_separated(args))?;
2005                }
2006                if let Some(return_type) = returns {
2007                    write!(f, " {}", return_type)?;
2008                }
2009                write!(f, "{params}")?;
2010                write!(f, "{with_options}")?;
2011                Ok(())
2012            }
2013            Statement::CreateAggregate {
2014                or_replace,
2015                if_not_exists,
2016                name,
2017                args,
2018                returns,
2019                append_only,
2020                params,
2021            } => {
2022                write!(
2023                    f,
2024                    "CREATE {or_replace}AGGREGATE {if_not_exists}{name}",
2025                    or_replace = if *or_replace { "OR REPLACE " } else { "" },
2026                    if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
2027                )?;
2028                write!(f, "({})", display_comma_separated(args))?;
2029                write!(f, " RETURNS {}", returns)?;
2030                if *append_only {
2031                    write!(f, " APPEND ONLY")?;
2032                }
2033                write!(f, "{params}")?;
2034                Ok(())
2035            }
2036            Statement::CreateView {
2037                name,
2038                or_replace,
2039                if_not_exists,
2040                columns,
2041                query,
2042                materialized,
2043                with_options,
2044                emit_mode,
2045            } => {
2046                write!(
2047                    f,
2048                    "CREATE {or_replace}{materialized}VIEW {if_not_exists}{name}",
2049                    or_replace = if *or_replace { "OR REPLACE " } else { "" },
2050                    materialized = if *materialized { "MATERIALIZED " } else { "" },
2051                    if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
2052                    name = name
2053                )?;
2054                if !with_options.is_empty() {
2055                    write!(f, " WITH ({})", display_comma_separated(with_options))?;
2056                }
2057                if !columns.is_empty() {
2058                    write!(f, " ({})", display_comma_separated(columns))?;
2059                }
2060                write!(f, " AS {}", query)?;
2061                if let Some(emit_mode) = emit_mode {
2062                    write!(f, " EMIT {}", emit_mode)?;
2063                }
2064                Ok(())
2065            }
2066            Statement::CreateTable {
2067                name,
2068                columns,
2069                wildcard_idx,
2070                constraints,
2071                with_options,
2072                or_replace,
2073                if_not_exists,
2074                temporary,
2075                format_encode,
2076                source_watermarks,
2077                append_only,
2078                on_conflict,
2079                with_version_columns,
2080                query,
2081                cdc_table_info,
2082                include_column_options,
2083                webhook_info,
2084                engine,
2085            } => {
2086                // We want to allow the following options
2087                // Empty column list, allowed by PostgreSQL:
2088                //   `CREATE TABLE t ()`
2089                // No columns provided for CREATE TABLE AS:
2090                //   `CREATE TABLE t AS SELECT a from t2`
2091                // Columns provided for CREATE TABLE AS:
2092                //   `CREATE TABLE t (a INT) AS SELECT a from t2`
2093                write!(
2094                    f,
2095                    "CREATE {or_replace}{temporary}TABLE {if_not_exists}{name}",
2096                    or_replace = if *or_replace { "OR REPLACE " } else { "" },
2097                    if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
2098                    temporary = if *temporary { "TEMPORARY " } else { "" },
2099                    name = name,
2100                )?;
2101                if !columns.is_empty() || !constraints.is_empty() {
2102                    write!(
2103                        f,
2104                        " {}",
2105                        fmt_create_items(columns, constraints, source_watermarks, *wildcard_idx)?
2106                    )?;
2107                } else if query.is_none() {
2108                    // PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
2109                    write!(f, " ()")?;
2110                }
2111                if *append_only {
2112                    write!(f, " APPEND ONLY")?;
2113                }
2114
2115                if let Some(on_conflict_behavior) = on_conflict {
2116                    write!(f, " ON CONFLICT {}", on_conflict_behavior)?;
2117                }
2118                if !with_version_columns.is_empty() {
2119                    write!(
2120                        f,
2121                        " WITH VERSION COLUMN({})",
2122                        display_comma_separated(with_version_columns)
2123                    )?;
2124                }
2125                if !include_column_options.is_empty() {
2126                    write!(f, " {}", display_separated(include_column_options, " "))?;
2127                }
2128                if !with_options.is_empty() {
2129                    write!(f, " WITH ({})", display_comma_separated(with_options))?;
2130                }
2131                if let Some(format_encode) = format_encode {
2132                    write!(f, " {}", format_encode)?;
2133                }
2134                if let Some(query) = query {
2135                    write!(f, " AS {}", query)?;
2136                }
2137                if let Some(info) = cdc_table_info {
2138                    write!(f, " FROM {}", info.source_name)?;
2139                    write!(f, " TABLE '{}'", info.external_table_name)?;
2140                }
2141                if let Some(info) = webhook_info
2142                    && let Some(signature_expr) = &info.signature_expr
2143                {
2144                    if let Some(secret) = &info.secret_ref {
2145                        write!(f, " VALIDATE SECRET {}", secret.secret_name)?;
2146                    } else {
2147                        write!(f, " VALIDATE")?;
2148                    }
2149                    write!(f, " AS {}", signature_expr)?;
2150                }
2151                match engine {
2152                    Engine::Hummock => {}
2153                    Engine::Iceberg => {
2154                        write!(f, " ENGINE = {}", engine)?;
2155                    }
2156                }
2157                Ok(())
2158            }
2159            Statement::CreateIndex {
2160                name,
2161                table_name,
2162                columns,
2163                method,
2164                include,
2165                distributed_by,
2166                unique,
2167                if_not_exists,
2168                with_properties,
2169            } => write!(
2170                f,
2171                "CREATE {unique}INDEX {if_not_exists}{name} ON {table_name}{method}({columns}){include}{distributed_by}{with_properties}",
2172                unique = if *unique { "UNIQUE " } else { "" },
2173                if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
2174                name = name,
2175                table_name = table_name,
2176                method = if let Some(method) = method {
2177                    format!(" USING {} ", method)
2178                } else {
2179                    "".to_owned()
2180                },
2181                columns = display_comma_separated(columns),
2182                include = if include.is_empty() {
2183                    "".to_owned()
2184                } else {
2185                    format!(" INCLUDE({})", display_separated(include, ","))
2186                },
2187                distributed_by = if distributed_by.is_empty() {
2188                    "".to_owned()
2189                } else {
2190                    format!(
2191                        " DISTRIBUTED BY({})",
2192                        display_separated(distributed_by, ",")
2193                    )
2194                },
2195                with_properties = if !with_properties.0.is_empty() {
2196                    format!(" {}", with_properties)
2197                } else {
2198                    "".to_owned()
2199                },
2200            ),
2201            Statement::CreateSource { stmt } => write!(f, "CREATE SOURCE {}", stmt,),
2202            Statement::CreateSink { stmt } => {
2203                if stmt.or_replace {
2204                    write!(f, "REPLACE SINK {}", stmt)
2205                } else {
2206                    write!(f, "CREATE SINK {}", stmt)
2207                }
2208            }
2209            Statement::CreateSubscription { stmt } => write!(f, "CREATE SUBSCRIPTION {}", stmt,),
2210            Statement::CreateConnection { stmt } => write!(f, "CREATE CONNECTION {}", stmt,),
2211            Statement::DeclareCursor { stmt } => write!(f, "DECLARE {}", stmt,),
2212            Statement::FetchCursor { stmt } => write!(f, "FETCH {}", stmt),
2213            Statement::CloseCursor { stmt } => write!(f, "CLOSE {}", stmt),
2214            Statement::CreateSecret { stmt } => write!(f, "CREATE SECRET {}", stmt),
2215            Statement::AlterDatabase { name, operation } => {
2216                write!(f, "ALTER DATABASE {} {}", name, operation)
2217            }
2218            Statement::AlterSchema { name, operation } => {
2219                write!(f, "ALTER SCHEMA {} {}", name, operation)
2220            }
2221            Statement::AlterTable { name, operation } => {
2222                write!(f, "ALTER TABLE {} {}", name, operation)
2223            }
2224            Statement::AlterIndex { name, operation } => {
2225                write!(f, "ALTER INDEX {} {}", name, operation)
2226            }
2227            Statement::AlterView {
2228                materialized,
2229                name,
2230                operation,
2231            } => {
2232                write!(
2233                    f,
2234                    "ALTER {}VIEW {} {}",
2235                    if *materialized { "MATERIALIZED " } else { "" },
2236                    name,
2237                    operation
2238                )
2239            }
2240            Statement::AlterSink { name, operation } => {
2241                write!(f, "ALTER SINK {} {}", name, operation)
2242            }
2243            Statement::AlterSubscription { name, operation } => {
2244                write!(f, "ALTER SUBSCRIPTION {} {}", name, operation)
2245            }
2246            Statement::AlterSource { name, operation } => {
2247                write!(f, "ALTER SOURCE {} {}", name, operation)
2248            }
2249            Statement::AlterFunction {
2250                name,
2251                args,
2252                operation,
2253            } => {
2254                write!(f, "ALTER FUNCTION {}", name)?;
2255                if let Some(args) = args {
2256                    write!(f, "({})", display_comma_separated(args))?;
2257                }
2258                write!(f, " {}", operation)
2259            }
2260            Statement::AlterConnection { name, operation } => {
2261                write!(f, "ALTER CONNECTION {} {}", name, operation)
2262            }
2263            Statement::AlterSecret { name, operation } => {
2264                write!(f, "ALTER SECRET {}", name)?;
2265                write!(f, "{}", operation)
2266            }
2267            Statement::Discard(t) => write!(f, "DISCARD {}", t),
2268            Statement::Drop(stmt) => write!(f, "DROP {}", stmt),
2269            Statement::DropFunction {
2270                if_exists,
2271                func_desc,
2272                option,
2273            } => {
2274                write!(
2275                    f,
2276                    "DROP FUNCTION{} {}",
2277                    if *if_exists { " IF EXISTS" } else { "" },
2278                    display_comma_separated(func_desc),
2279                )?;
2280                if let Some(op) = option {
2281                    write!(f, " {}", op)?;
2282                }
2283                Ok(())
2284            }
2285            Statement::DropAggregate {
2286                if_exists,
2287                func_desc,
2288                option,
2289            } => {
2290                write!(
2291                    f,
2292                    "DROP AGGREGATE{} {}",
2293                    if *if_exists { " IF EXISTS" } else { "" },
2294                    display_comma_separated(func_desc),
2295                )?;
2296                if let Some(op) = option {
2297                    write!(f, " {}", op)?;
2298                }
2299                Ok(())
2300            }
2301            Statement::SetVariable {
2302                local,
2303                variable,
2304                value,
2305            } => {
2306                f.write_str("SET ")?;
2307                if *local {
2308                    f.write_str("LOCAL ")?;
2309                }
2310                write!(f, "{name} = {value}", name = variable,)
2311            }
2312            Statement::ShowVariable { variable } => {
2313                write!(f, "SHOW")?;
2314                if !variable.is_empty() {
2315                    write!(f, " {}", display_separated(variable, " "))?;
2316                }
2317                Ok(())
2318            }
2319            Statement::StartTransaction { modes } => {
2320                write!(f, "START TRANSACTION")?;
2321                if !modes.is_empty() {
2322                    write!(f, " {}", display_comma_separated(modes))?;
2323                }
2324                Ok(())
2325            }
2326            Statement::Abort => {
2327                write!(f, "ABORT")?;
2328                Ok(())
2329            }
2330            Statement::SetTransaction {
2331                modes,
2332                snapshot,
2333                session,
2334            } => {
2335                if *session {
2336                    write!(f, "SET SESSION CHARACTERISTICS AS TRANSACTION")?;
2337                } else {
2338                    write!(f, "SET TRANSACTION")?;
2339                }
2340                if !modes.is_empty() {
2341                    write!(f, " {}", display_comma_separated(modes))?;
2342                }
2343                if let Some(snapshot_id) = snapshot {
2344                    write!(f, " SNAPSHOT {}", snapshot_id)?;
2345                }
2346                Ok(())
2347            }
2348            Statement::SetTimeZone { local, value } => {
2349                write!(f, "SET")?;
2350                if *local {
2351                    write!(f, " LOCAL")?;
2352                }
2353                write!(f, " TIME ZONE {}", value)?;
2354                Ok(())
2355            }
2356            Statement::Commit { chain } => {
2357                write!(f, "COMMIT{}", if *chain { " AND CHAIN" } else { "" },)
2358            }
2359            Statement::Rollback { chain } => {
2360                write!(f, "ROLLBACK{}", if *chain { " AND CHAIN" } else { "" },)
2361            }
2362            Statement::CreateSchema {
2363                schema_name,
2364                if_not_exists,
2365                owner,
2366            } => {
2367                write!(
2368                    f,
2369                    "CREATE SCHEMA {if_not_exists}{name}",
2370                    if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
2371                    name = schema_name
2372                )?;
2373                if let Some(user) = owner {
2374                    write!(f, " AUTHORIZATION {}", user)?;
2375                }
2376                Ok(())
2377            }
2378            Statement::Grant {
2379                privileges,
2380                objects,
2381                grantees,
2382                with_grant_option,
2383                granted_by,
2384            } => {
2385                write!(f, "GRANT {} ", privileges)?;
2386                write!(f, "ON {} ", objects)?;
2387                write!(f, "TO {}", display_comma_separated(grantees))?;
2388                if *with_grant_option {
2389                    write!(f, " WITH GRANT OPTION")?;
2390                }
2391                if let Some(grantor) = granted_by {
2392                    write!(f, " GRANTED BY {}", grantor)?;
2393                }
2394                Ok(())
2395            }
2396            Statement::Revoke {
2397                privileges,
2398                objects,
2399                grantees,
2400                granted_by,
2401                revoke_grant_option,
2402                cascade,
2403            } => {
2404                write!(
2405                    f,
2406                    "REVOKE {}{} ",
2407                    if *revoke_grant_option {
2408                        "GRANT OPTION FOR "
2409                    } else {
2410                        ""
2411                    },
2412                    privileges
2413                )?;
2414                write!(f, "ON {} ", objects)?;
2415                write!(f, "FROM {}", display_comma_separated(grantees))?;
2416                if let Some(grantor) = granted_by {
2417                    write!(f, " GRANTED BY {}", grantor)?;
2418                }
2419                write!(f, " {}", if *cascade { "CASCADE" } else { "RESTRICT" })?;
2420                Ok(())
2421            }
2422            Statement::Deallocate { name, prepare } => {
2423                if let Some(name) = name {
2424                    write!(
2425                        f,
2426                        "DEALLOCATE {prepare}{name}",
2427                        prepare = if *prepare { "PREPARE " } else { "" },
2428                        name = name,
2429                    )
2430                } else {
2431                    write!(
2432                        f,
2433                        "DEALLOCATE {prepare}ALL",
2434                        prepare = if *prepare { "PREPARE " } else { "" },
2435                    )
2436                }
2437            }
2438            Statement::Execute { name, parameters } => {
2439                write!(f, "EXECUTE {}", name)?;
2440                if !parameters.is_empty() {
2441                    write!(f, "({})", display_comma_separated(parameters))?;
2442                }
2443                Ok(())
2444            }
2445            Statement::Prepare {
2446                name,
2447                data_types,
2448                statement,
2449            } => {
2450                write!(f, "PREPARE {} ", name)?;
2451                if !data_types.is_empty() {
2452                    write!(f, "({}) ", display_comma_separated(data_types))?;
2453                }
2454                write!(f, "AS ")?;
2455                statement.fmt_unchecked(f)
2456            }
2457            Statement::Comment {
2458                object_type,
2459                object_name,
2460                comment,
2461            } => {
2462                write!(f, "COMMENT ON {} {} IS ", object_type, object_name)?;
2463                if let Some(c) = comment {
2464                    write!(f, "'{}'", c)
2465                } else {
2466                    write!(f, "NULL")
2467                }
2468            }
2469            Statement::CreateUser(statement) => {
2470                write!(f, "CREATE USER {}", statement)
2471            }
2472            Statement::AlterUser(statement) => {
2473                write!(f, "ALTER USER {}", statement)
2474            }
2475            Statement::AlterSystem { param, value } => {
2476                f.write_str("ALTER SYSTEM SET ")?;
2477                write!(f, "{param} = {value}",)
2478            }
2479            Statement::Flush => {
2480                write!(f, "FLUSH")
2481            }
2482            Statement::Wait(target) => match target {
2483                WaitTarget::All => write!(f, "WAIT"),
2484                WaitTarget::Table(name) => write!(f, "WAIT TABLE {name}"),
2485                WaitTarget::MaterializedView(name) => {
2486                    write!(f, "WAIT MATERIALIZED VIEW {name}")
2487                }
2488                WaitTarget::Sink(name) => write!(f, "WAIT SINK {name}"),
2489                WaitTarget::Index(name) => write!(f, "WAIT INDEX {name}"),
2490            },
2491            Statement::Backup => {
2492                write!(f, "BACKUP")?;
2493                Ok(())
2494            }
2495            Statement::Begin { modes } => {
2496                write!(f, "BEGIN")?;
2497                if !modes.is_empty() {
2498                    write!(f, " {}", display_comma_separated(modes))?;
2499                }
2500                Ok(())
2501            }
2502            Statement::CancelJobs(jobs) => {
2503                write!(f, "CANCEL JOBS {}", display_comma_separated(&jobs.0))?;
2504                Ok(())
2505            }
2506            Statement::Kill(worker_process_id) => {
2507                write!(f, "KILL '{}'", worker_process_id)?;
2508                Ok(())
2509            }
2510            Statement::Recover => {
2511                write!(f, "RECOVER")?;
2512                Ok(())
2513            }
2514            Statement::Use { db_name } => {
2515                write!(f, "USE {}", db_name)?;
2516                Ok(())
2517            }
2518            Statement::Vacuum { object_name, full } => {
2519                if *full {
2520                    write!(f, "VACUUM FULL {}", object_name)?;
2521                } else {
2522                    write!(f, "VACUUM {}", object_name)?;
2523                }
2524                Ok(())
2525            }
2526            Statement::AlterFragment {
2527                fragment_ids,
2528                operation,
2529            } => {
2530                write!(
2531                    f,
2532                    "ALTER FRAGMENT {} {}",
2533                    display_comma_separated(fragment_ids),
2534                    operation
2535                )
2536            }
2537            Statement::AlterCompactionGroup {
2538                group_ids,
2539                operation,
2540            } => {
2541                write!(
2542                    f,
2543                    "ALTER COMPACTION GROUP {} {}",
2544                    display_comma_separated(group_ids),
2545                    operation
2546                )
2547            }
2548            Statement::AlterDefaultPrivileges {
2549                target_users,
2550                schema_names,
2551                operation,
2552            } => {
2553                write!(f, "ALTER DEFAULT PRIVILEGES")?;
2554                if let Some(target_users) = target_users {
2555                    write!(f, " FOR {}", display_comma_separated(target_users))?;
2556                }
2557                if let Some(schema_names) = schema_names {
2558                    write!(f, " IN SCHEMA {}", display_comma_separated(schema_names))?;
2559                }
2560                write!(f, " {}", operation)
2561            }
2562        }
2563    }
2564
2565    pub fn is_create(&self) -> bool {
2566        matches!(
2567            self,
2568            Statement::CreateTable { .. }
2569                | Statement::CreateView { .. }
2570                | Statement::CreateSource { .. }
2571                | Statement::CreateSink { .. }
2572                | Statement::CreateSubscription { .. }
2573                | Statement::CreateConnection { .. }
2574                | Statement::CreateSecret { .. }
2575                | Statement::CreateUser { .. }
2576                | Statement::CreateDatabase { .. }
2577                | Statement::CreateFunction { .. }
2578                | Statement::CreateAggregate { .. }
2579                | Statement::CreateIndex { .. }
2580                | Statement::CreateSchema { .. }
2581        )
2582    }
2583}
2584
2585impl Display for IncludeOptionItem {
2586    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2587        let Self {
2588            column_type,
2589            inner_field,
2590            header_inner_expect_type,
2591            column_alias,
2592        } = self;
2593        write!(f, "INCLUDE {}", column_type)?;
2594        if let Some(inner_field) = inner_field {
2595            write!(f, " '{}'", value::escape_single_quote_string(inner_field))?;
2596            if let Some(expected_type) = header_inner_expect_type {
2597                write!(f, " {}", expected_type)?;
2598            }
2599        }
2600        if let Some(alias) = column_alias {
2601            write!(f, " AS {}", alias)?;
2602        }
2603        Ok(())
2604    }
2605}
2606
2607#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2608#[non_exhaustive]
2609pub enum OnInsert {
2610    /// ON DUPLICATE KEY UPDATE (MySQL when the key already exists, then execute an update instead)
2611    DuplicateKeyUpdate(Vec<Assignment>),
2612}
2613
2614impl fmt::Display for OnInsert {
2615    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2616        match self {
2617            Self::DuplicateKeyUpdate(expr) => write!(
2618                f,
2619                " ON DUPLICATE KEY UPDATE {}",
2620                display_comma_separated(expr)
2621            ),
2622        }
2623    }
2624}
2625
2626/// Privileges granted in a GRANT statement or revoked in a REVOKE statement.
2627#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2628pub enum Privileges {
2629    /// All privileges applicable to the object type
2630    All {
2631        /// Optional keyword from the spec, ignored in practice
2632        with_privileges_keyword: bool,
2633    },
2634    /// Specific privileges (e.g. `SELECT`, `INSERT`)
2635    Actions(Vec<Action>),
2636}
2637
2638impl fmt::Display for Privileges {
2639    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2640        match self {
2641            Privileges::All {
2642                with_privileges_keyword,
2643            } => {
2644                write!(
2645                    f,
2646                    "ALL{}",
2647                    if *with_privileges_keyword {
2648                        " PRIVILEGES"
2649                    } else {
2650                        ""
2651                    }
2652                )
2653            }
2654            Privileges::Actions(actions) => {
2655                write!(f, "{}", display_comma_separated(actions))
2656            }
2657        }
2658    }
2659}
2660
2661/// A privilege on a database object (table, sequence, etc.).
2662#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2663pub enum Action {
2664    Connect,
2665    Create,
2666    Delete,
2667    Execute,
2668    Insert { columns: Option<Vec<Ident>> },
2669    References { columns: Option<Vec<Ident>> },
2670    Select { columns: Option<Vec<Ident>> },
2671    Temporary,
2672    Trigger,
2673    Truncate,
2674    Update { columns: Option<Vec<Ident>> },
2675    Usage,
2676}
2677
2678impl fmt::Display for Action {
2679    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2680        match self {
2681            Action::Connect => f.write_str("CONNECT")?,
2682            Action::Create => f.write_str("CREATE")?,
2683            Action::Delete => f.write_str("DELETE")?,
2684            Action::Execute => f.write_str("EXECUTE")?,
2685            Action::Insert { .. } => f.write_str("INSERT")?,
2686            Action::References { .. } => f.write_str("REFERENCES")?,
2687            Action::Select { .. } => f.write_str("SELECT")?,
2688            Action::Temporary => f.write_str("TEMPORARY")?,
2689            Action::Trigger => f.write_str("TRIGGER")?,
2690            Action::Truncate => f.write_str("TRUNCATE")?,
2691            Action::Update { .. } => f.write_str("UPDATE")?,
2692            Action::Usage => f.write_str("USAGE")?,
2693        };
2694        match self {
2695            Action::Insert { columns }
2696            | Action::References { columns }
2697            | Action::Select { columns }
2698            | Action::Update { columns } => {
2699                if let Some(columns) = columns {
2700                    write!(f, " ({})", display_comma_separated(columns))?;
2701                }
2702            }
2703            _ => (),
2704        };
2705        Ok(())
2706    }
2707}
2708
2709/// Objects on which privileges are granted in a GRANT statement.
2710#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2711pub enum GrantObjects {
2712    /// Grant privileges on `ALL SEQUENCES IN SCHEMA <schema_name> [, ...]`
2713    AllSequencesInSchema { schemas: Vec<ObjectName> },
2714    /// Grant privileges on `ALL TABLES IN SCHEMA <schema_name> [, ...]`
2715    AllTablesInSchema { schemas: Vec<ObjectName> },
2716    /// Grant privileges on `ALL SOURCES IN SCHEMA <schema_name> [, ...]`
2717    AllSourcesInSchema { schemas: Vec<ObjectName> },
2718    /// Grant privileges on `ALL SINKS IN SCHEMA <schema_name> [, ...]`
2719    AllSinksInSchema { schemas: Vec<ObjectName> },
2720    /// Grant privileges on `ALL MATERIALIZED VIEWS IN SCHEMA <schema_name> [, ...]`
2721    AllMviewsInSchema { schemas: Vec<ObjectName> },
2722    /// Grant privileges on `ALL VIEWS IN SCHEMA <schema_name> [, ...]`
2723    AllViewsInSchema { schemas: Vec<ObjectName> },
2724    /// Grant privileges on `ALL FUNCTIONS IN SCHEMA <schema_name> [, ...]`
2725    AllFunctionsInSchema { schemas: Vec<ObjectName> },
2726    /// Grant privileges on `ALL SECRETS IN SCHEMA <schema_name> [, ...]`
2727    AllSecretsInSchema { schemas: Vec<ObjectName> },
2728    /// Grant privileges on `ALL SUBSCRIPTIONS IN SCHEMA <schema_name> [, ...]`
2729    AllSubscriptionsInSchema { schemas: Vec<ObjectName> },
2730    /// Grant privileges on `ALL CONNECTIONS IN SCHEMA <schema_name> [, ...]`
2731    AllConnectionsInSchema { schemas: Vec<ObjectName> },
2732    /// Grant privileges on specific databases
2733    Databases(Vec<ObjectName>),
2734    /// Grant privileges on specific schemas
2735    Schemas(Vec<ObjectName>),
2736    /// Grant privileges on specific sources
2737    Sources(Vec<ObjectName>),
2738    /// Grant privileges on specific materialized views
2739    Mviews(Vec<ObjectName>),
2740    /// Grant privileges on specific sequences
2741    Sequences(Vec<ObjectName>),
2742    /// Grant privileges on specific tables
2743    Tables(Vec<ObjectName>),
2744    /// Grant privileges on specific sinks
2745    Sinks(Vec<ObjectName>),
2746    /// Grant privileges on specific views
2747    Views(Vec<ObjectName>),
2748    /// Grant privileges on specific connections
2749    Connections(Vec<ObjectName>),
2750    /// Grant privileges on specific subscriptions
2751    Subscriptions(Vec<ObjectName>),
2752    /// Grant privileges on specific functions
2753    Functions(Vec<FunctionDesc>),
2754    /// Grant privileges on specific secrets
2755    Secrets(Vec<ObjectName>),
2756}
2757
2758impl fmt::Display for GrantObjects {
2759    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2760        match self {
2761            GrantObjects::Sequences(sequences) => {
2762                write!(f, "SEQUENCE {}", display_comma_separated(sequences))
2763            }
2764            GrantObjects::Schemas(schemas) => {
2765                write!(f, "SCHEMA {}", display_comma_separated(schemas))
2766            }
2767            GrantObjects::Tables(tables) => {
2768                write!(f, "{}", display_comma_separated(tables))
2769            }
2770            GrantObjects::AllSequencesInSchema { schemas } => {
2771                write!(
2772                    f,
2773                    "ALL SEQUENCES IN SCHEMA {}",
2774                    display_comma_separated(schemas)
2775                )
2776            }
2777            GrantObjects::AllTablesInSchema { schemas } => {
2778                write!(
2779                    f,
2780                    "ALL TABLES IN SCHEMA {}",
2781                    display_comma_separated(schemas)
2782                )
2783            }
2784            GrantObjects::AllSourcesInSchema { schemas } => {
2785                write!(
2786                    f,
2787                    "ALL SOURCES IN SCHEMA {}",
2788                    display_comma_separated(schemas)
2789                )
2790            }
2791            GrantObjects::AllMviewsInSchema { schemas } => {
2792                write!(
2793                    f,
2794                    "ALL MATERIALIZED VIEWS IN SCHEMA {}",
2795                    display_comma_separated(schemas)
2796                )
2797            }
2798            GrantObjects::AllSinksInSchema { schemas } => {
2799                write!(
2800                    f,
2801                    "ALL SINKS IN SCHEMA {}",
2802                    display_comma_separated(schemas)
2803                )
2804            }
2805            GrantObjects::AllViewsInSchema { schemas } => {
2806                write!(
2807                    f,
2808                    "ALL VIEWS IN SCHEMA {}",
2809                    display_comma_separated(schemas)
2810                )
2811            }
2812            GrantObjects::AllFunctionsInSchema { schemas } => {
2813                write!(
2814                    f,
2815                    "ALL FUNCTIONS IN SCHEMA {}",
2816                    display_comma_separated(schemas)
2817                )
2818            }
2819            GrantObjects::AllSecretsInSchema { schemas } => {
2820                write!(
2821                    f,
2822                    "ALL SECRETS IN SCHEMA {}",
2823                    display_comma_separated(schemas)
2824                )
2825            }
2826            GrantObjects::AllSubscriptionsInSchema { schemas } => {
2827                write!(
2828                    f,
2829                    "ALL SUBSCRIPTIONS IN SCHEMA {}",
2830                    display_comma_separated(schemas)
2831                )
2832            }
2833            GrantObjects::AllConnectionsInSchema { schemas } => {
2834                write!(
2835                    f,
2836                    "ALL CONNECTIONS IN SCHEMA {}",
2837                    display_comma_separated(schemas)
2838                )
2839            }
2840            GrantObjects::Databases(databases) => {
2841                write!(f, "DATABASE {}", display_comma_separated(databases))
2842            }
2843            GrantObjects::Sources(sources) => {
2844                write!(f, "SOURCE {}", display_comma_separated(sources))
2845            }
2846            GrantObjects::Mviews(mviews) => {
2847                write!(f, "MATERIALIZED VIEW {}", display_comma_separated(mviews))
2848            }
2849            GrantObjects::Sinks(sinks) => {
2850                write!(f, "SINK {}", display_comma_separated(sinks))
2851            }
2852            GrantObjects::Views(views) => {
2853                write!(f, "VIEW {}", display_comma_separated(views))
2854            }
2855            GrantObjects::Connections(connections) => {
2856                write!(f, "CONNECTION {}", display_comma_separated(connections))
2857            }
2858            GrantObjects::Subscriptions(subscriptions) => {
2859                write!(f, "SUBSCRIPTION {}", display_comma_separated(subscriptions))
2860            }
2861            GrantObjects::Functions(func_descs) => {
2862                write!(f, "FUNCTION {}", display_comma_separated(func_descs))
2863            }
2864            GrantObjects::Secrets(secrets) => {
2865                write!(f, "SECRET {}", display_comma_separated(secrets))
2866            }
2867        }
2868    }
2869}
2870
2871#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2872pub enum PrivilegeObjectType {
2873    Tables,
2874    Sources,
2875    Sinks,
2876    Mviews,
2877    Views,
2878    Functions,
2879    Connections,
2880    Secrets,
2881    Subscriptions,
2882    Schemas,
2883}
2884
2885impl fmt::Display for PrivilegeObjectType {
2886    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2887        match self {
2888            PrivilegeObjectType::Tables => f.write_str("TABLES")?,
2889            PrivilegeObjectType::Sources => f.write_str("SOURCES")?,
2890            PrivilegeObjectType::Sinks => f.write_str("SINKS")?,
2891            PrivilegeObjectType::Mviews => f.write_str("MATERIALIZED VIEWS")?,
2892            PrivilegeObjectType::Views => f.write_str("VIEWS")?,
2893            PrivilegeObjectType::Functions => f.write_str("FUNCTIONS")?,
2894            PrivilegeObjectType::Connections => f.write_str("CONNECTIONS")?,
2895            PrivilegeObjectType::Secrets => f.write_str("SECRETS")?,
2896            PrivilegeObjectType::Subscriptions => f.write_str("SUBSCRIPTIONS")?,
2897            PrivilegeObjectType::Schemas => f.write_str("SCHEMAS")?,
2898        };
2899        Ok(())
2900    }
2901}
2902
2903#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2904pub enum DefaultPrivilegeOperation {
2905    Grant {
2906        privileges: Privileges,
2907        object_type: PrivilegeObjectType,
2908        grantees: Vec<Ident>,
2909        with_grant_option: bool,
2910    },
2911    Revoke {
2912        privileges: Privileges,
2913        object_type: PrivilegeObjectType,
2914        grantees: Vec<Ident>,
2915        revoke_grant_option: bool,
2916        cascade: bool,
2917    },
2918}
2919
2920impl fmt::Display for DefaultPrivilegeOperation {
2921    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2922        match self {
2923            DefaultPrivilegeOperation::Grant {
2924                privileges,
2925                object_type,
2926                grantees,
2927                with_grant_option,
2928            } => {
2929                write!(
2930                    f,
2931                    "GRANT {} ON {} TO {}",
2932                    privileges,
2933                    object_type,
2934                    display_comma_separated(grantees)
2935                )?;
2936                if *with_grant_option {
2937                    write!(f, " WITH GRANT OPTION")?;
2938                }
2939            }
2940            DefaultPrivilegeOperation::Revoke {
2941                privileges,
2942                object_type,
2943                grantees,
2944                revoke_grant_option,
2945                cascade,
2946            } => {
2947                write!(f, "REVOKE")?;
2948                if *revoke_grant_option {
2949                    write!(f, " GRANT OPTION FOR")?;
2950                }
2951                write!(
2952                    f,
2953                    " {} ON {} FROM {}",
2954                    privileges,
2955                    object_type,
2956                    display_comma_separated(grantees)
2957                )?;
2958                write!(f, " {}", if *cascade { "CASCADE" } else { "RESTRICT" })?;
2959            }
2960        }
2961        Ok(())
2962    }
2963}
2964
2965impl DefaultPrivilegeOperation {
2966    pub fn for_schemas(&self) -> bool {
2967        match &self {
2968            DefaultPrivilegeOperation::Grant { object_type, .. } => {
2969                object_type == &PrivilegeObjectType::Schemas
2970            }
2971            DefaultPrivilegeOperation::Revoke { object_type, .. } => {
2972                object_type == &PrivilegeObjectType::Schemas
2973            }
2974        }
2975    }
2976}
2977
2978#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2979pub enum AssignmentValue {
2980    /// An expression, e.g. `foo = 1`
2981    Expr(Expr),
2982    /// The `DEFAULT` keyword, e.g. `foo = DEFAULT`
2983    Default,
2984}
2985
2986impl fmt::Display for AssignmentValue {
2987    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2988        match self {
2989            AssignmentValue::Expr(expr) => write!(f, "{}", expr),
2990            AssignmentValue::Default => f.write_str("DEFAULT"),
2991        }
2992    }
2993}
2994
2995/// SQL assignment `foo = { expr | DEFAULT }` as used in SQLUpdate
2996#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2997pub struct Assignment {
2998    pub id: Vec<Ident>,
2999    pub value: AssignmentValue,
3000}
3001
3002impl fmt::Display for Assignment {
3003    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3004        write!(f, "{} = {}", display_separated(&self.id, "."), self.value)
3005    }
3006}
3007
3008#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3009pub enum FunctionArgExpr {
3010    Expr(Expr),
3011    /// Expr is an arbitrary expression, returning either a table or a column.
3012    /// Idents are the prefix of `*`, which are consecutive field accesses.
3013    /// e.g. `(table.v1).*` or `(table).v1.*`
3014    ExprQualifiedWildcard(Expr, Vec<Ident>),
3015    /// Qualified wildcard, e.g. `alias.*` or `schema.table.*`, followed by optional
3016    /// except syntax
3017    QualifiedWildcard(ObjectName, Option<Vec<Expr>>),
3018    /// An unqualified `*` or `* except (columns)`
3019    Wildcard(Option<Vec<Expr>>),
3020    /// A secret reference, e.g. `SECRET my_secret` or `SECRET my_secret AS FILE`
3021    SecretRef(SecretRefValue),
3022}
3023
3024impl fmt::Display for FunctionArgExpr {
3025    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3026        match self {
3027            FunctionArgExpr::Expr(expr) => write!(f, "{}", expr),
3028            FunctionArgExpr::ExprQualifiedWildcard(expr, prefix) => {
3029                write!(
3030                    f,
3031                    "({}){}.*",
3032                    expr,
3033                    prefix
3034                        .iter()
3035                        .format_with("", |i, f| f(&format_args!(".{i}")))
3036                )
3037            }
3038            FunctionArgExpr::QualifiedWildcard(prefix, except) => match except {
3039                Some(exprs) => write!(
3040                    f,
3041                    "{}.* EXCEPT ({})",
3042                    prefix,
3043                    exprs
3044                        .iter()
3045                        .map(|v| v.to_string())
3046                        .collect::<Vec<String>>()
3047                        .as_slice()
3048                        .join(", ")
3049                ),
3050                None => write!(f, "{}.*", prefix),
3051            },
3052
3053            FunctionArgExpr::SecretRef(secret_ref) => write!(f, "SECRET {}", secret_ref),
3054            FunctionArgExpr::Wildcard(except) => match except {
3055                Some(exprs) => write!(
3056                    f,
3057                    "* EXCEPT ({})",
3058                    exprs
3059                        .iter()
3060                        .map(|v| v.to_string())
3061                        .collect::<Vec<String>>()
3062                        .as_slice()
3063                        .join(", ")
3064                ),
3065                None => f.write_str("*"),
3066            },
3067        }
3068    }
3069}
3070
3071#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3072pub enum FunctionArg {
3073    Named { name: Ident, arg: FunctionArgExpr },
3074    Unnamed(FunctionArgExpr),
3075}
3076
3077impl FunctionArg {
3078    pub fn get_expr(&self) -> FunctionArgExpr {
3079        match self {
3080            FunctionArg::Named { name: _, arg } => arg.clone(),
3081            FunctionArg::Unnamed(arg) => arg.clone(),
3082        }
3083    }
3084}
3085
3086impl fmt::Display for FunctionArg {
3087    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3088        match self {
3089            FunctionArg::Named { name, arg } => write!(f, "{} => {}", name, arg),
3090            FunctionArg::Unnamed(unnamed_arg) => write!(f, "{}", unnamed_arg),
3091        }
3092    }
3093}
3094
3095/// A list of function arguments, including additional modifiers like `DISTINCT` or `ORDER BY`.
3096/// This basically holds all the information between the `(` and `)` in a function call.
3097#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3098pub struct FunctionArgList {
3099    /// Aggregate function calls may have a `DISTINCT`, e.g. `count(DISTINCT x)`.
3100    pub distinct: bool,
3101    pub args: Vec<FunctionArg>,
3102    /// Whether the last argument is variadic, e.g. `foo(a, b, VARIADIC c)`.
3103    pub variadic: bool,
3104    /// Aggregate function calls may have an `ORDER BY`, e.g. `array_agg(x ORDER BY y)`.
3105    pub order_by: Vec<OrderByExpr>,
3106    /// Window function calls may have an `IGNORE NULLS`, e.g. `first_value(x IGNORE NULLS)`.
3107    pub ignore_nulls: bool,
3108}
3109
3110impl fmt::Display for FunctionArgList {
3111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3112        write!(f, "(")?;
3113        if self.distinct {
3114            write!(f, "DISTINCT ")?;
3115        }
3116        if self.variadic {
3117            for arg in &self.args[0..self.args.len() - 1] {
3118                write!(f, "{}, ", arg)?;
3119            }
3120            write!(f, "VARIADIC {}", self.args.last().unwrap())?;
3121        } else {
3122            write!(f, "{}", display_comma_separated(&self.args))?;
3123        }
3124        if !self.order_by.is_empty() {
3125            write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
3126        }
3127        if self.ignore_nulls {
3128            write!(f, " IGNORE NULLS")?;
3129        }
3130        write!(f, ")")?;
3131        Ok(())
3132    }
3133}
3134
3135impl FunctionArgList {
3136    pub fn empty() -> Self {
3137        Self {
3138            distinct: false,
3139            args: vec![],
3140            variadic: false,
3141            order_by: vec![],
3142            ignore_nulls: false,
3143        }
3144    }
3145
3146    pub fn args_only(args: Vec<FunctionArg>) -> Self {
3147        Self {
3148            distinct: false,
3149            args,
3150            variadic: false,
3151            order_by: vec![],
3152            ignore_nulls: false,
3153        }
3154    }
3155
3156    pub fn is_args_only(&self) -> bool {
3157        !self.distinct && !self.variadic && self.order_by.is_empty() && !self.ignore_nulls
3158    }
3159
3160    pub fn for_agg(distinct: bool, args: Vec<FunctionArg>, order_by: Vec<OrderByExpr>) -> Self {
3161        Self {
3162            distinct,
3163            args,
3164            variadic: false,
3165            order_by,
3166            ignore_nulls: false,
3167        }
3168    }
3169}
3170
3171/// A function call
3172#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3173pub struct Function {
3174    /// Whether the function is prefixed with `AGGREGATE:`
3175    pub scalar_as_agg: bool,
3176    /// Function name.
3177    pub name: ObjectName,
3178    /// Argument list of the function call, i.e. things in `()`.
3179    pub arg_list: FunctionArgList,
3180    /// `WITHIN GROUP` clause of the function call, for ordered-set aggregate functions.
3181    /// FIXME(rc): why we only support one expression here?
3182    pub within_group: Option<Box<OrderByExpr>>,
3183    /// `FILTER` clause of the function call, for aggregate and window (not supported yet) functions.
3184    pub filter: Option<Box<Expr>>,
3185    /// `OVER` clause of the function call, for window functions.
3186    pub over: Option<Window>,
3187}
3188
3189impl Function {
3190    pub fn no_arg(name: ObjectName) -> Self {
3191        Self {
3192            scalar_as_agg: false,
3193            name,
3194            arg_list: FunctionArgList::empty(),
3195            within_group: None,
3196            filter: None,
3197            over: None,
3198        }
3199    }
3200}
3201
3202impl fmt::Display for Function {
3203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3204        if self.scalar_as_agg {
3205            write!(f, "AGGREGATE:")?;
3206        }
3207        write!(f, "{}{}", self.name, self.arg_list)?;
3208        if let Some(within_group) = &self.within_group {
3209            write!(f, " WITHIN GROUP (ORDER BY {})", within_group)?;
3210        }
3211        if let Some(filter) = &self.filter {
3212            write!(f, " FILTER (WHERE {})", filter)?;
3213        }
3214        if let Some(o) = &self.over {
3215            write!(f, " OVER {}", o)?;
3216        }
3217        Ok(())
3218    }
3219}
3220
3221#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3222pub enum ObjectType {
3223    Table,
3224    View,
3225    MaterializedView,
3226    Index,
3227    Schema,
3228    Source,
3229    Sink,
3230    Database,
3231    User,
3232    Connection,
3233    Secret,
3234    Subscription,
3235}
3236
3237impl fmt::Display for ObjectType {
3238    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3239        f.write_str(match self {
3240            ObjectType::Table => "TABLE",
3241            ObjectType::View => "VIEW",
3242            ObjectType::MaterializedView => "MATERIALIZED VIEW",
3243            ObjectType::Index => "INDEX",
3244            ObjectType::Schema => "SCHEMA",
3245            ObjectType::Source => "SOURCE",
3246            ObjectType::Sink => "SINK",
3247            ObjectType::Database => "DATABASE",
3248            ObjectType::User => "USER",
3249            ObjectType::Secret => "SECRET",
3250            ObjectType::Connection => "CONNECTION",
3251            ObjectType::Subscription => "SUBSCRIPTION",
3252        })
3253    }
3254}
3255
3256impl ParseTo for ObjectType {
3257    fn parse_to(parser: &mut Parser<'_>) -> ModalResult<Self> {
3258        let object_type = if parser.parse_keyword(Keyword::TABLE) {
3259            ObjectType::Table
3260        } else if parser.parse_keyword(Keyword::VIEW) {
3261            ObjectType::View
3262        } else if parser.parse_keywords(&[Keyword::MATERIALIZED, Keyword::VIEW]) {
3263            ObjectType::MaterializedView
3264        } else if parser.parse_keyword(Keyword::SOURCE) {
3265            ObjectType::Source
3266        } else if parser.parse_keyword(Keyword::SINK) {
3267            ObjectType::Sink
3268        } else if parser.parse_keyword(Keyword::INDEX) {
3269            ObjectType::Index
3270        } else if parser.parse_keyword(Keyword::SCHEMA) {
3271            ObjectType::Schema
3272        } else if parser.parse_keyword(Keyword::DATABASE) {
3273            ObjectType::Database
3274        } else if parser.parse_keyword(Keyword::USER) {
3275            ObjectType::User
3276        } else if parser.parse_keyword(Keyword::CONNECTION) {
3277            ObjectType::Connection
3278        } else if parser.parse_keyword(Keyword::SECRET) {
3279            ObjectType::Secret
3280        } else if parser.parse_keyword(Keyword::SUBSCRIPTION) {
3281            ObjectType::Subscription
3282        } else {
3283            return parser.expected(
3284                "TABLE, VIEW, INDEX, MATERIALIZED VIEW, SOURCE, SINK, SUBSCRIPTION, SCHEMA, DATABASE, USER, SECRET or CONNECTION after DROP",
3285            );
3286        };
3287        Ok(object_type)
3288    }
3289}
3290
3291#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3292pub struct SqlOption {
3293    pub name: ObjectName,
3294    pub value: SqlOptionValue,
3295}
3296
3297impl fmt::Display for SqlOption {
3298    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3299        let should_redact = REDACT_SQL_OPTION_KEYWORDS
3300            .try_with(|keywords| {
3301                let sql_option_name = self.name.real_value().to_lowercase();
3302                keywords.iter().any(|k| sql_option_name.contains(k))
3303            })
3304            .unwrap_or(false);
3305        if should_redact {
3306            write!(f, "{} = [REDACTED]", self.name)
3307        } else {
3308            write!(f, "{} = {}", self.name, self.value)
3309        }
3310    }
3311}
3312
3313impl TryFrom<(&String, &String)> for SqlOption {
3314    type Error = ParserError;
3315
3316    fn try_from((name, value): (&String, &String)) -> Result<Self, Self::Error> {
3317        // Use from_real_value to properly escape the name, which handles cases like
3318        // "debezium.column.truncate.to.2000000.chars" where "2000000" would be
3319        // tokenized as a number instead of an identifier if not properly quoted.
3320        let name_parts: Vec<&str> = name.split('.').collect();
3321        let object_name = ObjectName(name_parts.into_iter().map(Ident::from_real_value).collect());
3322
3323        // Wrap the value in single quotes so it is always parsed as a string literal.
3324        // This prevents values containing special characters (e.g., "jdbc:postgresql://...")
3325        // from being incorrectly tokenized. Escape any embedded single quotes.
3326        let escaped_value = value.replace('\'', "''");
3327        let query = format!("{} = '{}'", object_name, escaped_value);
3328        let mut tokenizer = Tokenizer::new(query.as_str());
3329        let tokens = tokenizer.tokenize_with_location()?;
3330        let mut parser = Parser(&tokens);
3331        parser
3332            .parse_sql_option()
3333            .map_err(|e| ParserError::ParserError(e.to_string()))
3334    }
3335}
3336
3337#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3338pub enum SqlOptionValue {
3339    Value(Value),
3340    SecretRef(SecretRefValue),
3341    ConnectionRef(ConnectionRefValue),
3342    BackfillOrder(BackfillOrderStrategy),
3343}
3344
3345impl SqlOptionValue {
3346    /// Returns a `NULL` value.
3347    pub const fn null() -> Self {
3348        Self::Value(Value::Null)
3349    }
3350}
3351
3352impl fmt::Display for SqlOptionValue {
3353    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3354        match self {
3355            SqlOptionValue::Value(value) => write!(f, "{}", value),
3356            SqlOptionValue::SecretRef(secret_ref) => write!(f, "secret {}", secret_ref),
3357            SqlOptionValue::ConnectionRef(connection_ref) => {
3358                write!(f, "{}", connection_ref)
3359            }
3360            SqlOptionValue::BackfillOrder(order) => {
3361                write!(f, "{}", order)
3362            }
3363        }
3364    }
3365}
3366
3367impl From<Value> for SqlOptionValue {
3368    fn from(value: Value) -> Self {
3369        SqlOptionValue::Value(value)
3370    }
3371}
3372
3373#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3374pub enum EmitMode {
3375    Immediately,
3376    OnWindowClose,
3377}
3378
3379impl fmt::Display for EmitMode {
3380    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3381        f.write_str(match self {
3382            EmitMode::Immediately => "IMMEDIATELY",
3383            EmitMode::OnWindowClose => "ON WINDOW CLOSE",
3384        })
3385    }
3386}
3387
3388#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3389pub enum OnConflict {
3390    UpdateFull,
3391    Nothing,
3392    UpdateIfNotNull,
3393}
3394
3395impl fmt::Display for OnConflict {
3396    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3397        f.write_str(match self {
3398            OnConflict::UpdateFull => "DO UPDATE FULL",
3399            OnConflict::Nothing => "DO NOTHING",
3400            OnConflict::UpdateIfNotNull => "DO UPDATE IF NOT NULL",
3401        })
3402    }
3403}
3404
3405#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3406pub enum Engine {
3407    Hummock,
3408    Iceberg,
3409}
3410
3411impl fmt::Display for crate::ast::Engine {
3412    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3413        f.write_str(match self {
3414            crate::ast::Engine::Hummock => "HUMMOCK",
3415            crate::ast::Engine::Iceberg => "ICEBERG",
3416        })
3417    }
3418}
3419
3420#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3421pub enum SetTimeZoneValue {
3422    Ident(Ident),
3423    Literal(Value),
3424    Local,
3425    Default,
3426}
3427
3428impl fmt::Display for SetTimeZoneValue {
3429    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3430        match self {
3431            SetTimeZoneValue::Ident(ident) => write!(f, "{}", ident),
3432            SetTimeZoneValue::Literal(value) => write!(f, "{}", value),
3433            SetTimeZoneValue::Local => f.write_str("LOCAL"),
3434            SetTimeZoneValue::Default => f.write_str("DEFAULT"),
3435        }
3436    }
3437}
3438
3439#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3440pub enum TransactionMode {
3441    AccessMode(TransactionAccessMode),
3442    IsolationLevel(TransactionIsolationLevel),
3443}
3444
3445impl fmt::Display for TransactionMode {
3446    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3447        use TransactionMode::*;
3448        match self {
3449            AccessMode(access_mode) => write!(f, "{}", access_mode),
3450            IsolationLevel(iso_level) => write!(f, "ISOLATION LEVEL {}", iso_level),
3451        }
3452    }
3453}
3454
3455#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3456pub enum TransactionAccessMode {
3457    ReadOnly,
3458    ReadWrite,
3459}
3460
3461impl fmt::Display for TransactionAccessMode {
3462    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3463        use TransactionAccessMode::*;
3464        f.write_str(match self {
3465            ReadOnly => "READ ONLY",
3466            ReadWrite => "READ WRITE",
3467        })
3468    }
3469}
3470
3471#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3472pub enum TransactionIsolationLevel {
3473    ReadUncommitted,
3474    ReadCommitted,
3475    RepeatableRead,
3476    Serializable,
3477}
3478
3479impl fmt::Display for TransactionIsolationLevel {
3480    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3481        use TransactionIsolationLevel::*;
3482        f.write_str(match self {
3483            ReadUncommitted => "READ UNCOMMITTED",
3484            ReadCommitted => "READ COMMITTED",
3485            RepeatableRead => "REPEATABLE READ",
3486            Serializable => "SERIALIZABLE",
3487        })
3488    }
3489}
3490
3491#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3492pub enum ShowStatementFilter {
3493    Like(String),
3494    ILike(String),
3495    Where(Expr),
3496}
3497
3498impl fmt::Display for ShowStatementFilter {
3499    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3500        use ShowStatementFilter::*;
3501        match self {
3502            Like(pattern) => write!(f, "LIKE '{}'", value::escape_single_quote_string(pattern)),
3503            ILike(pattern) => write!(f, "ILIKE {}", value::escape_single_quote_string(pattern)),
3504            Where(expr) => write!(f, "WHERE {}", expr),
3505        }
3506    }
3507}
3508
3509/// Function describe in DROP FUNCTION.
3510#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3511pub enum DropFunctionOption {
3512    Restrict,
3513    Cascade,
3514}
3515
3516impl fmt::Display for DropFunctionOption {
3517    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3518        match self {
3519            DropFunctionOption::Restrict => write!(f, "RESTRICT "),
3520            DropFunctionOption::Cascade => write!(f, "CASCADE  "),
3521        }
3522    }
3523}
3524
3525/// Function describe in DROP FUNCTION.
3526#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3527pub struct FunctionDesc {
3528    pub name: ObjectName,
3529    pub args: Option<Vec<OperateFunctionArg>>,
3530}
3531
3532impl fmt::Display for FunctionDesc {
3533    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3534        write!(f, "{}", self.name)?;
3535        if let Some(args) = &self.args {
3536            write!(f, "({})", display_comma_separated(args))?;
3537        }
3538        Ok(())
3539    }
3540}
3541
3542/// Function argument in CREATE FUNCTION.
3543#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3544pub struct OperateFunctionArg {
3545    pub mode: Option<ArgMode>,
3546    pub name: Option<Ident>,
3547    pub data_type: DataType,
3548    pub default_expr: Option<Expr>,
3549}
3550
3551impl OperateFunctionArg {
3552    /// Returns an unnamed argument.
3553    pub fn unnamed(data_type: DataType) -> Self {
3554        Self {
3555            mode: None,
3556            name: None,
3557            data_type,
3558            default_expr: None,
3559        }
3560    }
3561
3562    /// Returns an argument with name.
3563    pub fn with_name(name: &str, data_type: DataType) -> Self {
3564        Self {
3565            mode: None,
3566            name: Some(name.into()),
3567            data_type,
3568            default_expr: None,
3569        }
3570    }
3571}
3572
3573impl fmt::Display for OperateFunctionArg {
3574    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3575        if let Some(mode) = &self.mode {
3576            write!(f, "{} ", mode)?;
3577        }
3578        if let Some(name) = &self.name {
3579            write!(f, "{} ", name)?;
3580        }
3581        write!(f, "{}", self.data_type)?;
3582        if let Some(default_expr) = &self.default_expr {
3583            write!(f, " = {}", default_expr)?;
3584        }
3585        Ok(())
3586    }
3587}
3588
3589/// The mode of an argument in CREATE FUNCTION.
3590#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3591pub enum ArgMode {
3592    In,
3593    Out,
3594    InOut,
3595}
3596
3597impl fmt::Display for ArgMode {
3598    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3599        match self {
3600            ArgMode::In => write!(f, "IN"),
3601            ArgMode::Out => write!(f, "OUT"),
3602            ArgMode::InOut => write!(f, "INOUT"),
3603        }
3604    }
3605}
3606
3607/// These attributes inform the query optimizer about the behavior of the function.
3608#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3609pub enum FunctionBehavior {
3610    Immutable,
3611    Stable,
3612    Volatile,
3613}
3614
3615impl fmt::Display for FunctionBehavior {
3616    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3617        match self {
3618            FunctionBehavior::Immutable => write!(f, "IMMUTABLE"),
3619            FunctionBehavior::Stable => write!(f, "STABLE"),
3620            FunctionBehavior::Volatile => write!(f, "VOLATILE"),
3621        }
3622    }
3623}
3624
3625#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3626pub enum FunctionDefinition {
3627    Identifier(String),
3628    SingleQuotedDef(String),
3629    DoubleDollarDef(String),
3630}
3631
3632impl fmt::Display for FunctionDefinition {
3633    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3634        match self {
3635            FunctionDefinition::Identifier(s) => write!(f, "{s}")?,
3636            FunctionDefinition::SingleQuotedDef(s) => write!(f, "'{s}'")?,
3637            FunctionDefinition::DoubleDollarDef(s) => write!(f, "$${s}$$")?,
3638        }
3639        Ok(())
3640    }
3641}
3642
3643impl FunctionDefinition {
3644    /// Returns the function definition as a string slice.
3645    pub fn as_str(&self) -> &str {
3646        match self {
3647            FunctionDefinition::Identifier(s) => s,
3648            FunctionDefinition::SingleQuotedDef(s) => s,
3649            FunctionDefinition::DoubleDollarDef(s) => s,
3650        }
3651    }
3652
3653    /// Returns the function definition as a string.
3654    pub fn into_string(self) -> String {
3655        match self {
3656            FunctionDefinition::Identifier(s) => s,
3657            FunctionDefinition::SingleQuotedDef(s) => s,
3658            FunctionDefinition::DoubleDollarDef(s) => s,
3659        }
3660    }
3661}
3662
3663/// Return types of a function.
3664#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3665pub enum CreateFunctionReturns {
3666    /// RETURNS rettype
3667    Value(DataType),
3668    /// RETURNS TABLE ( column_name column_type [, ...] )
3669    Table(Vec<TableColumnDef>),
3670}
3671
3672impl fmt::Display for CreateFunctionReturns {
3673    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3674        match self {
3675            Self::Value(data_type) => write!(f, "RETURNS {}", data_type),
3676            Self::Table(columns) => {
3677                write!(f, "RETURNS TABLE ({})", display_comma_separated(columns))
3678            }
3679        }
3680    }
3681}
3682
3683/// Table column definition
3684#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3685pub struct TableColumnDef {
3686    pub name: Ident,
3687    pub data_type: DataType,
3688}
3689
3690impl fmt::Display for TableColumnDef {
3691    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3692        write!(f, "{} {}", self.name, self.data_type)
3693    }
3694}
3695
3696/// Postgres specific feature.
3697///
3698/// See [Postgresdocs](https://www.postgresql.org/docs/15/sql-createfunction.html)
3699/// for more details
3700#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
3701pub struct CreateFunctionBody {
3702    /// LANGUAGE lang_name
3703    pub language: Option<Ident>,
3704    /// RUNTIME runtime_name
3705    pub runtime: Option<Ident>,
3706
3707    /// IMMUTABLE | STABLE | VOLATILE
3708    pub behavior: Option<FunctionBehavior>,
3709    /// AS 'definition'
3710    ///
3711    /// Note that Hive's `AS class_name` is also parsed here.
3712    pub as_: Option<FunctionDefinition>,
3713    /// RETURN expression
3714    pub return_: Option<Expr>,
3715    /// USING ...
3716    pub using: Option<CreateFunctionUsing>,
3717}
3718
3719impl fmt::Display for CreateFunctionBody {
3720    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3721        if let Some(language) = &self.language {
3722            write!(f, " LANGUAGE {language}")?;
3723        }
3724        if let Some(runtime) = &self.runtime {
3725            write!(f, " RUNTIME {runtime}")?;
3726        }
3727        if let Some(behavior) = &self.behavior {
3728            write!(f, " {behavior}")?;
3729        }
3730        if let Some(definition) = &self.as_ {
3731            write!(f, " AS {definition}")?;
3732        }
3733        if let Some(expr) = &self.return_ {
3734            write!(f, " RETURN {expr}")?;
3735        }
3736        if let Some(using) = &self.using {
3737            write!(f, " {using}")?;
3738        }
3739        Ok(())
3740    }
3741}
3742
3743#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
3744pub struct CreateFunctionWithOptions {
3745    /// Always retry on network errors.
3746    pub always_retry_on_network_error: Option<bool>,
3747    /// Use async functions (only available for JS UDF)
3748    pub r#async: Option<bool>,
3749    /// Call in batch mode (only available for JS UDF)
3750    pub batch: Option<bool>,
3751}
3752
3753/// TODO(kwannoel): Generate from the struct definition instead.
3754impl TryFrom<Vec<SqlOption>> for CreateFunctionWithOptions {
3755    type Error = StrError;
3756
3757    fn try_from(with_options: Vec<SqlOption>) -> Result<Self, Self::Error> {
3758        let mut options = Self::default();
3759        for option in with_options {
3760            match option.name.to_string().to_lowercase().as_str() {
3761                "always_retry_on_network_error" => {
3762                    options.always_retry_on_network_error = Some(matches!(
3763                        option.value,
3764                        SqlOptionValue::Value(Value::Boolean(true))
3765                    ));
3766                }
3767                "async" => {
3768                    options.r#async = Some(matches!(
3769                        option.value,
3770                        SqlOptionValue::Value(Value::Boolean(true))
3771                    ))
3772                }
3773                "batch" => {
3774                    options.batch = Some(matches!(
3775                        option.value,
3776                        SqlOptionValue::Value(Value::Boolean(true))
3777                    ))
3778                }
3779                _ => {
3780                    return Err(StrError(format!("unknown option: {}", option.name)));
3781                }
3782            }
3783        }
3784        Ok(options)
3785    }
3786}
3787
3788impl Display for CreateFunctionWithOptions {
3789    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3790        if self == &Self::default() {
3791            return Ok(());
3792        }
3793        let mut options = vec![];
3794        if let Some(v) = self.always_retry_on_network_error {
3795            options.push(format!("always_retry_on_network_error = {}", v));
3796        }
3797        if let Some(v) = self.r#async {
3798            options.push(format!("async = {}", v));
3799        }
3800        if let Some(v) = self.batch {
3801            options.push(format!("batch = {}", v));
3802        }
3803        write!(f, " WITH ( {} )", display_comma_separated(&options))
3804    }
3805}
3806
3807#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3808pub enum CreateFunctionUsing {
3809    Link(String),
3810    Base64(String),
3811}
3812
3813impl fmt::Display for CreateFunctionUsing {
3814    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3815        write!(f, "USING ")?;
3816        match self {
3817            CreateFunctionUsing::Link(uri) => write!(f, "LINK '{uri}'"),
3818            CreateFunctionUsing::Base64(s) => {
3819                write!(f, "BASE64 '{s}'")
3820            }
3821        }
3822    }
3823}
3824
3825#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3826pub struct ConfigParam {
3827    pub param: Ident,
3828    pub value: SetVariableValue,
3829}
3830
3831impl fmt::Display for ConfigParam {
3832    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3833        write!(f, "SET {} = {}", self.param, self.value)
3834    }
3835}
3836
3837#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3838pub enum SetVariableValue {
3839    Single(SetVariableValueSingle),
3840    List(Vec<SetVariableValueSingle>),
3841    Default,
3842}
3843
3844impl From<SetVariableValueSingle> for SetVariableValue {
3845    fn from(value: SetVariableValueSingle) -> Self {
3846        SetVariableValue::Single(value)
3847    }
3848}
3849
3850impl fmt::Display for SetVariableValue {
3851    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3852        use SetVariableValue::*;
3853        match self {
3854            Single(val) => write!(f, "{}", val),
3855            List(list) => write!(f, "{}", display_comma_separated(list),),
3856            Default => write!(f, "DEFAULT"),
3857        }
3858    }
3859}
3860
3861#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3862pub enum SetVariableValueSingle {
3863    Ident(Ident),
3864    Literal(Value),
3865    Raw(String),
3866}
3867
3868impl SetVariableValueSingle {
3869    pub fn to_string_unquoted(&self) -> String {
3870        match self {
3871            Self::Literal(Value::SingleQuotedString(s))
3872            | Self::Literal(Value::DoubleQuotedString(s))
3873            | Self::Raw(s) => s.clone(),
3874            _ => self.to_string(),
3875        }
3876    }
3877}
3878
3879impl fmt::Display for SetVariableValueSingle {
3880    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3881        use SetVariableValueSingle::*;
3882        match self {
3883            Ident(ident) => write!(f, "{}", ident),
3884            Literal(literal) => write!(f, "{}", literal),
3885            Raw(raw) => write!(f, "{}", raw),
3886        }
3887    }
3888}
3889
3890#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3891pub enum AsOf {
3892    ProcessTime,
3893    // used by time travel
3894    ProcessTimeWithInterval((String, DateTimeField)),
3895    // the number of seconds that have elapsed since the Unix epoch, which is January 1, 1970 at 00:00:00 Coordinated Universal Time (UTC).
3896    TimestampNum(i64),
3897    TimestampString(String),
3898    VersionNum(i64),
3899    VersionString(String),
3900}
3901
3902impl fmt::Display for AsOf {
3903    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3904        use AsOf::*;
3905        match self {
3906            ProcessTime => write!(f, " FOR SYSTEM_TIME AS OF PROCTIME()"),
3907            ProcessTimeWithInterval((value, leading_field)) => write!(
3908                f,
3909                " FOR SYSTEM_TIME AS OF NOW() - '{}' {}",
3910                value, leading_field
3911            ),
3912            TimestampNum(ts) => write!(f, " FOR SYSTEM_TIME AS OF {}", ts),
3913            TimestampString(ts) => write!(f, " FOR SYSTEM_TIME AS OF '{}'", ts),
3914            VersionNum(v) => write!(f, " FOR SYSTEM_VERSION AS OF {}", v),
3915            VersionString(v) => write!(f, " FOR SYSTEM_VERSION AS OF '{}'", v),
3916        }
3917    }
3918}
3919
3920#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3921pub enum DiscardType {
3922    All,
3923}
3924
3925impl fmt::Display for DiscardType {
3926    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3927        use DiscardType::*;
3928        match self {
3929            All => write!(f, "ALL"),
3930        }
3931    }
3932}
3933
3934// We decouple "default" from none,
3935// so we can choose strategies that make the most sense.
3936#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
3937pub enum BackfillOrderStrategy {
3938    #[default]
3939    Default,
3940    None,
3941    Auto,
3942    Fixed(Vec<(ObjectName, ObjectName)>),
3943}
3944
3945impl fmt::Display for BackfillOrderStrategy {
3946    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3947        use BackfillOrderStrategy::*;
3948        match self {
3949            Default => write!(f, "DEFAULT"),
3950            None => write!(f, "NONE"),
3951            Auto => write!(f, "AUTO"),
3952            Fixed(map) => {
3953                let mut parts = vec![];
3954                for (start, end) in map {
3955                    parts.push(format!("{} -> {}", start, end));
3956                }
3957                write!(f, "FIXED({})", display_comma_separated(&parts))
3958            }
3959        }
3960    }
3961}
3962
3963impl Statement {
3964    pub fn to_redacted_string(&self, keywords: RedactSqlOptionKeywordsRef) -> String {
3965        REDACT_SQL_OPTION_KEYWORDS.sync_scope(keywords, || self.to_string_unchecked())
3966    }
3967
3968    /// Create a new `CREATE TABLE` statement with the given `name` and empty fields.
3969    pub fn default_create_table(name: ObjectName) -> Self {
3970        Self::CreateTable {
3971            name,
3972            or_replace: false,
3973            temporary: false,
3974            if_not_exists: false,
3975            columns: Vec::new(),
3976            wildcard_idx: None,
3977            constraints: Vec::new(),
3978            with_options: Vec::new(),
3979            format_encode: None,
3980            source_watermarks: Vec::new(),
3981            append_only: false,
3982            on_conflict: None,
3983            with_version_columns: Vec::new(),
3984            query: None,
3985            cdc_table_info: None,
3986            include_column_options: Vec::new(),
3987            webhook_info: None,
3988            engine: Engine::Hummock,
3989        }
3990    }
3991}
3992
3993#[cfg(test)]
3994mod tests {
3995    use super::*;
3996
3997    #[test]
3998    fn test_grouping_sets_display() {
3999        // a and b in different group
4000        let grouping_sets = Expr::GroupingSets(vec![
4001            vec![Expr::Identifier(Ident::new_unchecked("a"))],
4002            vec![Expr::Identifier(Ident::new_unchecked("b"))],
4003        ]);
4004        assert_eq!("GROUPING SETS ((a), (b))", format!("{}", grouping_sets));
4005
4006        // a and b in the same group
4007        let grouping_sets = Expr::GroupingSets(vec![vec![
4008            Expr::Identifier(Ident::new_unchecked("a")),
4009            Expr::Identifier(Ident::new_unchecked("b")),
4010        ]]);
4011        assert_eq!("GROUPING SETS ((a, b))", format!("{}", grouping_sets));
4012
4013        // (a, b) and (c, d) in different group
4014        let grouping_sets = Expr::GroupingSets(vec![
4015            vec![
4016                Expr::Identifier(Ident::new_unchecked("a")),
4017                Expr::Identifier(Ident::new_unchecked("b")),
4018            ],
4019            vec![
4020                Expr::Identifier(Ident::new_unchecked("c")),
4021                Expr::Identifier(Ident::new_unchecked("d")),
4022            ],
4023        ]);
4024        assert_eq!(
4025            "GROUPING SETS ((a, b), (c, d))",
4026            format!("{}", grouping_sets)
4027        );
4028    }
4029
4030    #[test]
4031    fn test_rollup_display() {
4032        let rollup = Expr::Rollup(vec![vec![Expr::Identifier(Ident::new_unchecked("a"))]]);
4033        assert_eq!("ROLLUP (a)", format!("{}", rollup));
4034
4035        let rollup = Expr::Rollup(vec![vec![
4036            Expr::Identifier(Ident::new_unchecked("a")),
4037            Expr::Identifier(Ident::new_unchecked("b")),
4038        ]]);
4039        assert_eq!("ROLLUP ((a, b))", format!("{}", rollup));
4040
4041        let rollup = Expr::Rollup(vec![
4042            vec![Expr::Identifier(Ident::new_unchecked("a"))],
4043            vec![Expr::Identifier(Ident::new_unchecked("b"))],
4044        ]);
4045        assert_eq!("ROLLUP (a, b)", format!("{}", rollup));
4046
4047        let rollup = Expr::Rollup(vec![
4048            vec![Expr::Identifier(Ident::new_unchecked("a"))],
4049            vec![
4050                Expr::Identifier(Ident::new_unchecked("b")),
4051                Expr::Identifier(Ident::new_unchecked("c")),
4052            ],
4053            vec![Expr::Identifier(Ident::new_unchecked("d"))],
4054        ]);
4055        assert_eq!("ROLLUP (a, (b, c), d)", format!("{}", rollup));
4056    }
4057
4058    #[test]
4059    fn test_cube_display() {
4060        let cube = Expr::Cube(vec![vec![Expr::Identifier(Ident::new_unchecked("a"))]]);
4061        assert_eq!("CUBE (a)", format!("{}", cube));
4062
4063        let cube = Expr::Cube(vec![vec![
4064            Expr::Identifier(Ident::new_unchecked("a")),
4065            Expr::Identifier(Ident::new_unchecked("b")),
4066        ]]);
4067        assert_eq!("CUBE ((a, b))", format!("{}", cube));
4068
4069        let cube = Expr::Cube(vec![
4070            vec![Expr::Identifier(Ident::new_unchecked("a"))],
4071            vec![Expr::Identifier(Ident::new_unchecked("b"))],
4072        ]);
4073        assert_eq!("CUBE (a, b)", format!("{}", cube));
4074
4075        let cube = Expr::Cube(vec![
4076            vec![Expr::Identifier(Ident::new_unchecked("a"))],
4077            vec![
4078                Expr::Identifier(Ident::new_unchecked("b")),
4079                Expr::Identifier(Ident::new_unchecked("c")),
4080            ],
4081            vec![Expr::Identifier(Ident::new_unchecked("d"))],
4082        ]);
4083        assert_eq!("CUBE (a, (b, c), d)", format!("{}", cube));
4084    }
4085
4086    #[test]
4087    fn test_array_index_display() {
4088        let array_index = Expr::Index {
4089            obj: Box::new(Expr::Identifier(Ident::new_unchecked("v1"))),
4090            index: Box::new(Expr::Value(Value::Number("1".into()))),
4091        };
4092        assert_eq!("v1[1]", format!("{}", array_index));
4093
4094        let array_index2 = Expr::Index {
4095            obj: Box::new(array_index),
4096            index: Box::new(Expr::Value(Value::Number("1".into()))),
4097        };
4098        assert_eq!("v1[1][1]", format!("{}", array_index2));
4099    }
4100
4101    #[test]
4102    /// issue: https://github.com/risingwavelabs/risingwave/issues/7635
4103    fn test_nested_op_display() {
4104        let binary_op = Expr::BinaryOp {
4105            left: Box::new(Expr::Value(Value::Boolean(true))),
4106            op: BinaryOperator::Or,
4107            right: Box::new(Expr::IsNotFalse(Box::new(Expr::Value(Value::Boolean(
4108                true,
4109            ))))),
4110        };
4111        assert_eq!("true OR true IS NOT FALSE", format!("{}", binary_op));
4112
4113        let unary_op = Expr::UnaryOp {
4114            op: UnaryOperator::Not,
4115            expr: Box::new(Expr::IsNotFalse(Box::new(Expr::Value(Value::Boolean(
4116                true,
4117            ))))),
4118        };
4119        assert_eq!("NOT true IS NOT FALSE", format!("{}", unary_op));
4120    }
4121
4122    #[test]
4123    fn test_create_function_display() {
4124        let create_function = Statement::CreateFunction {
4125            or_replace: false,
4126            temporary: false,
4127            if_not_exists: false,
4128            name: ObjectName(vec![Ident::new_unchecked("foo")]),
4129            args: Some(vec![OperateFunctionArg::unnamed(DataType::Int)]),
4130            returns: Some(CreateFunctionReturns::Value(DataType::Int)),
4131            params: CreateFunctionBody {
4132                language: Some(Ident::new_unchecked("python")),
4133                runtime: None,
4134                behavior: Some(FunctionBehavior::Immutable),
4135                as_: Some(FunctionDefinition::SingleQuotedDef("SELECT 1".to_owned())),
4136                return_: None,
4137                using: None,
4138            },
4139            with_options: CreateFunctionWithOptions {
4140                always_retry_on_network_error: None,
4141                r#async: None,
4142                batch: None,
4143            },
4144        };
4145        assert_eq!(
4146            "CREATE FUNCTION foo(INT) RETURNS INT LANGUAGE python IMMUTABLE AS 'SELECT 1'",
4147            format!("{}", create_function)
4148        );
4149        let create_function = Statement::CreateFunction {
4150            or_replace: false,
4151            temporary: false,
4152            if_not_exists: false,
4153            name: ObjectName(vec![Ident::new_unchecked("foo")]),
4154            args: Some(vec![OperateFunctionArg::unnamed(DataType::Int)]),
4155            returns: Some(CreateFunctionReturns::Value(DataType::Int)),
4156            params: CreateFunctionBody {
4157                language: Some(Ident::new_unchecked("python")),
4158                runtime: None,
4159                behavior: Some(FunctionBehavior::Immutable),
4160                as_: Some(FunctionDefinition::SingleQuotedDef("SELECT 1".to_owned())),
4161                return_: None,
4162                using: None,
4163            },
4164            with_options: CreateFunctionWithOptions {
4165                always_retry_on_network_error: Some(true),
4166                r#async: None,
4167                batch: None,
4168            },
4169        };
4170        assert_eq!(
4171            "CREATE FUNCTION foo(INT) RETURNS INT LANGUAGE python IMMUTABLE AS 'SELECT 1' WITH ( always_retry_on_network_error = true )",
4172            format!("{}", create_function)
4173        );
4174    }
4175}