risingwave_sqlparser/ast/
mod.rs

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