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