Skip to main content

risingwave_sqlparser/ast/
mod.rs

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