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