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