Skip to main content

mz_sql_parser/ast/defs/
statement.rs

1// Copyright 2018 sqlparser-rs contributors. All rights reserved.
2// Copyright Materialize, Inc. and contributors. All rights reserved.
3//
4// This file is derived from the sqlparser-rs project, available at
5// https://github.com/andygrove/sqlparser-rs. It was incorporated
6// directly into Materialize on December 21, 2019.
7//
8// Licensed under the Apache License, Version 2.0 (the "License");
9// you may not use this file except in compliance with the License.
10// You may obtain a copy of the License in the LICENSE file at the
11// root of this repository, or online at
12//
13//     http://www.apache.org/licenses/LICENSE-2.0
14//
15// Unless required by applicable law or agreed to in writing, software
16// distributed under the License is distributed on an "AS IS" BASIS,
17// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18// See the License for the specific language governing permissions and
19// limitations under the License.
20
21use std::collections::BTreeMap;
22use std::fmt;
23
24use enum_kinds::EnumKind;
25use serde::{Deserialize, Serialize};
26use smallvec::{SmallVec, smallvec};
27
28use crate::ast::display::{self, AstDisplay, AstFormatter, WithOptionName};
29use crate::ast::{
30    AstInfo, ColumnDef, ConnectionOption, ConnectionOptionName, ContinualTaskOption,
31    CreateConnectionOption, CreateConnectionType, CreateSinkConnection, CreateSourceConnection,
32    CreateSourceOption, CreateSourceOptionName, CteMutRecColumnDef, DeferredItemName, Expr, Format,
33    FormatSpecifier, IcebergSinkMode, Ident, IntervalValue, KeyConstraint, MaterializedViewOption,
34    Query, SelectItem, SinkEnvelope, SourceEnvelope, SourceIncludeMetadata, SubscribeOutput,
35    TableAlias, TableConstraint, TableWithJoins, UnresolvedDatabaseName, UnresolvedItemName,
36    UnresolvedObjectName, UnresolvedSchemaName, Value,
37};
38
39/// A top-level statement (SELECT, INSERT, CREATE, etc.)
40#[allow(clippy::large_enum_variant)]
41#[derive(Debug, Clone, PartialEq, Eq, Hash, EnumKind)]
42#[enum_kind(StatementKind, derive(Serialize, Deserialize))]
43pub enum Statement<T: AstInfo> {
44    Select(SelectStatement<T>),
45    Insert(InsertStatement<T>),
46    Copy(CopyStatement<T>),
47    Update(UpdateStatement<T>),
48    Delete(DeleteStatement<T>),
49    CreateConnection(CreateConnectionStatement<T>),
50    CreateDatabase(CreateDatabaseStatement),
51    CreateSchema(CreateSchemaStatement),
52    CreateWebhookSource(CreateWebhookSourceStatement<T>),
53    CreateSource(CreateSourceStatement<T>),
54    CreateSubsource(CreateSubsourceStatement<T>),
55    CreateSink(CreateSinkStatement<T>),
56    CreateView(CreateViewStatement<T>),
57    CreateMaterializedView(CreateMaterializedViewStatement<T>),
58    CreateContinualTask(CreateContinualTaskStatement<T>),
59    CreateTable(CreateTableStatement<T>),
60    CreateTableFromSource(CreateTableFromSourceStatement<T>),
61    CreateIndex(CreateIndexStatement<T>),
62    CreateType(CreateTypeStatement<T>),
63    CreateRole(CreateRoleStatement),
64    CreateCluster(CreateClusterStatement<T>),
65    CreateClusterReplica(CreateClusterReplicaStatement<T>),
66    CreateSecret(CreateSecretStatement<T>),
67    CreateNetworkPolicy(CreateNetworkPolicyStatement<T>),
68    AlterCluster(AlterClusterStatement<T>),
69    AlterOwner(AlterOwnerStatement<T>),
70    AlterObjectRename(AlterObjectRenameStatement),
71    AlterObjectSwap(AlterObjectSwapStatement),
72    AlterRetainHistory(AlterRetainHistoryStatement<T>),
73    AlterIndex(AlterIndexStatement<T>),
74    AlterSecret(AlterSecretStatement<T>),
75    AlterSetCluster(AlterSetClusterStatement<T>),
76    AlterSink(AlterSinkStatement<T>),
77    AlterSource(AlterSourceStatement<T>),
78    AlterSystemSet(AlterSystemSetStatement),
79    AlterSystemReset(AlterSystemResetStatement),
80    AlterSystemResetAll(AlterSystemResetAllStatement),
81    AlterConnection(AlterConnectionStatement<T>),
82    AlterNetworkPolicy(AlterNetworkPolicyStatement<T>),
83    AlterRole(AlterRoleStatement<T>),
84    AlterTableAddColumn(AlterTableAddColumnStatement<T>),
85    AlterMaterializedViewApplyReplacement(AlterMaterializedViewApplyReplacementStatement),
86    Discard(DiscardStatement),
87    DropObjects(DropObjectsStatement),
88    DropOwned(DropOwnedStatement<T>),
89    SetVariable(SetVariableStatement),
90    ResetVariable(ResetVariableStatement),
91    Show(ShowStatement<T>),
92    StartTransaction(StartTransactionStatement),
93    SetTransaction(SetTransactionStatement),
94    Commit(CommitStatement),
95    Rollback(RollbackStatement),
96    Subscribe(SubscribeStatement<T>),
97    ExplainPlan(ExplainPlanStatement<T>),
98    ExplainPushdown(ExplainPushdownStatement<T>),
99    ExplainTimestamp(ExplainTimestampStatement<T>),
100    ExplainSinkSchema(ExplainSinkSchemaStatement<T>),
101    ExplainAnalyzeObject(ExplainAnalyzeObjectStatement<T>),
102    ExplainAnalyzeCluster(ExplainAnalyzeClusterStatement),
103    Declare(DeclareStatement<T>),
104    Fetch(FetchStatement<T>),
105    Close(CloseStatement),
106    Prepare(PrepareStatement<T>),
107    Execute(ExecuteStatement<T>),
108    Deallocate(DeallocateStatement),
109    Raise(RaiseStatement),
110    GrantRole(GrantRoleStatement<T>),
111    RevokeRole(RevokeRoleStatement<T>),
112    GrantPrivileges(GrantPrivilegesStatement<T>),
113    RevokePrivileges(RevokePrivilegesStatement<T>),
114    AlterDefaultPrivileges(AlterDefaultPrivilegesStatement<T>),
115    ReassignOwned(ReassignOwnedStatement<T>),
116    ValidateConnection(ValidateConnectionStatement<T>),
117    Comment(CommentStatement<T>),
118}
119
120impl<T: AstInfo> AstDisplay for Statement<T> {
121    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
122        match self {
123            Statement::Select(stmt) => f.write_node(stmt),
124            Statement::Insert(stmt) => f.write_node(stmt),
125            Statement::Copy(stmt) => f.write_node(stmt),
126            Statement::Update(stmt) => f.write_node(stmt),
127            Statement::Delete(stmt) => f.write_node(stmt),
128            Statement::CreateConnection(stmt) => f.write_node(stmt),
129            Statement::CreateDatabase(stmt) => f.write_node(stmt),
130            Statement::CreateSchema(stmt) => f.write_node(stmt),
131            Statement::CreateWebhookSource(stmt) => f.write_node(stmt),
132            Statement::CreateSource(stmt) => f.write_node(stmt),
133            Statement::CreateSubsource(stmt) => f.write_node(stmt),
134            Statement::CreateSink(stmt) => f.write_node(stmt),
135            Statement::CreateView(stmt) => f.write_node(stmt),
136            Statement::CreateMaterializedView(stmt) => f.write_node(stmt),
137            Statement::CreateContinualTask(stmt) => f.write_node(stmt),
138            Statement::CreateTable(stmt) => f.write_node(stmt),
139            Statement::CreateTableFromSource(stmt) => f.write_node(stmt),
140            Statement::CreateIndex(stmt) => f.write_node(stmt),
141            Statement::CreateRole(stmt) => f.write_node(stmt),
142            Statement::CreateSecret(stmt) => f.write_node(stmt),
143            Statement::CreateType(stmt) => f.write_node(stmt),
144            Statement::CreateCluster(stmt) => f.write_node(stmt),
145            Statement::CreateClusterReplica(stmt) => f.write_node(stmt),
146            Statement::CreateNetworkPolicy(stmt) => f.write_node(stmt),
147            Statement::AlterCluster(stmt) => f.write_node(stmt),
148            Statement::AlterNetworkPolicy(stmt) => f.write_node(stmt),
149            Statement::AlterOwner(stmt) => f.write_node(stmt),
150            Statement::AlterObjectRename(stmt) => f.write_node(stmt),
151            Statement::AlterRetainHistory(stmt) => f.write_node(stmt),
152            Statement::AlterObjectSwap(stmt) => f.write_node(stmt),
153            Statement::AlterIndex(stmt) => f.write_node(stmt),
154            Statement::AlterSetCluster(stmt) => f.write_node(stmt),
155            Statement::AlterSecret(stmt) => f.write_node(stmt),
156            Statement::AlterSink(stmt) => f.write_node(stmt),
157            Statement::AlterSource(stmt) => f.write_node(stmt),
158            Statement::AlterSystemSet(stmt) => f.write_node(stmt),
159            Statement::AlterSystemReset(stmt) => f.write_node(stmt),
160            Statement::AlterSystemResetAll(stmt) => f.write_node(stmt),
161            Statement::AlterConnection(stmt) => f.write_node(stmt),
162            Statement::AlterRole(stmt) => f.write_node(stmt),
163            Statement::AlterTableAddColumn(stmt) => f.write_node(stmt),
164            Statement::AlterMaterializedViewApplyReplacement(stmt) => f.write_node(stmt),
165            Statement::Discard(stmt) => f.write_node(stmt),
166            Statement::DropObjects(stmt) => f.write_node(stmt),
167            Statement::DropOwned(stmt) => f.write_node(stmt),
168            Statement::SetVariable(stmt) => f.write_node(stmt),
169            Statement::ResetVariable(stmt) => f.write_node(stmt),
170            Statement::Show(stmt) => f.write_node(stmt),
171            Statement::StartTransaction(stmt) => f.write_node(stmt),
172            Statement::SetTransaction(stmt) => f.write_node(stmt),
173            Statement::Commit(stmt) => f.write_node(stmt),
174            Statement::Rollback(stmt) => f.write_node(stmt),
175            Statement::Subscribe(stmt) => f.write_node(stmt),
176            Statement::ExplainPlan(stmt) => f.write_node(stmt),
177            Statement::ExplainPushdown(stmt) => f.write_node(stmt),
178            Statement::ExplainAnalyzeObject(stmt) => f.write_node(stmt),
179            Statement::ExplainAnalyzeCluster(stmt) => f.write_node(stmt),
180            Statement::ExplainTimestamp(stmt) => f.write_node(stmt),
181            Statement::ExplainSinkSchema(stmt) => f.write_node(stmt),
182            Statement::Declare(stmt) => f.write_node(stmt),
183            Statement::Close(stmt) => f.write_node(stmt),
184            Statement::Fetch(stmt) => f.write_node(stmt),
185            Statement::Prepare(stmt) => f.write_node(stmt),
186            Statement::Execute(stmt) => f.write_node(stmt),
187            Statement::Deallocate(stmt) => f.write_node(stmt),
188            Statement::Raise(stmt) => f.write_node(stmt),
189            Statement::GrantRole(stmt) => f.write_node(stmt),
190            Statement::RevokeRole(stmt) => f.write_node(stmt),
191            Statement::GrantPrivileges(stmt) => f.write_node(stmt),
192            Statement::RevokePrivileges(stmt) => f.write_node(stmt),
193            Statement::AlterDefaultPrivileges(stmt) => f.write_node(stmt),
194            Statement::ReassignOwned(stmt) => f.write_node(stmt),
195            Statement::ValidateConnection(stmt) => f.write_node(stmt),
196            Statement::Comment(stmt) => f.write_node(stmt),
197        }
198    }
199}
200impl_display_t!(Statement);
201
202/// A static str for each statement kind
203pub fn statement_kind_label_value(kind: StatementKind) -> &'static str {
204    match kind {
205        StatementKind::Select => "select",
206        StatementKind::Insert => "insert",
207        StatementKind::Copy => "copy",
208        StatementKind::Update => "update",
209        StatementKind::Delete => "delete",
210        StatementKind::CreateConnection => "create_connection",
211        StatementKind::CreateDatabase => "create_database",
212        StatementKind::CreateSchema => "create_schema",
213        StatementKind::CreateWebhookSource => "create_webhook",
214        StatementKind::CreateSource => "create_source",
215        StatementKind::CreateSubsource => "create_subsource",
216        StatementKind::CreateSink => "create_sink",
217        StatementKind::CreateView => "create_view",
218        StatementKind::CreateMaterializedView => "create_materialized_view",
219        StatementKind::CreateContinualTask => "create_continual_task",
220        StatementKind::CreateTable => "create_table",
221        StatementKind::CreateTableFromSource => "create_table_from_source",
222        StatementKind::CreateIndex => "create_index",
223        StatementKind::CreateType => "create_type",
224        StatementKind::CreateRole => "create_role",
225        StatementKind::CreateCluster => "create_cluster",
226        StatementKind::CreateClusterReplica => "create_cluster_replica",
227        StatementKind::CreateSecret => "create_secret",
228        StatementKind::CreateNetworkPolicy => "create_network_policy",
229        StatementKind::AlterCluster => "alter_cluster",
230        StatementKind::AlterObjectRename => "alter_object_rename",
231        StatementKind::AlterRetainHistory => "alter_retain_history",
232        StatementKind::AlterObjectSwap => "alter_object_swap",
233        StatementKind::AlterIndex => "alter_index",
234        StatementKind::AlterNetworkPolicy => "alter_network_policy",
235        StatementKind::AlterRole => "alter_role",
236        StatementKind::AlterSecret => "alter_secret",
237        StatementKind::AlterSetCluster => "alter_set_cluster",
238        StatementKind::AlterSink => "alter_sink",
239        StatementKind::AlterSource => "alter_source",
240        StatementKind::AlterSystemSet => "alter_system_set",
241        StatementKind::AlterSystemReset => "alter_system_reset",
242        StatementKind::AlterSystemResetAll => "alter_system_reset_all",
243        StatementKind::AlterOwner => "alter_owner",
244        StatementKind::AlterConnection => "alter_connection",
245        StatementKind::AlterTableAddColumn => "alter_table",
246        StatementKind::AlterMaterializedViewApplyReplacement => {
247            "alter_materialized_view_apply_replacement"
248        }
249        StatementKind::Discard => "discard",
250        StatementKind::DropObjects => "drop_objects",
251        StatementKind::DropOwned => "drop_owned",
252        StatementKind::SetVariable => "set_variable",
253        StatementKind::ResetVariable => "reset_variable",
254        StatementKind::Show => "show",
255        StatementKind::StartTransaction => "start_transaction",
256        StatementKind::SetTransaction => "set_transaction",
257        StatementKind::Commit => "commit",
258        StatementKind::Rollback => "rollback",
259        StatementKind::Subscribe => "subscribe",
260        StatementKind::ExplainPlan => "explain_plan",
261        StatementKind::ExplainPushdown => "explain_pushdown",
262        StatementKind::ExplainAnalyzeObject => "explain_analyze_object",
263        StatementKind::ExplainAnalyzeCluster => "explain_analyze_cluster",
264        StatementKind::ExplainTimestamp => "explain_timestamp",
265        StatementKind::ExplainSinkSchema => "explain_sink_schema",
266        StatementKind::Declare => "declare",
267        StatementKind::Fetch => "fetch",
268        StatementKind::Close => "close",
269        StatementKind::Prepare => "prepare",
270        StatementKind::Execute => "execute",
271        StatementKind::Deallocate => "deallocate",
272        StatementKind::Raise => "raise",
273        StatementKind::GrantRole => "grant_role",
274        StatementKind::RevokeRole => "revoke_role",
275        StatementKind::GrantPrivileges => "grant_privileges",
276        StatementKind::RevokePrivileges => "revoke_privileges",
277        StatementKind::AlterDefaultPrivileges => "alter_default_privileges",
278        StatementKind::ReassignOwned => "reassign_owned",
279        StatementKind::ValidateConnection => "validate_connection",
280        StatementKind::Comment => "comment",
281    }
282}
283
284/// `SELECT`
285#[derive(Debug, Clone, PartialEq, Eq, Hash)]
286pub struct SelectStatement<T: AstInfo> {
287    pub query: Query<T>,
288    pub as_of: Option<AsOf<T>>,
289}
290
291impl<T: AstInfo> AstDisplay for SelectStatement<T> {
292    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
293        f.write_node(&self.query);
294        if let Some(as_of) = &self.as_of {
295            f.write_str(" ");
296            f.write_node(as_of);
297        }
298    }
299}
300impl_display_t!(SelectStatement);
301
302/// `INSERT`
303#[derive(Debug, Clone, PartialEq, Eq, Hash)]
304pub struct InsertStatement<T: AstInfo> {
305    /// TABLE
306    pub table_name: T::ItemName,
307    /// COLUMNS
308    pub columns: Vec<Ident>,
309    /// A SQL query that specifies what to insert.
310    pub source: InsertSource<T>,
311    /// RETURNING
312    pub returning: Vec<SelectItem<T>>,
313}
314
315impl<T: AstInfo> AstDisplay for InsertStatement<T> {
316    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
317        f.write_str("INSERT INTO ");
318        f.write_node(&self.table_name);
319        if !self.columns.is_empty() {
320            f.write_str(" (");
321            f.write_node(&display::comma_separated(&self.columns));
322            f.write_str(")");
323        }
324        f.write_str(" ");
325        f.write_node(&self.source);
326        if !self.returning.is_empty() {
327            f.write_str(" RETURNING ");
328            f.write_node(&display::comma_separated(&self.returning));
329        }
330    }
331}
332impl_display_t!(InsertStatement);
333
334#[derive(Debug, Clone, PartialEq, Eq, Hash)]
335pub enum CopyRelation<T: AstInfo> {
336    Named {
337        name: T::ItemName,
338        columns: Vec<Ident>,
339    },
340    Select(SelectStatement<T>),
341    Subscribe(SubscribeStatement<T>),
342}
343
344#[derive(Debug, Clone, PartialEq, Eq, Hash)]
345pub enum CopyDirection {
346    To,
347    From,
348}
349
350impl AstDisplay for CopyDirection {
351    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
352        f.write_str(match self {
353            CopyDirection::To => "TO",
354            CopyDirection::From => "FROM",
355        })
356    }
357}
358impl_display!(CopyDirection);
359
360#[derive(Debug, Clone, PartialEq, Eq, Hash)]
361pub enum CopyTarget<T: AstInfo> {
362    Stdin,
363    Stdout,
364    Expr(Expr<T>),
365}
366
367impl<T: AstInfo> AstDisplay for CopyTarget<T> {
368    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
369        match self {
370            CopyTarget::Stdin => f.write_str("STDIN"),
371            CopyTarget::Stdout => f.write_str("STDOUT"),
372            CopyTarget::Expr(expr) => f.write_node(expr),
373        }
374    }
375}
376impl_display_t!(CopyTarget);
377
378#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
379pub enum CopyOptionName {
380    Format,
381    Delimiter,
382    Null,
383    Escape,
384    Quote,
385    Header,
386    AwsConnection,
387    MaxFileSize,
388    Files,
389    Pattern,
390}
391
392impl AstDisplay for CopyOptionName {
393    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
394        f.write_str(match self {
395            CopyOptionName::Format => "FORMAT",
396            CopyOptionName::Delimiter => "DELIMITER",
397            CopyOptionName::Null => "NULL",
398            CopyOptionName::Escape => "ESCAPE",
399            CopyOptionName::Quote => "QUOTE",
400            CopyOptionName::Header => "HEADER",
401            CopyOptionName::AwsConnection => "AWS CONNECTION",
402            CopyOptionName::MaxFileSize => "MAX FILE SIZE",
403            CopyOptionName::Files => "FILES",
404            CopyOptionName::Pattern => "PATTERN",
405        })
406    }
407}
408
409impl WithOptionName for CopyOptionName {
410    /// # WARNING
411    ///
412    /// Whenever implementing this trait consider very carefully whether or not
413    /// this value could contain sensitive user data. If you're uncertain, err
414    /// on the conservative side and return `true`.
415    fn redact_value(&self) -> bool {
416        match self {
417            CopyOptionName::Format
418            | CopyOptionName::Delimiter
419            | CopyOptionName::Null
420            | CopyOptionName::Escape
421            | CopyOptionName::Quote
422            | CopyOptionName::Header
423            | CopyOptionName::AwsConnection
424            | CopyOptionName::MaxFileSize => false,
425            CopyOptionName::Files | CopyOptionName::Pattern => true,
426        }
427    }
428}
429
430#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
431pub struct CopyOption<T: AstInfo> {
432    pub name: CopyOptionName,
433    pub value: Option<WithOptionValue<T>>,
434}
435impl_display_for_with_option!(CopyOption);
436
437/// `COPY`
438#[derive(Debug, Clone, PartialEq, Eq, Hash)]
439pub struct CopyStatement<T: AstInfo> {
440    /// RELATION
441    pub relation: CopyRelation<T>,
442    /// DIRECTION
443    pub direction: CopyDirection,
444    // TARGET
445    pub target: CopyTarget<T>,
446    // OPTIONS
447    pub options: Vec<CopyOption<T>>,
448}
449
450impl<T: AstInfo> AstDisplay for CopyStatement<T> {
451    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
452        f.write_str("COPY ");
453        match &self.relation {
454            CopyRelation::Named { name, columns } => {
455                f.write_node(name);
456                if !columns.is_empty() {
457                    f.write_str("(");
458                    f.write_node(&display::comma_separated(columns));
459                    f.write_str(")");
460                }
461            }
462            CopyRelation::Select(query) => {
463                f.write_str("(");
464                f.write_node(query);
465                f.write_str(")");
466            }
467            CopyRelation::Subscribe(query) => {
468                f.write_str("(");
469                f.write_node(query);
470                f.write_str(")");
471            }
472        };
473        f.write_str(" ");
474        f.write_node(&self.direction);
475        f.write_str(" ");
476        f.write_node(&self.target);
477        if !self.options.is_empty() {
478            f.write_str(" WITH (");
479            f.write_node(&display::comma_separated(&self.options));
480            f.write_str(")");
481        }
482    }
483}
484impl_display_t!(CopyStatement);
485
486/// `UPDATE`
487#[derive(Debug, Clone, PartialEq, Eq, Hash)]
488pub struct UpdateStatement<T: AstInfo> {
489    /// `FROM`
490    pub table_name: T::ItemName,
491    pub alias: Option<TableAlias>,
492    /// Column assignments
493    pub assignments: Vec<Assignment<T>>,
494    /// WHERE
495    pub selection: Option<Expr<T>>,
496}
497
498impl<T: AstInfo> AstDisplay for UpdateStatement<T> {
499    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
500        f.write_str("UPDATE ");
501        f.write_node(&self.table_name);
502        if let Some(alias) = &self.alias {
503            f.write_str(" AS ");
504            f.write_node(alias);
505        }
506        if !self.assignments.is_empty() {
507            f.write_str(" SET ");
508            f.write_node(&display::comma_separated(&self.assignments));
509        }
510        if let Some(selection) = &self.selection {
511            f.write_str(" WHERE ");
512            f.write_node(selection);
513        }
514    }
515}
516impl_display_t!(UpdateStatement);
517
518/// `DELETE`
519#[derive(Debug, Clone, PartialEq, Eq, Hash)]
520pub struct DeleteStatement<T: AstInfo> {
521    /// `FROM`
522    pub table_name: T::ItemName,
523    /// `AS`
524    pub alias: Option<TableAlias>,
525    /// `USING`
526    pub using: Vec<TableWithJoins<T>>,
527    /// `WHERE`
528    pub selection: Option<Expr<T>>,
529}
530
531impl<T: AstInfo> AstDisplay for DeleteStatement<T> {
532    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
533        f.write_str("DELETE FROM ");
534        f.write_node(&self.table_name);
535        if let Some(alias) = &self.alias {
536            f.write_str(" AS ");
537            f.write_node(alias);
538        }
539        if !self.using.is_empty() {
540            f.write_str(" USING ");
541            f.write_node(&display::comma_separated(&self.using));
542        }
543        if let Some(selection) = &self.selection {
544            f.write_str(" WHERE ");
545            f.write_node(selection);
546        }
547    }
548}
549impl_display_t!(DeleteStatement);
550
551/// `CREATE DATABASE`
552#[derive(Debug, Clone, PartialEq, Eq, Hash)]
553pub struct CreateDatabaseStatement {
554    pub name: UnresolvedDatabaseName,
555    pub if_not_exists: bool,
556}
557
558impl AstDisplay for CreateDatabaseStatement {
559    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
560        f.write_str("CREATE DATABASE ");
561        if self.if_not_exists {
562            f.write_str("IF NOT EXISTS ");
563        }
564        f.write_node(&self.name);
565    }
566}
567impl_display!(CreateDatabaseStatement);
568
569/// `CREATE SCHEMA`
570#[derive(Debug, Clone, PartialEq, Eq, Hash)]
571pub struct CreateSchemaStatement {
572    pub name: UnresolvedSchemaName,
573    pub if_not_exists: bool,
574}
575
576impl AstDisplay for CreateSchemaStatement {
577    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
578        f.write_str("CREATE SCHEMA ");
579        if self.if_not_exists {
580            f.write_str("IF NOT EXISTS ");
581        }
582        f.write_node(&self.name);
583    }
584}
585impl_display!(CreateSchemaStatement);
586
587#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
588pub struct ConnectionDefaultAwsPrivatelink<T: AstInfo> {
589    pub connection: T::ItemName,
590    // TODO port should be switched to a vec of options similar to KafkaBrokerAwsPrivatelink if ever support more than port
591    pub port: Option<u16>,
592}
593
594impl<T: AstInfo> AstDisplay for ConnectionDefaultAwsPrivatelink<T> {
595    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
596        f.write_node(&self.connection);
597        if let Some(port) = self.port {
598            f.write_str(" (PORT ");
599            f.write_node(&display::escape_single_quote_string(&port.to_string()));
600            f.write_str(")");
601        }
602    }
603}
604impl_display_t!(ConnectionDefaultAwsPrivatelink);
605
606#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
607pub struct KafkaBroker<T: AstInfo> {
608    pub address: String,
609    pub tunnel: KafkaBrokerTunnel<T>,
610}
611
612impl<T: AstInfo> AstDisplay for KafkaBroker<T> {
613    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
614        f.write_str("'");
615        f.write_node(&display::escape_single_quote_string(&self.address));
616        f.write_str("'");
617        f.write_node(&self.tunnel);
618    }
619}
620
621impl_display_t!(KafkaBroker);
622
623#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
624pub enum KafkaBrokerTunnel<T: AstInfo> {
625    Direct,
626    AwsPrivatelink(KafkaBrokerAwsPrivatelink<T>),
627    SshTunnel(T::ItemName),
628}
629
630impl<T: AstInfo> AstDisplay for KafkaBrokerTunnel<T> {
631    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
632        use KafkaBrokerTunnel::*;
633        match self {
634            Direct => {}
635            AwsPrivatelink(aws) => {
636                f.write_str(" ");
637                f.write_node(aws);
638            }
639            Self::SshTunnel(connection) => {
640                f.write_str("USING SSH TUNNEL ");
641                f.write_node(connection);
642            }
643        }
644    }
645}
646
647impl_display_t!(KafkaBrokerTunnel);
648
649#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
650pub enum KafkaBrokerAwsPrivatelinkOptionName {
651    AvailabilityZone,
652    Port,
653}
654
655impl AstDisplay for KafkaBrokerAwsPrivatelinkOptionName {
656    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
657        match self {
658            Self::AvailabilityZone => f.write_str("AVAILABILITY ZONE"),
659            Self::Port => f.write_str("PORT"),
660        }
661    }
662}
663impl_display!(KafkaBrokerAwsPrivatelinkOptionName);
664
665impl WithOptionName for KafkaBrokerAwsPrivatelinkOptionName {
666    /// # WARNING
667    ///
668    /// Whenever implementing this trait consider very carefully whether or not
669    /// this value could contain sensitive user data. If you're uncertain, err
670    /// on the conservative side and return `true`.
671    fn redact_value(&self) -> bool {
672        match self {
673            Self::AvailabilityZone | Self::Port => false,
674        }
675    }
676}
677
678#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
679pub struct KafkaBrokerAwsPrivatelinkOption<T: AstInfo> {
680    pub name: KafkaBrokerAwsPrivatelinkOptionName,
681    pub value: Option<WithOptionValue<T>>,
682}
683impl_display_for_with_option!(KafkaBrokerAwsPrivatelinkOption);
684impl_display_t!(KafkaBrokerAwsPrivatelinkOption);
685
686#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
687pub struct KafkaBrokerAwsPrivatelink<T: AstInfo> {
688    pub connection: T::ItemName,
689    pub options: Vec<KafkaBrokerAwsPrivatelinkOption<T>>,
690}
691
692impl<T: AstInfo> AstDisplay for KafkaBrokerAwsPrivatelink<T> {
693    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
694        f.write_str("USING AWS PRIVATELINK ");
695        f.write_node(&self.connection);
696        if !self.options.is_empty() {
697            f.write_str(" (");
698            f.write_node(&display::comma_separated(&self.options));
699            f.write_str(")");
700        }
701    }
702}
703impl_display_t!(KafkaBrokerAwsPrivatelink);
704
705/// `CREATE CONNECTION` refactor WIP
706#[derive(Debug, Clone, PartialEq, Eq, Hash)]
707pub struct CreateConnectionStatement<T: AstInfo> {
708    pub name: UnresolvedItemName,
709    pub connection_type: CreateConnectionType,
710    pub if_not_exists: bool,
711    pub values: Vec<ConnectionOption<T>>,
712    pub with_options: Vec<CreateConnectionOption<T>>,
713}
714
715impl<T: AstInfo> AstDisplay for CreateConnectionStatement<T> {
716    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
717        f.write_str("CREATE CONNECTION ");
718        if self.if_not_exists {
719            f.write_str("IF NOT EXISTS ");
720        }
721        f.write_node(&self.name);
722        f.write_str(" TO ");
723        self.connection_type.fmt(f);
724        f.write_str(" (");
725        f.write_node(&display::comma_separated(&self.values));
726        f.write_str(")");
727
728        if !self.with_options.is_empty() {
729            f.write_str(" WITH (");
730            f.write_node(&display::comma_separated(&self.with_options));
731            f.write_str(")");
732        }
733    }
734}
735impl_display_t!(CreateConnectionStatement);
736
737/// `VALIDATE CONNECTION`
738#[derive(Debug, Clone, PartialEq, Eq, Hash)]
739pub struct ValidateConnectionStatement<T: AstInfo> {
740    /// The connection to validate
741    pub name: T::ItemName,
742}
743
744impl<T: AstInfo> AstDisplay for ValidateConnectionStatement<T> {
745    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
746        f.write_str("VALIDATE CONNECTION ");
747        f.write_node(&self.name);
748    }
749}
750impl_display_t!(ValidateConnectionStatement);
751
752/// `CREATE (SOURCE | TABLE) <name> FROM WEBHOOK`
753#[derive(Debug, Clone, PartialEq, Eq, Hash)]
754pub struct CreateWebhookSourceStatement<T: AstInfo> {
755    pub name: UnresolvedItemName,
756    pub is_table: bool,
757    pub if_not_exists: bool,
758    pub body_format: Format<T>,
759    pub include_headers: CreateWebhookSourceIncludeHeaders,
760    pub validate_using: Option<CreateWebhookSourceCheck<T>>,
761    pub in_cluster: Option<T::ClusterName>,
762}
763
764impl<T: AstInfo> AstDisplay for CreateWebhookSourceStatement<T> {
765    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
766        f.write_str("CREATE ");
767
768        if self.is_table {
769            f.write_str("TABLE ");
770        } else {
771            f.write_str("SOURCE ");
772        }
773
774        if self.if_not_exists {
775            f.write_str("IF NOT EXISTS ");
776        }
777        f.write_node(&self.name);
778
779        // CREATE TABLE ... FROM WEBHOOK does not support specifying a cluster.
780        if !self.is_table {
781            if let Some(cluster_name) = &self.in_cluster {
782                f.write_str(" IN CLUSTER ");
783                f.write_node(cluster_name);
784            }
785        }
786
787        f.write_str(" FROM WEBHOOK ");
788
789        f.write_str("BODY FORMAT ");
790        f.write_node(&self.body_format);
791
792        f.write_node(&self.include_headers);
793
794        if let Some(validate) = &self.validate_using {
795            f.write_str(" ");
796            f.write_node(validate);
797        }
798    }
799}
800
801impl_display_t!(CreateWebhookSourceStatement);
802
803/// `CHECK ( ... )`
804#[derive(Debug, Clone, PartialEq, Eq, Hash)]
805pub struct CreateWebhookSourceCheck<T: AstInfo> {
806    pub options: Option<CreateWebhookSourceCheckOptions<T>>,
807    pub using: Expr<T>,
808}
809
810impl<T: AstInfo> AstDisplay for CreateWebhookSourceCheck<T> {
811    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
812        f.write_str("CHECK (");
813
814        if let Some(options) = &self.options {
815            f.write_node(options);
816            f.write_str(" ");
817        }
818
819        f.write_node(&self.using);
820        f.write_str(")");
821    }
822}
823
824impl_display_t!(CreateWebhookSourceCheck);
825
826/// `CHECK ( WITH ( ... ) )`
827#[derive(Debug, Clone, PartialEq, Eq, Hash)]
828pub struct CreateWebhookSourceCheckOptions<T: AstInfo> {
829    pub secrets: Vec<CreateWebhookSourceSecret<T>>,
830    pub headers: Vec<CreateWebhookSourceHeader>,
831    pub bodies: Vec<CreateWebhookSourceBody>,
832}
833
834impl<T: AstInfo> AstDisplay for CreateWebhookSourceCheckOptions<T> {
835    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
836        f.write_str("WITH (");
837
838        let mut delim = "";
839        if !self.headers.is_empty() {
840            f.write_node(&display::comma_separated(&self.headers[..]));
841            delim = ", ";
842        }
843        if !self.bodies.is_empty() {
844            f.write_str(delim);
845            f.write_node(&display::comma_separated(&self.bodies[..]));
846            delim = ", ";
847        }
848        if !self.secrets.is_empty() {
849            f.write_str(delim);
850            f.write_node(&display::comma_separated(&self.secrets[..]));
851        }
852
853        f.write_str(")");
854    }
855}
856
857impl_display_t!(CreateWebhookSourceCheckOptions);
858
859/// `SECRET ... [AS ...] [BYTES]`
860#[derive(Debug, Clone, PartialEq, Eq, Hash)]
861pub struct CreateWebhookSourceSecret<T: AstInfo> {
862    pub secret: T::ItemName,
863    pub alias: Option<Ident>,
864    pub use_bytes: bool,
865}
866
867impl<T: AstInfo> AstDisplay for CreateWebhookSourceSecret<T> {
868    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
869        f.write_str("SECRET ");
870        f.write_node(&self.secret);
871
872        if let Some(alias) = &self.alias {
873            f.write_str(" AS ");
874            f.write_node(alias);
875        }
876
877        if self.use_bytes {
878            f.write_str(" BYTES");
879        }
880    }
881}
882
883impl_display_t!(CreateWebhookSourceSecret);
884
885/// `HEADER [AS ...] [BYTES]`
886#[derive(Debug, Clone, PartialEq, Eq, Hash)]
887pub struct CreateWebhookSourceHeader {
888    pub alias: Option<Ident>,
889    pub use_bytes: bool,
890}
891
892impl AstDisplay for CreateWebhookSourceHeader {
893    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
894        f.write_str("HEADERS");
895
896        if let Some(alias) = &self.alias {
897            f.write_str(" AS ");
898            f.write_node(alias);
899        }
900
901        if self.use_bytes {
902            f.write_str(" BYTES");
903        }
904    }
905}
906
907impl_display!(CreateWebhookSourceHeader);
908
909/// `BODY [AS ...] [BYTES]`
910#[derive(Debug, Clone, PartialEq, Eq, Hash)]
911pub struct CreateWebhookSourceBody {
912    pub alias: Option<Ident>,
913    pub use_bytes: bool,
914}
915
916impl AstDisplay for CreateWebhookSourceBody {
917    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
918        f.write_str("BODY");
919
920        if let Some(alias) = &self.alias {
921            f.write_str(" AS ");
922            f.write_node(alias);
923        }
924
925        if self.use_bytes {
926            f.write_str(" BYTES");
927        }
928    }
929}
930
931impl_display!(CreateWebhookSourceBody);
932
933/// `INCLUDE [HEADER | HEADERS]`
934#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
935pub struct CreateWebhookSourceIncludeHeaders {
936    /// Mapping individual header names to columns in the source.
937    pub mappings: Vec<CreateWebhookSourceMapHeader>,
938    /// Whether or not to include the `headers` column, and any filtering we might want to do.
939    pub column: Option<Vec<CreateWebhookSourceFilterHeader>>,
940}
941
942impl AstDisplay for CreateWebhookSourceIncludeHeaders {
943    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
944        if !self.mappings.is_empty() {
945            f.write_str(" ");
946        }
947        f.write_node(&display::separated(&self.mappings[..], " "));
948
949        if let Some(column) = &self.column {
950            f.write_str(" INCLUDE HEADERS");
951
952            if !column.is_empty() {
953                f.write_str(" ");
954                f.write_str("(");
955                f.write_node(&display::comma_separated(&column[..]));
956                f.write_str(")");
957            }
958        }
959    }
960}
961
962impl_display!(CreateWebhookSourceIncludeHeaders);
963
964#[derive(Debug, Clone, PartialEq, Eq, Hash)]
965pub struct CreateWebhookSourceFilterHeader {
966    pub block: bool,
967    pub header_name: String,
968}
969
970impl AstDisplay for CreateWebhookSourceFilterHeader {
971    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
972        if self.block {
973            f.write_str("NOT ");
974        }
975        f.write_node(&display::escaped_string_literal(&self.header_name));
976    }
977}
978
979impl_display!(CreateWebhookSourceFilterHeader);
980
981/// `INCLUDE HEADER <name> [AS <alias>] [BYTES]`
982#[derive(Debug, Clone, PartialEq, Eq, Hash)]
983pub struct CreateWebhookSourceMapHeader {
984    pub header_name: String,
985    pub column_name: Ident,
986    pub use_bytes: bool,
987}
988
989impl AstDisplay for CreateWebhookSourceMapHeader {
990    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
991        f.write_str("INCLUDE HEADER ");
992
993        f.write_node(&display::escaped_string_literal(&self.header_name));
994
995        f.write_str(" AS ");
996        f.write_node(&self.column_name);
997
998        if self.use_bytes {
999            f.write_str(" BYTES");
1000        }
1001    }
1002}
1003
1004impl_display!(CreateWebhookSourceMapHeader);
1005
1006/// `CREATE SOURCE`
1007#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1008pub struct CreateSourceStatement<T: AstInfo> {
1009    pub name: UnresolvedItemName,
1010    pub in_cluster: Option<T::ClusterName>,
1011    pub col_names: Vec<Ident>,
1012    pub connection: CreateSourceConnection<T>,
1013    pub include_metadata: Vec<SourceIncludeMetadata>,
1014    pub format: Option<FormatSpecifier<T>>,
1015    pub envelope: Option<SourceEnvelope>,
1016    pub if_not_exists: bool,
1017    pub key_constraint: Option<KeyConstraint>,
1018    pub with_options: Vec<CreateSourceOption<T>>,
1019    pub external_references: Option<ExternalReferences>,
1020    pub progress_subsource: Option<DeferredItemName<T>>,
1021}
1022
1023impl<T: AstInfo> AstDisplay for CreateSourceStatement<T> {
1024    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1025        f.write_str("CREATE SOURCE ");
1026        if self.if_not_exists {
1027            f.write_str("IF NOT EXISTS ");
1028        }
1029        f.write_node(&self.name);
1030        if !self.col_names.is_empty() {
1031            f.write_str(" (");
1032            f.write_node(&display::comma_separated(&self.col_names));
1033            if let Some(key_constraint) = &self.key_constraint {
1034                f.write_str(", ");
1035                f.write_node(key_constraint);
1036            }
1037            f.write_str(")");
1038        } else if let Some(key_constraint) = &self.key_constraint {
1039            f.write_str(" (");
1040            f.write_node(key_constraint);
1041            f.write_str(")")
1042        }
1043        if let Some(cluster) = &self.in_cluster {
1044            f.write_str(" IN CLUSTER ");
1045            f.write_node(cluster);
1046        }
1047        f.write_str(" FROM ");
1048        f.write_node(&self.connection);
1049        if let Some(format) = &self.format {
1050            f.write_str(" ");
1051            f.write_node(format);
1052        }
1053        if !self.include_metadata.is_empty() {
1054            f.write_str(" INCLUDE ");
1055            f.write_node(&display::comma_separated(&self.include_metadata));
1056        }
1057
1058        if let Some(envelope) = &self.envelope {
1059            f.write_str(" ENVELOPE ");
1060            f.write_node(envelope);
1061        }
1062
1063        if let Some(subsources) = &self.external_references {
1064            f.write_str(" ");
1065            f.write_node(subsources);
1066        }
1067
1068        if let Some(progress) = &self.progress_subsource {
1069            f.write_str(" EXPOSE PROGRESS AS ");
1070            f.write_node(progress);
1071        }
1072
1073        if !self.with_options.is_empty() {
1074            f.write_str(" WITH (");
1075            f.write_node(&display::comma_separated(&self.with_options));
1076            f.write_str(")");
1077        }
1078    }
1079}
1080impl_display_t!(CreateSourceStatement);
1081
1082/// A selected external reference in a FOR TABLES (..) statement
1083#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1084pub struct ExternalReferenceExport {
1085    pub reference: UnresolvedItemName,
1086    pub alias: Option<UnresolvedItemName>,
1087}
1088
1089impl AstDisplay for ExternalReferenceExport {
1090    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1091        f.write_node(&self.reference);
1092        if let Some(alias) = &self.alias {
1093            f.write_str(" AS ");
1094            f.write_node(alias);
1095        }
1096    }
1097}
1098impl_display!(ExternalReferenceExport);
1099
1100/// Specifies which set of external references to generate a source export
1101/// for in a `CREATE SOURCE` statement.
1102#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1103pub enum ExternalReferences {
1104    /// A subset defined with FOR TABLES (...)
1105    SubsetTables(Vec<ExternalReferenceExport>),
1106    /// A subset defined with FOR SCHEMAS (...)
1107    SubsetSchemas(Vec<Ident>),
1108    /// FOR ALL TABLES
1109    All,
1110}
1111
1112impl AstDisplay for ExternalReferences {
1113    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1114        match self {
1115            Self::SubsetTables(tables) => {
1116                f.write_str("FOR TABLES (");
1117                f.write_node(&display::comma_separated(tables));
1118                f.write_str(")");
1119            }
1120            Self::SubsetSchemas(schemas) => {
1121                f.write_str("FOR SCHEMAS (");
1122                f.write_node(&display::comma_separated(schemas));
1123                f.write_str(")");
1124            }
1125            Self::All => f.write_str("FOR ALL TABLES"),
1126        }
1127    }
1128}
1129impl_display!(ExternalReferences);
1130
1131/// An option in a `CREATE SUBSOURCE` statement.
1132#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1133pub enum CreateSubsourceOptionName {
1134    Progress,
1135    /// Tracks which item this subsource references in the primary source.
1136    ExternalReference,
1137    /// The `RETAIN HISTORY` option
1138    RetainHistory,
1139    /// Columns whose types you want to unconditionally format as text
1140    TextColumns,
1141    /// Columns you want to exclude when ingesting data
1142    ExcludeColumns,
1143    /// `DETAILS` for this subsource, hex-encoded protobuf type
1144    /// `mz_storage_types::sources::SourceExportStatementDetails`
1145    Details,
1146}
1147
1148impl AstDisplay for CreateSubsourceOptionName {
1149    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1150        f.write_str(match self {
1151            CreateSubsourceOptionName::Progress => "PROGRESS",
1152            CreateSubsourceOptionName::ExternalReference => "EXTERNAL REFERENCE",
1153            CreateSubsourceOptionName::RetainHistory => "RETAIN HISTORY",
1154            CreateSubsourceOptionName::TextColumns => "TEXT COLUMNS",
1155            CreateSubsourceOptionName::ExcludeColumns => "EXCLUDE COLUMNS",
1156            CreateSubsourceOptionName::Details => "DETAILS",
1157        })
1158    }
1159}
1160
1161impl WithOptionName for CreateSubsourceOptionName {
1162    /// # WARNING
1163    ///
1164    /// Whenever implementing this trait consider very carefully whether or not
1165    /// this value could contain sensitive user data. If you're uncertain, err
1166    /// on the conservative side and return `true`.
1167    fn redact_value(&self) -> bool {
1168        match self {
1169            CreateSubsourceOptionName::Progress
1170            | CreateSubsourceOptionName::ExternalReference
1171            | CreateSubsourceOptionName::RetainHistory
1172            | CreateSubsourceOptionName::Details
1173            | CreateSubsourceOptionName::TextColumns
1174            | CreateSubsourceOptionName::ExcludeColumns => false,
1175        }
1176    }
1177}
1178
1179#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1180pub struct CreateSubsourceOption<T: AstInfo> {
1181    pub name: CreateSubsourceOptionName,
1182    pub value: Option<WithOptionValue<T>>,
1183}
1184impl_display_for_with_option!(CreateSubsourceOption);
1185
1186/// `CREATE SUBSOURCE`
1187#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1188pub struct CreateSubsourceStatement<T: AstInfo> {
1189    pub name: UnresolvedItemName,
1190    pub columns: Vec<ColumnDef<T>>,
1191    /// Tracks the primary source of this subsource if an ingestion export (i.e.
1192    /// not a progress subsource).
1193    pub of_source: Option<T::ItemName>,
1194    pub constraints: Vec<TableConstraint<T>>,
1195    pub if_not_exists: bool,
1196    pub with_options: Vec<CreateSubsourceOption<T>>,
1197}
1198
1199impl<T: AstInfo> AstDisplay for CreateSubsourceStatement<T> {
1200    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1201        f.write_str("CREATE SUBSOURCE ");
1202        if self.if_not_exists {
1203            f.write_str("IF NOT EXISTS ");
1204        }
1205
1206        f.write_node(&self.name);
1207        f.write_str(" (");
1208        f.write_node(&display::comma_separated(&self.columns));
1209        if !self.constraints.is_empty() {
1210            f.write_str(", ");
1211            f.write_node(&display::comma_separated(&self.constraints));
1212        }
1213        f.write_str(")");
1214
1215        if let Some(of_source) = &self.of_source {
1216            f.write_str(" OF SOURCE ");
1217            f.write_node(of_source);
1218        }
1219
1220        if !self.with_options.is_empty() {
1221            f.write_str(" WITH (");
1222            f.write_node(&display::comma_separated(&self.with_options));
1223            f.write_str(")");
1224        }
1225    }
1226}
1227impl_display_t!(CreateSubsourceStatement);
1228
1229/// An option in a `CREATE SINK` statement.
1230#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1231pub enum CreateSinkOptionName {
1232    Snapshot,
1233    Version,
1234    PartitionStrategy,
1235    CommitInterval,
1236}
1237
1238impl AstDisplay for CreateSinkOptionName {
1239    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1240        match self {
1241            CreateSinkOptionName::Snapshot => {
1242                f.write_str("SNAPSHOT");
1243            }
1244            CreateSinkOptionName::Version => {
1245                f.write_str("VERSION");
1246            }
1247            CreateSinkOptionName::PartitionStrategy => {
1248                f.write_str("PARTITION STRATEGY");
1249            }
1250            CreateSinkOptionName::CommitInterval => {
1251                f.write_str("COMMIT INTERVAL");
1252            }
1253        }
1254    }
1255}
1256
1257impl WithOptionName for CreateSinkOptionName {
1258    /// # WARNING
1259    ///
1260    /// Whenever implementing this trait consider very carefully whether or not
1261    /// this value could contain sensitive user data. If you're uncertain, err
1262    /// on the conservative side and return `true`.
1263    fn redact_value(&self) -> bool {
1264        match self {
1265            CreateSinkOptionName::Snapshot => false,
1266            CreateSinkOptionName::Version => false,
1267            CreateSinkOptionName::PartitionStrategy => false,
1268            CreateSinkOptionName::CommitInterval => false,
1269        }
1270    }
1271}
1272
1273#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1274pub struct CreateSinkOption<T: AstInfo> {
1275    pub name: CreateSinkOptionName,
1276    pub value: Option<WithOptionValue<T>>,
1277}
1278impl_display_for_with_option!(CreateSinkOption);
1279
1280/// `CREATE SINK`
1281#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1282pub struct CreateSinkStatement<T: AstInfo> {
1283    pub name: Option<UnresolvedItemName>,
1284    pub in_cluster: Option<T::ClusterName>,
1285    pub if_not_exists: bool,
1286    pub from: T::ItemName,
1287    pub connection: CreateSinkConnection<T>,
1288    pub format: Option<FormatSpecifier<T>>,
1289    pub envelope: Option<SinkEnvelope>,
1290    pub mode: Option<IcebergSinkMode>,
1291    pub with_options: Vec<CreateSinkOption<T>>,
1292}
1293
1294impl<T: AstInfo> AstDisplay for CreateSinkStatement<T> {
1295    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1296        f.write_str("CREATE SINK ");
1297        if self.if_not_exists {
1298            f.write_str("IF NOT EXISTS ");
1299        }
1300        if let Some(name) = &self.name {
1301            f.write_node(&name);
1302            f.write_str(" ");
1303        }
1304        if let Some(cluster) = &self.in_cluster {
1305            f.write_str("IN CLUSTER ");
1306            f.write_node(cluster);
1307            f.write_str(" ");
1308        }
1309        f.write_str("FROM ");
1310        f.write_node(&self.from);
1311        f.write_str(" INTO ");
1312        f.write_node(&self.connection);
1313        if let Some(format) = &self.format {
1314            f.write_str(" ");
1315            f.write_node(format);
1316        }
1317        if let Some(envelope) = &self.envelope {
1318            f.write_str(" ENVELOPE ");
1319            f.write_node(envelope);
1320        }
1321        if let Some(mode) = &self.mode {
1322            f.write_str(" MODE ");
1323            f.write_node(mode);
1324        }
1325
1326        if !self.with_options.is_empty() {
1327            f.write_str(" WITH (");
1328            f.write_node(&display::comma_separated(&self.with_options));
1329            f.write_str(")");
1330        }
1331    }
1332}
1333impl_display_t!(CreateSinkStatement);
1334
1335#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1336pub struct ViewDefinition<T: AstInfo> {
1337    /// View name
1338    pub name: UnresolvedItemName,
1339    pub columns: Vec<Ident>,
1340    pub query: Query<T>,
1341}
1342
1343impl<T: AstInfo> AstDisplay for ViewDefinition<T> {
1344    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1345        f.write_node(&self.name);
1346
1347        if !self.columns.is_empty() {
1348            f.write_str(" (");
1349            f.write_node(&display::comma_separated(&self.columns));
1350            f.write_str(")");
1351        }
1352
1353        f.write_str(" AS ");
1354        f.write_node(&self.query);
1355    }
1356}
1357impl_display_t!(ViewDefinition);
1358
1359/// `CREATE VIEW`
1360#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1361pub struct CreateViewStatement<T: AstInfo> {
1362    pub if_exists: IfExistsBehavior,
1363    pub temporary: bool,
1364    pub definition: ViewDefinition<T>,
1365}
1366
1367impl<T: AstInfo> AstDisplay for CreateViewStatement<T> {
1368    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1369        f.write_str("CREATE");
1370        if self.if_exists == IfExistsBehavior::Replace {
1371            f.write_str(" OR REPLACE");
1372        }
1373        if self.temporary {
1374            f.write_str(" TEMPORARY");
1375        }
1376
1377        f.write_str(" VIEW");
1378
1379        if self.if_exists == IfExistsBehavior::Skip {
1380            f.write_str(" IF NOT EXISTS");
1381        }
1382
1383        f.write_str(" ");
1384        f.write_node(&self.definition);
1385    }
1386}
1387impl_display_t!(CreateViewStatement);
1388
1389/// `CREATE MATERIALIZED VIEW`
1390#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1391pub struct CreateMaterializedViewStatement<T: AstInfo> {
1392    pub if_exists: IfExistsBehavior,
1393    pub name: UnresolvedItemName,
1394    pub columns: Vec<Ident>,
1395    pub replacement_for: Option<T::ItemName>,
1396    pub in_cluster: Option<T::ClusterName>,
1397    pub query: Query<T>,
1398    pub as_of: Option<u64>,
1399    pub with_options: Vec<MaterializedViewOption<T>>,
1400}
1401
1402impl<T: AstInfo> AstDisplay for CreateMaterializedViewStatement<T> {
1403    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1404        f.write_str("CREATE");
1405        if self.if_exists == IfExistsBehavior::Replace {
1406            f.write_str(" OR REPLACE");
1407        }
1408        if self.replacement_for.is_some() {
1409            f.write_str(" REPLACEMENT");
1410        }
1411
1412        f.write_str(" MATERIALIZED VIEW");
1413
1414        if self.if_exists == IfExistsBehavior::Skip {
1415            f.write_str(" IF NOT EXISTS");
1416        }
1417
1418        f.write_str(" ");
1419        f.write_node(&self.name);
1420
1421        if !self.columns.is_empty() {
1422            f.write_str(" (");
1423            f.write_node(&display::comma_separated(&self.columns));
1424            f.write_str(")");
1425        }
1426
1427        if let Some(target) = &self.replacement_for {
1428            f.write_str(" FOR ");
1429            f.write_node(target);
1430        }
1431
1432        if let Some(cluster) = &self.in_cluster {
1433            f.write_str(" IN CLUSTER ");
1434            f.write_node(cluster);
1435        }
1436
1437        if !self.with_options.is_empty() {
1438            f.write_str(" WITH (");
1439            f.write_node(&display::comma_separated(&self.with_options));
1440            f.write_str(")");
1441        }
1442
1443        f.write_str(" AS ");
1444        f.write_node(&self.query);
1445
1446        if let Some(time) = &self.as_of {
1447            f.write_str(" AS OF ");
1448            f.write_str(time);
1449        }
1450    }
1451}
1452impl_display_t!(CreateMaterializedViewStatement);
1453
1454/// `CREATE CONTINUAL TASK`
1455#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1456pub struct CreateContinualTaskStatement<T: AstInfo> {
1457    pub name: T::ItemName,
1458    pub columns: Option<Vec<CteMutRecColumnDef<T>>>,
1459    pub in_cluster: Option<T::ClusterName>,
1460    pub as_of: Option<u64>,
1461    pub with_options: Vec<ContinualTaskOption<T>>,
1462
1463    // The thing we get input diffs from
1464    pub input: T::ItemName,
1465
1466    // The txn to execute on each set of diffs
1467    pub stmts: Vec<ContinualTaskStmt<T>>,
1468
1469    pub sugar: Option<CreateContinualTaskSugar<T>>,
1470}
1471
1472#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1473pub enum ContinualTaskStmt<T: AstInfo> {
1474    Delete(DeleteStatement<T>),
1475    Insert(InsertStatement<T>),
1476}
1477
1478impl<T: AstInfo> AstDisplay for ContinualTaskStmt<T> {
1479    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1480        match self {
1481            ContinualTaskStmt::Delete(stmt) => f.write_node(stmt),
1482            ContinualTaskStmt::Insert(stmt) => f.write_node(stmt),
1483        }
1484    }
1485}
1486
1487#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1488pub enum CreateContinualTaskSugar<T: AstInfo> {
1489    Transform { transform: Query<T> },
1490    Retain { retain: Expr<T> },
1491}
1492
1493impl<T: AstInfo> AstDisplay for CreateContinualTaskStatement<T> {
1494    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1495        f.write_str("CREATE CONTINUAL TASK ");
1496        f.write_node(&self.name);
1497        if let Some(columns) = &self.columns {
1498            f.write_str(" (");
1499            f.write_node(&display::comma_separated(columns));
1500            f.write_str(")");
1501        }
1502
1503        if let Some(cluster) = &self.in_cluster {
1504            f.write_str(" IN CLUSTER ");
1505            f.write_node(cluster);
1506        }
1507
1508        if !self.with_options.is_empty() {
1509            f.write_str(" WITH (");
1510            f.write_node(&display::comma_separated(&self.with_options));
1511            f.write_str(")");
1512        }
1513
1514        match &self.sugar {
1515            Some(CreateContinualTaskSugar::Transform { transform }) => {
1516                f.write_str(" FROM TRANSFORM ");
1517                f.write_node(&self.input);
1518                f.write_str(" USING ");
1519                f.write_str("(");
1520                f.write_node(transform);
1521                f.write_str(")");
1522            }
1523            Some(CreateContinualTaskSugar::Retain { retain }) => {
1524                f.write_str(" FROM RETAIN ");
1525                f.write_node(&self.input);
1526                f.write_str(" WHILE ");
1527                f.write_str("(");
1528                f.write_node(retain);
1529                f.write_str(")");
1530            }
1531            None => {
1532                f.write_str(" ON INPUT ");
1533                f.write_node(&self.input);
1534                f.write_str(" AS (");
1535                for (idx, stmt) in self.stmts.iter().enumerate() {
1536                    if idx > 0 {
1537                        f.write_str("; ");
1538                    }
1539                    f.write_node(stmt);
1540                }
1541                f.write_str(")");
1542            }
1543        }
1544
1545        if let Some(time) = &self.as_of {
1546            f.write_str(" AS OF ");
1547            f.write_str(time);
1548        }
1549    }
1550}
1551impl_display_t!(CreateContinualTaskStatement);
1552
1553/// `ALTER SET CLUSTER`
1554#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1555pub struct AlterSetClusterStatement<T: AstInfo> {
1556    pub if_exists: bool,
1557    pub name: UnresolvedItemName,
1558    pub object_type: ObjectType,
1559    pub set_cluster: T::ClusterName,
1560}
1561
1562impl<T: AstInfo> AstDisplay for AlterSetClusterStatement<T> {
1563    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1564        f.write_str("ALTER ");
1565        f.write_node(&self.object_type);
1566
1567        if self.if_exists {
1568            f.write_str(" IF EXISTS");
1569        }
1570
1571        f.write_str(" ");
1572        f.write_node(&self.name);
1573
1574        f.write_str(" SET CLUSTER ");
1575        f.write_node(&self.set_cluster);
1576    }
1577}
1578impl_display_t!(AlterSetClusterStatement);
1579
1580/// `CREATE TABLE`
1581#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1582pub struct CreateTableStatement<T: AstInfo> {
1583    /// Table name
1584    pub name: UnresolvedItemName,
1585    /// Optional schema
1586    pub columns: Vec<ColumnDef<T>>,
1587    pub constraints: Vec<TableConstraint<T>>,
1588    pub if_not_exists: bool,
1589    pub temporary: bool,
1590    pub with_options: Vec<TableOption<T>>,
1591}
1592
1593impl<T: AstInfo> AstDisplay for CreateTableStatement<T> {
1594    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1595        let Self {
1596            name,
1597            columns,
1598            constraints,
1599            if_not_exists,
1600            temporary,
1601            with_options,
1602        } = self;
1603        f.write_str("CREATE ");
1604        if *temporary {
1605            f.write_str("TEMPORARY ");
1606        }
1607        f.write_str("TABLE ");
1608        if *if_not_exists {
1609            f.write_str("IF NOT EXISTS ");
1610        }
1611        f.write_node(name);
1612        f.write_str(" (");
1613        f.write_node(&display::comma_separated(columns));
1614        if !self.constraints.is_empty() {
1615            f.write_str(", ");
1616            f.write_node(&display::comma_separated(constraints));
1617        }
1618        f.write_str(")");
1619        if !with_options.is_empty() {
1620            f.write_str(" WITH (");
1621            f.write_node(&display::comma_separated(&self.with_options));
1622            f.write_str(")");
1623        }
1624    }
1625}
1626impl_display_t!(CreateTableStatement);
1627
1628#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1629pub enum TableOptionName {
1630    // The `PARTITION BY` option
1631    PartitionBy,
1632    // The `RETAIN HISTORY` option
1633    RetainHistory,
1634    /// A special option to test that we do redact values.
1635    RedactedTest,
1636}
1637
1638impl AstDisplay for TableOptionName {
1639    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1640        match self {
1641            TableOptionName::PartitionBy => {
1642                f.write_str("PARTITION BY");
1643            }
1644            TableOptionName::RetainHistory => {
1645                f.write_str("RETAIN HISTORY");
1646            }
1647            TableOptionName::RedactedTest => {
1648                f.write_str("REDACTED");
1649            }
1650        }
1651    }
1652}
1653
1654impl WithOptionName for TableOptionName {
1655    /// # WARNING
1656    ///
1657    /// Whenever implementing this trait consider very carefully whether or not
1658    /// this value could contain sensitive user data. If you're uncertain, err
1659    /// on the conservative side and return `true`.
1660    fn redact_value(&self) -> bool {
1661        match self {
1662            TableOptionName::PartitionBy => false,
1663            TableOptionName::RetainHistory => false,
1664            TableOptionName::RedactedTest => true,
1665        }
1666    }
1667}
1668
1669#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1670pub struct TableOption<T: AstInfo> {
1671    pub name: TableOptionName,
1672    pub value: Option<WithOptionValue<T>>,
1673}
1674impl_display_for_with_option!(TableOption);
1675
1676#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1677pub enum TableFromSourceOptionName {
1678    /// Columns whose types you want to unconditionally format as text
1679    TextColumns,
1680    /// Columns you want to exclude when ingesting data
1681    ExcludeColumns,
1682    /// Hex-encoded protobuf of a `ProtoSourceExportStatementDetails`
1683    /// message, which includes details necessary for planning this
1684    /// table as a Source Export
1685    Details,
1686    /// Partition the given table by the provided columns.
1687    PartitionBy,
1688    // The `RETAIN HISTORY` option
1689    RetainHistory,
1690}
1691
1692impl AstDisplay for TableFromSourceOptionName {
1693    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1694        f.write_str(match self {
1695            TableFromSourceOptionName::TextColumns => "TEXT COLUMNS",
1696            TableFromSourceOptionName::ExcludeColumns => "EXCLUDE COLUMNS",
1697            TableFromSourceOptionName::Details => "DETAILS",
1698            TableFromSourceOptionName::PartitionBy => "PARTITION BY",
1699            TableFromSourceOptionName::RetainHistory => "RETAIN HISTORY",
1700        })
1701    }
1702}
1703impl_display!(TableFromSourceOptionName);
1704
1705impl WithOptionName for TableFromSourceOptionName {
1706    /// # WARNING
1707    ///
1708    /// Whenever implementing this trait consider very carefully whether or not
1709    /// this value could contain sensitive user data. If you're uncertain, err
1710    /// on the conservative side and return `true`.
1711    fn redact_value(&self) -> bool {
1712        match self {
1713            TableFromSourceOptionName::Details
1714            | TableFromSourceOptionName::TextColumns
1715            | TableFromSourceOptionName::ExcludeColumns
1716            | TableFromSourceOptionName::RetainHistory
1717            | TableFromSourceOptionName::PartitionBy => false,
1718        }
1719    }
1720}
1721
1722#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1723pub struct TableFromSourceOption<T: AstInfo> {
1724    pub name: TableFromSourceOptionName,
1725    pub value: Option<WithOptionValue<T>>,
1726}
1727impl_display_for_with_option!(TableFromSourceOption);
1728
1729/// `CREATE TABLE .. FROM SOURCE` columns specification
1730/// can have 3 states:
1731/// Before purification they can be `NotSpecified` or `Named`
1732/// by the user to specify the column names to use.
1733/// After purification they can be in any of the 3 states.
1734/// For some source types we define the columns during purification
1735/// and for others the columns are defined during planning based
1736/// on the encoding option of the source.
1737#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1738pub enum TableFromSourceColumns<T: AstInfo> {
1739    /// The user did not specify which columns to use.
1740    NotSpecified,
1741    /// The user requested the named columns. Only compatible
1742    /// with source types that allow user-specified column names.
1743    Named(Vec<Ident>),
1744    /// Columns defined during purification for some source types.
1745    Defined(Vec<ColumnDef<T>>),
1746}
1747
1748/// `CREATE TABLE .. FROM SOURCE`
1749#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1750pub struct CreateTableFromSourceStatement<T: AstInfo> {
1751    pub name: UnresolvedItemName,
1752    pub columns: TableFromSourceColumns<T>,
1753    pub constraints: Vec<TableConstraint<T>>,
1754    pub if_not_exists: bool,
1755    pub source: T::ItemName,
1756    pub external_reference: Option<UnresolvedItemName>,
1757    pub with_options: Vec<TableFromSourceOption<T>>,
1758    pub include_metadata: Vec<SourceIncludeMetadata>,
1759    pub format: Option<FormatSpecifier<T>>,
1760    pub envelope: Option<SourceEnvelope>,
1761}
1762
1763impl<T: AstInfo> AstDisplay for CreateTableFromSourceStatement<T> {
1764    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1765        let Self {
1766            name,
1767            columns,
1768            constraints,
1769            source,
1770            external_reference,
1771            if_not_exists,
1772            with_options,
1773            include_metadata,
1774            format,
1775            envelope,
1776        } = self;
1777        f.write_str("CREATE TABLE ");
1778        if *if_not_exists {
1779            f.write_str("IF NOT EXISTS ");
1780        }
1781        f.write_node(name);
1782        if !matches!(columns, TableFromSourceColumns::NotSpecified) || !constraints.is_empty() {
1783            f.write_str(" (");
1784
1785            match columns {
1786                TableFromSourceColumns::NotSpecified => unreachable!(),
1787                TableFromSourceColumns::Named(columns) => {
1788                    f.write_node(&display::comma_separated(columns))
1789                }
1790                TableFromSourceColumns::Defined(columns) => {
1791                    f.write_node(&display::comma_separated(columns))
1792                }
1793            };
1794            if !constraints.is_empty() {
1795                f.write_str(", ");
1796                f.write_node(&display::comma_separated(constraints));
1797            }
1798            f.write_str(")");
1799        }
1800        f.write_str(" FROM SOURCE ");
1801        f.write_node(source);
1802        if let Some(external_reference) = external_reference {
1803            f.write_str(" (REFERENCE = ");
1804            f.write_node(external_reference);
1805            f.write_str(")");
1806        }
1807
1808        if let Some(format) = &format {
1809            f.write_str(" ");
1810            f.write_node(format);
1811        }
1812        if !include_metadata.is_empty() {
1813            f.write_str(" INCLUDE ");
1814            f.write_node(&display::comma_separated(include_metadata));
1815        }
1816        if let Some(envelope) = &envelope {
1817            f.write_str(" ENVELOPE ");
1818            f.write_node(envelope);
1819        }
1820        if !with_options.is_empty() {
1821            f.write_str(" WITH (");
1822            f.write_node(&display::comma_separated(with_options));
1823            f.write_str(")");
1824        }
1825    }
1826}
1827impl_display_t!(CreateTableFromSourceStatement);
1828
1829/// `CREATE INDEX`
1830#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1831pub struct CreateIndexStatement<T: AstInfo> {
1832    /// Optional index name.
1833    pub name: Option<Ident>,
1834    pub in_cluster: Option<T::ClusterName>,
1835    /// `ON` table or view name
1836    pub on_name: T::ItemName,
1837    /// Expressions that form part of the index key. If not included, the
1838    /// key_parts will be inferred from the named object.
1839    pub key_parts: Option<Vec<Expr<T>>>,
1840    pub with_options: Vec<IndexOption<T>>,
1841    pub if_not_exists: bool,
1842}
1843
1844impl<T: AstInfo> AstDisplay for CreateIndexStatement<T> {
1845    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1846        f.write_str("CREATE ");
1847        if self.key_parts.is_none() {
1848            f.write_str("DEFAULT ");
1849        }
1850        f.write_str("INDEX ");
1851        if self.if_not_exists {
1852            f.write_str("IF NOT EXISTS ");
1853        }
1854        if let Some(name) = &self.name {
1855            f.write_node(name);
1856            f.write_str(" ");
1857        }
1858        if let Some(cluster) = &self.in_cluster {
1859            f.write_str("IN CLUSTER ");
1860            f.write_node(cluster);
1861            f.write_str(" ");
1862        }
1863        f.write_str("ON ");
1864        f.write_node(&self.on_name);
1865        if let Some(key_parts) = &self.key_parts {
1866            f.write_str(" (");
1867            f.write_node(&display::comma_separated(key_parts));
1868            f.write_str(")");
1869        }
1870        if !self.with_options.is_empty() {
1871            f.write_str(" WITH (");
1872            f.write_node(&display::comma_separated(&self.with_options));
1873            f.write_str(")");
1874        }
1875    }
1876}
1877impl_display_t!(CreateIndexStatement);
1878
1879/// An option in a `CREATE CLUSTER` statement.
1880#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1881pub enum IndexOptionName {
1882    // The `RETAIN HISTORY` option
1883    RetainHistory,
1884}
1885
1886impl AstDisplay for IndexOptionName {
1887    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1888        match self {
1889            IndexOptionName::RetainHistory => {
1890                f.write_str("RETAIN HISTORY");
1891            }
1892        }
1893    }
1894}
1895
1896impl WithOptionName for IndexOptionName {
1897    /// # WARNING
1898    ///
1899    /// Whenever implementing this trait consider very carefully whether or not
1900    /// this value could contain sensitive user data. If you're uncertain, err
1901    /// on the conservative side and return `true`.
1902    fn redact_value(&self) -> bool {
1903        match self {
1904            IndexOptionName::RetainHistory => false,
1905        }
1906    }
1907}
1908
1909#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1910pub struct IndexOption<T: AstInfo> {
1911    pub name: IndexOptionName,
1912    pub value: Option<WithOptionValue<T>>,
1913}
1914impl_display_for_with_option!(IndexOption);
1915
1916/// A `CREATE ROLE` statement.
1917#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1918pub struct CreateRoleStatement {
1919    /// The specified role.
1920    pub name: Ident,
1921    /// Any options that were attached, in the order they were presented.
1922    pub options: Vec<RoleAttribute>,
1923}
1924
1925impl AstDisplay for CreateRoleStatement {
1926    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1927        f.write_str("CREATE ");
1928        f.write_str("ROLE ");
1929        f.write_node(&self.name);
1930        for option in &self.options {
1931            f.write_str(" ");
1932            option.fmt(f)
1933        }
1934    }
1935}
1936impl_display!(CreateRoleStatement);
1937
1938/// Attributes that can be attached to roles.
1939#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1940pub enum RoleAttribute {
1941    /// The `INHERIT` option.
1942    Inherit,
1943    /// The `NOINHERIT` option.
1944    NoInherit,
1945    /// The `PASSWORD` option.
1946    Password(Option<String>),
1947    // The following are not supported, but included to give helpful error messages.
1948    Login,
1949    NoLogin,
1950    SuperUser,
1951    NoSuperUser,
1952    CreateCluster,
1953    NoCreateCluster,
1954    CreateDB,
1955    NoCreateDB,
1956    CreateRole,
1957    NoCreateRole,
1958}
1959
1960impl AstDisplay for RoleAttribute {
1961    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1962        match self {
1963            RoleAttribute::SuperUser => f.write_str("SUPERUSER"),
1964            RoleAttribute::NoSuperUser => f.write_str("NOSUPERUSER"),
1965            RoleAttribute::Login => f.write_str("LOGIN"),
1966            RoleAttribute::NoLogin => f.write_str("NOLOGIN"),
1967            RoleAttribute::Inherit => f.write_str("INHERIT"),
1968            RoleAttribute::NoInherit => f.write_str("NOINHERIT"),
1969            RoleAttribute::CreateCluster => f.write_str("CREATECLUSTER"),
1970            RoleAttribute::NoCreateCluster => f.write_str("NOCREATECLUSTER"),
1971            RoleAttribute::CreateDB => f.write_str("CREATEDB"),
1972            RoleAttribute::NoCreateDB => f.write_str("NOCREATEDB"),
1973            RoleAttribute::CreateRole => f.write_str("CREATEROLE"),
1974            RoleAttribute::NoCreateRole => f.write_str("NOCREATEROLE"),
1975            RoleAttribute::Password(_) => f.write_str("PASSWORD"),
1976        }
1977    }
1978}
1979impl_display!(RoleAttribute);
1980
1981/// `ALTER ROLE role_name [SET | RESET] ...`
1982#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1983pub enum SetRoleVar {
1984    /// `SET name TO value`
1985    Set { name: Ident, value: SetVariableTo },
1986    /// `RESET name`
1987    Reset { name: Ident },
1988}
1989
1990impl AstDisplay for SetRoleVar {
1991    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1992        match self {
1993            SetRoleVar::Set { name, value } => {
1994                f.write_str("SET ");
1995                f.write_node(name);
1996                f.write_str(" = ");
1997                f.write_node(value);
1998            }
1999            SetRoleVar::Reset { name } => {
2000                f.write_str("RESET ");
2001                f.write_node(name);
2002            }
2003        }
2004    }
2005}
2006impl_display!(SetRoleVar);
2007
2008/// AN `ALTER NETWORK POLICY` statement.
2009#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2010pub struct AlterNetworkPolicyStatement<T: AstInfo> {
2011    /// The specified Network Policy.
2012    pub name: Ident,
2013    /// Any options that were attached, in the order they were presented.
2014    pub options: Vec<NetworkPolicyOption<T>>,
2015}
2016
2017impl<T: AstInfo> AstDisplay for AlterNetworkPolicyStatement<T> {
2018    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2019        f.write_str("ALTER ");
2020        f.write_str("NETWORK POLICY ");
2021        f.write_node(&self.name);
2022        f.write_str(" SET (");
2023        f.write_node(&display::comma_separated(&self.options));
2024        f.write_str(" )");
2025    }
2026}
2027impl_display_t!(AlterNetworkPolicyStatement);
2028
2029/// A `CREATE NETWORK POLICY` statement.
2030#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2031pub struct CreateNetworkPolicyStatement<T: AstInfo> {
2032    /// The specified network policy.
2033    pub name: Ident,
2034    /// Any options that were attached, in the order they were presented.
2035    pub options: Vec<NetworkPolicyOption<T>>,
2036}
2037
2038impl<T: AstInfo> AstDisplay for CreateNetworkPolicyStatement<T> {
2039    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2040        f.write_str("CREATE ");
2041        f.write_str("NETWORK POLICY ");
2042        f.write_node(&self.name);
2043        f.write_str(" (");
2044        f.write_node(&display::comma_separated(&self.options));
2045        f.write_str(" )");
2046    }
2047}
2048impl_display_t!(CreateNetworkPolicyStatement);
2049
2050#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2051pub struct NetworkPolicyOption<T: AstInfo> {
2052    pub name: NetworkPolicyOptionName,
2053    pub value: Option<WithOptionValue<T>>,
2054}
2055
2056#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2057pub enum NetworkPolicyOptionName {
2058    Rules,
2059}
2060
2061impl WithOptionName for NetworkPolicyOptionName {
2062    /// # WARNING
2063    ///
2064    /// Whenever implementing this trait consider very carefully whether or not
2065    /// this value could contain sensitive user data. If you're uncertain, err
2066    /// on the conservative side and return `true`.
2067    fn redact_value(&self) -> bool {
2068        match self {
2069            NetworkPolicyOptionName::Rules => false,
2070        }
2071    }
2072}
2073
2074impl AstDisplay for NetworkPolicyOptionName {
2075    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2076        match self {
2077            NetworkPolicyOptionName::Rules => f.write_str("RULES"),
2078        }
2079    }
2080}
2081impl_display_for_with_option!(NetworkPolicyOption);
2082
2083#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2084pub struct NetworkPolicyRuleDefinition<T: AstInfo> {
2085    pub name: Ident,
2086    pub options: Vec<NetworkPolicyRuleOption<T>>,
2087}
2088
2089impl<T: AstInfo> AstDisplay for NetworkPolicyRuleDefinition<T> {
2090    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2091        f.write_node(&self.name);
2092        f.write_str(" (");
2093        f.write_node(&display::comma_separated(&self.options));
2094        f.write_str(" )");
2095    }
2096}
2097
2098#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2099pub struct NetworkPolicyRuleOption<T: AstInfo> {
2100    pub name: NetworkPolicyRuleOptionName,
2101    pub value: Option<WithOptionValue<T>>,
2102}
2103
2104#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2105pub enum NetworkPolicyRuleOptionName {
2106    Direction,
2107    Action,
2108    Address,
2109}
2110
2111impl WithOptionName for NetworkPolicyRuleOptionName {
2112    /// # WARNING
2113    ///
2114    /// Whenever implementing this trait consider very carefully whether or not
2115    /// this value could contain sensitive user data. If you're uncertain, err
2116    /// on the conservative side and return `true`.
2117    fn redact_value(&self) -> bool {
2118        match self {
2119            NetworkPolicyRuleOptionName::Direction
2120            | NetworkPolicyRuleOptionName::Action
2121            | NetworkPolicyRuleOptionName::Address => false,
2122        }
2123    }
2124}
2125
2126impl AstDisplay for NetworkPolicyRuleOptionName {
2127    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2128        match self {
2129            NetworkPolicyRuleOptionName::Direction => f.write_str("DIRECTION"),
2130            NetworkPolicyRuleOptionName::Action => f.write_str("ACTION"),
2131            NetworkPolicyRuleOptionName::Address => f.write_str("ADDRESS"),
2132        }
2133    }
2134}
2135
2136impl_display_for_with_option!(NetworkPolicyRuleOption);
2137
2138/// A `CREATE SECRET` statement.
2139#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2140pub struct CreateSecretStatement<T: AstInfo> {
2141    pub name: UnresolvedItemName,
2142    pub if_not_exists: bool,
2143    pub value: Expr<T>,
2144}
2145
2146impl<T: AstInfo> AstDisplay for CreateSecretStatement<T> {
2147    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2148        f.write_str("CREATE SECRET ");
2149        if self.if_not_exists {
2150            f.write_str("IF NOT EXISTS ");
2151        }
2152        f.write_node(&self.name);
2153        f.write_str(" AS ");
2154
2155        if f.redacted() {
2156            f.write_str("'<REDACTED>'");
2157        } else {
2158            f.write_node(&self.value);
2159        }
2160    }
2161}
2162impl_display_t!(CreateSecretStatement);
2163
2164/// `CREATE TYPE ..`
2165#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2166pub struct CreateTypeStatement<T: AstInfo> {
2167    /// Name of the created type.
2168    pub name: UnresolvedItemName,
2169    /// The new type's "base type".
2170    pub as_type: CreateTypeAs<T>,
2171}
2172
2173impl<T: AstInfo> AstDisplay for CreateTypeStatement<T> {
2174    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2175        f.write_str("CREATE TYPE ");
2176        f.write_node(&self.name);
2177        f.write_str(" AS ");
2178        match &self.as_type {
2179            CreateTypeAs::List { options } => {
2180                f.write_str(&self.as_type);
2181                f.write_str("(");
2182                if !options.is_empty() {
2183                    f.write_node(&display::comma_separated(options));
2184                }
2185                f.write_str(")");
2186            }
2187            CreateTypeAs::Map { options } => {
2188                f.write_str(&self.as_type);
2189                f.write_str("(");
2190                if !options.is_empty() {
2191                    f.write_node(&display::comma_separated(options));
2192                }
2193                f.write_str(")");
2194            }
2195            CreateTypeAs::Record { column_defs } => {
2196                f.write_str("(");
2197                if !column_defs.is_empty() {
2198                    f.write_node(&display::comma_separated(column_defs));
2199                }
2200                f.write_str(")");
2201            }
2202        };
2203    }
2204}
2205impl_display_t!(CreateTypeStatement);
2206
2207#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2208pub enum ClusterOptionName {
2209    /// The `AVAILABILITY ZONES [[=] '[' <values> ']' ]` option.
2210    AvailabilityZones,
2211    /// The `DISK` option.
2212    Disk,
2213    /// The `INTROSPECTION INTERVAL [[=] <interval>]` option.
2214    IntrospectionInterval,
2215    /// The `INTROSPECTION DEBUGGING [[=] <enabled>]` option.
2216    IntrospectionDebugging,
2217    /// The `MANAGED` option.
2218    Managed,
2219    /// The `REPLICAS` option.
2220    Replicas,
2221    /// The `REPLICATION FACTOR` option.
2222    ReplicationFactor,
2223    /// The `SIZE` option.
2224    Size,
2225    /// The `SCHEDULE` option.
2226    Schedule,
2227    /// The `WORKLOAD CLASS` option.
2228    WorkloadClass,
2229}
2230
2231impl AstDisplay for ClusterOptionName {
2232    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2233        match self {
2234            ClusterOptionName::AvailabilityZones => f.write_str("AVAILABILITY ZONES"),
2235            ClusterOptionName::Disk => f.write_str("DISK"),
2236            ClusterOptionName::IntrospectionDebugging => f.write_str("INTROSPECTION DEBUGGING"),
2237            ClusterOptionName::IntrospectionInterval => f.write_str("INTROSPECTION INTERVAL"),
2238            ClusterOptionName::Managed => f.write_str("MANAGED"),
2239            ClusterOptionName::Replicas => f.write_str("REPLICAS"),
2240            ClusterOptionName::ReplicationFactor => f.write_str("REPLICATION FACTOR"),
2241            ClusterOptionName::Size => f.write_str("SIZE"),
2242            ClusterOptionName::Schedule => f.write_str("SCHEDULE"),
2243            ClusterOptionName::WorkloadClass => f.write_str("WORKLOAD CLASS"),
2244        }
2245    }
2246}
2247
2248impl WithOptionName for ClusterOptionName {
2249    /// # WARNING
2250    ///
2251    /// Whenever implementing this trait consider very carefully whether or not
2252    /// this value could contain sensitive user data. If you're uncertain, err
2253    /// on the conservative side and return `true`.
2254    fn redact_value(&self) -> bool {
2255        match self {
2256            ClusterOptionName::AvailabilityZones
2257            | ClusterOptionName::Disk
2258            | ClusterOptionName::IntrospectionDebugging
2259            | ClusterOptionName::IntrospectionInterval
2260            | ClusterOptionName::Managed
2261            | ClusterOptionName::Replicas
2262            | ClusterOptionName::ReplicationFactor
2263            | ClusterOptionName::Size
2264            | ClusterOptionName::Schedule
2265            | ClusterOptionName::WorkloadClass => false,
2266        }
2267    }
2268}
2269
2270#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2271/// An option in a `CREATE CLUSTER` statement.
2272pub struct ClusterOption<T: AstInfo> {
2273    pub name: ClusterOptionName,
2274    pub value: Option<WithOptionValue<T>>,
2275}
2276impl_display_for_with_option!(ClusterOption);
2277
2278#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2279pub enum ClusterAlterUntilReadyOptionName {
2280    Timeout,
2281    OnTimeout,
2282}
2283
2284impl AstDisplay for ClusterAlterUntilReadyOptionName {
2285    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2286        match self {
2287            Self::Timeout => f.write_str("TIMEOUT"),
2288            Self::OnTimeout => f.write_str("ON TIMEOUT"),
2289        }
2290    }
2291}
2292
2293impl WithOptionName for ClusterAlterUntilReadyOptionName {
2294    /// # WARNING
2295    ///
2296    /// Whenever implementing this trait consider very carefully whether or not
2297    /// this value could contain sensitive user data. If you're uncertain, err
2298    /// on the conservative side and return `true`.
2299    fn redact_value(&self) -> bool {
2300        match self {
2301            ClusterAlterUntilReadyOptionName::Timeout
2302            | ClusterAlterUntilReadyOptionName::OnTimeout => false,
2303        }
2304    }
2305}
2306
2307#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2308pub struct ClusterAlterUntilReadyOption<T: AstInfo> {
2309    pub name: ClusterAlterUntilReadyOptionName,
2310    pub value: Option<WithOptionValue<T>>,
2311}
2312impl_display_for_with_option!(ClusterAlterUntilReadyOption);
2313
2314#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2315pub enum ClusterAlterOptionName {
2316    Wait,
2317}
2318
2319impl AstDisplay for ClusterAlterOptionName {
2320    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2321        match self {
2322            ClusterAlterOptionName::Wait => f.write_str("WAIT"),
2323        }
2324    }
2325}
2326
2327impl WithOptionName for ClusterAlterOptionName {
2328    /// # WARNING
2329    ///
2330    /// Whenever implementing this trait consider very carefully whether or not
2331    /// this value could contain sensitive user data. If you're uncertain, err
2332    /// on the conservative side and return `true`.
2333    fn redact_value(&self) -> bool {
2334        match self {
2335            ClusterAlterOptionName::Wait => false,
2336        }
2337    }
2338}
2339
2340#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2341pub enum ClusterAlterOptionValue<T: AstInfo> {
2342    For(Value),
2343    UntilReady(Vec<ClusterAlterUntilReadyOption<T>>),
2344}
2345
2346impl<T: AstInfo> AstDisplay for ClusterAlterOptionValue<T> {
2347    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2348        match self {
2349            ClusterAlterOptionValue::For(duration) => {
2350                f.write_str("FOR ");
2351                f.write_node(duration);
2352            }
2353            ClusterAlterOptionValue::UntilReady(options) => {
2354                f.write_str("UNTIL READY (");
2355                f.write_node(&display::comma_separated(options));
2356                f.write_str(")");
2357            }
2358        }
2359    }
2360}
2361
2362#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2363/// An option in a `ALTER CLUSTER... WITH` statement.
2364pub struct ClusterAlterOption<T: AstInfo> {
2365    pub name: ClusterAlterOptionName,
2366    pub value: Option<WithOptionValue<T>>,
2367}
2368
2369impl_display_for_with_option!(ClusterAlterOption);
2370
2371// Note: the `AstDisplay` implementation and `Parser::parse_` method for this
2372// enum are generated automatically by this crate's `build.rs`.
2373#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2374pub enum ClusterFeatureName {
2375    ReoptimizeImportedViews,
2376    EnableNewOuterJoinLowering,
2377    EnableEagerDeltaJoins,
2378    EnableVariadicLeftJoinLowering,
2379    EnableLetrecFixpointAnalysis,
2380    EnableJoinPrioritizeArranged,
2381    EnableProjectionPushdownAfterRelationCse,
2382}
2383
2384impl WithOptionName for ClusterFeatureName {
2385    /// # WARNING
2386    ///
2387    /// Whenever implementing this trait consider very carefully whether or not
2388    /// this value could contain sensitive user data. If you're uncertain, err
2389    /// on the conservative side and return `true`.
2390    fn redact_value(&self) -> bool {
2391        match self {
2392            Self::ReoptimizeImportedViews
2393            | Self::EnableNewOuterJoinLowering
2394            | Self::EnableEagerDeltaJoins
2395            | Self::EnableVariadicLeftJoinLowering
2396            | Self::EnableLetrecFixpointAnalysis
2397            | Self::EnableJoinPrioritizeArranged
2398            | Self::EnableProjectionPushdownAfterRelationCse => false,
2399        }
2400    }
2401}
2402
2403#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2404pub struct ClusterFeature<T: AstInfo> {
2405    pub name: ClusterFeatureName,
2406    pub value: Option<WithOptionValue<T>>,
2407}
2408impl_display_for_with_option!(ClusterFeature);
2409
2410/// `CREATE CLUSTER ..`
2411#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2412pub struct CreateClusterStatement<T: AstInfo> {
2413    /// Name of the created cluster.
2414    pub name: Ident,
2415    /// The comma-separated options.
2416    pub options: Vec<ClusterOption<T>>,
2417    /// The comma-separated features enabled on the cluster.
2418    pub features: Vec<ClusterFeature<T>>,
2419}
2420
2421impl<T: AstInfo> AstDisplay for CreateClusterStatement<T> {
2422    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2423        f.write_str("CREATE CLUSTER ");
2424        f.write_node(&self.name);
2425        if !self.options.is_empty() {
2426            f.write_str(" (");
2427            f.write_node(&display::comma_separated(&self.options));
2428            f.write_str(")");
2429        }
2430        if !self.features.is_empty() {
2431            f.write_str(" FEATURES (");
2432            f.write_node(&display::comma_separated(&self.features));
2433            f.write_str(")");
2434        }
2435    }
2436}
2437impl_display_t!(CreateClusterStatement);
2438
2439#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2440pub struct ReplicaDefinition<T: AstInfo> {
2441    /// Name of the created replica.
2442    pub name: Ident,
2443    /// The comma-separated options.
2444    pub options: Vec<ReplicaOption<T>>,
2445}
2446
2447// Note that this display is meant for replicas defined inline when creating
2448// clusters.
2449impl<T: AstInfo> AstDisplay for ReplicaDefinition<T> {
2450    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2451        f.write_node(&self.name);
2452        f.write_str(" (");
2453        f.write_node(&display::comma_separated(&self.options));
2454        f.write_str(")");
2455    }
2456}
2457impl_display_t!(ReplicaDefinition);
2458
2459#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2460pub enum AlterClusterAction<T: AstInfo> {
2461    SetOptions {
2462        options: Vec<ClusterOption<T>>,
2463        with_options: Vec<ClusterAlterOption<T>>,
2464    },
2465    ResetOptions(Vec<ClusterOptionName>),
2466}
2467
2468/// `ALTER CLUSTER .. SET ...`
2469#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2470pub struct AlterClusterStatement<T: AstInfo> {
2471    /// The `IF EXISTS` option.
2472    pub if_exists: bool,
2473    /// Name of the altered cluster.
2474    pub name: Ident,
2475    /// The action.
2476    pub action: AlterClusterAction<T>,
2477}
2478
2479impl<T: AstInfo> AstDisplay for AlterClusterStatement<T> {
2480    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2481        f.write_str("ALTER CLUSTER ");
2482        if self.if_exists {
2483            f.write_str("IF EXISTS ");
2484        }
2485        f.write_node(&self.name);
2486        f.write_str(" ");
2487        match &self.action {
2488            AlterClusterAction::SetOptions {
2489                options,
2490                with_options,
2491            } => {
2492                f.write_str("SET (");
2493                f.write_node(&display::comma_separated(options));
2494                f.write_str(")");
2495                if !with_options.is_empty() {
2496                    f.write_str(" WITH (");
2497                    f.write_node(&display::comma_separated(with_options));
2498                    f.write_str(")");
2499                }
2500            }
2501            AlterClusterAction::ResetOptions(options) => {
2502                f.write_str("RESET (");
2503                f.write_node(&display::comma_separated(options));
2504                f.write_str(")");
2505            }
2506        }
2507    }
2508}
2509impl_display_t!(AlterClusterStatement);
2510
2511/// `CREATE CLUSTER REPLICA ..`
2512#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2513pub struct CreateClusterReplicaStatement<T: AstInfo> {
2514    /// Name of the replica's cluster.
2515    pub of_cluster: Ident,
2516    /// The replica's definition.
2517    pub definition: ReplicaDefinition<T>,
2518}
2519
2520impl<T: AstInfo> AstDisplay for CreateClusterReplicaStatement<T> {
2521    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2522        f.write_str("CREATE CLUSTER REPLICA ");
2523        f.write_node(&self.of_cluster);
2524        f.write_str(".");
2525        f.write_node(&self.definition.name);
2526        f.write_str(" (");
2527        f.write_node(&display::comma_separated(&self.definition.options));
2528        f.write_str(")");
2529    }
2530}
2531impl_display_t!(CreateClusterReplicaStatement);
2532
2533#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2534pub enum ReplicaOptionName {
2535    /// The `BILLED AS [=] <value>` option.
2536    BilledAs,
2537    /// The `SIZE [[=] <size>]` option.
2538    Size,
2539    /// The `AVAILABILITY ZONE [[=] <id>]` option.
2540    AvailabilityZone,
2541    /// The `STORAGE ADDRESSES` option.
2542    StorageAddresses,
2543    /// The `STORAGECTL ADDRESSES` option.
2544    StoragectlAddresses,
2545    /// The `COMPUTECTL ADDRESSES` option.
2546    ComputectlAddresses,
2547    /// The `COMPUTE ADDRESSES` option.
2548    ComputeAddresses,
2549    /// The `WORKERS` option.
2550    Workers,
2551    /// The `INTERNAL` option.
2552    Internal,
2553    /// The `INTROSPECTION INTERVAL [[=] <interval>]` option.
2554    IntrospectionInterval,
2555    /// The `INTROSPECTION DEBUGGING [[=] <enabled>]` option.
2556    IntrospectionDebugging,
2557    /// The `DISK [[=] <enabled>]` option.
2558    Disk,
2559}
2560
2561impl AstDisplay for ReplicaOptionName {
2562    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2563        match self {
2564            ReplicaOptionName::BilledAs => f.write_str("BILLED AS"),
2565            ReplicaOptionName::Size => f.write_str("SIZE"),
2566            ReplicaOptionName::AvailabilityZone => f.write_str("AVAILABILITY ZONE"),
2567            ReplicaOptionName::StorageAddresses => f.write_str("STORAGE ADDRESSES"),
2568            ReplicaOptionName::StoragectlAddresses => f.write_str("STORAGECTL ADDRESSES"),
2569            ReplicaOptionName::ComputectlAddresses => f.write_str("COMPUTECTL ADDRESSES"),
2570            ReplicaOptionName::ComputeAddresses => f.write_str("COMPUTE ADDRESSES"),
2571            ReplicaOptionName::Workers => f.write_str("WORKERS"),
2572            ReplicaOptionName::Internal => f.write_str("INTERNAL"),
2573            ReplicaOptionName::IntrospectionInterval => f.write_str("INTROSPECTION INTERVAL"),
2574            ReplicaOptionName::IntrospectionDebugging => f.write_str("INTROSPECTION DEBUGGING"),
2575            ReplicaOptionName::Disk => f.write_str("DISK"),
2576        }
2577    }
2578}
2579
2580impl WithOptionName for ReplicaOptionName {
2581    /// # WARNING
2582    ///
2583    /// Whenever implementing this trait consider very carefully whether or not
2584    /// this value could contain sensitive user data. If you're uncertain, err
2585    /// on the conservative side and return `true`.
2586    fn redact_value(&self) -> bool {
2587        match self {
2588            ReplicaOptionName::BilledAs
2589            | ReplicaOptionName::Size
2590            | ReplicaOptionName::AvailabilityZone
2591            | ReplicaOptionName::StorageAddresses
2592            | ReplicaOptionName::StoragectlAddresses
2593            | ReplicaOptionName::ComputectlAddresses
2594            | ReplicaOptionName::ComputeAddresses
2595            | ReplicaOptionName::Workers
2596            | ReplicaOptionName::Internal
2597            | ReplicaOptionName::IntrospectionInterval
2598            | ReplicaOptionName::IntrospectionDebugging
2599            | ReplicaOptionName::Disk => false,
2600        }
2601    }
2602}
2603
2604#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2605/// An option in a `CREATE CLUSTER REPLICA` statement.
2606pub struct ReplicaOption<T: AstInfo> {
2607    pub name: ReplicaOptionName,
2608    pub value: Option<WithOptionValue<T>>,
2609}
2610impl_display_for_with_option!(ReplicaOption);
2611
2612/// `CREATE TYPE .. AS <TYPE>`
2613#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2614pub enum CreateTypeAs<T: AstInfo> {
2615    List {
2616        options: Vec<CreateTypeListOption<T>>,
2617    },
2618    Map {
2619        options: Vec<CreateTypeMapOption<T>>,
2620    },
2621    Record {
2622        column_defs: Vec<ColumnDef<T>>,
2623    },
2624}
2625
2626impl<T: AstInfo> AstDisplay for CreateTypeAs<T> {
2627    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2628        match self {
2629            CreateTypeAs::List { .. } => f.write_str("LIST "),
2630            CreateTypeAs::Map { .. } => f.write_str("MAP "),
2631            CreateTypeAs::Record { .. } => f.write_str("RECORD "),
2632        }
2633    }
2634}
2635impl_display_t!(CreateTypeAs);
2636
2637#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2638pub enum CreateTypeListOptionName {
2639    ElementType,
2640}
2641
2642impl AstDisplay for CreateTypeListOptionName {
2643    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2644        f.write_str(match self {
2645            CreateTypeListOptionName::ElementType => "ELEMENT TYPE",
2646        })
2647    }
2648}
2649
2650impl WithOptionName for CreateTypeListOptionName {
2651    /// # WARNING
2652    ///
2653    /// Whenever implementing this trait consider very carefully whether or not
2654    /// this value could contain sensitive user data. If you're uncertain, err
2655    /// on the conservative side and return `true`.
2656    fn redact_value(&self) -> bool {
2657        match self {
2658            CreateTypeListOptionName::ElementType => false,
2659        }
2660    }
2661}
2662
2663#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2664pub struct CreateTypeListOption<T: AstInfo> {
2665    pub name: CreateTypeListOptionName,
2666    pub value: Option<WithOptionValue<T>>,
2667}
2668impl_display_for_with_option!(CreateTypeListOption);
2669
2670#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2671pub enum CreateTypeMapOptionName {
2672    KeyType,
2673    ValueType,
2674}
2675
2676impl AstDisplay for CreateTypeMapOptionName {
2677    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2678        f.write_str(match self {
2679            CreateTypeMapOptionName::KeyType => "KEY TYPE",
2680            CreateTypeMapOptionName::ValueType => "VALUE TYPE",
2681        })
2682    }
2683}
2684
2685impl WithOptionName for CreateTypeMapOptionName {
2686    /// # WARNING
2687    ///
2688    /// Whenever implementing this trait consider very carefully whether or not
2689    /// this value could contain sensitive user data. If you're uncertain, err
2690    /// on the conservative side and return `true`.
2691    fn redact_value(&self) -> bool {
2692        match self {
2693            CreateTypeMapOptionName::KeyType | CreateTypeMapOptionName::ValueType => false,
2694        }
2695    }
2696}
2697
2698#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2699pub struct CreateTypeMapOption<T: AstInfo> {
2700    pub name: CreateTypeMapOptionName,
2701    pub value: Option<WithOptionValue<T>>,
2702}
2703impl_display_for_with_option!(CreateTypeMapOption);
2704
2705/// `ALTER <OBJECT> ... OWNER TO`
2706#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2707pub struct AlterOwnerStatement<T: AstInfo> {
2708    pub object_type: ObjectType,
2709    pub if_exists: bool,
2710    pub name: UnresolvedObjectName,
2711    pub new_owner: T::RoleName,
2712}
2713
2714impl<T: AstInfo> AstDisplay for AlterOwnerStatement<T> {
2715    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2716        f.write_str("ALTER ");
2717        f.write_node(&self.object_type);
2718        f.write_str(" ");
2719        if self.if_exists {
2720            f.write_str("IF EXISTS ");
2721        }
2722        f.write_node(&self.name);
2723        f.write_str(" OWNER TO ");
2724        f.write_node(&self.new_owner);
2725    }
2726}
2727impl_display_t!(AlterOwnerStatement);
2728
2729/// `ALTER <OBJECT> ... RENAME TO`
2730#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2731pub struct AlterObjectRenameStatement {
2732    pub object_type: ObjectType,
2733    pub if_exists: bool,
2734    pub name: UnresolvedObjectName,
2735    pub to_item_name: Ident,
2736}
2737
2738impl AstDisplay for AlterObjectRenameStatement {
2739    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2740        f.write_str("ALTER ");
2741        f.write_node(&self.object_type);
2742        f.write_str(" ");
2743        if self.if_exists {
2744            f.write_str("IF EXISTS ");
2745        }
2746        f.write_node(&self.name);
2747        f.write_str(" RENAME TO ");
2748        f.write_node(&self.to_item_name);
2749    }
2750}
2751impl_display!(AlterObjectRenameStatement);
2752
2753/// `ALTER <OBJECT> ... [RE]SET (RETAIN HISTORY [FOR ...])`
2754#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2755pub struct AlterRetainHistoryStatement<T: AstInfo> {
2756    pub object_type: ObjectType,
2757    pub if_exists: bool,
2758    pub name: UnresolvedObjectName,
2759    pub history: Option<WithOptionValue<T>>,
2760}
2761
2762impl<T: AstInfo> AstDisplay for AlterRetainHistoryStatement<T> {
2763    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2764        f.write_str("ALTER ");
2765        f.write_node(&self.object_type);
2766        f.write_str(" ");
2767        if self.if_exists {
2768            f.write_str("IF EXISTS ");
2769        }
2770        f.write_node(&self.name);
2771        if let Some(history) = &self.history {
2772            f.write_str(" SET (RETAIN HISTORY ");
2773            f.write_node(history);
2774        } else {
2775            f.write_str(" RESET (RETAIN HISTORY");
2776        }
2777        f.write_str(")");
2778    }
2779}
2780impl_display_t!(AlterRetainHistoryStatement);
2781
2782/// `ALTER <OBJECT> SWAP ...`
2783#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2784pub struct AlterObjectSwapStatement {
2785    pub object_type: ObjectType,
2786    pub name_a: UnresolvedObjectName,
2787    pub name_b: Ident,
2788}
2789
2790impl AstDisplay for AlterObjectSwapStatement {
2791    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2792        f.write_str("ALTER ");
2793
2794        f.write_node(&self.object_type);
2795        f.write_str(" ");
2796        f.write_node(&self.name_a);
2797
2798        f.write_str(" SWAP WITH ");
2799        f.write_node(&self.name_b);
2800    }
2801}
2802impl_display!(AlterObjectSwapStatement);
2803
2804#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2805pub enum AlterIndexAction<T: AstInfo> {
2806    SetOptions(Vec<IndexOption<T>>),
2807    ResetOptions(Vec<IndexOptionName>),
2808}
2809
2810/// `ALTER INDEX ... {RESET, SET}`
2811#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2812pub struct AlterIndexStatement<T: AstInfo> {
2813    pub index_name: UnresolvedItemName,
2814    pub if_exists: bool,
2815    pub action: AlterIndexAction<T>,
2816}
2817
2818impl<T: AstInfo> AstDisplay for AlterIndexStatement<T> {
2819    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2820        f.write_str("ALTER INDEX ");
2821        if self.if_exists {
2822            f.write_str("IF EXISTS ");
2823        }
2824        f.write_node(&self.index_name);
2825        f.write_str(" ");
2826
2827        match &self.action {
2828            AlterIndexAction::SetOptions(options) => {
2829                f.write_str("SET (");
2830                f.write_node(&display::comma_separated(options));
2831                f.write_str(")");
2832            }
2833            AlterIndexAction::ResetOptions(options) => {
2834                f.write_str("RESET (");
2835                f.write_node(&display::comma_separated(options));
2836                f.write_str(")");
2837            }
2838        }
2839    }
2840}
2841
2842impl_display_t!(AlterIndexStatement);
2843
2844#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2845pub enum AlterSinkAction<T: AstInfo> {
2846    SetOptions(Vec<CreateSinkOption<T>>),
2847    ResetOptions(Vec<CreateSinkOptionName>),
2848    ChangeRelation(T::ItemName),
2849}
2850
2851#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2852pub struct AlterSinkStatement<T: AstInfo> {
2853    pub sink_name: UnresolvedItemName,
2854    pub if_exists: bool,
2855    pub action: AlterSinkAction<T>,
2856}
2857
2858impl<T: AstInfo> AstDisplay for AlterSinkStatement<T> {
2859    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2860        f.write_str("ALTER SINK ");
2861        if self.if_exists {
2862            f.write_str("IF EXISTS ");
2863        }
2864        f.write_node(&self.sink_name);
2865        f.write_str(" ");
2866
2867        match &self.action {
2868            AlterSinkAction::ChangeRelation(from) => {
2869                f.write_str("SET FROM ");
2870                f.write_node(from);
2871            }
2872            AlterSinkAction::SetOptions(options) => {
2873                f.write_str("SET (");
2874                f.write_node(&display::comma_separated(options));
2875                f.write_str(")");
2876            }
2877            AlterSinkAction::ResetOptions(options) => {
2878                f.write_str("RESET (");
2879                f.write_node(&display::comma_separated(options));
2880                f.write_str(")");
2881            }
2882        }
2883    }
2884}
2885
2886#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2887pub enum AlterSourceAddSubsourceOptionName {
2888    /// Columns whose types you want to unconditionally format as text
2889    TextColumns,
2890    /// Columns you want to ignore when ingesting data
2891    ExcludeColumns,
2892    /// Updated `DETAILS` for an ingestion, e.g.
2893    /// [`crate::ast::PgConfigOptionName::Details`]
2894    /// or
2895    /// [`crate::ast::MySqlConfigOptionName::Details`].
2896    Details,
2897}
2898
2899impl AstDisplay for AlterSourceAddSubsourceOptionName {
2900    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2901        f.write_str(match self {
2902            AlterSourceAddSubsourceOptionName::TextColumns => "TEXT COLUMNS",
2903            AlterSourceAddSubsourceOptionName::ExcludeColumns => "EXCLUDE COLUMNS",
2904            AlterSourceAddSubsourceOptionName::Details => "DETAILS",
2905        })
2906    }
2907}
2908impl_display!(AlterSourceAddSubsourceOptionName);
2909
2910impl WithOptionName for AlterSourceAddSubsourceOptionName {
2911    /// # WARNING
2912    ///
2913    /// Whenever implementing this trait consider very carefully whether or not
2914    /// this value could contain sensitive user data. If you're uncertain, err
2915    /// on the conservative side and return `true`.
2916    fn redact_value(&self) -> bool {
2917        match self {
2918            AlterSourceAddSubsourceOptionName::Details
2919            | AlterSourceAddSubsourceOptionName::TextColumns
2920            | AlterSourceAddSubsourceOptionName::ExcludeColumns => false,
2921        }
2922    }
2923}
2924
2925#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2926/// An option in an `ALTER SOURCE...ADD SUBSOURCE` statement.
2927pub struct AlterSourceAddSubsourceOption<T: AstInfo> {
2928    pub name: AlterSourceAddSubsourceOptionName,
2929    pub value: Option<WithOptionValue<T>>,
2930}
2931impl_display_for_with_option!(AlterSourceAddSubsourceOption);
2932impl_display_t!(AlterSourceAddSubsourceOption);
2933
2934#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2935pub enum AlterSourceAction<T: AstInfo> {
2936    SetOptions(Vec<CreateSourceOption<T>>),
2937    ResetOptions(Vec<CreateSourceOptionName>),
2938    AddSubsources {
2939        external_references: Vec<ExternalReferenceExport>,
2940        options: Vec<AlterSourceAddSubsourceOption<T>>,
2941    },
2942    DropSubsources {
2943        if_exists: bool,
2944        cascade: bool,
2945        names: Vec<UnresolvedItemName>,
2946    },
2947    RefreshReferences,
2948}
2949
2950impl<T: AstInfo> AstDisplay for AlterSourceAction<T> {
2951    fn fmt<W>(&self, f: &mut AstFormatter<W>)
2952    where
2953        W: fmt::Write,
2954    {
2955        match &self {
2956            AlterSourceAction::SetOptions(options) => {
2957                f.write_str("SET (");
2958                f.write_node(&display::comma_separated(options));
2959                f.write_str(")");
2960            }
2961            AlterSourceAction::ResetOptions(options) => {
2962                f.write_str("RESET (");
2963                f.write_node(&display::comma_separated(options));
2964                f.write_str(")");
2965            }
2966            AlterSourceAction::DropSubsources {
2967                if_exists,
2968                cascade,
2969                names,
2970            } => {
2971                f.write_str("DROP SUBSOURCE ");
2972                if *if_exists {
2973                    f.write_str("IF EXISTS ");
2974                }
2975
2976                f.write_node(&display::comma_separated(names));
2977
2978                if *cascade {
2979                    f.write_str(" CASCADE");
2980                }
2981            }
2982            AlterSourceAction::AddSubsources {
2983                external_references: subsources,
2984                options,
2985            } => {
2986                f.write_str("ADD SUBSOURCE ");
2987
2988                f.write_node(&display::comma_separated(subsources));
2989
2990                if !options.is_empty() {
2991                    f.write_str(" WITH (");
2992                    f.write_node(&display::comma_separated(options));
2993                    f.write_str(")");
2994                }
2995            }
2996            AlterSourceAction::RefreshReferences => {
2997                f.write_str("REFRESH REFERENCES");
2998            }
2999        }
3000    }
3001}
3002
3003#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3004pub struct AlterSourceStatement<T: AstInfo> {
3005    pub source_name: UnresolvedItemName,
3006    pub if_exists: bool,
3007    pub action: AlterSourceAction<T>,
3008}
3009
3010impl<T: AstInfo> AstDisplay for AlterSourceStatement<T> {
3011    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3012        f.write_str("ALTER SOURCE ");
3013        if self.if_exists {
3014            f.write_str("IF EXISTS ");
3015        }
3016        f.write_node(&self.source_name);
3017        f.write_str(" ");
3018        f.write_node(&self.action)
3019    }
3020}
3021
3022impl_display_t!(AlterSourceStatement);
3023
3024/// `ALTER SECRET ... AS`
3025#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3026pub struct AlterSecretStatement<T: AstInfo> {
3027    pub name: UnresolvedItemName,
3028    pub if_exists: bool,
3029    pub value: Expr<T>,
3030}
3031
3032impl<T: AstInfo> AstDisplay for AlterSecretStatement<T> {
3033    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3034        f.write_str("ALTER SECRET ");
3035        if self.if_exists {
3036            f.write_str("IF EXISTS ");
3037        }
3038        f.write_node(&self.name);
3039        f.write_str(" AS ");
3040
3041        if f.redacted() {
3042            f.write_str("'<REDACTED>'");
3043        } else {
3044            f.write_node(&self.value);
3045        }
3046    }
3047}
3048
3049impl_display_t!(AlterSecretStatement);
3050
3051#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3052pub enum AlterConnectionAction<T: AstInfo> {
3053    RotateKeys,
3054    SetOption(ConnectionOption<T>),
3055    DropOption(ConnectionOptionName),
3056}
3057
3058impl<T: AstInfo> AstDisplay for AlterConnectionAction<T> {
3059    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3060        match self {
3061            AlterConnectionAction::RotateKeys => f.write_str("ROTATE KEYS"),
3062            AlterConnectionAction::SetOption(option) => {
3063                f.write_str("SET (");
3064                f.write_node(option);
3065                f.write_str(")");
3066            }
3067            AlterConnectionAction::DropOption(option) => {
3068                f.write_str("DROP (");
3069                f.write_node(option);
3070                f.write_str(")");
3071            }
3072        }
3073    }
3074}
3075impl_display_t!(AlterConnectionAction);
3076
3077#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3078pub enum AlterConnectionOptionName {
3079    Validate,
3080}
3081
3082impl AstDisplay for AlterConnectionOptionName {
3083    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3084        f.write_str(match self {
3085            AlterConnectionOptionName::Validate => "VALIDATE",
3086        })
3087    }
3088}
3089impl_display!(AlterConnectionOptionName);
3090
3091impl WithOptionName for AlterConnectionOptionName {
3092    /// # WARNING
3093    ///
3094    /// Whenever implementing this trait consider very carefully whether or not
3095    /// this value could contain sensitive user data. If you're uncertain, err
3096    /// on the conservative side and return `true`.
3097    fn redact_value(&self) -> bool {
3098        match self {
3099            AlterConnectionOptionName::Validate => false,
3100        }
3101    }
3102}
3103
3104#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3105/// An option in an `ALTER CONNECTION...` statement.
3106pub struct AlterConnectionOption<T: AstInfo> {
3107    pub name: AlterConnectionOptionName,
3108    pub value: Option<WithOptionValue<T>>,
3109}
3110impl_display_for_with_option!(AlterConnectionOption);
3111impl_display_t!(AlterConnectionOption);
3112
3113/// `ALTER CONNECTION`
3114#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3115pub struct AlterConnectionStatement<T: AstInfo> {
3116    pub name: UnresolvedItemName,
3117    pub if_exists: bool,
3118    pub actions: Vec<AlterConnectionAction<T>>,
3119    pub with_options: Vec<AlterConnectionOption<T>>,
3120}
3121
3122impl<T: AstInfo> AstDisplay for AlterConnectionStatement<T> {
3123    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3124        f.write_str("ALTER CONNECTION ");
3125        if self.if_exists {
3126            f.write_str("IF EXISTS ");
3127        }
3128        f.write_node(&self.name);
3129        f.write_str(" ");
3130        f.write_node(&display::comma_separated(&self.actions));
3131
3132        if !self.with_options.is_empty() {
3133            f.write_str(" WITH (");
3134            f.write_node(&display::comma_separated(&self.with_options));
3135            f.write_str(")");
3136        }
3137    }
3138}
3139
3140impl_display_t!(AlterConnectionStatement);
3141
3142/// `ALTER ROLE`
3143#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3144pub struct AlterRoleStatement<T: AstInfo> {
3145    /// The specified role.
3146    pub name: T::RoleName,
3147    /// Alterations we're making to the role.
3148    pub option: AlterRoleOption,
3149}
3150
3151impl<T: AstInfo> AstDisplay for AlterRoleStatement<T> {
3152    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3153        f.write_str("ALTER ROLE ");
3154        f.write_node(&self.name);
3155        f.write_node(&self.option);
3156    }
3157}
3158impl_display_t!(AlterRoleStatement);
3159
3160/// `ALTER ROLE ... [ WITH | SET ] ...`
3161#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3162pub enum AlterRoleOption {
3163    /// Any options that were attached, in the order they were presented.
3164    Attributes(Vec<RoleAttribute>),
3165    /// A variable that we want to provide a default value for this role.
3166    Variable(SetRoleVar),
3167}
3168
3169impl AstDisplay for AlterRoleOption {
3170    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3171        match self {
3172            AlterRoleOption::Attributes(attrs) => {
3173                for attr in attrs {
3174                    f.write_str(" ");
3175                    attr.fmt(f)
3176                }
3177            }
3178            AlterRoleOption::Variable(var) => {
3179                f.write_str(" ");
3180                f.write_node(var);
3181            }
3182        }
3183    }
3184}
3185impl_display!(AlterRoleOption);
3186
3187/// `ALTER TABLE ... ADD COLUMN ...`
3188#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3189pub struct AlterTableAddColumnStatement<T: AstInfo> {
3190    pub if_exists: bool,
3191    pub name: UnresolvedItemName,
3192    pub if_col_not_exist: bool,
3193    pub column_name: Ident,
3194    pub data_type: T::DataType,
3195}
3196
3197impl<T: AstInfo> AstDisplay for AlterTableAddColumnStatement<T> {
3198    fn fmt<W>(&self, f: &mut AstFormatter<W>)
3199    where
3200        W: fmt::Write,
3201    {
3202        f.write_str("ALTER TABLE ");
3203        if self.if_exists {
3204            f.write_str("IF EXISTS ");
3205        }
3206        f.write_node(&self.name);
3207
3208        f.write_str(" ADD COLUMN ");
3209        if self.if_col_not_exist {
3210            f.write_str("IF NOT EXISTS ");
3211        }
3212
3213        f.write_node(&self.column_name);
3214        f.write_str(" ");
3215        f.write_node(&self.data_type);
3216    }
3217}
3218
3219impl_display_t!(AlterTableAddColumnStatement);
3220
3221/// `ALTER MATERIALIZED VIEW ... APPLY REPLACEMENT ...`
3222#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3223pub struct AlterMaterializedViewApplyReplacementStatement {
3224    pub if_exists: bool,
3225    pub name: UnresolvedItemName,
3226    pub replacement_name: UnresolvedItemName,
3227}
3228
3229impl AstDisplay for AlterMaterializedViewApplyReplacementStatement {
3230    fn fmt<W>(&self, f: &mut AstFormatter<W>)
3231    where
3232        W: fmt::Write,
3233    {
3234        f.write_str("ALTER MATERIALIZED VIEW ");
3235        if self.if_exists {
3236            f.write_str("IF EXISTS ");
3237        }
3238        f.write_node(&self.name);
3239
3240        f.write_str(" APPLY REPLACEMENT ");
3241        f.write_node(&self.replacement_name);
3242    }
3243}
3244
3245impl_display!(AlterMaterializedViewApplyReplacementStatement);
3246
3247#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3248pub struct DiscardStatement {
3249    pub target: DiscardTarget,
3250}
3251
3252impl AstDisplay for DiscardStatement {
3253    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3254        f.write_str("DISCARD ");
3255        f.write_node(&self.target);
3256    }
3257}
3258impl_display!(DiscardStatement);
3259
3260#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3261pub enum DiscardTarget {
3262    Plans,
3263    Sequences,
3264    Temp,
3265    All,
3266}
3267
3268impl AstDisplay for DiscardTarget {
3269    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3270        match self {
3271            DiscardTarget::Plans => f.write_str("PLANS"),
3272            DiscardTarget::Sequences => f.write_str("SEQUENCES"),
3273            DiscardTarget::Temp => f.write_str("TEMP"),
3274            DiscardTarget::All => f.write_str("ALL"),
3275        }
3276    }
3277}
3278impl_display!(DiscardTarget);
3279
3280/// `DROP`
3281#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3282pub struct DropObjectsStatement {
3283    /// The type of the object to drop: TABLE, VIEW, etc.
3284    pub object_type: ObjectType,
3285    /// An optional `IF EXISTS` clause. (Non-standard.)
3286    pub if_exists: bool,
3287    /// One or more objects to drop. (ANSI SQL requires exactly one.)
3288    pub names: Vec<UnresolvedObjectName>,
3289    /// Whether `CASCADE` was specified. This will be `false` when
3290    /// `RESTRICT` was specified.
3291    pub cascade: bool,
3292}
3293
3294impl AstDisplay for DropObjectsStatement {
3295    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3296        f.write_str("DROP ");
3297        f.write_node(&self.object_type);
3298        f.write_str(" ");
3299        if self.if_exists {
3300            f.write_str("IF EXISTS ");
3301        }
3302        f.write_node(&display::comma_separated(&self.names));
3303        if self.cascade && self.object_type != ObjectType::Database {
3304            f.write_str(" CASCADE");
3305        } else if !self.cascade && self.object_type == ObjectType::Database {
3306            f.write_str(" RESTRICT");
3307        }
3308    }
3309}
3310impl_display!(DropObjectsStatement);
3311
3312/// `DROP OWNED BY ...`
3313#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3314pub struct DropOwnedStatement<T: AstInfo> {
3315    /// The roles whose owned objects are being dropped.
3316    pub role_names: Vec<T::RoleName>,
3317    /// Whether `CASCADE` was specified. `false` for `RESTRICT` and `None` if no drop behavior at
3318    /// all was specified.
3319    pub cascade: Option<bool>,
3320}
3321
3322impl<T: AstInfo> DropOwnedStatement<T> {
3323    pub fn cascade(&self) -> bool {
3324        self.cascade == Some(true)
3325    }
3326}
3327
3328impl<T: AstInfo> AstDisplay for DropOwnedStatement<T> {
3329    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3330        f.write_str("DROP OWNED BY ");
3331        f.write_node(&display::comma_separated(&self.role_names));
3332        if let Some(true) = self.cascade {
3333            f.write_str(" CASCADE");
3334        } else if let Some(false) = self.cascade {
3335            f.write_str(" RESTRICT");
3336        }
3337    }
3338}
3339impl_display_t!(DropOwnedStatement);
3340
3341#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3342pub struct QualifiedReplica {
3343    pub cluster: Ident,
3344    pub replica: Ident,
3345}
3346
3347impl AstDisplay for QualifiedReplica {
3348    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3349        f.write_node(&self.cluster);
3350        f.write_str(".");
3351        f.write_node(&self.replica);
3352    }
3353}
3354impl_display!(QualifiedReplica);
3355
3356/// `SET <variable>`
3357///
3358/// Note: this is not a standard SQL statement, but it is supported by at
3359/// least MySQL and PostgreSQL. Not all MySQL-specific syntactic forms are
3360/// supported yet.
3361#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3362pub struct SetVariableStatement {
3363    pub local: bool,
3364    pub variable: Ident,
3365    pub to: SetVariableTo,
3366}
3367
3368impl AstDisplay for SetVariableStatement {
3369    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3370        f.write_str("SET ");
3371        if self.local {
3372            f.write_str("LOCAL ");
3373        }
3374        f.write_node(&self.variable);
3375        f.write_str(" = ");
3376        f.write_node(&self.to);
3377    }
3378}
3379impl_display!(SetVariableStatement);
3380
3381/// `RESET <variable>`
3382///
3383/// Note: this is not a standard SQL statement, but it is supported by at
3384/// least MySQL and PostgreSQL. Not all syntactic forms are supported yet.
3385#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3386pub struct ResetVariableStatement {
3387    pub variable: Ident,
3388}
3389
3390impl AstDisplay for ResetVariableStatement {
3391    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3392        f.write_str("RESET ");
3393        f.write_node(&self.variable);
3394    }
3395}
3396impl_display!(ResetVariableStatement);
3397
3398/// `SHOW <variable>`
3399#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3400pub struct ShowVariableStatement {
3401    pub variable: Ident,
3402}
3403
3404impl AstDisplay for ShowVariableStatement {
3405    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3406        f.write_str("SHOW ");
3407        f.write_node(&self.variable);
3408    }
3409}
3410impl_display!(ShowVariableStatement);
3411
3412/// `INSPECT SHARD <id>`
3413#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3414pub struct InspectShardStatement {
3415    pub id: String,
3416}
3417
3418impl AstDisplay for InspectShardStatement {
3419    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3420        f.write_str("INSPECT SHARD ");
3421        f.write_str("'");
3422        f.write_node(&display::escape_single_quote_string(&self.id));
3423        f.write_str("'");
3424    }
3425}
3426impl_display!(InspectShardStatement);
3427
3428#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3429pub enum ShowObjectType<T: AstInfo> {
3430    MaterializedView {
3431        in_cluster: Option<T::ClusterName>,
3432    },
3433    Index {
3434        in_cluster: Option<T::ClusterName>,
3435        on_object: Option<T::ItemName>,
3436    },
3437    Table {
3438        on_source: Option<T::ItemName>,
3439    },
3440    View,
3441    Source {
3442        in_cluster: Option<T::ClusterName>,
3443    },
3444    Sink {
3445        in_cluster: Option<T::ClusterName>,
3446    },
3447    Type,
3448    Role,
3449    Cluster,
3450    ClusterReplica,
3451    Object,
3452    Secret,
3453    Connection,
3454    Database,
3455    Schema {
3456        from: Option<T::DatabaseName>,
3457    },
3458    Subsource {
3459        on_source: Option<T::ItemName>,
3460    },
3461    Privileges {
3462        object_type: Option<SystemObjectType>,
3463        role: Option<T::RoleName>,
3464    },
3465    DefaultPrivileges {
3466        object_type: Option<ObjectType>,
3467        role: Option<T::RoleName>,
3468    },
3469    RoleMembership {
3470        role: Option<T::RoleName>,
3471    },
3472    ContinualTask {
3473        in_cluster: Option<T::ClusterName>,
3474    },
3475    NetworkPolicy,
3476}
3477/// `SHOW <object>S`
3478///
3479/// ```sql
3480/// SHOW TABLES;
3481/// SHOW SOURCES;
3482/// SHOW VIEWS;
3483/// SHOW SINKS;
3484/// ```
3485#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3486pub struct ShowObjectsStatement<T: AstInfo> {
3487    pub object_type: ShowObjectType<T>,
3488    pub from: Option<T::SchemaName>,
3489    pub filter: Option<ShowStatementFilter<T>>,
3490}
3491
3492impl<T: AstInfo> AstDisplay for ShowObjectsStatement<T> {
3493    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3494        f.write_str("SHOW");
3495        f.write_str(" ");
3496
3497        f.write_str(match &self.object_type {
3498            ShowObjectType::Table { .. } => "TABLES",
3499            ShowObjectType::View => "VIEWS",
3500            ShowObjectType::Source { .. } => "SOURCES",
3501            ShowObjectType::Sink { .. } => "SINKS",
3502            ShowObjectType::Type => "TYPES",
3503            ShowObjectType::Role => "ROLES",
3504            ShowObjectType::Cluster => "CLUSTERS",
3505            ShowObjectType::ClusterReplica => "CLUSTER REPLICAS",
3506            ShowObjectType::Object => "OBJECTS",
3507            ShowObjectType::Secret => "SECRETS",
3508            ShowObjectType::Connection => "CONNECTIONS",
3509            ShowObjectType::MaterializedView { .. } => "MATERIALIZED VIEWS",
3510            ShowObjectType::Index { .. } => "INDEXES",
3511            ShowObjectType::Database => "DATABASES",
3512            ShowObjectType::Schema { .. } => "SCHEMAS",
3513            ShowObjectType::Subsource { .. } => "SUBSOURCES",
3514            ShowObjectType::Privileges { .. } => "PRIVILEGES",
3515            ShowObjectType::DefaultPrivileges { .. } => "DEFAULT PRIVILEGES",
3516            ShowObjectType::RoleMembership { .. } => "ROLE MEMBERSHIP",
3517            ShowObjectType::ContinualTask { .. } => "CONTINUAL TASKS",
3518            ShowObjectType::NetworkPolicy => "NETWORK POLICIES",
3519        });
3520
3521        if let ShowObjectType::Index { on_object, .. } = &self.object_type {
3522            if let Some(on_object) = on_object {
3523                f.write_str(" ON ");
3524                f.write_node(on_object);
3525            }
3526        }
3527
3528        if let ShowObjectType::Schema { from: Some(from) } = &self.object_type {
3529            f.write_str(" FROM ");
3530            f.write_node(from);
3531        }
3532
3533        if let Some(from) = &self.from {
3534            f.write_str(" FROM ");
3535            f.write_node(from);
3536        }
3537
3538        // append IN CLUSTER clause
3539        match &self.object_type {
3540            ShowObjectType::MaterializedView { in_cluster }
3541            | ShowObjectType::Index { in_cluster, .. }
3542            | ShowObjectType::Sink { in_cluster }
3543            | ShowObjectType::Source { in_cluster }
3544            | ShowObjectType::ContinualTask { in_cluster } => {
3545                if let Some(cluster) = in_cluster {
3546                    f.write_str(" IN CLUSTER ");
3547                    f.write_node(cluster);
3548                }
3549            }
3550            _ => (),
3551        }
3552
3553        if let ShowObjectType::Subsource { on_source } = &self.object_type {
3554            if let Some(on_source) = on_source {
3555                f.write_str(" ON ");
3556                f.write_node(on_source);
3557            }
3558        }
3559
3560        if let ShowObjectType::Table { on_source } = &self.object_type {
3561            if let Some(on_source) = on_source {
3562                f.write_str(" ON ");
3563                f.write_node(on_source);
3564            }
3565        }
3566
3567        if let ShowObjectType::Privileges { object_type, role } = &self.object_type {
3568            if let Some(object_type) = object_type {
3569                f.write_str(" ON ");
3570                f.write_node(object_type);
3571                if let SystemObjectType::Object(_) = object_type {
3572                    f.write_str("S");
3573                }
3574            }
3575            if let Some(role) = role {
3576                f.write_str(" FOR ");
3577                f.write_node(role);
3578            }
3579        }
3580
3581        if let ShowObjectType::DefaultPrivileges { object_type, role } = &self.object_type {
3582            if let Some(object_type) = object_type {
3583                f.write_str(" ON ");
3584                f.write_node(object_type);
3585                f.write_str("S");
3586            }
3587            if let Some(role) = role {
3588                f.write_str(" FOR ");
3589                f.write_node(role);
3590            }
3591        }
3592
3593        if let ShowObjectType::RoleMembership {
3594            role: Some(role), ..
3595        } = &self.object_type
3596        {
3597            f.write_str(" FOR ");
3598            f.write_node(role);
3599        }
3600
3601        if let Some(filter) = &self.filter {
3602            f.write_str(" ");
3603            f.write_node(filter);
3604        }
3605    }
3606}
3607impl_display_t!(ShowObjectsStatement);
3608
3609/// `SHOW COLUMNS`
3610///
3611/// Note: this is a MySQL-specific statement.
3612#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3613pub struct ShowColumnsStatement<T: AstInfo> {
3614    pub table_name: T::ItemName,
3615    pub filter: Option<ShowStatementFilter<T>>,
3616}
3617
3618impl<T: AstInfo> AstDisplay for ShowColumnsStatement<T> {
3619    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3620        f.write_str("SHOW ");
3621        f.write_str("COLUMNS FROM ");
3622        f.write_node(&self.table_name);
3623        if let Some(filter) = &self.filter {
3624            f.write_str(" ");
3625            f.write_node(filter);
3626        }
3627    }
3628}
3629impl_display_t!(ShowColumnsStatement);
3630
3631/// `SHOW [REDACTED] CREATE VIEW <view>`
3632#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3633pub struct ShowCreateViewStatement<T: AstInfo> {
3634    pub view_name: T::ItemName,
3635    pub redacted: bool,
3636}
3637
3638impl<T: AstInfo> AstDisplay for ShowCreateViewStatement<T> {
3639    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3640        f.write_str("SHOW ");
3641        if self.redacted {
3642            f.write_str("REDACTED ");
3643        }
3644        f.write_str("CREATE VIEW ");
3645        f.write_node(&self.view_name);
3646    }
3647}
3648impl_display_t!(ShowCreateViewStatement);
3649
3650/// `SHOW [REDACTED] CREATE MATERIALIZED VIEW <name>`
3651#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3652pub struct ShowCreateMaterializedViewStatement<T: AstInfo> {
3653    pub materialized_view_name: T::ItemName,
3654    pub redacted: bool,
3655}
3656
3657impl<T: AstInfo> AstDisplay for ShowCreateMaterializedViewStatement<T> {
3658    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3659        f.write_str("SHOW ");
3660        if self.redacted {
3661            f.write_str("REDACTED ");
3662        }
3663        f.write_str("CREATE MATERIALIZED VIEW ");
3664        f.write_node(&self.materialized_view_name);
3665    }
3666}
3667impl_display_t!(ShowCreateMaterializedViewStatement);
3668
3669/// `SHOW [REDACTED] CREATE SOURCE <source>`
3670#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3671pub struct ShowCreateSourceStatement<T: AstInfo> {
3672    pub source_name: T::ItemName,
3673    pub redacted: bool,
3674}
3675
3676impl<T: AstInfo> AstDisplay for ShowCreateSourceStatement<T> {
3677    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3678        f.write_str("SHOW ");
3679        if self.redacted {
3680            f.write_str("REDACTED ");
3681        }
3682        f.write_str("CREATE SOURCE ");
3683        f.write_node(&self.source_name);
3684    }
3685}
3686impl_display_t!(ShowCreateSourceStatement);
3687
3688/// `SHOW [REDACTED] CREATE TABLE <table>`
3689#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3690pub struct ShowCreateTableStatement<T: AstInfo> {
3691    pub table_name: T::ItemName,
3692    pub redacted: bool,
3693}
3694
3695impl<T: AstInfo> AstDisplay for ShowCreateTableStatement<T> {
3696    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3697        f.write_str("SHOW ");
3698        if self.redacted {
3699            f.write_str("REDACTED ");
3700        }
3701        f.write_str("CREATE TABLE ");
3702        f.write_node(&self.table_name);
3703    }
3704}
3705impl_display_t!(ShowCreateTableStatement);
3706
3707/// `SHOW [REDACTED] CREATE SINK <sink>`
3708#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3709pub struct ShowCreateSinkStatement<T: AstInfo> {
3710    pub sink_name: T::ItemName,
3711    pub redacted: bool,
3712}
3713
3714impl<T: AstInfo> AstDisplay for ShowCreateSinkStatement<T> {
3715    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3716        f.write_str("SHOW ");
3717        if self.redacted {
3718            f.write_str("REDACTED ");
3719        }
3720        f.write_str("CREATE SINK ");
3721        f.write_node(&self.sink_name);
3722    }
3723}
3724impl_display_t!(ShowCreateSinkStatement);
3725
3726/// `SHOW [REDACTED] CREATE INDEX <index>`
3727#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3728pub struct ShowCreateIndexStatement<T: AstInfo> {
3729    pub index_name: T::ItemName,
3730    pub redacted: bool,
3731}
3732
3733impl<T: AstInfo> AstDisplay for ShowCreateIndexStatement<T> {
3734    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3735        f.write_str("SHOW ");
3736        if self.redacted {
3737            f.write_str("REDACTED ");
3738        }
3739        f.write_str("CREATE INDEX ");
3740        f.write_node(&self.index_name);
3741    }
3742}
3743impl_display_t!(ShowCreateIndexStatement);
3744
3745/// `SHOW [REDACTED] CREATE CONNECTION <connection>`
3746#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3747pub struct ShowCreateConnectionStatement<T: AstInfo> {
3748    pub connection_name: T::ItemName,
3749    pub redacted: bool,
3750}
3751
3752impl<T: AstInfo> AstDisplay for ShowCreateConnectionStatement<T> {
3753    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3754        f.write_str("SHOW ");
3755        if self.redacted {
3756            f.write_str("REDACTED ");
3757        }
3758        f.write_str("CREATE CONNECTION ");
3759        f.write_node(&self.connection_name);
3760    }
3761}
3762
3763#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3764pub struct ShowCreateClusterStatement<T: AstInfo> {
3765    pub cluster_name: T::ClusterName,
3766}
3767
3768impl<T: AstInfo> AstDisplay for ShowCreateClusterStatement<T> {
3769    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3770        f.write_str("SHOW CREATE CLUSTER ");
3771        f.write_node(&self.cluster_name);
3772    }
3773}
3774
3775/// `{ BEGIN [ TRANSACTION | WORK ] | START TRANSACTION } ...`
3776#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3777pub struct StartTransactionStatement {
3778    pub modes: Vec<TransactionMode>,
3779}
3780
3781impl AstDisplay for StartTransactionStatement {
3782    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3783        f.write_str("START TRANSACTION");
3784        if !self.modes.is_empty() {
3785            f.write_str(" ");
3786            f.write_node(&display::comma_separated(&self.modes));
3787        }
3788    }
3789}
3790impl_display!(StartTransactionStatement);
3791
3792/// `SHOW [REDACTED] CREATE TYPE <type>`
3793#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3794pub struct ShowCreateTypeStatement<T: AstInfo> {
3795    pub type_name: T::DataType,
3796    pub redacted: bool,
3797}
3798
3799impl<T: AstInfo> AstDisplay for ShowCreateTypeStatement<T> {
3800    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3801        f.write_str("SHOW ");
3802        if self.redacted {
3803            f.write_str("REDACTED ");
3804        }
3805        f.write_str("CREATE TYPE ");
3806        f.write_node(&self.type_name);
3807    }
3808}
3809
3810/// `SET TRANSACTION ...`
3811#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3812pub struct SetTransactionStatement {
3813    pub local: bool,
3814    pub modes: Vec<TransactionMode>,
3815}
3816
3817impl AstDisplay for SetTransactionStatement {
3818    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3819        f.write_str("SET ");
3820        if !self.local {
3821            f.write_str("SESSION CHARACTERISTICS AS ");
3822        }
3823        f.write_str("TRANSACTION");
3824        if !self.modes.is_empty() {
3825            f.write_str(" ");
3826            f.write_node(&display::comma_separated(&self.modes));
3827        }
3828    }
3829}
3830impl_display!(SetTransactionStatement);
3831
3832/// `COMMIT [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
3833#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3834pub struct CommitStatement {
3835    pub chain: bool,
3836}
3837
3838impl AstDisplay for CommitStatement {
3839    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3840        f.write_str("COMMIT");
3841        if self.chain {
3842            f.write_str(" AND CHAIN");
3843        }
3844    }
3845}
3846impl_display!(CommitStatement);
3847
3848/// `ROLLBACK [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
3849#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3850pub struct RollbackStatement {
3851    pub chain: bool,
3852}
3853
3854impl AstDisplay for RollbackStatement {
3855    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3856        f.write_str("ROLLBACK");
3857        if self.chain {
3858            f.write_str(" AND CHAIN");
3859        }
3860    }
3861}
3862impl_display!(RollbackStatement);
3863
3864#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3865pub enum SubscribeOptionName {
3866    Snapshot,
3867    Progress,
3868}
3869
3870impl AstDisplay for SubscribeOptionName {
3871    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3872        match self {
3873            SubscribeOptionName::Snapshot => f.write_str("SNAPSHOT"),
3874            SubscribeOptionName::Progress => f.write_str("PROGRESS"),
3875        }
3876    }
3877}
3878impl_display!(SubscribeOptionName);
3879
3880impl WithOptionName for SubscribeOptionName {
3881    /// # WARNING
3882    ///
3883    /// Whenever implementing this trait consider very carefully whether or not
3884    /// this value could contain sensitive user data. If you're uncertain, err
3885    /// on the conservative side and return `true`.
3886    fn redact_value(&self) -> bool {
3887        match self {
3888            SubscribeOptionName::Snapshot | SubscribeOptionName::Progress => false,
3889        }
3890    }
3891}
3892
3893#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3894pub struct SubscribeOption<T: AstInfo> {
3895    pub name: SubscribeOptionName,
3896    pub value: Option<WithOptionValue<T>>,
3897}
3898impl_display_for_with_option!(SubscribeOption);
3899impl_display_t!(SubscribeOption);
3900
3901/// `SUBSCRIBE`
3902#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3903pub struct SubscribeStatement<T: AstInfo> {
3904    pub relation: SubscribeRelation<T>,
3905    pub options: Vec<SubscribeOption<T>>,
3906    pub as_of: Option<AsOf<T>>,
3907    pub up_to: Option<Expr<T>>,
3908    pub output: SubscribeOutput<T>,
3909}
3910
3911impl<T: AstInfo> AstDisplay for SubscribeStatement<T> {
3912    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3913        f.write_str("SUBSCRIBE ");
3914        f.write_node(&self.relation);
3915        if !self.options.is_empty() {
3916            f.write_str(" WITH (");
3917            f.write_node(&display::comma_separated(&self.options));
3918            f.write_str(")");
3919        }
3920        if let Some(as_of) = &self.as_of {
3921            f.write_str(" ");
3922            f.write_node(as_of);
3923        }
3924        if let Some(up_to) = &self.up_to {
3925            f.write_str(" UP TO ");
3926            f.write_node(up_to);
3927        }
3928        f.write_str(&self.output);
3929    }
3930}
3931impl_display_t!(SubscribeStatement);
3932
3933#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3934pub enum SubscribeRelation<T: AstInfo> {
3935    Name(T::ItemName),
3936    Query(Query<T>),
3937}
3938
3939impl<T: AstInfo> AstDisplay for SubscribeRelation<T> {
3940    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3941        match self {
3942            SubscribeRelation::Name(name) => f.write_node(name),
3943            SubscribeRelation::Query(query) => {
3944                f.write_str("(");
3945                f.write_node(query);
3946                f.write_str(")");
3947            }
3948        }
3949    }
3950}
3951impl_display_t!(SubscribeRelation);
3952
3953#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3954pub struct ExplainPlanStatement<T: AstInfo> {
3955    pub stage: Option<ExplainStage>,
3956    pub with_options: Vec<ExplainPlanOption<T>>,
3957    pub format: Option<ExplainFormat>,
3958    pub explainee: Explainee<T>,
3959}
3960
3961impl<T: AstInfo> ExplainPlanStatement<T> {
3962    pub fn stage(&self) -> ExplainStage {
3963        self.stage.unwrap_or(ExplainStage::PhysicalPlan)
3964    }
3965
3966    pub fn format(&self) -> ExplainFormat {
3967        self.format.unwrap_or(ExplainFormat::Text)
3968    }
3969}
3970
3971impl<T: AstInfo> AstDisplay for ExplainPlanStatement<T> {
3972    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3973        f.write_str("EXPLAIN");
3974        if let Some(stage) = &self.stage {
3975            f.write_str(" ");
3976            f.write_node(stage);
3977        }
3978        if !self.with_options.is_empty() {
3979            f.write_str(" WITH (");
3980            f.write_node(&display::comma_separated(&self.with_options));
3981            f.write_str(")");
3982        }
3983        if let Some(format) = &self.format {
3984            f.write_str(" AS ");
3985            f.write_node(format);
3986        }
3987        if self.stage.is_some() {
3988            f.write_str(" FOR");
3989        }
3990        f.write_str(" ");
3991        f.write_node(&self.explainee);
3992    }
3993}
3994impl_display_t!(ExplainPlanStatement);
3995
3996// Note: the `AstDisplay` implementation and `Parser::parse_` method for this
3997// enum are generated automatically by this crate's `build.rs`.
3998#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3999pub enum ExplainPlanOptionName {
4000    Arity,
4001    Cardinality,
4002    ColumnNames,
4003    FilterPushdown,
4004    HumanizedExpressions,
4005    JoinImplementations,
4006    Keys,
4007    LinearChains,
4008    NonNegative,
4009    NoFastPath,
4010    NoNotices,
4011    NodeIdentifiers,
4012    RawPlans,
4013    RawSyntax,
4014    Raw, // Listed after the `Raw~` variants to keep the parser happy!
4015    Redacted,
4016    SubtreeSize,
4017    Timing,
4018    Types,
4019    Equivalences,
4020    ReoptimizeImportedViews,
4021    EnableNewOuterJoinLowering,
4022    EnableEagerDeltaJoins,
4023    EnableVariadicLeftJoinLowering,
4024    EnableLetrecFixpointAnalysis,
4025    EnableJoinPrioritizeArranged,
4026    EnableProjectionPushdownAfterRelationCse,
4027}
4028
4029impl WithOptionName for ExplainPlanOptionName {
4030    /// # WARNING
4031    ///
4032    /// Whenever implementing this trait consider very carefully whether or not
4033    /// this value could contain sensitive user data. If you're uncertain, err
4034    /// on the conservative side and return `true`.
4035    fn redact_value(&self) -> bool {
4036        match self {
4037            Self::Arity
4038            | Self::Cardinality
4039            | Self::ColumnNames
4040            | Self::FilterPushdown
4041            | Self::HumanizedExpressions
4042            | Self::JoinImplementations
4043            | Self::Keys
4044            | Self::LinearChains
4045            | Self::NonNegative
4046            | Self::NoFastPath
4047            | Self::NoNotices
4048            | Self::NodeIdentifiers
4049            | Self::RawPlans
4050            | Self::RawSyntax
4051            | Self::Raw
4052            | Self::Redacted
4053            | Self::SubtreeSize
4054            | Self::Timing
4055            | Self::Types
4056            | Self::Equivalences
4057            | Self::ReoptimizeImportedViews
4058            | Self::EnableNewOuterJoinLowering
4059            | Self::EnableEagerDeltaJoins
4060            | Self::EnableVariadicLeftJoinLowering
4061            | Self::EnableLetrecFixpointAnalysis
4062            | Self::EnableJoinPrioritizeArranged
4063            | Self::EnableProjectionPushdownAfterRelationCse => false,
4064        }
4065    }
4066}
4067
4068#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4069pub struct ExplainPlanOption<T: AstInfo> {
4070    pub name: ExplainPlanOptionName,
4071    pub value: Option<WithOptionValue<T>>,
4072}
4073impl_display_for_with_option!(ExplainPlanOption);
4074
4075#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4076pub enum ExplainSinkSchemaFor {
4077    Key,
4078    Value,
4079}
4080#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4081pub struct ExplainSinkSchemaStatement<T: AstInfo> {
4082    pub schema_for: ExplainSinkSchemaFor,
4083    pub format: Option<ExplainFormat>,
4084    pub statement: CreateSinkStatement<T>,
4085}
4086
4087impl<T: AstInfo> AstDisplay for ExplainSinkSchemaStatement<T> {
4088    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4089        f.write_str("EXPLAIN ");
4090        match &self.schema_for {
4091            ExplainSinkSchemaFor::Key => f.write_str("KEY"),
4092            ExplainSinkSchemaFor::Value => f.write_str("VALUE"),
4093        }
4094        f.write_str(" SCHEMA");
4095        if let Some(format) = &self.format {
4096            f.write_str(" AS ");
4097            f.write_node(format);
4098        }
4099        f.write_str(" FOR ");
4100        f.write_node(&self.statement);
4101    }
4102}
4103impl_display_t!(ExplainSinkSchemaStatement);
4104
4105#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4106pub struct ExplainPushdownStatement<T: AstInfo> {
4107    pub explainee: Explainee<T>,
4108}
4109
4110impl<T: AstInfo> AstDisplay for ExplainPushdownStatement<T> {
4111    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4112        f.write_str("EXPLAIN FILTER PUSHDOWN FOR ");
4113        f.write_node(&self.explainee);
4114    }
4115}
4116impl_display_t!(ExplainPushdownStatement);
4117
4118#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
4119pub enum ExplainAnalyzeComputationProperty {
4120    Cpu,
4121    Memory,
4122}
4123
4124#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4125pub enum ExplainAnalyzeProperty {
4126    Computation(ExplainAnalyzeComputationProperties),
4127    Hints,
4128}
4129
4130#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4131pub struct ExplainAnalyzeComputationProperties {
4132    /// Must be non-empty.
4133    pub properties: Vec<ExplainAnalyzeComputationProperty>,
4134    pub skew: bool,
4135}
4136#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4137pub struct ExplainAnalyzeObjectStatement<T: AstInfo> {
4138    pub properties: ExplainAnalyzeProperty,
4139    /// Should only be `Explainee::Index` or `Explainee::MaterializedView`
4140    pub explainee: Explainee<T>,
4141    pub as_sql: bool,
4142}
4143
4144impl<T: AstInfo> AstDisplay for ExplainAnalyzeObjectStatement<T> {
4145    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4146        f.write_str("EXPLAIN ANALYZE");
4147        match &self.properties {
4148            ExplainAnalyzeProperty::Computation(ExplainAnalyzeComputationProperties {
4149                properties,
4150                skew,
4151            }) => {
4152                let mut first = true;
4153                for property in properties {
4154                    if first {
4155                        first = false;
4156                    } else {
4157                        f.write_str(",");
4158                    }
4159                    match property {
4160                        ExplainAnalyzeComputationProperty::Cpu => f.write_str(" CPU"),
4161                        ExplainAnalyzeComputationProperty::Memory => f.write_str(" MEMORY"),
4162                    }
4163                }
4164                if *skew {
4165                    f.write_str(" WITH SKEW");
4166                }
4167            }
4168            ExplainAnalyzeProperty::Hints => f.write_str(" HINTS"),
4169        }
4170        f.write_str(" FOR ");
4171        f.write_node(&self.explainee);
4172        if self.as_sql {
4173            f.write_str(" AS SQL");
4174        }
4175    }
4176}
4177impl_display_t!(ExplainAnalyzeObjectStatement);
4178
4179#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4180pub struct ExplainAnalyzeClusterStatement {
4181    pub properties: ExplainAnalyzeComputationProperties,
4182    pub as_sql: bool,
4183}
4184
4185impl AstDisplay for ExplainAnalyzeClusterStatement {
4186    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4187        f.write_str("EXPLAIN ANALYZE CLUSTER");
4188
4189        let mut first = true;
4190        for property in &self.properties.properties {
4191            if first {
4192                first = false;
4193            } else {
4194                f.write_str(",");
4195            }
4196            match property {
4197                ExplainAnalyzeComputationProperty::Cpu => f.write_str(" CPU"),
4198                ExplainAnalyzeComputationProperty::Memory => f.write_str(" MEMORY"),
4199            }
4200        }
4201
4202        if self.properties.skew {
4203            f.write_str(" WITH SKEW");
4204        }
4205        if self.as_sql {
4206            f.write_str(" AS SQL");
4207        }
4208    }
4209}
4210impl_display!(ExplainAnalyzeClusterStatement);
4211
4212#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4213pub struct ExplainTimestampStatement<T: AstInfo> {
4214    pub format: Option<ExplainFormat>,
4215    pub select: SelectStatement<T>,
4216}
4217
4218impl<T: AstInfo> ExplainTimestampStatement<T> {
4219    pub fn format(&self) -> ExplainFormat {
4220        self.format.unwrap_or(ExplainFormat::Text)
4221    }
4222}
4223
4224impl<T: AstInfo> AstDisplay for ExplainTimestampStatement<T> {
4225    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4226        f.write_str("EXPLAIN TIMESTAMP");
4227        if let Some(format) = &self.format {
4228            f.write_str(" AS ");
4229            f.write_node(format);
4230        }
4231        f.write_str(" FOR ");
4232        f.write_node(&self.select);
4233    }
4234}
4235impl_display_t!(ExplainTimestampStatement);
4236
4237#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4238pub enum InsertSource<T: AstInfo> {
4239    Query(Query<T>),
4240    DefaultValues,
4241}
4242
4243impl<T: AstInfo> AstDisplay for InsertSource<T> {
4244    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4245        match self {
4246            InsertSource::Query(query) => f.write_node(query),
4247            InsertSource::DefaultValues => f.write_str("DEFAULT VALUES"),
4248        }
4249    }
4250}
4251impl_display_t!(InsertSource);
4252
4253#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
4254pub enum ObjectType {
4255    Table,
4256    View,
4257    MaterializedView,
4258    Source,
4259    Sink,
4260    Index,
4261    Type,
4262    Role,
4263    Cluster,
4264    ClusterReplica,
4265    Secret,
4266    Connection,
4267    Database,
4268    Schema,
4269    Func,
4270    Subsource,
4271    ContinualTask,
4272    NetworkPolicy,
4273}
4274
4275impl ObjectType {
4276    pub fn lives_in_schema(&self) -> bool {
4277        match self {
4278            ObjectType::Table
4279            | ObjectType::View
4280            | ObjectType::MaterializedView
4281            | ObjectType::Source
4282            | ObjectType::Sink
4283            | ObjectType::Index
4284            | ObjectType::Type
4285            | ObjectType::Secret
4286            | ObjectType::Connection
4287            | ObjectType::Func
4288            | ObjectType::Subsource
4289            | ObjectType::ContinualTask => true,
4290            ObjectType::Database
4291            | ObjectType::Schema
4292            | ObjectType::Cluster
4293            | ObjectType::ClusterReplica
4294            | ObjectType::Role
4295            | ObjectType::NetworkPolicy => false,
4296        }
4297    }
4298}
4299
4300impl AstDisplay for ObjectType {
4301    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4302        f.write_str(match self {
4303            ObjectType::Table => "TABLE",
4304            ObjectType::View => "VIEW",
4305            ObjectType::MaterializedView => "MATERIALIZED VIEW",
4306            ObjectType::Source => "SOURCE",
4307            ObjectType::Sink => "SINK",
4308            ObjectType::Index => "INDEX",
4309            ObjectType::Type => "TYPE",
4310            ObjectType::Role => "ROLE",
4311            ObjectType::Cluster => "CLUSTER",
4312            ObjectType::ClusterReplica => "CLUSTER REPLICA",
4313            ObjectType::Secret => "SECRET",
4314            ObjectType::Connection => "CONNECTION",
4315            ObjectType::Database => "DATABASE",
4316            ObjectType::Schema => "SCHEMA",
4317            ObjectType::Func => "FUNCTION",
4318            ObjectType::Subsource => "SUBSOURCE",
4319            ObjectType::ContinualTask => "CONTINUAL TASK",
4320            ObjectType::NetworkPolicy => "NETWORK POLICY",
4321        })
4322    }
4323}
4324impl_display!(ObjectType);
4325
4326#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
4327pub enum SystemObjectType {
4328    System,
4329    Object(ObjectType),
4330}
4331
4332impl AstDisplay for SystemObjectType {
4333    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4334        match self {
4335            SystemObjectType::System => f.write_str("SYSTEM"),
4336            SystemObjectType::Object(object) => f.write_node(object),
4337        }
4338    }
4339}
4340impl_display!(SystemObjectType);
4341
4342#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4343pub enum ShowStatementFilter<T: AstInfo> {
4344    Like(String),
4345    Where(Expr<T>),
4346}
4347
4348impl<T: AstInfo> AstDisplay for ShowStatementFilter<T> {
4349    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4350        use ShowStatementFilter::*;
4351        match self {
4352            Like(pattern) => {
4353                f.write_str("LIKE '");
4354                f.write_node(&display::escape_single_quote_string(pattern));
4355                f.write_str("'");
4356            }
4357            Where(expr) => {
4358                f.write_str("WHERE ");
4359                f.write_node(expr);
4360            }
4361        }
4362    }
4363}
4364impl_display_t!(ShowStatementFilter);
4365
4366#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4367pub enum WithOptionValue<T: AstInfo> {
4368    Value(Value),
4369    DataType(T::DataType),
4370    Secret(T::ItemName),
4371    Item(T::ItemName),
4372    UnresolvedItemName(UnresolvedItemName),
4373    Ident(Ident),
4374    Sequence(Vec<WithOptionValue<T>>),
4375    Map(BTreeMap<String, WithOptionValue<T>>),
4376    // Special cases.
4377    Expr(Expr<T>),
4378    ClusterReplicas(Vec<ReplicaDefinition<T>>),
4379    ConnectionKafkaBroker(KafkaBroker<T>),
4380    ConnectionAwsPrivatelink(ConnectionDefaultAwsPrivatelink<T>),
4381    RetainHistoryFor(Value),
4382    Refresh(RefreshOptionValue<T>),
4383    ClusterScheduleOptionValue(ClusterScheduleOptionValue),
4384    ClusterAlterStrategy(ClusterAlterOptionValue<T>),
4385    NetworkPolicyRules(Vec<NetworkPolicyRuleDefinition<T>>),
4386}
4387
4388impl<T: AstInfo> AstDisplay for WithOptionValue<T> {
4389    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4390        if f.redacted() {
4391            // When adding branches to this match statement, think about whether it is OK for us to collect
4392            // the value as part of our telemetry. Check the data management policy to be sure!
4393            match self {
4394                WithOptionValue::Value(_)
4395                | WithOptionValue::Sequence(_)
4396                | WithOptionValue::Map(_)
4397                | WithOptionValue::RetainHistoryFor(_)
4398                | WithOptionValue::Refresh(_)
4399                | WithOptionValue::Expr(_) => {
4400                    // These are redact-aware.
4401                }
4402                WithOptionValue::Secret(_) | WithOptionValue::ConnectionKafkaBroker(_) => {
4403                    f.write_str("'<REDACTED>'");
4404                    return;
4405                }
4406                WithOptionValue::DataType(_)
4407                | WithOptionValue::Item(_)
4408                | WithOptionValue::UnresolvedItemName(_)
4409                | WithOptionValue::Ident(_)
4410                | WithOptionValue::ConnectionAwsPrivatelink(_)
4411                | WithOptionValue::ClusterReplicas(_)
4412                | WithOptionValue::ClusterScheduleOptionValue(_)
4413                | WithOptionValue::ClusterAlterStrategy(_)
4414                | WithOptionValue::NetworkPolicyRules(_) => {
4415                    // These do not need redaction.
4416                }
4417            }
4418        }
4419        match self {
4420            WithOptionValue::Sequence(values) => {
4421                f.write_str("(");
4422                f.write_node(&display::comma_separated(values));
4423                f.write_str(")");
4424            }
4425            WithOptionValue::Map(values) => {
4426                f.write_str("MAP[");
4427                let len = values.len();
4428                for (i, (key, value)) in values.iter().enumerate() {
4429                    f.write_str("'");
4430                    f.write_node(&display::escape_single_quote_string(key));
4431                    f.write_str("' => ");
4432                    f.write_node(value);
4433                    if i + 1 < len {
4434                        f.write_str(", ");
4435                    }
4436                }
4437                f.write_str("]");
4438            }
4439            WithOptionValue::Expr(e) => f.write_node(e),
4440            WithOptionValue::Value(value) => f.write_node(value),
4441            WithOptionValue::DataType(typ) => f.write_node(typ),
4442            WithOptionValue::Secret(name) => {
4443                f.write_str("SECRET ");
4444                f.write_node(name)
4445            }
4446            WithOptionValue::Item(obj) => f.write_node(obj),
4447            WithOptionValue::UnresolvedItemName(r) => f.write_node(r),
4448            WithOptionValue::Ident(r) => f.write_node(r),
4449            WithOptionValue::ClusterReplicas(replicas) => {
4450                f.write_str("(");
4451                f.write_node(&display::comma_separated(replicas));
4452                f.write_str(")");
4453            }
4454            WithOptionValue::NetworkPolicyRules(rules) => {
4455                f.write_str("(");
4456                f.write_node(&display::comma_separated(rules));
4457                f.write_str(")");
4458            }
4459            WithOptionValue::ConnectionAwsPrivatelink(aws_privatelink) => {
4460                f.write_node(aws_privatelink);
4461            }
4462            WithOptionValue::ConnectionKafkaBroker(broker) => {
4463                f.write_node(broker);
4464            }
4465            WithOptionValue::RetainHistoryFor(value) => {
4466                f.write_str("FOR ");
4467                f.write_node(value);
4468            }
4469            WithOptionValue::Refresh(opt) => f.write_node(opt),
4470            WithOptionValue::ClusterScheduleOptionValue(value) => f.write_node(value),
4471            WithOptionValue::ClusterAlterStrategy(value) => f.write_node(value),
4472        }
4473    }
4474}
4475impl_display_t!(WithOptionValue);
4476
4477#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4478pub enum RefreshOptionValue<T: AstInfo> {
4479    OnCommit,
4480    AtCreation,
4481    At(RefreshAtOptionValue<T>),
4482    Every(RefreshEveryOptionValue<T>),
4483}
4484
4485#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4486pub struct RefreshAtOptionValue<T: AstInfo> {
4487    // We need an Expr because we want to support `mz_now()`.
4488    pub time: Expr<T>,
4489}
4490
4491#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4492pub struct RefreshEveryOptionValue<T: AstInfo> {
4493    // The refresh interval.
4494    pub interval: IntervalValue,
4495    // We need an Expr because we want to support `mz_now()`.
4496    pub aligned_to: Option<Expr<T>>,
4497}
4498
4499impl<T: AstInfo> AstDisplay for RefreshOptionValue<T> {
4500    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4501        match self {
4502            RefreshOptionValue::OnCommit => {
4503                f.write_str("ON COMMIT");
4504            }
4505            RefreshOptionValue::AtCreation => {
4506                f.write_str("AT CREATION");
4507            }
4508            RefreshOptionValue::At(RefreshAtOptionValue { time }) => {
4509                f.write_str("AT ");
4510                f.write_node(time);
4511            }
4512            RefreshOptionValue::Every(RefreshEveryOptionValue {
4513                interval,
4514                aligned_to,
4515            }) => {
4516                f.write_str("EVERY '");
4517                f.write_node(interval);
4518                if let Some(aligned_to) = aligned_to {
4519                    f.write_str(" ALIGNED TO ");
4520                    f.write_node(aligned_to)
4521                }
4522            }
4523        }
4524    }
4525}
4526
4527#[derive(
4528    Debug,
4529    Clone,
4530    PartialEq,
4531    Eq,
4532    Hash,
4533    PartialOrd,
4534    Ord,
4535    Deserialize,
4536    Serialize
4537)]
4538pub enum ClusterScheduleOptionValue {
4539    Manual,
4540    Refresh {
4541        hydration_time_estimate: Option<IntervalValue>,
4542    },
4543}
4544
4545impl Default for ClusterScheduleOptionValue {
4546    fn default() -> Self {
4547        // (Has to be consistent with `impl Default for ClusterSchedule`.)
4548        ClusterScheduleOptionValue::Manual
4549    }
4550}
4551
4552impl AstDisplay for ClusterScheduleOptionValue {
4553    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4554        match self {
4555            ClusterScheduleOptionValue::Manual => {
4556                f.write_str("MANUAL");
4557            }
4558            ClusterScheduleOptionValue::Refresh {
4559                hydration_time_estimate,
4560            } => {
4561                f.write_str("ON REFRESH");
4562                if let Some(hydration_time_estimate) = hydration_time_estimate {
4563                    f.write_str(" (HYDRATION TIME ESTIMATE = '");
4564                    f.write_node(hydration_time_estimate);
4565                    f.write_str(")");
4566                }
4567            }
4568        }
4569    }
4570}
4571
4572#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4573pub enum TransactionMode {
4574    AccessMode(TransactionAccessMode),
4575    IsolationLevel(TransactionIsolationLevel),
4576}
4577
4578impl AstDisplay for TransactionMode {
4579    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4580        use TransactionMode::*;
4581        match self {
4582            AccessMode(access_mode) => f.write_node(access_mode),
4583            IsolationLevel(iso_level) => {
4584                f.write_str("ISOLATION LEVEL ");
4585                f.write_node(iso_level);
4586            }
4587        }
4588    }
4589}
4590impl_display!(TransactionMode);
4591
4592#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4593pub enum TransactionAccessMode {
4594    ReadOnly,
4595    ReadWrite,
4596}
4597
4598impl AstDisplay for TransactionAccessMode {
4599    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4600        use TransactionAccessMode::*;
4601        f.write_str(match self {
4602            ReadOnly => "READ ONLY",
4603            ReadWrite => "READ WRITE",
4604        })
4605    }
4606}
4607impl_display!(TransactionAccessMode);
4608
4609#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
4610pub enum TransactionIsolationLevel {
4611    ReadUncommitted,
4612    ReadCommitted,
4613    RepeatableRead,
4614    Serializable,
4615    StrongSessionSerializable,
4616    StrictSerializable,
4617}
4618
4619impl AstDisplay for TransactionIsolationLevel {
4620    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4621        use TransactionIsolationLevel::*;
4622        f.write_str(match self {
4623            ReadUncommitted => "READ UNCOMMITTED",
4624            ReadCommitted => "READ COMMITTED",
4625            RepeatableRead => "REPEATABLE READ",
4626            Serializable => "SERIALIZABLE",
4627            StrongSessionSerializable => "STRONG SESSION SERIALIZABLE",
4628            StrictSerializable => "STRICT SERIALIZABLE",
4629        })
4630    }
4631}
4632impl_display!(TransactionIsolationLevel);
4633
4634#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4635pub enum SetVariableTo {
4636    Default,
4637    Values(Vec<SetVariableValue>),
4638}
4639
4640impl AstDisplay for SetVariableTo {
4641    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4642        use SetVariableTo::*;
4643        match self {
4644            Values(values) => f.write_node(&display::comma_separated(values)),
4645            Default => f.write_str("DEFAULT"),
4646        }
4647    }
4648}
4649impl_display!(SetVariableTo);
4650
4651#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4652pub enum SetVariableValue {
4653    Ident(Ident),
4654    Literal(Value),
4655}
4656
4657impl AstDisplay for SetVariableValue {
4658    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4659        use SetVariableValue::*;
4660        match self {
4661            Ident(ident) => f.write_node(ident),
4662            Literal(literal) => f.write_node(literal),
4663        }
4664    }
4665}
4666impl_display!(SetVariableValue);
4667
4668impl SetVariableValue {
4669    /// Returns the underlying value without quotes.
4670    pub fn into_unquoted_value(self) -> String {
4671        match self {
4672            // `lit.to_string` will quote a `Value::String`, so get the unquoted
4673            // version.
4674            SetVariableValue::Literal(Value::String(s)) => s,
4675            SetVariableValue::Literal(lit) => lit.to_string(),
4676            SetVariableValue::Ident(ident) => ident.into_string(),
4677        }
4678    }
4679}
4680
4681/// SQL assignment `foo = expr` as used in SQLUpdate
4682#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4683pub struct Assignment<T: AstInfo> {
4684    pub id: Ident,
4685    pub value: Expr<T>,
4686}
4687
4688impl<T: AstInfo> AstDisplay for Assignment<T> {
4689    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4690        f.write_node(&self.id);
4691        f.write_str(" = ");
4692        f.write_node(&self.value);
4693    }
4694}
4695impl_display_t!(Assignment);
4696
4697/// Specifies what [Statement::ExplainPlan] is actually explained.
4698#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4699pub enum ExplainStage {
4700    /// The mz_sql::HirRelationExpr after parsing
4701    RawPlan,
4702    /// The mz_expr::MirRelationExpr after decorrelation
4703    DecorrelatedPlan,
4704    /// The mz_expr::MirRelationExpr after local optimization
4705    LocalPlan,
4706    /// The mz_expr::MirRelationExpr after global optimization
4707    GlobalPlan,
4708    /// The mz_compute_types::plan::Plan
4709    PhysicalPlan,
4710    /// The complete trace of the plan through the optimizer
4711    Trace,
4712    /// Insights about the plan
4713    PlanInsights,
4714}
4715
4716impl ExplainStage {
4717    /// Return the tracing path that corresponds to a given stage.
4718    pub fn paths(&self) -> Option<SmallVec<[NamedPlan; 4]>> {
4719        use NamedPlan::*;
4720        match self {
4721            Self::RawPlan => Some(smallvec![Raw]),
4722            Self::DecorrelatedPlan => Some(smallvec![Decorrelated]),
4723            Self::LocalPlan => Some(smallvec![Local]),
4724            Self::GlobalPlan => Some(smallvec![Global]),
4725            Self::PhysicalPlan => Some(smallvec![Physical]),
4726            Self::Trace => None,
4727            Self::PlanInsights => Some(smallvec![Raw, Global, FastPath]),
4728        }
4729    }
4730
4731    // Whether instead of the plan associated with this [`ExplainStage`] we
4732    // should show the [`NamedPlan::FastPath`] plan if available.
4733    pub fn show_fast_path(&self) -> bool {
4734        match self {
4735            Self::RawPlan => false,
4736            Self::DecorrelatedPlan => false,
4737            Self::LocalPlan => false,
4738            Self::GlobalPlan => true,
4739            Self::PhysicalPlan => true,
4740            Self::Trace => false,
4741            Self::PlanInsights => false,
4742        }
4743    }
4744}
4745
4746impl AstDisplay for ExplainStage {
4747    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4748        match self {
4749            Self::RawPlan => f.write_str("RAW PLAN"),
4750            Self::DecorrelatedPlan => f.write_str("DECORRELATED PLAN"),
4751            Self::LocalPlan => f.write_str("LOCALLY OPTIMIZED PLAN"),
4752            Self::GlobalPlan => f.write_str("OPTIMIZED PLAN"),
4753            Self::PhysicalPlan => f.write_str("PHYSICAL PLAN"),
4754            Self::Trace => f.write_str("OPTIMIZER TRACE"),
4755            Self::PlanInsights => f.write_str("PLAN INSIGHTS"),
4756        }
4757    }
4758}
4759impl_display!(ExplainStage);
4760
4761/// An enum of named plans that identifies specific stages in an optimizer trace
4762/// where these plans can be found.
4763#[derive(Clone)]
4764pub enum NamedPlan {
4765    Raw,
4766    Decorrelated,
4767    Local,
4768    Global,
4769    Physical,
4770    FastPath,
4771}
4772
4773impl NamedPlan {
4774    /// Return the [`NamedPlan`] for a given `path` if it exists.
4775    pub fn of_path(value: &str) -> Option<Self> {
4776        match value {
4777            "optimize/raw" => Some(Self::Raw),
4778            "optimize/hir_to_mir" => Some(Self::Decorrelated),
4779            "optimize/local" => Some(Self::Local),
4780            "optimize/global" => Some(Self::Global),
4781            "optimize/finalize_dataflow" => Some(Self::Physical),
4782            "optimize/fast_path" => Some(Self::FastPath),
4783            _ => None,
4784        }
4785    }
4786
4787    /// Return the tracing path under which the plan can be found in an
4788    /// optimizer trace.
4789    pub fn path(&self) -> &'static str {
4790        match self {
4791            Self::Raw => "optimize/raw",
4792            Self::Decorrelated => "optimize/hir_to_mir",
4793            Self::Local => "optimize/local",
4794            Self::Global => "optimize/global",
4795            Self::Physical => "optimize/finalize_dataflow",
4796            Self::FastPath => "optimize/fast_path",
4797        }
4798    }
4799}
4800
4801/// What is being explained.
4802/// The bools mean whether this is an EXPLAIN BROKEN.
4803#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4804pub enum Explainee<T: AstInfo> {
4805    View(T::ItemName),
4806    MaterializedView(T::ItemName),
4807    Index(T::ItemName),
4808    ReplanView(T::ItemName),
4809    ReplanMaterializedView(T::ItemName),
4810    ReplanIndex(T::ItemName),
4811    Select(Box<SelectStatement<T>>, bool),
4812    CreateView(Box<CreateViewStatement<T>>, bool),
4813    CreateMaterializedView(Box<CreateMaterializedViewStatement<T>>, bool),
4814    CreateIndex(Box<CreateIndexStatement<T>>, bool),
4815    Subscribe(Box<SubscribeStatement<T>>, bool),
4816}
4817
4818impl<T: AstInfo> Explainee<T> {
4819    pub fn name(&self) -> Option<&T::ItemName> {
4820        match self {
4821            Self::View(name)
4822            | Self::ReplanView(name)
4823            | Self::MaterializedView(name)
4824            | Self::ReplanMaterializedView(name)
4825            | Self::Index(name)
4826            | Self::ReplanIndex(name) => Some(name),
4827            Self::Select(..)
4828            | Self::CreateView(..)
4829            | Self::CreateMaterializedView(..)
4830            | Self::CreateIndex(..)
4831            | Self::Subscribe(..) => None,
4832        }
4833    }
4834
4835    pub fn is_view(&self) -> bool {
4836        use Explainee::*;
4837        matches!(self, View(_) | ReplanView(_) | CreateView(_, _))
4838    }
4839}
4840
4841impl<T: AstInfo> AstDisplay for Explainee<T> {
4842    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4843        match self {
4844            Self::View(name) => {
4845                f.write_str("VIEW ");
4846                f.write_node(name);
4847            }
4848            Self::MaterializedView(name) => {
4849                f.write_str("MATERIALIZED VIEW ");
4850                f.write_node(name);
4851            }
4852            Self::Index(name) => {
4853                f.write_str("INDEX ");
4854                f.write_node(name);
4855            }
4856            Self::ReplanView(name) => {
4857                f.write_str("REPLAN VIEW ");
4858                f.write_node(name);
4859            }
4860            Self::ReplanMaterializedView(name) => {
4861                f.write_str("REPLAN MATERIALIZED VIEW ");
4862                f.write_node(name);
4863            }
4864            Self::ReplanIndex(name) => {
4865                f.write_str("REPLAN INDEX ");
4866                f.write_node(name);
4867            }
4868            Self::Select(select, broken) => {
4869                if *broken {
4870                    f.write_str("BROKEN ");
4871                }
4872                f.write_node(select);
4873            }
4874            Self::CreateView(statement, broken) => {
4875                if *broken {
4876                    f.write_str("BROKEN ");
4877                }
4878                f.write_node(statement);
4879            }
4880            Self::CreateMaterializedView(statement, broken) => {
4881                if *broken {
4882                    f.write_str("BROKEN ");
4883                }
4884                f.write_node(statement);
4885            }
4886            Self::CreateIndex(statement, broken) => {
4887                if *broken {
4888                    f.write_str("BROKEN ");
4889                }
4890                f.write_node(statement);
4891            }
4892            Self::Subscribe(statement, broken) => {
4893                if *broken {
4894                    f.write_str("BROKEN ");
4895                }
4896                f.write_node(statement);
4897            }
4898        }
4899    }
4900}
4901impl_display_t!(Explainee);
4902
4903#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
4904pub enum ExplainFormat {
4905    /// Human readable display format
4906    Text,
4907    /// Human readable display format with full debug information
4908    VerboseText,
4909    /// Machine-consumable JSON format
4910    Json,
4911    /// Machine-consumable DOT (graphviz) format
4912    Dot,
4913}
4914
4915impl AstDisplay for ExplainFormat {
4916    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4917        match self {
4918            Self::Text => f.write_str("TEXT"),
4919            Self::VerboseText => f.write_str("VERBOSE TEXT"),
4920            Self::Json => f.write_str("JSON"),
4921            Self::Dot => f.write_str("DOT"),
4922        }
4923    }
4924}
4925impl_display!(ExplainFormat);
4926
4927#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4928pub enum IfExistsBehavior {
4929    Error,
4930    Skip,
4931    Replace,
4932}
4933
4934/// `DECLARE ...`
4935#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4936pub struct DeclareStatement<T: AstInfo> {
4937    pub name: Ident,
4938    pub stmt: Box<T::NestedStatement>,
4939    pub sql: String,
4940}
4941
4942impl<T: AstInfo> AstDisplay for DeclareStatement<T> {
4943    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4944        f.write_str("DECLARE ");
4945        f.write_node(&self.name);
4946        f.write_str(" CURSOR FOR ");
4947        f.write_node(&self.stmt);
4948    }
4949}
4950impl_display_t!(DeclareStatement);
4951
4952/// `CLOSE ...`
4953#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4954pub struct CloseStatement {
4955    pub name: Ident,
4956}
4957
4958impl AstDisplay for CloseStatement {
4959    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4960        f.write_str("CLOSE ");
4961        f.write_node(&self.name);
4962    }
4963}
4964impl_display!(CloseStatement);
4965
4966#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4967pub enum FetchOptionName {
4968    Timeout,
4969}
4970
4971impl AstDisplay for FetchOptionName {
4972    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4973        f.write_str(match self {
4974            FetchOptionName::Timeout => "TIMEOUT",
4975        })
4976    }
4977}
4978
4979impl WithOptionName for FetchOptionName {
4980    /// # WARNING
4981    ///
4982    /// Whenever implementing this trait consider very carefully whether or not
4983    /// this value could contain sensitive user data. If you're uncertain, err
4984    /// on the conservative side and return `true`.
4985    fn redact_value(&self) -> bool {
4986        match self {
4987            FetchOptionName::Timeout => false,
4988        }
4989    }
4990}
4991
4992#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4993pub struct FetchOption<T: AstInfo> {
4994    pub name: FetchOptionName,
4995    pub value: Option<WithOptionValue<T>>,
4996}
4997impl_display_for_with_option!(FetchOption);
4998
4999/// `FETCH ...`
5000#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5001pub struct FetchStatement<T: AstInfo> {
5002    pub name: Ident,
5003    pub count: Option<FetchDirection>,
5004    pub options: Vec<FetchOption<T>>,
5005}
5006
5007impl<T: AstInfo> AstDisplay for FetchStatement<T> {
5008    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5009        f.write_str("FETCH ");
5010        if let Some(ref count) = self.count {
5011            f.write_str(format!("{} ", count));
5012        }
5013        f.write_node(&self.name);
5014        if !self.options.is_empty() {
5015            f.write_str(" WITH (");
5016            f.write_node(&display::comma_separated(&self.options));
5017            f.write_str(")");
5018        }
5019    }
5020}
5021impl_display_t!(FetchStatement);
5022
5023#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5024pub enum FetchDirection {
5025    ForwardAll,
5026    ForwardCount(u64),
5027}
5028
5029impl AstDisplay for FetchDirection {
5030    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5031        match self {
5032            FetchDirection::ForwardAll => f.write_str("ALL"),
5033            FetchDirection::ForwardCount(count) => f.write_str(format!("{}", count)),
5034        }
5035    }
5036}
5037impl_display!(FetchDirection);
5038
5039/// `PREPARE ...`
5040#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5041pub struct PrepareStatement<T: AstInfo> {
5042    pub name: Ident,
5043    pub stmt: Box<T::NestedStatement>,
5044    pub sql: String,
5045}
5046
5047impl<T: AstInfo> AstDisplay for PrepareStatement<T> {
5048    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5049        f.write_str("PREPARE ");
5050        f.write_node(&self.name);
5051        f.write_str(" AS ");
5052        f.write_node(&self.stmt);
5053    }
5054}
5055impl_display_t!(PrepareStatement);
5056
5057/// `EXECUTE ...`
5058#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5059pub struct ExecuteStatement<T: AstInfo> {
5060    pub name: Ident,
5061    pub params: Vec<Expr<T>>,
5062}
5063
5064impl<T: AstInfo> AstDisplay for ExecuteStatement<T> {
5065    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5066        f.write_str("EXECUTE ");
5067        f.write_node(&self.name);
5068        if !self.params.is_empty() {
5069            f.write_str(" (");
5070            f.write_node(&display::comma_separated(&self.params));
5071            f.write_str(")");
5072        }
5073    }
5074}
5075impl_display_t!(ExecuteStatement);
5076
5077/// `DEALLOCATE ...`
5078#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5079pub struct DeallocateStatement {
5080    pub name: Option<Ident>,
5081}
5082
5083impl AstDisplay for DeallocateStatement {
5084    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5085        f.write_str("DEALLOCATE ");
5086        match &self.name {
5087            Some(name) => f.write_node(name),
5088            None => f.write_str("ALL"),
5089        };
5090    }
5091}
5092impl_display!(DeallocateStatement);
5093
5094/// `RAISE ...`
5095#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5096pub struct RaiseStatement {
5097    pub severity: NoticeSeverity,
5098}
5099
5100impl AstDisplay for RaiseStatement {
5101    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5102        f.write_str("RAISE ");
5103        f.write_node(&self.severity);
5104    }
5105}
5106impl_display!(RaiseStatement);
5107
5108#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5109pub enum NoticeSeverity {
5110    Debug,
5111    Info,
5112    Log,
5113    Notice,
5114    Warning,
5115}
5116
5117impl AstDisplay for NoticeSeverity {
5118    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5119        f.write_str(match self {
5120            NoticeSeverity::Debug => "DEBUG",
5121            NoticeSeverity::Info => "INFO",
5122            NoticeSeverity::Log => "LOG",
5123            NoticeSeverity::Notice => "NOTICE",
5124            NoticeSeverity::Warning => "WARNING",
5125        })
5126    }
5127}
5128impl_display!(NoticeSeverity);
5129
5130/// `ALTER SYSTEM SET ...`
5131#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5132pub struct AlterSystemSetStatement {
5133    pub name: Ident,
5134    pub to: SetVariableTo,
5135}
5136
5137impl AstDisplay for AlterSystemSetStatement {
5138    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5139        f.write_str("ALTER SYSTEM SET ");
5140        f.write_node(&self.name);
5141        f.write_str(" = ");
5142        f.write_node(&self.to);
5143    }
5144}
5145impl_display!(AlterSystemSetStatement);
5146
5147/// `ALTER SYSTEM RESET ...`
5148#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5149pub struct AlterSystemResetStatement {
5150    pub name: Ident,
5151}
5152
5153impl AstDisplay for AlterSystemResetStatement {
5154    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5155        f.write_str("ALTER SYSTEM RESET ");
5156        f.write_node(&self.name);
5157    }
5158}
5159impl_display!(AlterSystemResetStatement);
5160
5161/// `ALTER SYSTEM RESET ALL`
5162#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5163pub struct AlterSystemResetAllStatement {}
5164
5165impl AstDisplay for AlterSystemResetAllStatement {
5166    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5167        f.write_str("ALTER SYSTEM RESET ALL");
5168    }
5169}
5170impl_display!(AlterSystemResetAllStatement);
5171
5172#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5173pub enum AsOf<T: AstInfo> {
5174    At(Expr<T>),
5175    AtLeast(Expr<T>),
5176}
5177
5178impl<T: AstInfo> AstDisplay for AsOf<T> {
5179    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5180        f.write_str("AS OF ");
5181        match self {
5182            AsOf::At(expr) => f.write_node(expr),
5183            AsOf::AtLeast(expr) => {
5184                f.write_str("AT LEAST ");
5185                f.write_node(expr);
5186            }
5187        }
5188    }
5189}
5190impl_display_t!(AsOf);
5191
5192#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
5193pub enum ShowStatement<T: AstInfo> {
5194    ShowObjects(ShowObjectsStatement<T>),
5195    ShowColumns(ShowColumnsStatement<T>),
5196    ShowCreateView(ShowCreateViewStatement<T>),
5197    ShowCreateMaterializedView(ShowCreateMaterializedViewStatement<T>),
5198    ShowCreateSource(ShowCreateSourceStatement<T>),
5199    ShowCreateTable(ShowCreateTableStatement<T>),
5200    ShowCreateSink(ShowCreateSinkStatement<T>),
5201    ShowCreateIndex(ShowCreateIndexStatement<T>),
5202    ShowCreateConnection(ShowCreateConnectionStatement<T>),
5203    ShowCreateCluster(ShowCreateClusterStatement<T>),
5204    ShowCreateType(ShowCreateTypeStatement<T>),
5205    ShowVariable(ShowVariableStatement),
5206    InspectShard(InspectShardStatement),
5207}
5208
5209impl<T: AstInfo> AstDisplay for ShowStatement<T> {
5210    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5211        match self {
5212            ShowStatement::ShowObjects(stmt) => f.write_node(stmt),
5213            ShowStatement::ShowColumns(stmt) => f.write_node(stmt),
5214            ShowStatement::ShowCreateView(stmt) => f.write_node(stmt),
5215            ShowStatement::ShowCreateMaterializedView(stmt) => f.write_node(stmt),
5216            ShowStatement::ShowCreateSource(stmt) => f.write_node(stmt),
5217            ShowStatement::ShowCreateTable(stmt) => f.write_node(stmt),
5218            ShowStatement::ShowCreateSink(stmt) => f.write_node(stmt),
5219            ShowStatement::ShowCreateIndex(stmt) => f.write_node(stmt),
5220            ShowStatement::ShowCreateConnection(stmt) => f.write_node(stmt),
5221            ShowStatement::ShowCreateCluster(stmt) => f.write_node(stmt),
5222            ShowStatement::ShowCreateType(stmt) => f.write_node(stmt),
5223            ShowStatement::ShowVariable(stmt) => f.write_node(stmt),
5224            ShowStatement::InspectShard(stmt) => f.write_node(stmt),
5225        }
5226    }
5227}
5228impl_display_t!(ShowStatement);
5229
5230/// `GRANT ...`
5231#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5232pub struct GrantRoleStatement<T: AstInfo> {
5233    /// The roles that are gaining members.
5234    pub role_names: Vec<T::RoleName>,
5235    /// The roles that will be added to `role_name`.
5236    pub member_names: Vec<T::RoleName>,
5237}
5238
5239impl<T: AstInfo> AstDisplay for GrantRoleStatement<T> {
5240    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5241        f.write_str("GRANT ");
5242        f.write_node(&display::comma_separated(&self.role_names));
5243        f.write_str(" TO ");
5244        f.write_node(&display::comma_separated(&self.member_names));
5245    }
5246}
5247impl_display_t!(GrantRoleStatement);
5248
5249/// `REVOKE ...`
5250#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5251pub struct RevokeRoleStatement<T: AstInfo> {
5252    /// The roles that are losing members.
5253    pub role_names: Vec<T::RoleName>,
5254    /// The roles that will be removed from `role_name`.
5255    pub member_names: Vec<T::RoleName>,
5256}
5257
5258impl<T: AstInfo> AstDisplay for RevokeRoleStatement<T> {
5259    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5260        f.write_str("REVOKE ");
5261        f.write_node(&display::comma_separated(&self.role_names));
5262        f.write_str(" FROM ");
5263        f.write_node(&display::comma_separated(&self.member_names));
5264    }
5265}
5266impl_display_t!(RevokeRoleStatement);
5267
5268#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5269pub enum Privilege {
5270    SELECT,
5271    INSERT,
5272    UPDATE,
5273    DELETE,
5274    USAGE,
5275    CREATE,
5276    CREATEROLE,
5277    CREATEDB,
5278    CREATECLUSTER,
5279    CREATENETWORKPOLICY,
5280}
5281
5282impl AstDisplay for Privilege {
5283    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5284        f.write_str(match self {
5285            Privilege::SELECT => "SELECT",
5286            Privilege::INSERT => "INSERT",
5287            Privilege::UPDATE => "UPDATE",
5288            Privilege::DELETE => "DELETE",
5289            Privilege::CREATE => "CREATE",
5290            Privilege::USAGE => "USAGE",
5291            Privilege::CREATEROLE => "CREATEROLE",
5292            Privilege::CREATEDB => "CREATEDB",
5293            Privilege::CREATECLUSTER => "CREATECLUSTER",
5294            Privilege::CREATENETWORKPOLICY => "CREATENETWORKPOLICY",
5295        });
5296    }
5297}
5298impl_display!(Privilege);
5299
5300#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5301pub enum PrivilegeSpecification {
5302    All,
5303    Privileges(Vec<Privilege>),
5304}
5305
5306impl AstDisplay for PrivilegeSpecification {
5307    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5308        match self {
5309            PrivilegeSpecification::All => f.write_str("ALL"),
5310            PrivilegeSpecification::Privileges(privileges) => {
5311                f.write_node(&display::comma_separated(privileges))
5312            }
5313        }
5314    }
5315}
5316impl_display!(PrivilegeSpecification);
5317
5318#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5319pub enum GrantTargetSpecification<T: AstInfo> {
5320    Object {
5321        /// The type of object.
5322        ///
5323        /// Note: For views, materialized views, and sources this will be [`ObjectType::Table`].
5324        object_type: ObjectType,
5325        /// Specification of each object affected.
5326        object_spec_inner: GrantTargetSpecificationInner<T>,
5327    },
5328    System,
5329}
5330
5331#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5332pub enum GrantTargetSpecificationInner<T: AstInfo> {
5333    All(GrantTargetAllSpecification<T>),
5334    Objects { names: Vec<T::ObjectName> },
5335}
5336
5337#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5338pub enum GrantTargetAllSpecification<T: AstInfo> {
5339    All,
5340    AllDatabases { databases: Vec<T::DatabaseName> },
5341    AllSchemas { schemas: Vec<T::SchemaName> },
5342}
5343
5344impl<T: AstInfo> GrantTargetAllSpecification<T> {
5345    pub fn len(&self) -> usize {
5346        match self {
5347            GrantTargetAllSpecification::All => 1,
5348            GrantTargetAllSpecification::AllDatabases { databases } => databases.len(),
5349            GrantTargetAllSpecification::AllSchemas { schemas } => schemas.len(),
5350        }
5351    }
5352}
5353
5354impl<T: AstInfo> AstDisplay for GrantTargetSpecification<T> {
5355    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5356        match self {
5357            GrantTargetSpecification::Object {
5358                object_type,
5359                object_spec_inner,
5360            } => match object_spec_inner {
5361                GrantTargetSpecificationInner::All(all_spec) => match all_spec {
5362                    GrantTargetAllSpecification::All => {
5363                        f.write_str("ALL ");
5364                        f.write_node(object_type);
5365                        f.write_str("S");
5366                    }
5367                    GrantTargetAllSpecification::AllDatabases { databases } => {
5368                        f.write_str("ALL ");
5369                        f.write_node(object_type);
5370                        f.write_str("S IN DATABASE ");
5371                        f.write_node(&display::comma_separated(databases));
5372                    }
5373                    GrantTargetAllSpecification::AllSchemas { schemas } => {
5374                        f.write_str("ALL ");
5375                        f.write_node(object_type);
5376                        f.write_str("S IN SCHEMA ");
5377                        f.write_node(&display::comma_separated(schemas));
5378                    }
5379                },
5380                GrantTargetSpecificationInner::Objects { names } => {
5381                    f.write_node(object_type);
5382                    f.write_str(" ");
5383                    f.write_node(&display::comma_separated(names));
5384                }
5385            },
5386            GrantTargetSpecification::System => f.write_str("SYSTEM"),
5387        }
5388    }
5389}
5390impl_display_t!(GrantTargetSpecification);
5391
5392/// `GRANT ...`
5393#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5394pub struct GrantPrivilegesStatement<T: AstInfo> {
5395    /// The privileges being granted on an object.
5396    pub privileges: PrivilegeSpecification,
5397    /// The objects that are affected by the GRANT.
5398    pub target: GrantTargetSpecification<T>,
5399    /// The roles that will granted the privileges.
5400    pub roles: Vec<T::RoleName>,
5401}
5402
5403impl<T: AstInfo> AstDisplay for GrantPrivilegesStatement<T> {
5404    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5405        f.write_str("GRANT ");
5406        f.write_node(&self.privileges);
5407        f.write_str(" ON ");
5408        f.write_node(&self.target);
5409        f.write_str(" TO ");
5410        f.write_node(&display::comma_separated(&self.roles));
5411    }
5412}
5413impl_display_t!(GrantPrivilegesStatement);
5414
5415/// `REVOKE ...`
5416#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5417pub struct RevokePrivilegesStatement<T: AstInfo> {
5418    /// The privileges being revoked.
5419    pub privileges: PrivilegeSpecification,
5420    /// The objects that are affected by the REVOKE.
5421    pub target: GrantTargetSpecification<T>,
5422    /// The roles that will have privileges revoked.
5423    pub roles: Vec<T::RoleName>,
5424}
5425
5426impl<T: AstInfo> AstDisplay for RevokePrivilegesStatement<T> {
5427    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5428        f.write_str("REVOKE ");
5429        f.write_node(&self.privileges);
5430        f.write_str(" ON ");
5431        f.write_node(&self.target);
5432        f.write_str(" FROM ");
5433        f.write_node(&display::comma_separated(&self.roles));
5434    }
5435}
5436impl_display_t!(RevokePrivilegesStatement);
5437
5438#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5439pub enum TargetRoleSpecification<T: AstInfo> {
5440    /// Specific list of roles.
5441    Roles(Vec<T::RoleName>),
5442    /// All current and future roles.
5443    AllRoles,
5444}
5445
5446impl<T: AstInfo> AstDisplay for TargetRoleSpecification<T> {
5447    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5448        match self {
5449            TargetRoleSpecification::Roles(roles) => f.write_node(&display::comma_separated(roles)),
5450            TargetRoleSpecification::AllRoles => f.write_str("ALL ROLES"),
5451        }
5452    }
5453}
5454impl_display_t!(TargetRoleSpecification);
5455
5456#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5457pub struct AbbreviatedGrantStatement<T: AstInfo> {
5458    /// The privileges being granted.
5459    pub privileges: PrivilegeSpecification,
5460    /// The type of object.
5461    ///
5462    /// Note: For views, materialized views, and sources this will be [`ObjectType::Table`].
5463    pub object_type: ObjectType,
5464    /// The roles that will granted the privileges.
5465    pub grantees: Vec<T::RoleName>,
5466}
5467
5468impl<T: AstInfo> AstDisplay for AbbreviatedGrantStatement<T> {
5469    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5470        f.write_str("GRANT ");
5471        f.write_node(&self.privileges);
5472        f.write_str(" ON ");
5473        f.write_node(&self.object_type);
5474        f.write_str("S TO ");
5475        f.write_node(&display::comma_separated(&self.grantees));
5476    }
5477}
5478impl_display_t!(AbbreviatedGrantStatement);
5479
5480#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5481pub struct AbbreviatedRevokeStatement<T: AstInfo> {
5482    /// The privileges being revoked.
5483    pub privileges: PrivilegeSpecification,
5484    /// The type of object.
5485    ///
5486    /// Note: For views, materialized views, and sources this will be [`ObjectType::Table`].
5487    pub object_type: ObjectType,
5488    /// The roles that the privilege will be revoked from.
5489    pub revokees: Vec<T::RoleName>,
5490}
5491
5492impl<T: AstInfo> AstDisplay for AbbreviatedRevokeStatement<T> {
5493    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5494        f.write_str("REVOKE ");
5495        f.write_node(&self.privileges);
5496        f.write_str(" ON ");
5497        f.write_node(&self.object_type);
5498        f.write_str("S FROM ");
5499        f.write_node(&display::comma_separated(&self.revokees));
5500    }
5501}
5502impl_display_t!(AbbreviatedRevokeStatement);
5503
5504#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5505pub enum AbbreviatedGrantOrRevokeStatement<T: AstInfo> {
5506    Grant(AbbreviatedGrantStatement<T>),
5507    Revoke(AbbreviatedRevokeStatement<T>),
5508}
5509
5510impl<T: AstInfo> AbbreviatedGrantOrRevokeStatement<T> {
5511    pub fn privileges(&self) -> &PrivilegeSpecification {
5512        match self {
5513            AbbreviatedGrantOrRevokeStatement::Grant(grant) => &grant.privileges,
5514            AbbreviatedGrantOrRevokeStatement::Revoke(revoke) => &revoke.privileges,
5515        }
5516    }
5517
5518    pub fn object_type(&self) -> &ObjectType {
5519        match self {
5520            AbbreviatedGrantOrRevokeStatement::Grant(grant) => &grant.object_type,
5521            AbbreviatedGrantOrRevokeStatement::Revoke(revoke) => &revoke.object_type,
5522        }
5523    }
5524
5525    pub fn roles(&self) -> &Vec<T::RoleName> {
5526        match self {
5527            AbbreviatedGrantOrRevokeStatement::Grant(grant) => &grant.grantees,
5528            AbbreviatedGrantOrRevokeStatement::Revoke(revoke) => &revoke.revokees,
5529        }
5530    }
5531}
5532
5533impl<T: AstInfo> AstDisplay for AbbreviatedGrantOrRevokeStatement<T> {
5534    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5535        match self {
5536            AbbreviatedGrantOrRevokeStatement::Grant(grant) => f.write_node(grant),
5537            AbbreviatedGrantOrRevokeStatement::Revoke(revoke) => f.write_node(revoke),
5538        }
5539    }
5540}
5541impl_display_t!(AbbreviatedGrantOrRevokeStatement);
5542
5543/// `ALTER DEFAULT PRIVILEGES ...`
5544#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5545pub struct AlterDefaultPrivilegesStatement<T: AstInfo> {
5546    /// The roles for which created objects are affected.
5547    pub target_roles: TargetRoleSpecification<T>,
5548    /// The objects that are affected by the default privilege.
5549    pub target_objects: GrantTargetAllSpecification<T>,
5550    /// The privilege to grant or revoke.
5551    pub grant_or_revoke: AbbreviatedGrantOrRevokeStatement<T>,
5552}
5553
5554impl<T: AstInfo> AstDisplay for AlterDefaultPrivilegesStatement<T> {
5555    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5556        f.write_str("ALTER DEFAULT PRIVILEGES");
5557        match &self.target_roles {
5558            TargetRoleSpecification::Roles(_) => {
5559                f.write_str(" FOR ROLE ");
5560                f.write_node(&self.target_roles);
5561            }
5562            TargetRoleSpecification::AllRoles => {
5563                f.write_str(" FOR ");
5564                f.write_node(&self.target_roles);
5565            }
5566        }
5567        match &self.target_objects {
5568            GrantTargetAllSpecification::All => {}
5569            GrantTargetAllSpecification::AllDatabases { databases } => {
5570                f.write_str(" IN DATABASE ");
5571                f.write_node(&display::comma_separated(databases));
5572            }
5573            GrantTargetAllSpecification::AllSchemas { schemas } => {
5574                f.write_str(" IN SCHEMA ");
5575                f.write_node(&display::comma_separated(schemas));
5576            }
5577        }
5578        f.write_str(" ");
5579        f.write_node(&self.grant_or_revoke);
5580    }
5581}
5582impl_display_t!(AlterDefaultPrivilegesStatement);
5583
5584/// `REASSIGN OWNED ...`
5585#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5586pub struct ReassignOwnedStatement<T: AstInfo> {
5587    /// The roles whose owned objects are being reassigned.
5588    pub old_roles: Vec<T::RoleName>,
5589    /// The new owner of the objects.
5590    pub new_role: T::RoleName,
5591}
5592
5593impl<T: AstInfo> AstDisplay for ReassignOwnedStatement<T> {
5594    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5595        f.write_str("REASSIGN OWNED BY ");
5596        f.write_node(&display::comma_separated(&self.old_roles));
5597        f.write_str(" TO ");
5598        f.write_node(&self.new_role);
5599    }
5600}
5601impl_display_t!(ReassignOwnedStatement);
5602
5603/// `COMMENT ON ...`
5604#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5605pub struct CommentStatement<T: AstInfo> {
5606    pub object: CommentObjectType<T>,
5607    pub comment: Option<String>,
5608}
5609
5610impl<T: AstInfo> AstDisplay for CommentStatement<T> {
5611    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5612        f.write_str("COMMENT ON ");
5613        f.write_node(&self.object);
5614
5615        f.write_str(" IS ");
5616        match &self.comment {
5617            Some(s) => {
5618                f.write_str("'");
5619                f.write_node(&display::escape_single_quote_string(s));
5620                f.write_str("'");
5621            }
5622            None => f.write_str("NULL"),
5623        }
5624    }
5625}
5626impl_display_t!(CommentStatement);
5627
5628#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
5629pub struct ColumnName<T: AstInfo> {
5630    pub relation: T::ItemName,
5631    pub column: T::ColumnReference,
5632}
5633
5634impl<T: AstInfo> AstDisplay for ColumnName<T> {
5635    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5636        f.write_node(&self.relation);
5637        f.write_str(".");
5638        f.write_node(&self.column);
5639    }
5640}
5641impl_display_t!(ColumnName);
5642
5643#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5644pub enum CommentObjectType<T: AstInfo> {
5645    Table { name: T::ItemName },
5646    View { name: T::ItemName },
5647    Column { name: ColumnName<T> },
5648    MaterializedView { name: T::ItemName },
5649    Source { name: T::ItemName },
5650    Sink { name: T::ItemName },
5651    Index { name: T::ItemName },
5652    Func { name: T::ItemName },
5653    Connection { name: T::ItemName },
5654    Type { ty: T::DataType },
5655    Secret { name: T::ItemName },
5656    Role { name: T::RoleName },
5657    Database { name: T::DatabaseName },
5658    Schema { name: T::SchemaName },
5659    Cluster { name: T::ClusterName },
5660    ClusterReplica { name: QualifiedReplica },
5661    ContinualTask { name: T::ItemName },
5662    NetworkPolicy { name: T::NetworkPolicyName },
5663}
5664
5665impl<T: AstInfo> AstDisplay for CommentObjectType<T> {
5666    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5667        use CommentObjectType::*;
5668
5669        match self {
5670            Table { name } => {
5671                f.write_str("TABLE ");
5672                f.write_node(name);
5673            }
5674            View { name } => {
5675                f.write_str("VIEW ");
5676                f.write_node(name);
5677            }
5678            Column { name } => {
5679                f.write_str("COLUMN ");
5680                f.write_node(name);
5681            }
5682            MaterializedView { name } => {
5683                f.write_str("MATERIALIZED VIEW ");
5684                f.write_node(name);
5685            }
5686            Source { name } => {
5687                f.write_str("SOURCE ");
5688                f.write_node(name);
5689            }
5690            Sink { name } => {
5691                f.write_str("SINK ");
5692                f.write_node(name);
5693            }
5694            Index { name } => {
5695                f.write_str("INDEX ");
5696                f.write_node(name);
5697            }
5698            Func { name } => {
5699                f.write_str("FUNCTION ");
5700                f.write_node(name);
5701            }
5702            Connection { name } => {
5703                f.write_str("CONNECTION ");
5704                f.write_node(name);
5705            }
5706            Type { ty } => {
5707                f.write_str("TYPE ");
5708                f.write_node(ty);
5709            }
5710            Secret { name } => {
5711                f.write_str("SECRET ");
5712                f.write_node(name);
5713            }
5714            Role { name } => {
5715                f.write_str("ROLE ");
5716                f.write_node(name);
5717            }
5718            Database { name } => {
5719                f.write_str("DATABASE ");
5720                f.write_node(name);
5721            }
5722            Schema { name } => {
5723                f.write_str("SCHEMA ");
5724                f.write_node(name);
5725            }
5726            Cluster { name } => {
5727                f.write_str("CLUSTER ");
5728                f.write_node(name);
5729            }
5730            ClusterReplica { name } => {
5731                f.write_str("CLUSTER REPLICA ");
5732                f.write_node(name);
5733            }
5734            ContinualTask { name } => {
5735                f.write_str("CONTINUAL TASK ");
5736                f.write_node(name);
5737            }
5738            NetworkPolicy { name } => {
5739                f.write_str("NETWORK POLICY ");
5740                f.write_node(name);
5741            }
5742        }
5743    }
5744}
5745
5746impl_display_t!(CommentObjectType);
5747
5748// Include the `AstDisplay` implementations for simple options derived by the
5749// crate's build.rs script.
5750include!(concat!(env!("OUT_DIR"), "/display.simple_options.rs"));