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