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