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