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 replacing: 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
1404        f.write_str(" MATERIALIZED VIEW");
1405
1406        if self.if_exists == IfExistsBehavior::Skip {
1407            f.write_str(" IF NOT EXISTS");
1408        }
1409
1410        f.write_str(" ");
1411        f.write_node(&self.name);
1412
1413        if !self.columns.is_empty() {
1414            f.write_str(" (");
1415            f.write_node(&display::comma_separated(&self.columns));
1416            f.write_str(")");
1417        }
1418
1419        if let Some(target) = &self.replacing {
1420            f.write_str(" REPLACING ");
1421            f.write_node(target);
1422        }
1423
1424        if let Some(cluster) = &self.in_cluster {
1425            f.write_str(" IN CLUSTER ");
1426            f.write_node(cluster);
1427        }
1428
1429        if !self.with_options.is_empty() {
1430            f.write_str(" WITH (");
1431            f.write_node(&display::comma_separated(&self.with_options));
1432            f.write_str(")");
1433        }
1434
1435        f.write_str(" AS ");
1436        f.write_node(&self.query);
1437
1438        if let Some(time) = &self.as_of {
1439            f.write_str(" AS OF ");
1440            f.write_str(time);
1441        }
1442    }
1443}
1444impl_display_t!(CreateMaterializedViewStatement);
1445
1446/// `CREATE CONTINUAL TASK`
1447#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1448pub struct CreateContinualTaskStatement<T: AstInfo> {
1449    pub name: T::ItemName,
1450    pub columns: Option<Vec<CteMutRecColumnDef<T>>>,
1451    pub in_cluster: Option<T::ClusterName>,
1452    pub as_of: Option<u64>,
1453    pub with_options: Vec<ContinualTaskOption<T>>,
1454
1455    // The thing we get input diffs from
1456    pub input: T::ItemName,
1457
1458    // The txn to execute on each set of diffs
1459    pub stmts: Vec<ContinualTaskStmt<T>>,
1460
1461    pub sugar: Option<CreateContinualTaskSugar<T>>,
1462}
1463
1464#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1465pub enum ContinualTaskStmt<T: AstInfo> {
1466    Delete(DeleteStatement<T>),
1467    Insert(InsertStatement<T>),
1468}
1469
1470impl<T: AstInfo> AstDisplay for ContinualTaskStmt<T> {
1471    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1472        match self {
1473            ContinualTaskStmt::Delete(stmt) => f.write_node(stmt),
1474            ContinualTaskStmt::Insert(stmt) => f.write_node(stmt),
1475        }
1476    }
1477}
1478
1479#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1480pub enum CreateContinualTaskSugar<T: AstInfo> {
1481    Transform { transform: Query<T> },
1482    Retain { retain: Expr<T> },
1483}
1484
1485impl<T: AstInfo> AstDisplay for CreateContinualTaskStatement<T> {
1486    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1487        f.write_str("CREATE CONTINUAL TASK ");
1488        f.write_node(&self.name);
1489        if let Some(columns) = &self.columns {
1490            f.write_str(" (");
1491            f.write_node(&display::comma_separated(columns));
1492            f.write_str(")");
1493        }
1494
1495        if let Some(cluster) = &self.in_cluster {
1496            f.write_str(" IN CLUSTER ");
1497            f.write_node(cluster);
1498        }
1499
1500        if !self.with_options.is_empty() {
1501            f.write_str(" WITH (");
1502            f.write_node(&display::comma_separated(&self.with_options));
1503            f.write_str(")");
1504        }
1505
1506        match &self.sugar {
1507            Some(CreateContinualTaskSugar::Transform { transform }) => {
1508                f.write_str(" FROM TRANSFORM ");
1509                f.write_node(&self.input);
1510                f.write_str(" USING ");
1511                f.write_str("(");
1512                f.write_node(transform);
1513                f.write_str(")");
1514            }
1515            Some(CreateContinualTaskSugar::Retain { retain }) => {
1516                f.write_str(" FROM RETAIN ");
1517                f.write_node(&self.input);
1518                f.write_str(" WHILE ");
1519                f.write_str("(");
1520                f.write_node(retain);
1521                f.write_str(")");
1522            }
1523            None => {
1524                f.write_str(" ON INPUT ");
1525                f.write_node(&self.input);
1526                f.write_str(" AS (");
1527                for (idx, stmt) in self.stmts.iter().enumerate() {
1528                    if idx > 0 {
1529                        f.write_str("; ");
1530                    }
1531                    f.write_node(stmt);
1532                }
1533                f.write_str(")");
1534            }
1535        }
1536
1537        if let Some(time) = &self.as_of {
1538            f.write_str(" AS OF ");
1539            f.write_str(time);
1540        }
1541    }
1542}
1543impl_display_t!(CreateContinualTaskStatement);
1544
1545/// `ALTER SET CLUSTER`
1546#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1547pub struct AlterSetClusterStatement<T: AstInfo> {
1548    pub if_exists: bool,
1549    pub name: UnresolvedItemName,
1550    pub object_type: ObjectType,
1551    pub set_cluster: T::ClusterName,
1552}
1553
1554impl<T: AstInfo> AstDisplay for AlterSetClusterStatement<T> {
1555    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1556        f.write_str("ALTER ");
1557        f.write_node(&self.object_type);
1558
1559        if self.if_exists {
1560            f.write_str(" IF EXISTS");
1561        }
1562
1563        f.write_str(" ");
1564        f.write_node(&self.name);
1565
1566        f.write_str(" SET CLUSTER ");
1567        f.write_node(&self.set_cluster);
1568    }
1569}
1570impl_display_t!(AlterSetClusterStatement);
1571
1572/// `CREATE TABLE`
1573#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1574pub struct CreateTableStatement<T: AstInfo> {
1575    /// Table name
1576    pub name: UnresolvedItemName,
1577    /// Optional schema
1578    pub columns: Vec<ColumnDef<T>>,
1579    pub constraints: Vec<TableConstraint<T>>,
1580    pub if_not_exists: bool,
1581    pub temporary: bool,
1582    pub with_options: Vec<TableOption<T>>,
1583}
1584
1585impl<T: AstInfo> AstDisplay for CreateTableStatement<T> {
1586    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1587        let Self {
1588            name,
1589            columns,
1590            constraints,
1591            if_not_exists,
1592            temporary,
1593            with_options,
1594        } = self;
1595        f.write_str("CREATE ");
1596        if *temporary {
1597            f.write_str("TEMPORARY ");
1598        }
1599        f.write_str("TABLE ");
1600        if *if_not_exists {
1601            f.write_str("IF NOT EXISTS ");
1602        }
1603        f.write_node(name);
1604        f.write_str(" (");
1605        f.write_node(&display::comma_separated(columns));
1606        if !self.constraints.is_empty() {
1607            f.write_str(", ");
1608            f.write_node(&display::comma_separated(constraints));
1609        }
1610        f.write_str(")");
1611        if !with_options.is_empty() {
1612            f.write_str(" WITH (");
1613            f.write_node(&display::comma_separated(&self.with_options));
1614            f.write_str(")");
1615        }
1616    }
1617}
1618impl_display_t!(CreateTableStatement);
1619
1620#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1621pub enum TableOptionName {
1622    // The `PARTITION BY` option
1623    PartitionBy,
1624    // The `RETAIN HISTORY` option
1625    RetainHistory,
1626    /// A special option to test that we do redact values.
1627    RedactedTest,
1628}
1629
1630impl AstDisplay for TableOptionName {
1631    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1632        match self {
1633            TableOptionName::PartitionBy => {
1634                f.write_str("PARTITION BY");
1635            }
1636            TableOptionName::RetainHistory => {
1637                f.write_str("RETAIN HISTORY");
1638            }
1639            TableOptionName::RedactedTest => {
1640                f.write_str("REDACTED");
1641            }
1642        }
1643    }
1644}
1645
1646impl WithOptionName for TableOptionName {
1647    /// # WARNING
1648    ///
1649    /// Whenever implementing this trait consider very carefully whether or not
1650    /// this value could contain sensitive user data. If you're uncertain, err
1651    /// on the conservative side and return `true`.
1652    fn redact_value(&self) -> bool {
1653        match self {
1654            TableOptionName::PartitionBy => false,
1655            TableOptionName::RetainHistory => false,
1656            TableOptionName::RedactedTest => true,
1657        }
1658    }
1659}
1660
1661#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1662pub struct TableOption<T: AstInfo> {
1663    pub name: TableOptionName,
1664    pub value: Option<WithOptionValue<T>>,
1665}
1666impl_display_for_with_option!(TableOption);
1667
1668#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1669pub enum TableFromSourceOptionName {
1670    /// Columns whose types you want to unconditionally format as text
1671    TextColumns,
1672    /// Columns you want to exclude when ingesting data
1673    ExcludeColumns,
1674    /// Hex-encoded protobuf of a `ProtoSourceExportStatementDetails`
1675    /// message, which includes details necessary for planning this
1676    /// table as a Source Export
1677    Details,
1678    /// Partition the given table by the provided columns.
1679    PartitionBy,
1680    // The `RETAIN HISTORY` option
1681    RetainHistory,
1682}
1683
1684impl AstDisplay for TableFromSourceOptionName {
1685    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1686        f.write_str(match self {
1687            TableFromSourceOptionName::TextColumns => "TEXT COLUMNS",
1688            TableFromSourceOptionName::ExcludeColumns => "EXCLUDE COLUMNS",
1689            TableFromSourceOptionName::Details => "DETAILS",
1690            TableFromSourceOptionName::PartitionBy => "PARTITION BY",
1691            TableFromSourceOptionName::RetainHistory => "RETAIN HISTORY",
1692        })
1693    }
1694}
1695impl_display!(TableFromSourceOptionName);
1696
1697impl WithOptionName for TableFromSourceOptionName {
1698    /// # WARNING
1699    ///
1700    /// Whenever implementing this trait consider very carefully whether or not
1701    /// this value could contain sensitive user data. If you're uncertain, err
1702    /// on the conservative side and return `true`.
1703    fn redact_value(&self) -> bool {
1704        match self {
1705            TableFromSourceOptionName::Details
1706            | TableFromSourceOptionName::TextColumns
1707            | TableFromSourceOptionName::ExcludeColumns
1708            | TableFromSourceOptionName::RetainHistory
1709            | TableFromSourceOptionName::PartitionBy => false,
1710        }
1711    }
1712}
1713
1714#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1715pub struct TableFromSourceOption<T: AstInfo> {
1716    pub name: TableFromSourceOptionName,
1717    pub value: Option<WithOptionValue<T>>,
1718}
1719impl_display_for_with_option!(TableFromSourceOption);
1720
1721/// `CREATE TABLE .. FROM SOURCE` columns specification
1722/// can have 3 states:
1723/// Before purification they can be `NotSpecified` or `Named`
1724/// by the user to specify the column names to use.
1725/// After purification they can be in any of the 3 states.
1726/// For some source types we define the columns during purification
1727/// and for others the columns are defined during planning based
1728/// on the encoding option of the source.
1729#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1730pub enum TableFromSourceColumns<T: AstInfo> {
1731    /// The user did not specify which columns to use.
1732    NotSpecified,
1733    /// The user requested the named columns. Only compatible
1734    /// with source types that allow user-specified column names.
1735    Named(Vec<Ident>),
1736    /// Columns defined during purification for some source types.
1737    Defined(Vec<ColumnDef<T>>),
1738}
1739
1740/// `CREATE TABLE .. FROM SOURCE`
1741#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1742pub struct CreateTableFromSourceStatement<T: AstInfo> {
1743    pub name: UnresolvedItemName,
1744    pub columns: TableFromSourceColumns<T>,
1745    pub constraints: Vec<TableConstraint<T>>,
1746    pub if_not_exists: bool,
1747    pub source: T::ItemName,
1748    pub external_reference: Option<UnresolvedItemName>,
1749    pub with_options: Vec<TableFromSourceOption<T>>,
1750    pub include_metadata: Vec<SourceIncludeMetadata>,
1751    pub format: Option<FormatSpecifier<T>>,
1752    pub envelope: Option<SourceEnvelope>,
1753}
1754
1755impl<T: AstInfo> AstDisplay for CreateTableFromSourceStatement<T> {
1756    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1757        let Self {
1758            name,
1759            columns,
1760            constraints,
1761            source,
1762            external_reference,
1763            if_not_exists,
1764            with_options,
1765            include_metadata,
1766            format,
1767            envelope,
1768        } = self;
1769        f.write_str("CREATE TABLE ");
1770        if *if_not_exists {
1771            f.write_str("IF NOT EXISTS ");
1772        }
1773        f.write_node(name);
1774        if !matches!(columns, TableFromSourceColumns::NotSpecified) || !constraints.is_empty() {
1775            f.write_str(" (");
1776
1777            match columns {
1778                TableFromSourceColumns::NotSpecified => unreachable!(),
1779                TableFromSourceColumns::Named(columns) => {
1780                    f.write_node(&display::comma_separated(columns))
1781                }
1782                TableFromSourceColumns::Defined(columns) => {
1783                    f.write_node(&display::comma_separated(columns))
1784                }
1785            };
1786            if !constraints.is_empty() {
1787                f.write_str(", ");
1788                f.write_node(&display::comma_separated(constraints));
1789            }
1790            f.write_str(")");
1791        }
1792        f.write_str(" FROM SOURCE ");
1793        f.write_node(source);
1794        if let Some(external_reference) = external_reference {
1795            f.write_str(" (REFERENCE = ");
1796            f.write_node(external_reference);
1797            f.write_str(")");
1798        }
1799
1800        if let Some(format) = &format {
1801            f.write_str(" ");
1802            f.write_node(format);
1803        }
1804        if !include_metadata.is_empty() {
1805            f.write_str(" INCLUDE ");
1806            f.write_node(&display::comma_separated(include_metadata));
1807        }
1808        if let Some(envelope) = &envelope {
1809            f.write_str(" ENVELOPE ");
1810            f.write_node(envelope);
1811        }
1812        if !with_options.is_empty() {
1813            f.write_str(" WITH (");
1814            f.write_node(&display::comma_separated(with_options));
1815            f.write_str(")");
1816        }
1817    }
1818}
1819impl_display_t!(CreateTableFromSourceStatement);
1820
1821/// `CREATE INDEX`
1822#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1823pub struct CreateIndexStatement<T: AstInfo> {
1824    /// Optional index name.
1825    pub name: Option<Ident>,
1826    pub in_cluster: Option<T::ClusterName>,
1827    /// `ON` table or view name
1828    pub on_name: T::ItemName,
1829    /// Expressions that form part of the index key. If not included, the
1830    /// key_parts will be inferred from the named object.
1831    pub key_parts: Option<Vec<Expr<T>>>,
1832    pub with_options: Vec<IndexOption<T>>,
1833    pub if_not_exists: bool,
1834}
1835
1836impl<T: AstInfo> AstDisplay for CreateIndexStatement<T> {
1837    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1838        f.write_str("CREATE ");
1839        if self.key_parts.is_none() {
1840            f.write_str("DEFAULT ");
1841        }
1842        f.write_str("INDEX ");
1843        if self.if_not_exists {
1844            f.write_str("IF NOT EXISTS ");
1845        }
1846        if let Some(name) = &self.name {
1847            f.write_node(name);
1848            f.write_str(" ");
1849        }
1850        if let Some(cluster) = &self.in_cluster {
1851            f.write_str("IN CLUSTER ");
1852            f.write_node(cluster);
1853            f.write_str(" ");
1854        }
1855        f.write_str("ON ");
1856        f.write_node(&self.on_name);
1857        if let Some(key_parts) = &self.key_parts {
1858            f.write_str(" (");
1859            f.write_node(&display::comma_separated(key_parts));
1860            f.write_str(")");
1861        }
1862        if !self.with_options.is_empty() {
1863            f.write_str(" WITH (");
1864            f.write_node(&display::comma_separated(&self.with_options));
1865            f.write_str(")");
1866        }
1867    }
1868}
1869impl_display_t!(CreateIndexStatement);
1870
1871/// An option in a `CREATE CLUSTER` statement.
1872#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1873pub enum IndexOptionName {
1874    // The `RETAIN HISTORY` option
1875    RetainHistory,
1876}
1877
1878impl AstDisplay for IndexOptionName {
1879    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1880        match self {
1881            IndexOptionName::RetainHistory => {
1882                f.write_str("RETAIN HISTORY");
1883            }
1884        }
1885    }
1886}
1887
1888impl WithOptionName for IndexOptionName {
1889    /// # WARNING
1890    ///
1891    /// Whenever implementing this trait consider very carefully whether or not
1892    /// this value could contain sensitive user data. If you're uncertain, err
1893    /// on the conservative side and return `true`.
1894    fn redact_value(&self) -> bool {
1895        match self {
1896            IndexOptionName::RetainHistory => false,
1897        }
1898    }
1899}
1900
1901#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1902pub struct IndexOption<T: AstInfo> {
1903    pub name: IndexOptionName,
1904    pub value: Option<WithOptionValue<T>>,
1905}
1906impl_display_for_with_option!(IndexOption);
1907
1908/// A `CREATE ROLE` statement.
1909#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1910pub struct CreateRoleStatement {
1911    /// The specified role.
1912    pub name: Ident,
1913    /// Any options that were attached, in the order they were presented.
1914    pub options: Vec<RoleAttribute>,
1915}
1916
1917impl AstDisplay for CreateRoleStatement {
1918    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1919        f.write_str("CREATE ");
1920        f.write_str("ROLE ");
1921        f.write_node(&self.name);
1922        for option in &self.options {
1923            f.write_str(" ");
1924            option.fmt(f)
1925        }
1926    }
1927}
1928impl_display!(CreateRoleStatement);
1929
1930/// Attributes that can be attached to roles.
1931#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1932pub enum RoleAttribute {
1933    /// The `INHERIT` option.
1934    Inherit,
1935    /// The `NOINHERIT` option.
1936    NoInherit,
1937    /// The `PASSWORD` option.
1938    Password(Option<String>),
1939    // The following are not supported, but included to give helpful error messages.
1940    Login,
1941    NoLogin,
1942    SuperUser,
1943    NoSuperUser,
1944    CreateCluster,
1945    NoCreateCluster,
1946    CreateDB,
1947    NoCreateDB,
1948    CreateRole,
1949    NoCreateRole,
1950}
1951
1952impl AstDisplay for RoleAttribute {
1953    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1954        match self {
1955            RoleAttribute::SuperUser => f.write_str("SUPERUSER"),
1956            RoleAttribute::NoSuperUser => f.write_str("NOSUPERUSER"),
1957            RoleAttribute::Login => f.write_str("LOGIN"),
1958            RoleAttribute::NoLogin => f.write_str("NOLOGIN"),
1959            RoleAttribute::Inherit => f.write_str("INHERIT"),
1960            RoleAttribute::NoInherit => f.write_str("NOINHERIT"),
1961            RoleAttribute::CreateCluster => f.write_str("CREATECLUSTER"),
1962            RoleAttribute::NoCreateCluster => f.write_str("NOCREATECLUSTER"),
1963            RoleAttribute::CreateDB => f.write_str("CREATEDB"),
1964            RoleAttribute::NoCreateDB => f.write_str("NOCREATEDB"),
1965            RoleAttribute::CreateRole => f.write_str("CREATEROLE"),
1966            RoleAttribute::NoCreateRole => f.write_str("NOCREATEROLE"),
1967            RoleAttribute::Password(_) => f.write_str("PASSWORD"),
1968        }
1969    }
1970}
1971impl_display!(RoleAttribute);
1972
1973/// `ALTER ROLE role_name [SET | RESET] ...`
1974#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1975pub enum SetRoleVar {
1976    /// `SET name TO value`
1977    Set { name: Ident, value: SetVariableTo },
1978    /// `RESET name`
1979    Reset { name: Ident },
1980}
1981
1982impl AstDisplay for SetRoleVar {
1983    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
1984        match self {
1985            SetRoleVar::Set { name, value } => {
1986                f.write_str("SET ");
1987                f.write_node(name);
1988                f.write_str(" = ");
1989                f.write_node(value);
1990            }
1991            SetRoleVar::Reset { name } => {
1992                f.write_str("RESET ");
1993                f.write_node(name);
1994            }
1995        }
1996    }
1997}
1998impl_display!(SetRoleVar);
1999
2000/// AN `ALTER NETWORK POLICY` statement.
2001#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2002pub struct AlterNetworkPolicyStatement<T: AstInfo> {
2003    /// The specified Network Policy.
2004    pub name: Ident,
2005    /// Any options that were attached, in the order they were presented.
2006    pub options: Vec<NetworkPolicyOption<T>>,
2007}
2008
2009impl<T: AstInfo> AstDisplay for AlterNetworkPolicyStatement<T> {
2010    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2011        f.write_str("ALTER ");
2012        f.write_str("NETWORK POLICY ");
2013        f.write_node(&self.name);
2014        f.write_str(" SET (");
2015        f.write_node(&display::comma_separated(&self.options));
2016        f.write_str(" )");
2017    }
2018}
2019impl_display_t!(AlterNetworkPolicyStatement);
2020
2021/// A `CREATE NETWORK POLICY` statement.
2022#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2023pub struct CreateNetworkPolicyStatement<T: AstInfo> {
2024    /// The specified network policy.
2025    pub name: Ident,
2026    /// Any options that were attached, in the order they were presented.
2027    pub options: Vec<NetworkPolicyOption<T>>,
2028}
2029
2030impl<T: AstInfo> AstDisplay for CreateNetworkPolicyStatement<T> {
2031    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2032        f.write_str("CREATE ");
2033        f.write_str("NETWORK POLICY ");
2034        f.write_node(&self.name);
2035        f.write_str(" (");
2036        f.write_node(&display::comma_separated(&self.options));
2037        f.write_str(" )");
2038    }
2039}
2040impl_display_t!(CreateNetworkPolicyStatement);
2041
2042#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2043pub struct NetworkPolicyOption<T: AstInfo> {
2044    pub name: NetworkPolicyOptionName,
2045    pub value: Option<WithOptionValue<T>>,
2046}
2047
2048#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2049pub enum NetworkPolicyOptionName {
2050    Rules,
2051}
2052
2053impl WithOptionName for NetworkPolicyOptionName {
2054    /// # WARNING
2055    ///
2056    /// Whenever implementing this trait consider very carefully whether or not
2057    /// this value could contain sensitive user data. If you're uncertain, err
2058    /// on the conservative side and return `true`.
2059    fn redact_value(&self) -> bool {
2060        match self {
2061            NetworkPolicyOptionName::Rules => false,
2062        }
2063    }
2064}
2065
2066impl AstDisplay for NetworkPolicyOptionName {
2067    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2068        match self {
2069            NetworkPolicyOptionName::Rules => f.write_str("RULES"),
2070        }
2071    }
2072}
2073impl_display_for_with_option!(NetworkPolicyOption);
2074
2075#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2076pub struct NetworkPolicyRuleDefinition<T: AstInfo> {
2077    pub name: Ident,
2078    pub options: Vec<NetworkPolicyRuleOption<T>>,
2079}
2080
2081impl<T: AstInfo> AstDisplay for NetworkPolicyRuleDefinition<T> {
2082    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2083        f.write_node(&self.name);
2084        f.write_str(" (");
2085        f.write_node(&display::comma_separated(&self.options));
2086        f.write_str(" )");
2087    }
2088}
2089
2090#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2091pub struct NetworkPolicyRuleOption<T: AstInfo> {
2092    pub name: NetworkPolicyRuleOptionName,
2093    pub value: Option<WithOptionValue<T>>,
2094}
2095
2096#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2097pub enum NetworkPolicyRuleOptionName {
2098    Direction,
2099    Action,
2100    Address,
2101}
2102
2103impl WithOptionName for NetworkPolicyRuleOptionName {
2104    /// # WARNING
2105    ///
2106    /// Whenever implementing this trait consider very carefully whether or not
2107    /// this value could contain sensitive user data. If you're uncertain, err
2108    /// on the conservative side and return `true`.
2109    fn redact_value(&self) -> bool {
2110        match self {
2111            NetworkPolicyRuleOptionName::Direction
2112            | NetworkPolicyRuleOptionName::Action
2113            | NetworkPolicyRuleOptionName::Address => false,
2114        }
2115    }
2116}
2117
2118impl AstDisplay for NetworkPolicyRuleOptionName {
2119    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2120        match self {
2121            NetworkPolicyRuleOptionName::Direction => f.write_str("DIRECTION"),
2122            NetworkPolicyRuleOptionName::Action => f.write_str("ACTION"),
2123            NetworkPolicyRuleOptionName::Address => f.write_str("ADDRESS"),
2124        }
2125    }
2126}
2127
2128impl_display_for_with_option!(NetworkPolicyRuleOption);
2129
2130/// A `CREATE SECRET` statement.
2131#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2132pub struct CreateSecretStatement<T: AstInfo> {
2133    pub name: UnresolvedItemName,
2134    pub if_not_exists: bool,
2135    pub value: Expr<T>,
2136}
2137
2138impl<T: AstInfo> AstDisplay for CreateSecretStatement<T> {
2139    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2140        f.write_str("CREATE SECRET ");
2141        if self.if_not_exists {
2142            f.write_str("IF NOT EXISTS ");
2143        }
2144        f.write_node(&self.name);
2145        f.write_str(" AS ");
2146
2147        if f.redacted() {
2148            f.write_str("'<REDACTED>'");
2149        } else {
2150            f.write_node(&self.value);
2151        }
2152    }
2153}
2154impl_display_t!(CreateSecretStatement);
2155
2156/// `CREATE TYPE ..`
2157#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2158pub struct CreateTypeStatement<T: AstInfo> {
2159    /// Name of the created type.
2160    pub name: UnresolvedItemName,
2161    /// The new type's "base type".
2162    pub as_type: CreateTypeAs<T>,
2163}
2164
2165impl<T: AstInfo> AstDisplay for CreateTypeStatement<T> {
2166    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2167        f.write_str("CREATE TYPE ");
2168        f.write_node(&self.name);
2169        f.write_str(" AS ");
2170        match &self.as_type {
2171            CreateTypeAs::List { options } => {
2172                f.write_str(&self.as_type);
2173                f.write_str("(");
2174                if !options.is_empty() {
2175                    f.write_node(&display::comma_separated(options));
2176                }
2177                f.write_str(")");
2178            }
2179            CreateTypeAs::Map { options } => {
2180                f.write_str(&self.as_type);
2181                f.write_str("(");
2182                if !options.is_empty() {
2183                    f.write_node(&display::comma_separated(options));
2184                }
2185                f.write_str(")");
2186            }
2187            CreateTypeAs::Record { column_defs } => {
2188                f.write_str("(");
2189                if !column_defs.is_empty() {
2190                    f.write_node(&display::comma_separated(column_defs));
2191                }
2192                f.write_str(")");
2193            }
2194        };
2195    }
2196}
2197impl_display_t!(CreateTypeStatement);
2198
2199#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2200pub enum ClusterOptionName {
2201    /// The `AVAILABILITY ZONES [[=] '[' <values> ']' ]` option.
2202    AvailabilityZones,
2203    /// The `DISK` option.
2204    Disk,
2205    /// The `INTROSPECTION INTERVAL [[=] <interval>]` option.
2206    IntrospectionInterval,
2207    /// The `INTROSPECTION DEBUGGING [[=] <enabled>]` option.
2208    IntrospectionDebugging,
2209    /// The `MANAGED` option.
2210    Managed,
2211    /// The `REPLICAS` option.
2212    Replicas,
2213    /// The `REPLICATION FACTOR` option.
2214    ReplicationFactor,
2215    /// The `SIZE` option.
2216    Size,
2217    /// The `SCHEDULE` option.
2218    Schedule,
2219    /// The `WORKLOAD CLASS` option.
2220    WorkloadClass,
2221}
2222
2223impl AstDisplay for ClusterOptionName {
2224    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2225        match self {
2226            ClusterOptionName::AvailabilityZones => f.write_str("AVAILABILITY ZONES"),
2227            ClusterOptionName::Disk => f.write_str("DISK"),
2228            ClusterOptionName::IntrospectionDebugging => f.write_str("INTROSPECTION DEBUGGING"),
2229            ClusterOptionName::IntrospectionInterval => f.write_str("INTROSPECTION INTERVAL"),
2230            ClusterOptionName::Managed => f.write_str("MANAGED"),
2231            ClusterOptionName::Replicas => f.write_str("REPLICAS"),
2232            ClusterOptionName::ReplicationFactor => f.write_str("REPLICATION FACTOR"),
2233            ClusterOptionName::Size => f.write_str("SIZE"),
2234            ClusterOptionName::Schedule => f.write_str("SCHEDULE"),
2235            ClusterOptionName::WorkloadClass => f.write_str("WORKLOAD CLASS"),
2236        }
2237    }
2238}
2239
2240impl WithOptionName for ClusterOptionName {
2241    /// # WARNING
2242    ///
2243    /// Whenever implementing this trait consider very carefully whether or not
2244    /// this value could contain sensitive user data. If you're uncertain, err
2245    /// on the conservative side and return `true`.
2246    fn redact_value(&self) -> bool {
2247        match self {
2248            ClusterOptionName::AvailabilityZones
2249            | ClusterOptionName::Disk
2250            | ClusterOptionName::IntrospectionDebugging
2251            | ClusterOptionName::IntrospectionInterval
2252            | ClusterOptionName::Managed
2253            | ClusterOptionName::Replicas
2254            | ClusterOptionName::ReplicationFactor
2255            | ClusterOptionName::Size
2256            | ClusterOptionName::Schedule
2257            | ClusterOptionName::WorkloadClass => false,
2258        }
2259    }
2260}
2261
2262#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2263/// An option in a `CREATE CLUSTER` statement.
2264pub struct ClusterOption<T: AstInfo> {
2265    pub name: ClusterOptionName,
2266    pub value: Option<WithOptionValue<T>>,
2267}
2268impl_display_for_with_option!(ClusterOption);
2269
2270#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2271pub enum ClusterAlterUntilReadyOptionName {
2272    Timeout,
2273    OnTimeout,
2274}
2275
2276impl AstDisplay for ClusterAlterUntilReadyOptionName {
2277    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2278        match self {
2279            Self::Timeout => f.write_str("TIMEOUT"),
2280            Self::OnTimeout => f.write_str("ON TIMEOUT"),
2281        }
2282    }
2283}
2284
2285impl WithOptionName for ClusterAlterUntilReadyOptionName {
2286    /// # WARNING
2287    ///
2288    /// Whenever implementing this trait consider very carefully whether or not
2289    /// this value could contain sensitive user data. If you're uncertain, err
2290    /// on the conservative side and return `true`.
2291    fn redact_value(&self) -> bool {
2292        match self {
2293            ClusterAlterUntilReadyOptionName::Timeout
2294            | ClusterAlterUntilReadyOptionName::OnTimeout => false,
2295        }
2296    }
2297}
2298
2299#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2300pub struct ClusterAlterUntilReadyOption<T: AstInfo> {
2301    pub name: ClusterAlterUntilReadyOptionName,
2302    pub value: Option<WithOptionValue<T>>,
2303}
2304impl_display_for_with_option!(ClusterAlterUntilReadyOption);
2305
2306#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2307pub enum ClusterAlterOptionName {
2308    Wait,
2309}
2310
2311impl AstDisplay for ClusterAlterOptionName {
2312    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2313        match self {
2314            ClusterAlterOptionName::Wait => f.write_str("WAIT"),
2315        }
2316    }
2317}
2318
2319impl WithOptionName for ClusterAlterOptionName {
2320    /// # WARNING
2321    ///
2322    /// Whenever implementing this trait consider very carefully whether or not
2323    /// this value could contain sensitive user data. If you're uncertain, err
2324    /// on the conservative side and return `true`.
2325    fn redact_value(&self) -> bool {
2326        match self {
2327            ClusterAlterOptionName::Wait => false,
2328        }
2329    }
2330}
2331
2332#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2333pub enum ClusterAlterOptionValue<T: AstInfo> {
2334    For(Value),
2335    UntilReady(Vec<ClusterAlterUntilReadyOption<T>>),
2336}
2337
2338impl<T: AstInfo> AstDisplay for ClusterAlterOptionValue<T> {
2339    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2340        match self {
2341            ClusterAlterOptionValue::For(duration) => {
2342                f.write_str("FOR ");
2343                f.write_node(duration);
2344            }
2345            ClusterAlterOptionValue::UntilReady(options) => {
2346                f.write_str("UNTIL READY (");
2347                f.write_node(&display::comma_separated(options));
2348                f.write_str(")");
2349            }
2350        }
2351    }
2352}
2353
2354#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2355/// An option in a `ALTER CLUSTER... WITH` statement.
2356pub struct ClusterAlterOption<T: AstInfo> {
2357    pub name: ClusterAlterOptionName,
2358    pub value: Option<WithOptionValue<T>>,
2359}
2360
2361impl_display_for_with_option!(ClusterAlterOption);
2362
2363// Note: the `AstDisplay` implementation and `Parser::parse_` method for this
2364// enum are generated automatically by this crate's `build.rs`.
2365#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2366pub enum ClusterFeatureName {
2367    ReoptimizeImportedViews,
2368    EnableNewOuterJoinLowering,
2369    EnableEagerDeltaJoins,
2370    EnableVariadicLeftJoinLowering,
2371    EnableLetrecFixpointAnalysis,
2372    EnableJoinPrioritizeArranged,
2373    EnableProjectionPushdownAfterRelationCse,
2374}
2375
2376impl WithOptionName for ClusterFeatureName {
2377    /// # WARNING
2378    ///
2379    /// Whenever implementing this trait consider very carefully whether or not
2380    /// this value could contain sensitive user data. If you're uncertain, err
2381    /// on the conservative side and return `true`.
2382    fn redact_value(&self) -> bool {
2383        match self {
2384            Self::ReoptimizeImportedViews
2385            | Self::EnableNewOuterJoinLowering
2386            | Self::EnableEagerDeltaJoins
2387            | Self::EnableVariadicLeftJoinLowering
2388            | Self::EnableLetrecFixpointAnalysis
2389            | Self::EnableJoinPrioritizeArranged
2390            | Self::EnableProjectionPushdownAfterRelationCse => false,
2391        }
2392    }
2393}
2394
2395#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2396pub struct ClusterFeature<T: AstInfo> {
2397    pub name: ClusterFeatureName,
2398    pub value: Option<WithOptionValue<T>>,
2399}
2400impl_display_for_with_option!(ClusterFeature);
2401
2402/// `CREATE CLUSTER ..`
2403#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2404pub struct CreateClusterStatement<T: AstInfo> {
2405    /// Name of the created cluster.
2406    pub name: Ident,
2407    /// The comma-separated options.
2408    pub options: Vec<ClusterOption<T>>,
2409    /// The comma-separated features enabled on the cluster.
2410    pub features: Vec<ClusterFeature<T>>,
2411}
2412
2413impl<T: AstInfo> AstDisplay for CreateClusterStatement<T> {
2414    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2415        f.write_str("CREATE CLUSTER ");
2416        f.write_node(&self.name);
2417        if !self.options.is_empty() {
2418            f.write_str(" (");
2419            f.write_node(&display::comma_separated(&self.options));
2420            f.write_str(")");
2421        }
2422        if !self.features.is_empty() {
2423            f.write_str(" FEATURES (");
2424            f.write_node(&display::comma_separated(&self.features));
2425            f.write_str(")");
2426        }
2427    }
2428}
2429impl_display_t!(CreateClusterStatement);
2430
2431#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2432pub struct ReplicaDefinition<T: AstInfo> {
2433    /// Name of the created replica.
2434    pub name: Ident,
2435    /// The comma-separated options.
2436    pub options: Vec<ReplicaOption<T>>,
2437}
2438
2439// Note that this display is meant for replicas defined inline when creating
2440// clusters.
2441impl<T: AstInfo> AstDisplay for ReplicaDefinition<T> {
2442    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2443        f.write_node(&self.name);
2444        f.write_str(" (");
2445        f.write_node(&display::comma_separated(&self.options));
2446        f.write_str(")");
2447    }
2448}
2449impl_display_t!(ReplicaDefinition);
2450
2451#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2452pub enum AlterClusterAction<T: AstInfo> {
2453    SetOptions {
2454        options: Vec<ClusterOption<T>>,
2455        with_options: Vec<ClusterAlterOption<T>>,
2456    },
2457    ResetOptions(Vec<ClusterOptionName>),
2458}
2459
2460/// `ALTER CLUSTER .. SET ...`
2461#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2462pub struct AlterClusterStatement<T: AstInfo> {
2463    /// The `IF EXISTS` option.
2464    pub if_exists: bool,
2465    /// Name of the altered cluster.
2466    pub name: Ident,
2467    /// The action.
2468    pub action: AlterClusterAction<T>,
2469}
2470
2471impl<T: AstInfo> AstDisplay for AlterClusterStatement<T> {
2472    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2473        f.write_str("ALTER CLUSTER ");
2474        if self.if_exists {
2475            f.write_str("IF EXISTS ");
2476        }
2477        f.write_node(&self.name);
2478        f.write_str(" ");
2479        match &self.action {
2480            AlterClusterAction::SetOptions {
2481                options,
2482                with_options,
2483            } => {
2484                f.write_str("SET (");
2485                f.write_node(&display::comma_separated(options));
2486                f.write_str(")");
2487                if !with_options.is_empty() {
2488                    f.write_str(" WITH (");
2489                    f.write_node(&display::comma_separated(with_options));
2490                    f.write_str(")");
2491                }
2492            }
2493            AlterClusterAction::ResetOptions(options) => {
2494                f.write_str("RESET (");
2495                f.write_node(&display::comma_separated(options));
2496                f.write_str(")");
2497            }
2498        }
2499    }
2500}
2501impl_display_t!(AlterClusterStatement);
2502
2503/// `CREATE CLUSTER REPLICA ..`
2504#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2505pub struct CreateClusterReplicaStatement<T: AstInfo> {
2506    /// Name of the replica's cluster.
2507    pub of_cluster: Ident,
2508    /// The replica's definition.
2509    pub definition: ReplicaDefinition<T>,
2510}
2511
2512impl<T: AstInfo> AstDisplay for CreateClusterReplicaStatement<T> {
2513    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2514        f.write_str("CREATE CLUSTER REPLICA ");
2515        f.write_node(&self.of_cluster);
2516        f.write_str(".");
2517        f.write_node(&self.definition.name);
2518        f.write_str(" (");
2519        f.write_node(&display::comma_separated(&self.definition.options));
2520        f.write_str(")");
2521    }
2522}
2523impl_display_t!(CreateClusterReplicaStatement);
2524
2525#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2526pub enum ReplicaOptionName {
2527    /// The `BILLED AS [=] <value>` option.
2528    BilledAs,
2529    /// The `SIZE [[=] <size>]` option.
2530    Size,
2531    /// The `AVAILABILITY ZONE [[=] <id>]` option.
2532    AvailabilityZone,
2533    /// The `STORAGE ADDRESSES` option.
2534    StorageAddresses,
2535    /// The `STORAGECTL ADDRESSES` option.
2536    StoragectlAddresses,
2537    /// The `COMPUTECTL ADDRESSES` option.
2538    ComputectlAddresses,
2539    /// The `COMPUTE ADDRESSES` option.
2540    ComputeAddresses,
2541    /// The `WORKERS` option.
2542    Workers,
2543    /// The `INTERNAL` option.
2544    Internal,
2545    /// The `INTROSPECTION INTERVAL [[=] <interval>]` option.
2546    IntrospectionInterval,
2547    /// The `INTROSPECTION DEBUGGING [[=] <enabled>]` option.
2548    IntrospectionDebugging,
2549    /// The `DISK [[=] <enabled>]` option.
2550    Disk,
2551}
2552
2553impl AstDisplay for ReplicaOptionName {
2554    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2555        match self {
2556            ReplicaOptionName::BilledAs => f.write_str("BILLED AS"),
2557            ReplicaOptionName::Size => f.write_str("SIZE"),
2558            ReplicaOptionName::AvailabilityZone => f.write_str("AVAILABILITY ZONE"),
2559            ReplicaOptionName::StorageAddresses => f.write_str("STORAGE ADDRESSES"),
2560            ReplicaOptionName::StoragectlAddresses => f.write_str("STORAGECTL ADDRESSES"),
2561            ReplicaOptionName::ComputectlAddresses => f.write_str("COMPUTECTL ADDRESSES"),
2562            ReplicaOptionName::ComputeAddresses => f.write_str("COMPUTE ADDRESSES"),
2563            ReplicaOptionName::Workers => f.write_str("WORKERS"),
2564            ReplicaOptionName::Internal => f.write_str("INTERNAL"),
2565            ReplicaOptionName::IntrospectionInterval => f.write_str("INTROSPECTION INTERVAL"),
2566            ReplicaOptionName::IntrospectionDebugging => f.write_str("INTROSPECTION DEBUGGING"),
2567            ReplicaOptionName::Disk => f.write_str("DISK"),
2568        }
2569    }
2570}
2571
2572impl WithOptionName for ReplicaOptionName {
2573    /// # WARNING
2574    ///
2575    /// Whenever implementing this trait consider very carefully whether or not
2576    /// this value could contain sensitive user data. If you're uncertain, err
2577    /// on the conservative side and return `true`.
2578    fn redact_value(&self) -> bool {
2579        match self {
2580            ReplicaOptionName::BilledAs
2581            | ReplicaOptionName::Size
2582            | ReplicaOptionName::AvailabilityZone
2583            | ReplicaOptionName::StorageAddresses
2584            | ReplicaOptionName::StoragectlAddresses
2585            | ReplicaOptionName::ComputectlAddresses
2586            | ReplicaOptionName::ComputeAddresses
2587            | ReplicaOptionName::Workers
2588            | ReplicaOptionName::Internal
2589            | ReplicaOptionName::IntrospectionInterval
2590            | ReplicaOptionName::IntrospectionDebugging
2591            | ReplicaOptionName::Disk => false,
2592        }
2593    }
2594}
2595
2596#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
2597/// An option in a `CREATE CLUSTER REPLICA` statement.
2598pub struct ReplicaOption<T: AstInfo> {
2599    pub name: ReplicaOptionName,
2600    pub value: Option<WithOptionValue<T>>,
2601}
2602impl_display_for_with_option!(ReplicaOption);
2603
2604/// `CREATE TYPE .. AS <TYPE>`
2605#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2606pub enum CreateTypeAs<T: AstInfo> {
2607    List {
2608        options: Vec<CreateTypeListOption<T>>,
2609    },
2610    Map {
2611        options: Vec<CreateTypeMapOption<T>>,
2612    },
2613    Record {
2614        column_defs: Vec<ColumnDef<T>>,
2615    },
2616}
2617
2618impl<T: AstInfo> AstDisplay for CreateTypeAs<T> {
2619    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2620        match self {
2621            CreateTypeAs::List { .. } => f.write_str("LIST "),
2622            CreateTypeAs::Map { .. } => f.write_str("MAP "),
2623            CreateTypeAs::Record { .. } => f.write_str("RECORD "),
2624        }
2625    }
2626}
2627impl_display_t!(CreateTypeAs);
2628
2629#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2630pub enum CreateTypeListOptionName {
2631    ElementType,
2632}
2633
2634impl AstDisplay for CreateTypeListOptionName {
2635    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2636        f.write_str(match self {
2637            CreateTypeListOptionName::ElementType => "ELEMENT TYPE",
2638        })
2639    }
2640}
2641
2642impl WithOptionName for CreateTypeListOptionName {
2643    /// # WARNING
2644    ///
2645    /// Whenever implementing this trait consider very carefully whether or not
2646    /// this value could contain sensitive user data. If you're uncertain, err
2647    /// on the conservative side and return `true`.
2648    fn redact_value(&self) -> bool {
2649        match self {
2650            CreateTypeListOptionName::ElementType => false,
2651        }
2652    }
2653}
2654
2655#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2656pub struct CreateTypeListOption<T: AstInfo> {
2657    pub name: CreateTypeListOptionName,
2658    pub value: Option<WithOptionValue<T>>,
2659}
2660impl_display_for_with_option!(CreateTypeListOption);
2661
2662#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2663pub enum CreateTypeMapOptionName {
2664    KeyType,
2665    ValueType,
2666}
2667
2668impl AstDisplay for CreateTypeMapOptionName {
2669    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2670        f.write_str(match self {
2671            CreateTypeMapOptionName::KeyType => "KEY TYPE",
2672            CreateTypeMapOptionName::ValueType => "VALUE TYPE",
2673        })
2674    }
2675}
2676
2677impl WithOptionName for CreateTypeMapOptionName {
2678    /// # WARNING
2679    ///
2680    /// Whenever implementing this trait consider very carefully whether or not
2681    /// this value could contain sensitive user data. If you're uncertain, err
2682    /// on the conservative side and return `true`.
2683    fn redact_value(&self) -> bool {
2684        match self {
2685            CreateTypeMapOptionName::KeyType | CreateTypeMapOptionName::ValueType => false,
2686        }
2687    }
2688}
2689
2690#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2691pub struct CreateTypeMapOption<T: AstInfo> {
2692    pub name: CreateTypeMapOptionName,
2693    pub value: Option<WithOptionValue<T>>,
2694}
2695impl_display_for_with_option!(CreateTypeMapOption);
2696
2697/// `ALTER <OBJECT> ... OWNER TO`
2698#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2699pub struct AlterOwnerStatement<T: AstInfo> {
2700    pub object_type: ObjectType,
2701    pub if_exists: bool,
2702    pub name: UnresolvedObjectName,
2703    pub new_owner: T::RoleName,
2704}
2705
2706impl<T: AstInfo> AstDisplay for AlterOwnerStatement<T> {
2707    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2708        f.write_str("ALTER ");
2709        f.write_node(&self.object_type);
2710        f.write_str(" ");
2711        if self.if_exists {
2712            f.write_str("IF EXISTS ");
2713        }
2714        f.write_node(&self.name);
2715        f.write_str(" OWNER TO ");
2716        f.write_node(&self.new_owner);
2717    }
2718}
2719impl_display_t!(AlterOwnerStatement);
2720
2721/// `ALTER <OBJECT> ... RENAME TO`
2722#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2723pub struct AlterObjectRenameStatement {
2724    pub object_type: ObjectType,
2725    pub if_exists: bool,
2726    pub name: UnresolvedObjectName,
2727    pub to_item_name: Ident,
2728}
2729
2730impl AstDisplay for AlterObjectRenameStatement {
2731    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2732        f.write_str("ALTER ");
2733        f.write_node(&self.object_type);
2734        f.write_str(" ");
2735        if self.if_exists {
2736            f.write_str("IF EXISTS ");
2737        }
2738        f.write_node(&self.name);
2739        f.write_str(" RENAME TO ");
2740        f.write_node(&self.to_item_name);
2741    }
2742}
2743impl_display!(AlterObjectRenameStatement);
2744
2745/// `ALTER <OBJECT> ... [RE]SET (RETAIN HISTORY [FOR ...])`
2746#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2747pub struct AlterRetainHistoryStatement<T: AstInfo> {
2748    pub object_type: ObjectType,
2749    pub if_exists: bool,
2750    pub name: UnresolvedObjectName,
2751    pub history: Option<WithOptionValue<T>>,
2752}
2753
2754impl<T: AstInfo> AstDisplay for AlterRetainHistoryStatement<T> {
2755    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2756        f.write_str("ALTER ");
2757        f.write_node(&self.object_type);
2758        f.write_str(" ");
2759        if self.if_exists {
2760            f.write_str("IF EXISTS ");
2761        }
2762        f.write_node(&self.name);
2763        if let Some(history) = &self.history {
2764            f.write_str(" SET (RETAIN HISTORY ");
2765            f.write_node(history);
2766        } else {
2767            f.write_str(" RESET (RETAIN HISTORY");
2768        }
2769        f.write_str(")");
2770    }
2771}
2772impl_display_t!(AlterRetainHistoryStatement);
2773
2774/// `ALTER <OBJECT> SWAP ...`
2775#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2776pub struct AlterObjectSwapStatement {
2777    pub object_type: ObjectType,
2778    pub name_a: UnresolvedObjectName,
2779    pub name_b: Ident,
2780}
2781
2782impl AstDisplay for AlterObjectSwapStatement {
2783    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2784        f.write_str("ALTER ");
2785
2786        f.write_node(&self.object_type);
2787        f.write_str(" ");
2788        f.write_node(&self.name_a);
2789
2790        f.write_str(" SWAP WITH ");
2791        f.write_node(&self.name_b);
2792    }
2793}
2794impl_display!(AlterObjectSwapStatement);
2795
2796#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2797pub enum AlterIndexAction<T: AstInfo> {
2798    SetOptions(Vec<IndexOption<T>>),
2799    ResetOptions(Vec<IndexOptionName>),
2800}
2801
2802/// `ALTER INDEX ... {RESET, SET}`
2803#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2804pub struct AlterIndexStatement<T: AstInfo> {
2805    pub index_name: UnresolvedItemName,
2806    pub if_exists: bool,
2807    pub action: AlterIndexAction<T>,
2808}
2809
2810impl<T: AstInfo> AstDisplay for AlterIndexStatement<T> {
2811    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2812        f.write_str("ALTER INDEX ");
2813        if self.if_exists {
2814            f.write_str("IF EXISTS ");
2815        }
2816        f.write_node(&self.index_name);
2817        f.write_str(" ");
2818
2819        match &self.action {
2820            AlterIndexAction::SetOptions(options) => {
2821                f.write_str("SET (");
2822                f.write_node(&display::comma_separated(options));
2823                f.write_str(")");
2824            }
2825            AlterIndexAction::ResetOptions(options) => {
2826                f.write_str("RESET (");
2827                f.write_node(&display::comma_separated(options));
2828                f.write_str(")");
2829            }
2830        }
2831    }
2832}
2833
2834impl_display_t!(AlterIndexStatement);
2835
2836#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2837pub enum AlterSinkAction<T: AstInfo> {
2838    SetOptions(Vec<CreateSinkOption<T>>),
2839    ResetOptions(Vec<CreateSinkOptionName>),
2840    ChangeRelation(T::ItemName),
2841}
2842
2843#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2844pub struct AlterSinkStatement<T: AstInfo> {
2845    pub sink_name: UnresolvedItemName,
2846    pub if_exists: bool,
2847    pub action: AlterSinkAction<T>,
2848}
2849
2850impl<T: AstInfo> AstDisplay for AlterSinkStatement<T> {
2851    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2852        f.write_str("ALTER SINK ");
2853        if self.if_exists {
2854            f.write_str("IF EXISTS ");
2855        }
2856        f.write_node(&self.sink_name);
2857        f.write_str(" ");
2858
2859        match &self.action {
2860            AlterSinkAction::ChangeRelation(from) => {
2861                f.write_str("SET FROM ");
2862                f.write_node(from);
2863            }
2864            AlterSinkAction::SetOptions(options) => {
2865                f.write_str("SET (");
2866                f.write_node(&display::comma_separated(options));
2867                f.write_str(")");
2868            }
2869            AlterSinkAction::ResetOptions(options) => {
2870                f.write_str("RESET (");
2871                f.write_node(&display::comma_separated(options));
2872                f.write_str(")");
2873            }
2874        }
2875    }
2876}
2877
2878#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2879pub enum AlterSourceAddSubsourceOptionName {
2880    /// Columns whose types you want to unconditionally format as text
2881    TextColumns,
2882    /// Columns you want to ignore when ingesting data
2883    ExcludeColumns,
2884    /// Updated `DETAILS` for an ingestion, e.g.
2885    /// [`crate::ast::PgConfigOptionName::Details`]
2886    /// or
2887    /// [`crate::ast::MySqlConfigOptionName::Details`].
2888    Details,
2889}
2890
2891impl AstDisplay for AlterSourceAddSubsourceOptionName {
2892    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
2893        f.write_str(match self {
2894            AlterSourceAddSubsourceOptionName::TextColumns => "TEXT COLUMNS",
2895            AlterSourceAddSubsourceOptionName::ExcludeColumns => "EXCLUDE COLUMNS",
2896            AlterSourceAddSubsourceOptionName::Details => "DETAILS",
2897        })
2898    }
2899}
2900impl_display!(AlterSourceAddSubsourceOptionName);
2901
2902impl WithOptionName for AlterSourceAddSubsourceOptionName {
2903    /// # WARNING
2904    ///
2905    /// Whenever implementing this trait consider very carefully whether or not
2906    /// this value could contain sensitive user data. If you're uncertain, err
2907    /// on the conservative side and return `true`.
2908    fn redact_value(&self) -> bool {
2909        match self {
2910            AlterSourceAddSubsourceOptionName::Details
2911            | AlterSourceAddSubsourceOptionName::TextColumns
2912            | AlterSourceAddSubsourceOptionName::ExcludeColumns => false,
2913        }
2914    }
2915}
2916
2917#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2918/// An option in an `ALTER SOURCE...ADD SUBSOURCE` statement.
2919pub struct AlterSourceAddSubsourceOption<T: AstInfo> {
2920    pub name: AlterSourceAddSubsourceOptionName,
2921    pub value: Option<WithOptionValue<T>>,
2922}
2923impl_display_for_with_option!(AlterSourceAddSubsourceOption);
2924impl_display_t!(AlterSourceAddSubsourceOption);
2925
2926#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2927pub enum AlterSourceAction<T: AstInfo> {
2928    SetOptions(Vec<CreateSourceOption<T>>),
2929    ResetOptions(Vec<CreateSourceOptionName>),
2930    AddSubsources {
2931        external_references: Vec<ExternalReferenceExport>,
2932        options: Vec<AlterSourceAddSubsourceOption<T>>,
2933    },
2934    DropSubsources {
2935        if_exists: bool,
2936        cascade: bool,
2937        names: Vec<UnresolvedItemName>,
2938    },
2939    RefreshReferences,
2940}
2941
2942impl<T: AstInfo> AstDisplay for AlterSourceAction<T> {
2943    fn fmt<W>(&self, f: &mut AstFormatter<W>)
2944    where
2945        W: fmt::Write,
2946    {
2947        match &self {
2948            AlterSourceAction::SetOptions(options) => {
2949                f.write_str("SET (");
2950                f.write_node(&display::comma_separated(options));
2951                f.write_str(")");
2952            }
2953            AlterSourceAction::ResetOptions(options) => {
2954                f.write_str("RESET (");
2955                f.write_node(&display::comma_separated(options));
2956                f.write_str(")");
2957            }
2958            AlterSourceAction::DropSubsources {
2959                if_exists,
2960                cascade,
2961                names,
2962            } => {
2963                f.write_str("DROP SUBSOURCE ");
2964                if *if_exists {
2965                    f.write_str("IF EXISTS ");
2966                }
2967
2968                f.write_node(&display::comma_separated(names));
2969
2970                if *cascade {
2971                    f.write_str(" CASCADE");
2972                }
2973            }
2974            AlterSourceAction::AddSubsources {
2975                external_references: subsources,
2976                options,
2977            } => {
2978                f.write_str("ADD SUBSOURCE ");
2979
2980                f.write_node(&display::comma_separated(subsources));
2981
2982                if !options.is_empty() {
2983                    f.write_str(" WITH (");
2984                    f.write_node(&display::comma_separated(options));
2985                    f.write_str(")");
2986                }
2987            }
2988            AlterSourceAction::RefreshReferences => {
2989                f.write_str("REFRESH REFERENCES");
2990            }
2991        }
2992    }
2993}
2994
2995#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2996pub struct AlterSourceStatement<T: AstInfo> {
2997    pub source_name: UnresolvedItemName,
2998    pub if_exists: bool,
2999    pub action: AlterSourceAction<T>,
3000}
3001
3002impl<T: AstInfo> AstDisplay for AlterSourceStatement<T> {
3003    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3004        f.write_str("ALTER SOURCE ");
3005        if self.if_exists {
3006            f.write_str("IF EXISTS ");
3007        }
3008        f.write_node(&self.source_name);
3009        f.write_str(" ");
3010        f.write_node(&self.action)
3011    }
3012}
3013
3014impl_display_t!(AlterSourceStatement);
3015
3016/// `ALTER SECRET ... AS`
3017#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3018pub struct AlterSecretStatement<T: AstInfo> {
3019    pub name: UnresolvedItemName,
3020    pub if_exists: bool,
3021    pub value: Expr<T>,
3022}
3023
3024impl<T: AstInfo> AstDisplay for AlterSecretStatement<T> {
3025    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3026        f.write_str("ALTER SECRET ");
3027        if self.if_exists {
3028            f.write_str("IF EXISTS ");
3029        }
3030        f.write_node(&self.name);
3031        f.write_str(" AS ");
3032
3033        if f.redacted() {
3034            f.write_str("'<REDACTED>'");
3035        } else {
3036            f.write_node(&self.value);
3037        }
3038    }
3039}
3040
3041impl_display_t!(AlterSecretStatement);
3042
3043#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3044pub enum AlterConnectionAction<T: AstInfo> {
3045    RotateKeys,
3046    SetOption(ConnectionOption<T>),
3047    DropOption(ConnectionOptionName),
3048}
3049
3050impl<T: AstInfo> AstDisplay for AlterConnectionAction<T> {
3051    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3052        match self {
3053            AlterConnectionAction::RotateKeys => f.write_str("ROTATE KEYS"),
3054            AlterConnectionAction::SetOption(option) => {
3055                f.write_str("SET (");
3056                f.write_node(option);
3057                f.write_str(")");
3058            }
3059            AlterConnectionAction::DropOption(option) => {
3060                f.write_str("DROP (");
3061                f.write_node(option);
3062                f.write_str(")");
3063            }
3064        }
3065    }
3066}
3067impl_display_t!(AlterConnectionAction);
3068
3069#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3070pub enum AlterConnectionOptionName {
3071    Validate,
3072}
3073
3074impl AstDisplay for AlterConnectionOptionName {
3075    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3076        f.write_str(match self {
3077            AlterConnectionOptionName::Validate => "VALIDATE",
3078        })
3079    }
3080}
3081impl_display!(AlterConnectionOptionName);
3082
3083impl WithOptionName for AlterConnectionOptionName {
3084    /// # WARNING
3085    ///
3086    /// Whenever implementing this trait consider very carefully whether or not
3087    /// this value could contain sensitive user data. If you're uncertain, err
3088    /// on the conservative side and return `true`.
3089    fn redact_value(&self) -> bool {
3090        match self {
3091            AlterConnectionOptionName::Validate => false,
3092        }
3093    }
3094}
3095
3096#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3097/// An option in an `ALTER CONNECTION...` statement.
3098pub struct AlterConnectionOption<T: AstInfo> {
3099    pub name: AlterConnectionOptionName,
3100    pub value: Option<WithOptionValue<T>>,
3101}
3102impl_display_for_with_option!(AlterConnectionOption);
3103impl_display_t!(AlterConnectionOption);
3104
3105/// `ALTER CONNECTION`
3106#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3107pub struct AlterConnectionStatement<T: AstInfo> {
3108    pub name: UnresolvedItemName,
3109    pub if_exists: bool,
3110    pub actions: Vec<AlterConnectionAction<T>>,
3111    pub with_options: Vec<AlterConnectionOption<T>>,
3112}
3113
3114impl<T: AstInfo> AstDisplay for AlterConnectionStatement<T> {
3115    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3116        f.write_str("ALTER CONNECTION ");
3117        if self.if_exists {
3118            f.write_str("IF EXISTS ");
3119        }
3120        f.write_node(&self.name);
3121        f.write_str(" ");
3122        f.write_node(&display::comma_separated(&self.actions));
3123
3124        if !self.with_options.is_empty() {
3125            f.write_str(" WITH (");
3126            f.write_node(&display::comma_separated(&self.with_options));
3127            f.write_str(")");
3128        }
3129    }
3130}
3131
3132impl_display_t!(AlterConnectionStatement);
3133
3134/// `ALTER ROLE`
3135#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3136pub struct AlterRoleStatement<T: AstInfo> {
3137    /// The specified role.
3138    pub name: T::RoleName,
3139    /// Alterations we're making to the role.
3140    pub option: AlterRoleOption,
3141}
3142
3143impl<T: AstInfo> AstDisplay for AlterRoleStatement<T> {
3144    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3145        f.write_str("ALTER ROLE ");
3146        f.write_node(&self.name);
3147        f.write_node(&self.option);
3148    }
3149}
3150impl_display_t!(AlterRoleStatement);
3151
3152/// `ALTER ROLE ... [ WITH | SET ] ...`
3153#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3154pub enum AlterRoleOption {
3155    /// Any options that were attached, in the order they were presented.
3156    Attributes(Vec<RoleAttribute>),
3157    /// A variable that we want to provide a default value for this role.
3158    Variable(SetRoleVar),
3159}
3160
3161impl AstDisplay for AlterRoleOption {
3162    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3163        match self {
3164            AlterRoleOption::Attributes(attrs) => {
3165                for attr in attrs {
3166                    f.write_str(" ");
3167                    attr.fmt(f)
3168                }
3169            }
3170            AlterRoleOption::Variable(var) => {
3171                f.write_str(" ");
3172                f.write_node(var);
3173            }
3174        }
3175    }
3176}
3177impl_display!(AlterRoleOption);
3178
3179/// `ALTER TABLE ... ADD COLUMN ...`
3180#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3181pub struct AlterTableAddColumnStatement<T: AstInfo> {
3182    pub if_exists: bool,
3183    pub name: UnresolvedItemName,
3184    pub if_col_not_exist: bool,
3185    pub column_name: Ident,
3186    pub data_type: T::DataType,
3187}
3188
3189impl<T: AstInfo> AstDisplay for AlterTableAddColumnStatement<T> {
3190    fn fmt<W>(&self, f: &mut AstFormatter<W>)
3191    where
3192        W: fmt::Write,
3193    {
3194        f.write_str("ALTER TABLE ");
3195        if self.if_exists {
3196            f.write_str("IF EXISTS ");
3197        }
3198        f.write_node(&self.name);
3199
3200        f.write_str(" ADD COLUMN ");
3201        if self.if_col_not_exist {
3202            f.write_str("IF NOT EXISTS ");
3203        }
3204
3205        f.write_node(&self.column_name);
3206        f.write_str(" ");
3207        f.write_node(&self.data_type);
3208    }
3209}
3210
3211impl_display_t!(AlterTableAddColumnStatement);
3212
3213/// `ALTER MATERIALIZED VIEW ... APPLY REPLACEMENT ...`
3214#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3215pub struct AlterMaterializedViewApplyReplacementStatement {
3216    pub if_exists: bool,
3217    pub name: UnresolvedItemName,
3218    pub replacement_name: UnresolvedItemName,
3219}
3220
3221impl AstDisplay for AlterMaterializedViewApplyReplacementStatement {
3222    fn fmt<W>(&self, f: &mut AstFormatter<W>)
3223    where
3224        W: fmt::Write,
3225    {
3226        f.write_str("ALTER MATERIALIZED VIEW ");
3227        if self.if_exists {
3228            f.write_str("IF EXISTS ");
3229        }
3230        f.write_node(&self.name);
3231
3232        f.write_str(" APPLY REPLACEMENT ");
3233        f.write_node(&self.replacement_name);
3234    }
3235}
3236
3237impl_display!(AlterMaterializedViewApplyReplacementStatement);
3238
3239#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3240pub struct DiscardStatement {
3241    pub target: DiscardTarget,
3242}
3243
3244impl AstDisplay for DiscardStatement {
3245    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3246        f.write_str("DISCARD ");
3247        f.write_node(&self.target);
3248    }
3249}
3250impl_display!(DiscardStatement);
3251
3252#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3253pub enum DiscardTarget {
3254    Plans,
3255    Sequences,
3256    Temp,
3257    All,
3258}
3259
3260impl AstDisplay for DiscardTarget {
3261    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3262        match self {
3263            DiscardTarget::Plans => f.write_str("PLANS"),
3264            DiscardTarget::Sequences => f.write_str("SEQUENCES"),
3265            DiscardTarget::Temp => f.write_str("TEMP"),
3266            DiscardTarget::All => f.write_str("ALL"),
3267        }
3268    }
3269}
3270impl_display!(DiscardTarget);
3271
3272/// `DROP`
3273#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3274pub struct DropObjectsStatement {
3275    /// The type of the object to drop: TABLE, VIEW, etc.
3276    pub object_type: ObjectType,
3277    /// An optional `IF EXISTS` clause. (Non-standard.)
3278    pub if_exists: bool,
3279    /// One or more objects to drop. (ANSI SQL requires exactly one.)
3280    pub names: Vec<UnresolvedObjectName>,
3281    /// Whether `CASCADE` was specified. This will be `false` when
3282    /// `RESTRICT` was specified.
3283    pub cascade: bool,
3284}
3285
3286impl AstDisplay for DropObjectsStatement {
3287    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3288        f.write_str("DROP ");
3289        f.write_node(&self.object_type);
3290        f.write_str(" ");
3291        if self.if_exists {
3292            f.write_str("IF EXISTS ");
3293        }
3294        f.write_node(&display::comma_separated(&self.names));
3295        if self.cascade && self.object_type != ObjectType::Database {
3296            f.write_str(" CASCADE");
3297        } else if !self.cascade && self.object_type == ObjectType::Database {
3298            f.write_str(" RESTRICT");
3299        }
3300    }
3301}
3302impl_display!(DropObjectsStatement);
3303
3304/// `DROP OWNED BY ...`
3305#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3306pub struct DropOwnedStatement<T: AstInfo> {
3307    /// The roles whose owned objects are being dropped.
3308    pub role_names: Vec<T::RoleName>,
3309    /// Whether `CASCADE` was specified. `false` for `RESTRICT` and `None` if no drop behavior at
3310    /// all was specified.
3311    pub cascade: Option<bool>,
3312}
3313
3314impl<T: AstInfo> DropOwnedStatement<T> {
3315    pub fn cascade(&self) -> bool {
3316        self.cascade == Some(true)
3317    }
3318}
3319
3320impl<T: AstInfo> AstDisplay for DropOwnedStatement<T> {
3321    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3322        f.write_str("DROP OWNED BY ");
3323        f.write_node(&display::comma_separated(&self.role_names));
3324        if let Some(true) = self.cascade {
3325            f.write_str(" CASCADE");
3326        } else if let Some(false) = self.cascade {
3327            f.write_str(" RESTRICT");
3328        }
3329    }
3330}
3331impl_display_t!(DropOwnedStatement);
3332
3333#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3334pub struct QualifiedReplica {
3335    pub cluster: Ident,
3336    pub replica: Ident,
3337}
3338
3339impl AstDisplay for QualifiedReplica {
3340    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3341        f.write_node(&self.cluster);
3342        f.write_str(".");
3343        f.write_node(&self.replica);
3344    }
3345}
3346impl_display!(QualifiedReplica);
3347
3348/// `SET <variable>`
3349///
3350/// Note: this is not a standard SQL statement, but it is supported by at
3351/// least MySQL and PostgreSQL. Not all MySQL-specific syntactic forms are
3352/// supported yet.
3353#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3354pub struct SetVariableStatement {
3355    pub local: bool,
3356    pub variable: Ident,
3357    pub to: SetVariableTo,
3358}
3359
3360impl AstDisplay for SetVariableStatement {
3361    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3362        f.write_str("SET ");
3363        if self.local {
3364            f.write_str("LOCAL ");
3365        }
3366        f.write_node(&self.variable);
3367        f.write_str(" = ");
3368        f.write_node(&self.to);
3369    }
3370}
3371impl_display!(SetVariableStatement);
3372
3373/// `RESET <variable>`
3374///
3375/// Note: this is not a standard SQL statement, but it is supported by at
3376/// least MySQL and PostgreSQL. Not all syntactic forms are supported yet.
3377#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3378pub struct ResetVariableStatement {
3379    pub variable: Ident,
3380}
3381
3382impl AstDisplay for ResetVariableStatement {
3383    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3384        f.write_str("RESET ");
3385        f.write_node(&self.variable);
3386    }
3387}
3388impl_display!(ResetVariableStatement);
3389
3390/// `SHOW <variable>`
3391#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3392pub struct ShowVariableStatement {
3393    pub variable: Ident,
3394}
3395
3396impl AstDisplay for ShowVariableStatement {
3397    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3398        f.write_str("SHOW ");
3399        f.write_node(&self.variable);
3400    }
3401}
3402impl_display!(ShowVariableStatement);
3403
3404/// `INSPECT SHARD <id>`
3405#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3406pub struct InspectShardStatement {
3407    pub id: String,
3408}
3409
3410impl AstDisplay for InspectShardStatement {
3411    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3412        f.write_str("INSPECT SHARD ");
3413        f.write_str("'");
3414        f.write_node(&display::escape_single_quote_string(&self.id));
3415        f.write_str("'");
3416    }
3417}
3418impl_display!(InspectShardStatement);
3419
3420#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3421pub enum ShowObjectType<T: AstInfo> {
3422    MaterializedView {
3423        in_cluster: Option<T::ClusterName>,
3424    },
3425    Index {
3426        in_cluster: Option<T::ClusterName>,
3427        on_object: Option<T::ItemName>,
3428    },
3429    Table {
3430        on_source: Option<T::ItemName>,
3431    },
3432    View,
3433    Source {
3434        in_cluster: Option<T::ClusterName>,
3435    },
3436    Sink {
3437        in_cluster: Option<T::ClusterName>,
3438    },
3439    Type,
3440    Role,
3441    Cluster,
3442    ClusterReplica,
3443    Object,
3444    Secret,
3445    Connection,
3446    Database,
3447    Schema {
3448        from: Option<T::DatabaseName>,
3449    },
3450    Subsource {
3451        on_source: Option<T::ItemName>,
3452    },
3453    Privileges {
3454        object_type: Option<SystemObjectType>,
3455        role: Option<T::RoleName>,
3456    },
3457    DefaultPrivileges {
3458        object_type: Option<ObjectType>,
3459        role: Option<T::RoleName>,
3460    },
3461    RoleMembership {
3462        role: Option<T::RoleName>,
3463    },
3464    ContinualTask {
3465        in_cluster: Option<T::ClusterName>,
3466    },
3467    NetworkPolicy,
3468}
3469/// `SHOW <object>S`
3470///
3471/// ```sql
3472/// SHOW TABLES;
3473/// SHOW SOURCES;
3474/// SHOW VIEWS;
3475/// SHOW SINKS;
3476/// ```
3477#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3478pub struct ShowObjectsStatement<T: AstInfo> {
3479    pub object_type: ShowObjectType<T>,
3480    pub from: Option<T::SchemaName>,
3481    pub filter: Option<ShowStatementFilter<T>>,
3482}
3483
3484impl<T: AstInfo> AstDisplay for ShowObjectsStatement<T> {
3485    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3486        f.write_str("SHOW");
3487        f.write_str(" ");
3488
3489        f.write_str(match &self.object_type {
3490            ShowObjectType::Table { .. } => "TABLES",
3491            ShowObjectType::View => "VIEWS",
3492            ShowObjectType::Source { .. } => "SOURCES",
3493            ShowObjectType::Sink { .. } => "SINKS",
3494            ShowObjectType::Type => "TYPES",
3495            ShowObjectType::Role => "ROLES",
3496            ShowObjectType::Cluster => "CLUSTERS",
3497            ShowObjectType::ClusterReplica => "CLUSTER REPLICAS",
3498            ShowObjectType::Object => "OBJECTS",
3499            ShowObjectType::Secret => "SECRETS",
3500            ShowObjectType::Connection => "CONNECTIONS",
3501            ShowObjectType::MaterializedView { .. } => "MATERIALIZED VIEWS",
3502            ShowObjectType::Index { .. } => "INDEXES",
3503            ShowObjectType::Database => "DATABASES",
3504            ShowObjectType::Schema { .. } => "SCHEMAS",
3505            ShowObjectType::Subsource { .. } => "SUBSOURCES",
3506            ShowObjectType::Privileges { .. } => "PRIVILEGES",
3507            ShowObjectType::DefaultPrivileges { .. } => "DEFAULT PRIVILEGES",
3508            ShowObjectType::RoleMembership { .. } => "ROLE MEMBERSHIP",
3509            ShowObjectType::ContinualTask { .. } => "CONTINUAL TASKS",
3510            ShowObjectType::NetworkPolicy => "NETWORK POLICIES",
3511        });
3512
3513        if let ShowObjectType::Index { on_object, .. } = &self.object_type {
3514            if let Some(on_object) = on_object {
3515                f.write_str(" ON ");
3516                f.write_node(on_object);
3517            }
3518        }
3519
3520        if let ShowObjectType::Schema { from: Some(from) } = &self.object_type {
3521            f.write_str(" FROM ");
3522            f.write_node(from);
3523        }
3524
3525        if let Some(from) = &self.from {
3526            f.write_str(" FROM ");
3527            f.write_node(from);
3528        }
3529
3530        // append IN CLUSTER clause
3531        match &self.object_type {
3532            ShowObjectType::MaterializedView { in_cluster }
3533            | ShowObjectType::Index { in_cluster, .. }
3534            | ShowObjectType::Sink { in_cluster }
3535            | ShowObjectType::Source { in_cluster }
3536            | ShowObjectType::ContinualTask { in_cluster } => {
3537                if let Some(cluster) = in_cluster {
3538                    f.write_str(" IN CLUSTER ");
3539                    f.write_node(cluster);
3540                }
3541            }
3542            _ => (),
3543        }
3544
3545        if let ShowObjectType::Subsource { on_source } = &self.object_type {
3546            if let Some(on_source) = on_source {
3547                f.write_str(" ON ");
3548                f.write_node(on_source);
3549            }
3550        }
3551
3552        if let ShowObjectType::Table { on_source } = &self.object_type {
3553            if let Some(on_source) = on_source {
3554                f.write_str(" ON ");
3555                f.write_node(on_source);
3556            }
3557        }
3558
3559        if let ShowObjectType::Privileges { object_type, role } = &self.object_type {
3560            if let Some(object_type) = object_type {
3561                f.write_str(" ON ");
3562                f.write_node(object_type);
3563                if let SystemObjectType::Object(_) = object_type {
3564                    f.write_str("S");
3565                }
3566            }
3567            if let Some(role) = role {
3568                f.write_str(" FOR ");
3569                f.write_node(role);
3570            }
3571        }
3572
3573        if let ShowObjectType::DefaultPrivileges { object_type, role } = &self.object_type {
3574            if let Some(object_type) = object_type {
3575                f.write_str(" ON ");
3576                f.write_node(object_type);
3577                f.write_str("S");
3578            }
3579            if let Some(role) = role {
3580                f.write_str(" FOR ");
3581                f.write_node(role);
3582            }
3583        }
3584
3585        if let ShowObjectType::RoleMembership {
3586            role: Some(role), ..
3587        } = &self.object_type
3588        {
3589            f.write_str(" FOR ");
3590            f.write_node(role);
3591        }
3592
3593        if let Some(filter) = &self.filter {
3594            f.write_str(" ");
3595            f.write_node(filter);
3596        }
3597    }
3598}
3599impl_display_t!(ShowObjectsStatement);
3600
3601/// `SHOW COLUMNS`
3602///
3603/// Note: this is a MySQL-specific statement.
3604#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3605pub struct ShowColumnsStatement<T: AstInfo> {
3606    pub table_name: T::ItemName,
3607    pub filter: Option<ShowStatementFilter<T>>,
3608}
3609
3610impl<T: AstInfo> AstDisplay for ShowColumnsStatement<T> {
3611    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3612        f.write_str("SHOW ");
3613        f.write_str("COLUMNS FROM ");
3614        f.write_node(&self.table_name);
3615        if let Some(filter) = &self.filter {
3616            f.write_str(" ");
3617            f.write_node(filter);
3618        }
3619    }
3620}
3621impl_display_t!(ShowColumnsStatement);
3622
3623/// `SHOW [REDACTED] CREATE VIEW <view>`
3624#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3625pub struct ShowCreateViewStatement<T: AstInfo> {
3626    pub view_name: T::ItemName,
3627    pub redacted: bool,
3628}
3629
3630impl<T: AstInfo> AstDisplay for ShowCreateViewStatement<T> {
3631    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3632        f.write_str("SHOW ");
3633        if self.redacted {
3634            f.write_str("REDACTED ");
3635        }
3636        f.write_str("CREATE VIEW ");
3637        f.write_node(&self.view_name);
3638    }
3639}
3640impl_display_t!(ShowCreateViewStatement);
3641
3642/// `SHOW [REDACTED] CREATE MATERIALIZED VIEW <name>`
3643#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3644pub struct ShowCreateMaterializedViewStatement<T: AstInfo> {
3645    pub materialized_view_name: T::ItemName,
3646    pub redacted: bool,
3647}
3648
3649impl<T: AstInfo> AstDisplay for ShowCreateMaterializedViewStatement<T> {
3650    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3651        f.write_str("SHOW ");
3652        if self.redacted {
3653            f.write_str("REDACTED ");
3654        }
3655        f.write_str("CREATE MATERIALIZED VIEW ");
3656        f.write_node(&self.materialized_view_name);
3657    }
3658}
3659impl_display_t!(ShowCreateMaterializedViewStatement);
3660
3661/// `SHOW [REDACTED] CREATE SOURCE <source>`
3662#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3663pub struct ShowCreateSourceStatement<T: AstInfo> {
3664    pub source_name: T::ItemName,
3665    pub redacted: bool,
3666}
3667
3668impl<T: AstInfo> AstDisplay for ShowCreateSourceStatement<T> {
3669    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3670        f.write_str("SHOW ");
3671        if self.redacted {
3672            f.write_str("REDACTED ");
3673        }
3674        f.write_str("CREATE SOURCE ");
3675        f.write_node(&self.source_name);
3676    }
3677}
3678impl_display_t!(ShowCreateSourceStatement);
3679
3680/// `SHOW [REDACTED] CREATE TABLE <table>`
3681#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3682pub struct ShowCreateTableStatement<T: AstInfo> {
3683    pub table_name: T::ItemName,
3684    pub redacted: bool,
3685}
3686
3687impl<T: AstInfo> AstDisplay for ShowCreateTableStatement<T> {
3688    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3689        f.write_str("SHOW ");
3690        if self.redacted {
3691            f.write_str("REDACTED ");
3692        }
3693        f.write_str("CREATE TABLE ");
3694        f.write_node(&self.table_name);
3695    }
3696}
3697impl_display_t!(ShowCreateTableStatement);
3698
3699/// `SHOW [REDACTED] CREATE SINK <sink>`
3700#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3701pub struct ShowCreateSinkStatement<T: AstInfo> {
3702    pub sink_name: T::ItemName,
3703    pub redacted: bool,
3704}
3705
3706impl<T: AstInfo> AstDisplay for ShowCreateSinkStatement<T> {
3707    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3708        f.write_str("SHOW ");
3709        if self.redacted {
3710            f.write_str("REDACTED ");
3711        }
3712        f.write_str("CREATE SINK ");
3713        f.write_node(&self.sink_name);
3714    }
3715}
3716impl_display_t!(ShowCreateSinkStatement);
3717
3718/// `SHOW [REDACTED] CREATE INDEX <index>`
3719#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3720pub struct ShowCreateIndexStatement<T: AstInfo> {
3721    pub index_name: T::ItemName,
3722    pub redacted: bool,
3723}
3724
3725impl<T: AstInfo> AstDisplay for ShowCreateIndexStatement<T> {
3726    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3727        f.write_str("SHOW ");
3728        if self.redacted {
3729            f.write_str("REDACTED ");
3730        }
3731        f.write_str("CREATE INDEX ");
3732        f.write_node(&self.index_name);
3733    }
3734}
3735impl_display_t!(ShowCreateIndexStatement);
3736
3737/// `SHOW [REDACTED] CREATE CONNECTION <connection>`
3738#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3739pub struct ShowCreateConnectionStatement<T: AstInfo> {
3740    pub connection_name: T::ItemName,
3741    pub redacted: bool,
3742}
3743
3744impl<T: AstInfo> AstDisplay for ShowCreateConnectionStatement<T> {
3745    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3746        f.write_str("SHOW ");
3747        if self.redacted {
3748            f.write_str("REDACTED ");
3749        }
3750        f.write_str("CREATE CONNECTION ");
3751        f.write_node(&self.connection_name);
3752    }
3753}
3754
3755#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3756pub struct ShowCreateClusterStatement<T: AstInfo> {
3757    pub cluster_name: T::ClusterName,
3758}
3759
3760impl<T: AstInfo> AstDisplay for ShowCreateClusterStatement<T> {
3761    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3762        f.write_str("SHOW CREATE CLUSTER ");
3763        f.write_node(&self.cluster_name);
3764    }
3765}
3766
3767/// `{ BEGIN [ TRANSACTION | WORK ] | START TRANSACTION } ...`
3768#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3769pub struct StartTransactionStatement {
3770    pub modes: Vec<TransactionMode>,
3771}
3772
3773impl AstDisplay for StartTransactionStatement {
3774    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3775        f.write_str("START TRANSACTION");
3776        if !self.modes.is_empty() {
3777            f.write_str(" ");
3778            f.write_node(&display::comma_separated(&self.modes));
3779        }
3780    }
3781}
3782impl_display!(StartTransactionStatement);
3783
3784/// `SHOW [REDACTED] CREATE TYPE <type>`
3785#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3786pub struct ShowCreateTypeStatement<T: AstInfo> {
3787    pub type_name: T::DataType,
3788    pub redacted: bool,
3789}
3790
3791impl<T: AstInfo> AstDisplay for ShowCreateTypeStatement<T> {
3792    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3793        f.write_str("SHOW ");
3794        if self.redacted {
3795            f.write_str("REDACTED ");
3796        }
3797        f.write_str("CREATE TYPE ");
3798        f.write_node(&self.type_name);
3799    }
3800}
3801
3802/// `SET TRANSACTION ...`
3803#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3804pub struct SetTransactionStatement {
3805    pub local: bool,
3806    pub modes: Vec<TransactionMode>,
3807}
3808
3809impl AstDisplay for SetTransactionStatement {
3810    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3811        f.write_str("SET ");
3812        if !self.local {
3813            f.write_str("SESSION CHARACTERISTICS AS ");
3814        }
3815        f.write_str("TRANSACTION");
3816        if !self.modes.is_empty() {
3817            f.write_str(" ");
3818            f.write_node(&display::comma_separated(&self.modes));
3819        }
3820    }
3821}
3822impl_display!(SetTransactionStatement);
3823
3824/// `COMMIT [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
3825#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3826pub struct CommitStatement {
3827    pub chain: bool,
3828}
3829
3830impl AstDisplay for CommitStatement {
3831    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3832        f.write_str("COMMIT");
3833        if self.chain {
3834            f.write_str(" AND CHAIN");
3835        }
3836    }
3837}
3838impl_display!(CommitStatement);
3839
3840/// `ROLLBACK [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
3841#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3842pub struct RollbackStatement {
3843    pub chain: bool,
3844}
3845
3846impl AstDisplay for RollbackStatement {
3847    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3848        f.write_str("ROLLBACK");
3849        if self.chain {
3850            f.write_str(" AND CHAIN");
3851        }
3852    }
3853}
3854impl_display!(RollbackStatement);
3855
3856#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3857pub enum SubscribeOptionName {
3858    Snapshot,
3859    Progress,
3860}
3861
3862impl AstDisplay for SubscribeOptionName {
3863    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3864        match self {
3865            SubscribeOptionName::Snapshot => f.write_str("SNAPSHOT"),
3866            SubscribeOptionName::Progress => f.write_str("PROGRESS"),
3867        }
3868    }
3869}
3870impl_display!(SubscribeOptionName);
3871
3872impl WithOptionName for SubscribeOptionName {
3873    /// # WARNING
3874    ///
3875    /// Whenever implementing this trait consider very carefully whether or not
3876    /// this value could contain sensitive user data. If you're uncertain, err
3877    /// on the conservative side and return `true`.
3878    fn redact_value(&self) -> bool {
3879        match self {
3880            SubscribeOptionName::Snapshot | SubscribeOptionName::Progress => false,
3881        }
3882    }
3883}
3884
3885#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3886pub struct SubscribeOption<T: AstInfo> {
3887    pub name: SubscribeOptionName,
3888    pub value: Option<WithOptionValue<T>>,
3889}
3890impl_display_for_with_option!(SubscribeOption);
3891impl_display_t!(SubscribeOption);
3892
3893/// `SUBSCRIBE`
3894#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3895pub struct SubscribeStatement<T: AstInfo> {
3896    pub relation: SubscribeRelation<T>,
3897    pub options: Vec<SubscribeOption<T>>,
3898    pub as_of: Option<AsOf<T>>,
3899    pub up_to: Option<Expr<T>>,
3900    pub output: SubscribeOutput<T>,
3901}
3902
3903impl<T: AstInfo> AstDisplay for SubscribeStatement<T> {
3904    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3905        f.write_str("SUBSCRIBE ");
3906        f.write_node(&self.relation);
3907        if !self.options.is_empty() {
3908            f.write_str(" WITH (");
3909            f.write_node(&display::comma_separated(&self.options));
3910            f.write_str(")");
3911        }
3912        if let Some(as_of) = &self.as_of {
3913            f.write_str(" ");
3914            f.write_node(as_of);
3915        }
3916        if let Some(up_to) = &self.up_to {
3917            f.write_str(" UP TO ");
3918            f.write_node(up_to);
3919        }
3920        f.write_str(&self.output);
3921    }
3922}
3923impl_display_t!(SubscribeStatement);
3924
3925#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3926pub enum SubscribeRelation<T: AstInfo> {
3927    Name(T::ItemName),
3928    Query(Query<T>),
3929}
3930
3931impl<T: AstInfo> AstDisplay for SubscribeRelation<T> {
3932    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3933        match self {
3934            SubscribeRelation::Name(name) => f.write_node(name),
3935            SubscribeRelation::Query(query) => {
3936                f.write_str("(");
3937                f.write_node(query);
3938                f.write_str(")");
3939            }
3940        }
3941    }
3942}
3943impl_display_t!(SubscribeRelation);
3944
3945#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3946pub struct ExplainPlanStatement<T: AstInfo> {
3947    pub stage: Option<ExplainStage>,
3948    pub with_options: Vec<ExplainPlanOption<T>>,
3949    pub format: Option<ExplainFormat>,
3950    pub explainee: Explainee<T>,
3951}
3952
3953impl<T: AstInfo> ExplainPlanStatement<T> {
3954    pub fn stage(&self) -> ExplainStage {
3955        self.stage.unwrap_or(ExplainStage::PhysicalPlan)
3956    }
3957
3958    pub fn format(&self) -> ExplainFormat {
3959        self.format.unwrap_or(ExplainFormat::Text)
3960    }
3961}
3962
3963impl<T: AstInfo> AstDisplay for ExplainPlanStatement<T> {
3964    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
3965        f.write_str("EXPLAIN");
3966        if let Some(stage) = &self.stage {
3967            f.write_str(" ");
3968            f.write_node(stage);
3969        }
3970        if !self.with_options.is_empty() {
3971            f.write_str(" WITH (");
3972            f.write_node(&display::comma_separated(&self.with_options));
3973            f.write_str(")");
3974        }
3975        if let Some(format) = &self.format {
3976            f.write_str(" AS ");
3977            f.write_node(format);
3978        }
3979        if self.stage.is_some() {
3980            f.write_str(" FOR");
3981        }
3982        f.write_str(" ");
3983        f.write_node(&self.explainee);
3984    }
3985}
3986impl_display_t!(ExplainPlanStatement);
3987
3988// Note: the `AstDisplay` implementation and `Parser::parse_` method for this
3989// enum are generated automatically by this crate's `build.rs`.
3990#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
3991pub enum ExplainPlanOptionName {
3992    Arity,
3993    Cardinality,
3994    ColumnNames,
3995    FilterPushdown,
3996    HumanizedExpressions,
3997    JoinImplementations,
3998    Keys,
3999    LinearChains,
4000    NonNegative,
4001    NoFastPath,
4002    NoNotices,
4003    NodeIdentifiers,
4004    RawPlans,
4005    RawSyntax,
4006    Raw, // Listed after the `Raw~` variants to keep the parser happy!
4007    Redacted,
4008    SubtreeSize,
4009    Timing,
4010    Types,
4011    Equivalences,
4012    ReoptimizeImportedViews,
4013    EnableNewOuterJoinLowering,
4014    EnableEagerDeltaJoins,
4015    EnableVariadicLeftJoinLowering,
4016    EnableLetrecFixpointAnalysis,
4017    EnableJoinPrioritizeArranged,
4018    EnableProjectionPushdownAfterRelationCse,
4019}
4020
4021impl WithOptionName for ExplainPlanOptionName {
4022    /// # WARNING
4023    ///
4024    /// Whenever implementing this trait consider very carefully whether or not
4025    /// this value could contain sensitive user data. If you're uncertain, err
4026    /// on the conservative side and return `true`.
4027    fn redact_value(&self) -> bool {
4028        match self {
4029            Self::Arity
4030            | Self::Cardinality
4031            | Self::ColumnNames
4032            | Self::FilterPushdown
4033            | Self::HumanizedExpressions
4034            | Self::JoinImplementations
4035            | Self::Keys
4036            | Self::LinearChains
4037            | Self::NonNegative
4038            | Self::NoFastPath
4039            | Self::NoNotices
4040            | Self::NodeIdentifiers
4041            | Self::RawPlans
4042            | Self::RawSyntax
4043            | Self::Raw
4044            | Self::Redacted
4045            | Self::SubtreeSize
4046            | Self::Timing
4047            | Self::Types
4048            | Self::Equivalences
4049            | Self::ReoptimizeImportedViews
4050            | Self::EnableNewOuterJoinLowering
4051            | Self::EnableEagerDeltaJoins
4052            | Self::EnableVariadicLeftJoinLowering
4053            | Self::EnableLetrecFixpointAnalysis
4054            | Self::EnableJoinPrioritizeArranged
4055            | Self::EnableProjectionPushdownAfterRelationCse => false,
4056        }
4057    }
4058}
4059
4060#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4061pub struct ExplainPlanOption<T: AstInfo> {
4062    pub name: ExplainPlanOptionName,
4063    pub value: Option<WithOptionValue<T>>,
4064}
4065impl_display_for_with_option!(ExplainPlanOption);
4066
4067#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4068pub enum ExplainSinkSchemaFor {
4069    Key,
4070    Value,
4071}
4072#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4073pub struct ExplainSinkSchemaStatement<T: AstInfo> {
4074    pub schema_for: ExplainSinkSchemaFor,
4075    pub format: Option<ExplainFormat>,
4076    pub statement: CreateSinkStatement<T>,
4077}
4078
4079impl<T: AstInfo> AstDisplay for ExplainSinkSchemaStatement<T> {
4080    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4081        f.write_str("EXPLAIN ");
4082        match &self.schema_for {
4083            ExplainSinkSchemaFor::Key => f.write_str("KEY"),
4084            ExplainSinkSchemaFor::Value => f.write_str("VALUE"),
4085        }
4086        f.write_str(" SCHEMA");
4087        if let Some(format) = &self.format {
4088            f.write_str(" AS ");
4089            f.write_node(format);
4090        }
4091        f.write_str(" FOR ");
4092        f.write_node(&self.statement);
4093    }
4094}
4095impl_display_t!(ExplainSinkSchemaStatement);
4096
4097#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4098pub struct ExplainPushdownStatement<T: AstInfo> {
4099    pub explainee: Explainee<T>,
4100}
4101
4102impl<T: AstInfo> AstDisplay for ExplainPushdownStatement<T> {
4103    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4104        f.write_str("EXPLAIN FILTER PUSHDOWN FOR ");
4105        f.write_node(&self.explainee);
4106    }
4107}
4108impl_display_t!(ExplainPushdownStatement);
4109
4110#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
4111pub enum ExplainAnalyzeComputationProperty {
4112    Cpu,
4113    Memory,
4114}
4115
4116#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4117pub enum ExplainAnalyzeProperty {
4118    Computation(ExplainAnalyzeComputationProperties),
4119    Hints,
4120}
4121
4122#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4123pub struct ExplainAnalyzeComputationProperties {
4124    /// Must be non-empty.
4125    pub properties: Vec<ExplainAnalyzeComputationProperty>,
4126    pub skew: bool,
4127}
4128#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4129pub struct ExplainAnalyzeObjectStatement<T: AstInfo> {
4130    pub properties: ExplainAnalyzeProperty,
4131    /// Should only be `Explainee::Index` or `Explainee::MaterializedView`
4132    pub explainee: Explainee<T>,
4133    pub as_sql: bool,
4134}
4135
4136impl<T: AstInfo> AstDisplay for ExplainAnalyzeObjectStatement<T> {
4137    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4138        f.write_str("EXPLAIN ANALYZE");
4139        match &self.properties {
4140            ExplainAnalyzeProperty::Computation(ExplainAnalyzeComputationProperties {
4141                properties,
4142                skew,
4143            }) => {
4144                let mut first = true;
4145                for property in properties {
4146                    if first {
4147                        first = false;
4148                    } else {
4149                        f.write_str(",");
4150                    }
4151                    match property {
4152                        ExplainAnalyzeComputationProperty::Cpu => f.write_str(" CPU"),
4153                        ExplainAnalyzeComputationProperty::Memory => f.write_str(" MEMORY"),
4154                    }
4155                }
4156                if *skew {
4157                    f.write_str(" WITH SKEW");
4158                }
4159            }
4160            ExplainAnalyzeProperty::Hints => f.write_str(" HINTS"),
4161        }
4162        f.write_str(" FOR ");
4163        f.write_node(&self.explainee);
4164        if self.as_sql {
4165            f.write_str(" AS SQL");
4166        }
4167    }
4168}
4169impl_display_t!(ExplainAnalyzeObjectStatement);
4170
4171#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4172pub struct ExplainAnalyzeClusterStatement {
4173    pub properties: ExplainAnalyzeComputationProperties,
4174    pub as_sql: bool,
4175}
4176
4177impl AstDisplay for ExplainAnalyzeClusterStatement {
4178    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4179        f.write_str("EXPLAIN ANALYZE CLUSTER");
4180
4181        let mut first = true;
4182        for property in &self.properties.properties {
4183            if first {
4184                first = false;
4185            } else {
4186                f.write_str(",");
4187            }
4188            match property {
4189                ExplainAnalyzeComputationProperty::Cpu => f.write_str(" CPU"),
4190                ExplainAnalyzeComputationProperty::Memory => f.write_str(" MEMORY"),
4191            }
4192        }
4193
4194        if self.properties.skew {
4195            f.write_str(" WITH SKEW");
4196        }
4197        if self.as_sql {
4198            f.write_str(" AS SQL");
4199        }
4200    }
4201}
4202impl_display!(ExplainAnalyzeClusterStatement);
4203
4204#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4205pub struct ExplainTimestampStatement<T: AstInfo> {
4206    pub format: Option<ExplainFormat>,
4207    pub select: SelectStatement<T>,
4208}
4209
4210impl<T: AstInfo> ExplainTimestampStatement<T> {
4211    pub fn format(&self) -> ExplainFormat {
4212        self.format.unwrap_or(ExplainFormat::Text)
4213    }
4214}
4215
4216impl<T: AstInfo> AstDisplay for ExplainTimestampStatement<T> {
4217    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4218        f.write_str("EXPLAIN TIMESTAMP");
4219        if let Some(format) = &self.format {
4220            f.write_str(" AS ");
4221            f.write_node(format);
4222        }
4223        f.write_str(" FOR ");
4224        f.write_node(&self.select);
4225    }
4226}
4227impl_display_t!(ExplainTimestampStatement);
4228
4229#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4230pub enum InsertSource<T: AstInfo> {
4231    Query(Query<T>),
4232    DefaultValues,
4233}
4234
4235impl<T: AstInfo> AstDisplay for InsertSource<T> {
4236    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4237        match self {
4238            InsertSource::Query(query) => f.write_node(query),
4239            InsertSource::DefaultValues => f.write_str("DEFAULT VALUES"),
4240        }
4241    }
4242}
4243impl_display_t!(InsertSource);
4244
4245#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
4246pub enum ObjectType {
4247    Table,
4248    View,
4249    MaterializedView,
4250    Source,
4251    Sink,
4252    Index,
4253    Type,
4254    Role,
4255    Cluster,
4256    ClusterReplica,
4257    Secret,
4258    Connection,
4259    Database,
4260    Schema,
4261    Func,
4262    Subsource,
4263    ContinualTask,
4264    NetworkPolicy,
4265}
4266
4267impl ObjectType {
4268    pub fn lives_in_schema(&self) -> bool {
4269        match self {
4270            ObjectType::Table
4271            | ObjectType::View
4272            | ObjectType::MaterializedView
4273            | ObjectType::Source
4274            | ObjectType::Sink
4275            | ObjectType::Index
4276            | ObjectType::Type
4277            | ObjectType::Secret
4278            | ObjectType::Connection
4279            | ObjectType::Func
4280            | ObjectType::Subsource
4281            | ObjectType::ContinualTask => true,
4282            ObjectType::Database
4283            | ObjectType::Schema
4284            | ObjectType::Cluster
4285            | ObjectType::ClusterReplica
4286            | ObjectType::Role
4287            | ObjectType::NetworkPolicy => false,
4288        }
4289    }
4290}
4291
4292impl AstDisplay for ObjectType {
4293    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4294        f.write_str(match self {
4295            ObjectType::Table => "TABLE",
4296            ObjectType::View => "VIEW",
4297            ObjectType::MaterializedView => "MATERIALIZED VIEW",
4298            ObjectType::Source => "SOURCE",
4299            ObjectType::Sink => "SINK",
4300            ObjectType::Index => "INDEX",
4301            ObjectType::Type => "TYPE",
4302            ObjectType::Role => "ROLE",
4303            ObjectType::Cluster => "CLUSTER",
4304            ObjectType::ClusterReplica => "CLUSTER REPLICA",
4305            ObjectType::Secret => "SECRET",
4306            ObjectType::Connection => "CONNECTION",
4307            ObjectType::Database => "DATABASE",
4308            ObjectType::Schema => "SCHEMA",
4309            ObjectType::Func => "FUNCTION",
4310            ObjectType::Subsource => "SUBSOURCE",
4311            ObjectType::ContinualTask => "CONTINUAL TASK",
4312            ObjectType::NetworkPolicy => "NETWORK POLICY",
4313        })
4314    }
4315}
4316impl_display!(ObjectType);
4317
4318#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
4319pub enum SystemObjectType {
4320    System,
4321    Object(ObjectType),
4322}
4323
4324impl AstDisplay for SystemObjectType {
4325    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4326        match self {
4327            SystemObjectType::System => f.write_str("SYSTEM"),
4328            SystemObjectType::Object(object) => f.write_node(object),
4329        }
4330    }
4331}
4332impl_display!(SystemObjectType);
4333
4334#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4335pub enum ShowStatementFilter<T: AstInfo> {
4336    Like(String),
4337    Where(Expr<T>),
4338}
4339
4340impl<T: AstInfo> AstDisplay for ShowStatementFilter<T> {
4341    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4342        use ShowStatementFilter::*;
4343        match self {
4344            Like(pattern) => {
4345                f.write_str("LIKE '");
4346                f.write_node(&display::escape_single_quote_string(pattern));
4347                f.write_str("'");
4348            }
4349            Where(expr) => {
4350                f.write_str("WHERE ");
4351                f.write_node(expr);
4352            }
4353        }
4354    }
4355}
4356impl_display_t!(ShowStatementFilter);
4357
4358#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4359pub enum WithOptionValue<T: AstInfo> {
4360    Value(Value),
4361    DataType(T::DataType),
4362    Secret(T::ItemName),
4363    Item(T::ItemName),
4364    UnresolvedItemName(UnresolvedItemName),
4365    Ident(Ident),
4366    Sequence(Vec<WithOptionValue<T>>),
4367    Map(BTreeMap<String, WithOptionValue<T>>),
4368    // Special cases.
4369    Expr(Expr<T>),
4370    ClusterReplicas(Vec<ReplicaDefinition<T>>),
4371    ConnectionKafkaBroker(KafkaBroker<T>),
4372    ConnectionAwsPrivatelink(ConnectionDefaultAwsPrivatelink<T>),
4373    RetainHistoryFor(Value),
4374    Refresh(RefreshOptionValue<T>),
4375    ClusterScheduleOptionValue(ClusterScheduleOptionValue),
4376    ClusterAlterStrategy(ClusterAlterOptionValue<T>),
4377    NetworkPolicyRules(Vec<NetworkPolicyRuleDefinition<T>>),
4378}
4379
4380impl<T: AstInfo> AstDisplay for WithOptionValue<T> {
4381    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4382        if f.redacted() {
4383            // When adding branches to this match statement, think about whether it is OK for us to collect
4384            // the value as part of our telemetry. Check the data management policy to be sure!
4385            match self {
4386                WithOptionValue::Value(_)
4387                | WithOptionValue::Sequence(_)
4388                | WithOptionValue::Map(_)
4389                | WithOptionValue::RetainHistoryFor(_)
4390                | WithOptionValue::Refresh(_)
4391                | WithOptionValue::Expr(_) => {
4392                    // These are redact-aware.
4393                }
4394                WithOptionValue::Secret(_) | WithOptionValue::ConnectionKafkaBroker(_) => {
4395                    f.write_str("'<REDACTED>'");
4396                    return;
4397                }
4398                WithOptionValue::DataType(_)
4399                | WithOptionValue::Item(_)
4400                | WithOptionValue::UnresolvedItemName(_)
4401                | WithOptionValue::Ident(_)
4402                | WithOptionValue::ConnectionAwsPrivatelink(_)
4403                | WithOptionValue::ClusterReplicas(_)
4404                | WithOptionValue::ClusterScheduleOptionValue(_)
4405                | WithOptionValue::ClusterAlterStrategy(_)
4406                | WithOptionValue::NetworkPolicyRules(_) => {
4407                    // These do not need redaction.
4408                }
4409            }
4410        }
4411        match self {
4412            WithOptionValue::Sequence(values) => {
4413                f.write_str("(");
4414                f.write_node(&display::comma_separated(values));
4415                f.write_str(")");
4416            }
4417            WithOptionValue::Map(values) => {
4418                f.write_str("MAP[");
4419                let len = values.len();
4420                for (i, (key, value)) in values.iter().enumerate() {
4421                    f.write_str("'");
4422                    f.write_node(&display::escape_single_quote_string(key));
4423                    f.write_str("' => ");
4424                    f.write_node(value);
4425                    if i + 1 < len {
4426                        f.write_str(", ");
4427                    }
4428                }
4429                f.write_str("]");
4430            }
4431            WithOptionValue::Expr(e) => f.write_node(e),
4432            WithOptionValue::Value(value) => f.write_node(value),
4433            WithOptionValue::DataType(typ) => f.write_node(typ),
4434            WithOptionValue::Secret(name) => {
4435                f.write_str("SECRET ");
4436                f.write_node(name)
4437            }
4438            WithOptionValue::Item(obj) => f.write_node(obj),
4439            WithOptionValue::UnresolvedItemName(r) => f.write_node(r),
4440            WithOptionValue::Ident(r) => f.write_node(r),
4441            WithOptionValue::ClusterReplicas(replicas) => {
4442                f.write_str("(");
4443                f.write_node(&display::comma_separated(replicas));
4444                f.write_str(")");
4445            }
4446            WithOptionValue::NetworkPolicyRules(rules) => {
4447                f.write_str("(");
4448                f.write_node(&display::comma_separated(rules));
4449                f.write_str(")");
4450            }
4451            WithOptionValue::ConnectionAwsPrivatelink(aws_privatelink) => {
4452                f.write_node(aws_privatelink);
4453            }
4454            WithOptionValue::ConnectionKafkaBroker(broker) => {
4455                f.write_node(broker);
4456            }
4457            WithOptionValue::RetainHistoryFor(value) => {
4458                f.write_str("FOR ");
4459                f.write_node(value);
4460            }
4461            WithOptionValue::Refresh(opt) => f.write_node(opt),
4462            WithOptionValue::ClusterScheduleOptionValue(value) => f.write_node(value),
4463            WithOptionValue::ClusterAlterStrategy(value) => f.write_node(value),
4464        }
4465    }
4466}
4467impl_display_t!(WithOptionValue);
4468
4469#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4470pub enum RefreshOptionValue<T: AstInfo> {
4471    OnCommit,
4472    AtCreation,
4473    At(RefreshAtOptionValue<T>),
4474    Every(RefreshEveryOptionValue<T>),
4475}
4476
4477#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4478pub struct RefreshAtOptionValue<T: AstInfo> {
4479    // We need an Expr because we want to support `mz_now()`.
4480    pub time: Expr<T>,
4481}
4482
4483#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4484pub struct RefreshEveryOptionValue<T: AstInfo> {
4485    // The refresh interval.
4486    pub interval: IntervalValue,
4487    // We need an Expr because we want to support `mz_now()`.
4488    pub aligned_to: Option<Expr<T>>,
4489}
4490
4491impl<T: AstInfo> AstDisplay for RefreshOptionValue<T> {
4492    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4493        match self {
4494            RefreshOptionValue::OnCommit => {
4495                f.write_str("ON COMMIT");
4496            }
4497            RefreshOptionValue::AtCreation => {
4498                f.write_str("AT CREATION");
4499            }
4500            RefreshOptionValue::At(RefreshAtOptionValue { time }) => {
4501                f.write_str("AT ");
4502                f.write_node(time);
4503            }
4504            RefreshOptionValue::Every(RefreshEveryOptionValue {
4505                interval,
4506                aligned_to,
4507            }) => {
4508                f.write_str("EVERY '");
4509                f.write_node(interval);
4510                if let Some(aligned_to) = aligned_to {
4511                    f.write_str(" ALIGNED TO ");
4512                    f.write_node(aligned_to)
4513                }
4514            }
4515        }
4516    }
4517}
4518
4519#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Deserialize, Serialize)]
4520pub enum ClusterScheduleOptionValue {
4521    Manual,
4522    Refresh {
4523        hydration_time_estimate: Option<IntervalValue>,
4524    },
4525}
4526
4527impl Default for ClusterScheduleOptionValue {
4528    fn default() -> Self {
4529        // (Has to be consistent with `impl Default for ClusterSchedule`.)
4530        ClusterScheduleOptionValue::Manual
4531    }
4532}
4533
4534impl AstDisplay for ClusterScheduleOptionValue {
4535    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4536        match self {
4537            ClusterScheduleOptionValue::Manual => {
4538                f.write_str("MANUAL");
4539            }
4540            ClusterScheduleOptionValue::Refresh {
4541                hydration_time_estimate,
4542            } => {
4543                f.write_str("ON REFRESH");
4544                if let Some(hydration_time_estimate) = hydration_time_estimate {
4545                    f.write_str(" (HYDRATION TIME ESTIMATE = '");
4546                    f.write_node(hydration_time_estimate);
4547                    f.write_str(")");
4548                }
4549            }
4550        }
4551    }
4552}
4553
4554#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4555pub enum TransactionMode {
4556    AccessMode(TransactionAccessMode),
4557    IsolationLevel(TransactionIsolationLevel),
4558}
4559
4560impl AstDisplay for TransactionMode {
4561    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4562        use TransactionMode::*;
4563        match self {
4564            AccessMode(access_mode) => f.write_node(access_mode),
4565            IsolationLevel(iso_level) => {
4566                f.write_str("ISOLATION LEVEL ");
4567                f.write_node(iso_level);
4568            }
4569        }
4570    }
4571}
4572impl_display!(TransactionMode);
4573
4574#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
4575pub enum TransactionAccessMode {
4576    ReadOnly,
4577    ReadWrite,
4578}
4579
4580impl AstDisplay for TransactionAccessMode {
4581    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4582        use TransactionAccessMode::*;
4583        f.write_str(match self {
4584            ReadOnly => "READ ONLY",
4585            ReadWrite => "READ WRITE",
4586        })
4587    }
4588}
4589impl_display!(TransactionAccessMode);
4590
4591#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
4592pub enum TransactionIsolationLevel {
4593    ReadUncommitted,
4594    ReadCommitted,
4595    RepeatableRead,
4596    Serializable,
4597    StrongSessionSerializable,
4598    StrictSerializable,
4599}
4600
4601impl AstDisplay for TransactionIsolationLevel {
4602    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4603        use TransactionIsolationLevel::*;
4604        f.write_str(match self {
4605            ReadUncommitted => "READ UNCOMMITTED",
4606            ReadCommitted => "READ COMMITTED",
4607            RepeatableRead => "REPEATABLE READ",
4608            Serializable => "SERIALIZABLE",
4609            StrongSessionSerializable => "STRONG SESSION SERIALIZABLE",
4610            StrictSerializable => "STRICT SERIALIZABLE",
4611        })
4612    }
4613}
4614impl_display!(TransactionIsolationLevel);
4615
4616#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4617pub enum SetVariableTo {
4618    Default,
4619    Values(Vec<SetVariableValue>),
4620}
4621
4622impl AstDisplay for SetVariableTo {
4623    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4624        use SetVariableTo::*;
4625        match self {
4626            Values(values) => f.write_node(&display::comma_separated(values)),
4627            Default => f.write_str("DEFAULT"),
4628        }
4629    }
4630}
4631impl_display!(SetVariableTo);
4632
4633#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4634pub enum SetVariableValue {
4635    Ident(Ident),
4636    Literal(Value),
4637}
4638
4639impl AstDisplay for SetVariableValue {
4640    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4641        use SetVariableValue::*;
4642        match self {
4643            Ident(ident) => f.write_node(ident),
4644            Literal(literal) => f.write_node(literal),
4645        }
4646    }
4647}
4648impl_display!(SetVariableValue);
4649
4650impl SetVariableValue {
4651    /// Returns the underlying value without quotes.
4652    pub fn into_unquoted_value(self) -> String {
4653        match self {
4654            // `lit.to_string` will quote a `Value::String`, so get the unquoted
4655            // version.
4656            SetVariableValue::Literal(Value::String(s)) => s,
4657            SetVariableValue::Literal(lit) => lit.to_string(),
4658            SetVariableValue::Ident(ident) => ident.into_string(),
4659        }
4660    }
4661}
4662
4663/// SQL assignment `foo = expr` as used in SQLUpdate
4664#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4665pub struct Assignment<T: AstInfo> {
4666    pub id: Ident,
4667    pub value: Expr<T>,
4668}
4669
4670impl<T: AstInfo> AstDisplay for Assignment<T> {
4671    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4672        f.write_node(&self.id);
4673        f.write_str(" = ");
4674        f.write_node(&self.value);
4675    }
4676}
4677impl_display_t!(Assignment);
4678
4679/// Specifies what [Statement::ExplainPlan] is actually explained.
4680#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4681pub enum ExplainStage {
4682    /// The mz_sql::HirRelationExpr after parsing
4683    RawPlan,
4684    /// The mz_expr::MirRelationExpr after decorrelation
4685    DecorrelatedPlan,
4686    /// The mz_expr::MirRelationExpr after local optimization
4687    LocalPlan,
4688    /// The mz_expr::MirRelationExpr after global optimization
4689    GlobalPlan,
4690    /// The mz_compute_types::plan::Plan
4691    PhysicalPlan,
4692    /// The complete trace of the plan through the optimizer
4693    Trace,
4694    /// Insights about the plan
4695    PlanInsights,
4696}
4697
4698impl ExplainStage {
4699    /// Return the tracing path that corresponds to a given stage.
4700    pub fn paths(&self) -> Option<SmallVec<[NamedPlan; 4]>> {
4701        use NamedPlan::*;
4702        match self {
4703            Self::RawPlan => Some(smallvec![Raw]),
4704            Self::DecorrelatedPlan => Some(smallvec![Decorrelated]),
4705            Self::LocalPlan => Some(smallvec![Local]),
4706            Self::GlobalPlan => Some(smallvec![Global]),
4707            Self::PhysicalPlan => Some(smallvec![Physical]),
4708            Self::Trace => None,
4709            Self::PlanInsights => Some(smallvec![Raw, Global, FastPath]),
4710        }
4711    }
4712
4713    // Whether instead of the plan associated with this [`ExplainStage`] we
4714    // should show the [`NamedPlan::FastPath`] plan if available.
4715    pub fn show_fast_path(&self) -> bool {
4716        match self {
4717            Self::RawPlan => false,
4718            Self::DecorrelatedPlan => false,
4719            Self::LocalPlan => false,
4720            Self::GlobalPlan => true,
4721            Self::PhysicalPlan => true,
4722            Self::Trace => false,
4723            Self::PlanInsights => false,
4724        }
4725    }
4726}
4727
4728impl AstDisplay for ExplainStage {
4729    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4730        match self {
4731            Self::RawPlan => f.write_str("RAW PLAN"),
4732            Self::DecorrelatedPlan => f.write_str("DECORRELATED PLAN"),
4733            Self::LocalPlan => f.write_str("LOCALLY OPTIMIZED PLAN"),
4734            Self::GlobalPlan => f.write_str("OPTIMIZED PLAN"),
4735            Self::PhysicalPlan => f.write_str("PHYSICAL PLAN"),
4736            Self::Trace => f.write_str("OPTIMIZER TRACE"),
4737            Self::PlanInsights => f.write_str("PLAN INSIGHTS"),
4738        }
4739    }
4740}
4741impl_display!(ExplainStage);
4742
4743/// An enum of named plans that identifies specific stages in an optimizer trace
4744/// where these plans can be found.
4745#[derive(Clone)]
4746pub enum NamedPlan {
4747    Raw,
4748    Decorrelated,
4749    Local,
4750    Global,
4751    Physical,
4752    FastPath,
4753}
4754
4755impl NamedPlan {
4756    /// Return the [`NamedPlan`] for a given `path` if it exists.
4757    pub fn of_path(value: &str) -> Option<Self> {
4758        match value {
4759            "optimize/raw" => Some(Self::Raw),
4760            "optimize/hir_to_mir" => Some(Self::Decorrelated),
4761            "optimize/local" => Some(Self::Local),
4762            "optimize/global" => Some(Self::Global),
4763            "optimize/finalize_dataflow" => Some(Self::Physical),
4764            "optimize/fast_path" => Some(Self::FastPath),
4765            _ => None,
4766        }
4767    }
4768
4769    /// Return the tracing path under which the plan can be found in an
4770    /// optimizer trace.
4771    pub fn path(&self) -> &'static str {
4772        match self {
4773            Self::Raw => "optimize/raw",
4774            Self::Decorrelated => "optimize/hir_to_mir",
4775            Self::Local => "optimize/local",
4776            Self::Global => "optimize/global",
4777            Self::Physical => "optimize/finalize_dataflow",
4778            Self::FastPath => "optimize/fast_path",
4779        }
4780    }
4781}
4782
4783/// What is being explained.
4784/// The bools mean whether this is an EXPLAIN BROKEN.
4785#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4786pub enum Explainee<T: AstInfo> {
4787    View(T::ItemName),
4788    MaterializedView(T::ItemName),
4789    Index(T::ItemName),
4790    ReplanView(T::ItemName),
4791    ReplanMaterializedView(T::ItemName),
4792    ReplanIndex(T::ItemName),
4793    Select(Box<SelectStatement<T>>, bool),
4794    CreateView(Box<CreateViewStatement<T>>, bool),
4795    CreateMaterializedView(Box<CreateMaterializedViewStatement<T>>, bool),
4796    CreateIndex(Box<CreateIndexStatement<T>>, bool),
4797}
4798
4799impl<T: AstInfo> Explainee<T> {
4800    pub fn name(&self) -> Option<&T::ItemName> {
4801        match self {
4802            Self::View(name)
4803            | Self::ReplanView(name)
4804            | Self::MaterializedView(name)
4805            | Self::ReplanMaterializedView(name)
4806            | Self::Index(name)
4807            | Self::ReplanIndex(name) => Some(name),
4808            Self::Select(..)
4809            | Self::CreateView(..)
4810            | Self::CreateMaterializedView(..)
4811            | Self::CreateIndex(..) => None,
4812        }
4813    }
4814
4815    pub fn is_view(&self) -> bool {
4816        use Explainee::*;
4817        matches!(self, View(_) | ReplanView(_) | CreateView(_, _))
4818    }
4819}
4820
4821impl<T: AstInfo> AstDisplay for Explainee<T> {
4822    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4823        match self {
4824            Self::View(name) => {
4825                f.write_str("VIEW ");
4826                f.write_node(name);
4827            }
4828            Self::MaterializedView(name) => {
4829                f.write_str("MATERIALIZED VIEW ");
4830                f.write_node(name);
4831            }
4832            Self::Index(name) => {
4833                f.write_str("INDEX ");
4834                f.write_node(name);
4835            }
4836            Self::ReplanView(name) => {
4837                f.write_str("REPLAN VIEW ");
4838                f.write_node(name);
4839            }
4840            Self::ReplanMaterializedView(name) => {
4841                f.write_str("REPLAN MATERIALIZED VIEW ");
4842                f.write_node(name);
4843            }
4844            Self::ReplanIndex(name) => {
4845                f.write_str("REPLAN INDEX ");
4846                f.write_node(name);
4847            }
4848            Self::Select(select, broken) => {
4849                if *broken {
4850                    f.write_str("BROKEN ");
4851                }
4852                f.write_node(select);
4853            }
4854            Self::CreateView(statement, broken) => {
4855                if *broken {
4856                    f.write_str("BROKEN ");
4857                }
4858                f.write_node(statement);
4859            }
4860            Self::CreateMaterializedView(statement, broken) => {
4861                if *broken {
4862                    f.write_str("BROKEN ");
4863                }
4864                f.write_node(statement);
4865            }
4866            Self::CreateIndex(statement, broken) => {
4867                if *broken {
4868                    f.write_str("BROKEN ");
4869                }
4870                f.write_node(statement);
4871            }
4872        }
4873    }
4874}
4875impl_display_t!(Explainee);
4876
4877#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
4878pub enum ExplainFormat {
4879    /// Human readable display format
4880    Text,
4881    /// Human readable display format with full debug information
4882    VerboseText,
4883    /// Machine-consumable JSON format
4884    Json,
4885    /// Machine-consumable DOT (graphviz) format
4886    Dot,
4887}
4888
4889impl AstDisplay for ExplainFormat {
4890    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4891        match self {
4892            Self::Text => f.write_str("TEXT"),
4893            Self::VerboseText => f.write_str("VERBOSE TEXT"),
4894            Self::Json => f.write_str("JSON"),
4895            Self::Dot => f.write_str("DOT"),
4896        }
4897    }
4898}
4899impl_display!(ExplainFormat);
4900
4901#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4902pub enum IfExistsBehavior {
4903    Error,
4904    Skip,
4905    Replace,
4906}
4907
4908/// `DECLARE ...`
4909#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4910pub struct DeclareStatement<T: AstInfo> {
4911    pub name: Ident,
4912    pub stmt: Box<T::NestedStatement>,
4913    pub sql: String,
4914}
4915
4916impl<T: AstInfo> AstDisplay for DeclareStatement<T> {
4917    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4918        f.write_str("DECLARE ");
4919        f.write_node(&self.name);
4920        f.write_str(" CURSOR FOR ");
4921        f.write_node(&self.stmt);
4922    }
4923}
4924impl_display_t!(DeclareStatement);
4925
4926/// `CLOSE ...`
4927#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4928pub struct CloseStatement {
4929    pub name: Ident,
4930}
4931
4932impl AstDisplay for CloseStatement {
4933    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4934        f.write_str("CLOSE ");
4935        f.write_node(&self.name);
4936    }
4937}
4938impl_display!(CloseStatement);
4939
4940#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4941pub enum FetchOptionName {
4942    Timeout,
4943}
4944
4945impl AstDisplay for FetchOptionName {
4946    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4947        f.write_str(match self {
4948            FetchOptionName::Timeout => "TIMEOUT",
4949        })
4950    }
4951}
4952
4953impl WithOptionName for FetchOptionName {
4954    /// # WARNING
4955    ///
4956    /// Whenever implementing this trait consider very carefully whether or not
4957    /// this value could contain sensitive user data. If you're uncertain, err
4958    /// on the conservative side and return `true`.
4959    fn redact_value(&self) -> bool {
4960        match self {
4961            FetchOptionName::Timeout => false,
4962        }
4963    }
4964}
4965
4966#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4967pub struct FetchOption<T: AstInfo> {
4968    pub name: FetchOptionName,
4969    pub value: Option<WithOptionValue<T>>,
4970}
4971impl_display_for_with_option!(FetchOption);
4972
4973/// `FETCH ...`
4974#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4975pub struct FetchStatement<T: AstInfo> {
4976    pub name: Ident,
4977    pub count: Option<FetchDirection>,
4978    pub options: Vec<FetchOption<T>>,
4979}
4980
4981impl<T: AstInfo> AstDisplay for FetchStatement<T> {
4982    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
4983        f.write_str("FETCH ");
4984        if let Some(ref count) = self.count {
4985            f.write_str(format!("{} ", count));
4986        }
4987        f.write_node(&self.name);
4988        if !self.options.is_empty() {
4989            f.write_str(" WITH (");
4990            f.write_node(&display::comma_separated(&self.options));
4991            f.write_str(")");
4992        }
4993    }
4994}
4995impl_display_t!(FetchStatement);
4996
4997#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4998pub enum FetchDirection {
4999    ForwardAll,
5000    ForwardCount(u64),
5001}
5002
5003impl AstDisplay for FetchDirection {
5004    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5005        match self {
5006            FetchDirection::ForwardAll => f.write_str("ALL"),
5007            FetchDirection::ForwardCount(count) => f.write_str(format!("{}", count)),
5008        }
5009    }
5010}
5011impl_display!(FetchDirection);
5012
5013/// `PREPARE ...`
5014#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5015pub struct PrepareStatement<T: AstInfo> {
5016    pub name: Ident,
5017    pub stmt: Box<T::NestedStatement>,
5018    pub sql: String,
5019}
5020
5021impl<T: AstInfo> AstDisplay for PrepareStatement<T> {
5022    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5023        f.write_str("PREPARE ");
5024        f.write_node(&self.name);
5025        f.write_str(" AS ");
5026        f.write_node(&self.stmt);
5027    }
5028}
5029impl_display_t!(PrepareStatement);
5030
5031/// `EXECUTE ...`
5032#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5033pub struct ExecuteStatement<T: AstInfo> {
5034    pub name: Ident,
5035    pub params: Vec<Expr<T>>,
5036}
5037
5038impl<T: AstInfo> AstDisplay for ExecuteStatement<T> {
5039    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5040        f.write_str("EXECUTE ");
5041        f.write_node(&self.name);
5042        if !self.params.is_empty() {
5043            f.write_str(" (");
5044            f.write_node(&display::comma_separated(&self.params));
5045            f.write_str(")");
5046        }
5047    }
5048}
5049impl_display_t!(ExecuteStatement);
5050
5051/// `DEALLOCATE ...`
5052#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5053pub struct DeallocateStatement {
5054    pub name: Option<Ident>,
5055}
5056
5057impl AstDisplay for DeallocateStatement {
5058    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5059        f.write_str("DEALLOCATE ");
5060        match &self.name {
5061            Some(name) => f.write_node(name),
5062            None => f.write_str("ALL"),
5063        };
5064    }
5065}
5066impl_display!(DeallocateStatement);
5067
5068/// `RAISE ...`
5069#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5070pub struct RaiseStatement {
5071    pub severity: NoticeSeverity,
5072}
5073
5074impl AstDisplay for RaiseStatement {
5075    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5076        f.write_str("RAISE ");
5077        f.write_node(&self.severity);
5078    }
5079}
5080impl_display!(RaiseStatement);
5081
5082#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5083pub enum NoticeSeverity {
5084    Debug,
5085    Info,
5086    Log,
5087    Notice,
5088    Warning,
5089}
5090
5091impl AstDisplay for NoticeSeverity {
5092    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5093        f.write_str(match self {
5094            NoticeSeverity::Debug => "DEBUG",
5095            NoticeSeverity::Info => "INFO",
5096            NoticeSeverity::Log => "LOG",
5097            NoticeSeverity::Notice => "NOTICE",
5098            NoticeSeverity::Warning => "WARNING",
5099        })
5100    }
5101}
5102impl_display!(NoticeSeverity);
5103
5104/// `ALTER SYSTEM SET ...`
5105#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5106pub struct AlterSystemSetStatement {
5107    pub name: Ident,
5108    pub to: SetVariableTo,
5109}
5110
5111impl AstDisplay for AlterSystemSetStatement {
5112    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5113        f.write_str("ALTER SYSTEM SET ");
5114        f.write_node(&self.name);
5115        f.write_str(" = ");
5116        f.write_node(&self.to);
5117    }
5118}
5119impl_display!(AlterSystemSetStatement);
5120
5121/// `ALTER SYSTEM RESET ...`
5122#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5123pub struct AlterSystemResetStatement {
5124    pub name: Ident,
5125}
5126
5127impl AstDisplay for AlterSystemResetStatement {
5128    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5129        f.write_str("ALTER SYSTEM RESET ");
5130        f.write_node(&self.name);
5131    }
5132}
5133impl_display!(AlterSystemResetStatement);
5134
5135/// `ALTER SYSTEM RESET ALL`
5136#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5137pub struct AlterSystemResetAllStatement {}
5138
5139impl AstDisplay for AlterSystemResetAllStatement {
5140    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5141        f.write_str("ALTER SYSTEM RESET ALL");
5142    }
5143}
5144impl_display!(AlterSystemResetAllStatement);
5145
5146#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5147pub enum AsOf<T: AstInfo> {
5148    At(Expr<T>),
5149    AtLeast(Expr<T>),
5150}
5151
5152impl<T: AstInfo> AstDisplay for AsOf<T> {
5153    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5154        f.write_str("AS OF ");
5155        match self {
5156            AsOf::At(expr) => f.write_node(expr),
5157            AsOf::AtLeast(expr) => {
5158                f.write_str("AT LEAST ");
5159                f.write_node(expr);
5160            }
5161        }
5162    }
5163}
5164impl_display_t!(AsOf);
5165
5166#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
5167pub enum ShowStatement<T: AstInfo> {
5168    ShowObjects(ShowObjectsStatement<T>),
5169    ShowColumns(ShowColumnsStatement<T>),
5170    ShowCreateView(ShowCreateViewStatement<T>),
5171    ShowCreateMaterializedView(ShowCreateMaterializedViewStatement<T>),
5172    ShowCreateSource(ShowCreateSourceStatement<T>),
5173    ShowCreateTable(ShowCreateTableStatement<T>),
5174    ShowCreateSink(ShowCreateSinkStatement<T>),
5175    ShowCreateIndex(ShowCreateIndexStatement<T>),
5176    ShowCreateConnection(ShowCreateConnectionStatement<T>),
5177    ShowCreateCluster(ShowCreateClusterStatement<T>),
5178    ShowCreateType(ShowCreateTypeStatement<T>),
5179    ShowVariable(ShowVariableStatement),
5180    InspectShard(InspectShardStatement),
5181}
5182
5183impl<T: AstInfo> AstDisplay for ShowStatement<T> {
5184    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5185        match self {
5186            ShowStatement::ShowObjects(stmt) => f.write_node(stmt),
5187            ShowStatement::ShowColumns(stmt) => f.write_node(stmt),
5188            ShowStatement::ShowCreateView(stmt) => f.write_node(stmt),
5189            ShowStatement::ShowCreateMaterializedView(stmt) => f.write_node(stmt),
5190            ShowStatement::ShowCreateSource(stmt) => f.write_node(stmt),
5191            ShowStatement::ShowCreateTable(stmt) => f.write_node(stmt),
5192            ShowStatement::ShowCreateSink(stmt) => f.write_node(stmt),
5193            ShowStatement::ShowCreateIndex(stmt) => f.write_node(stmt),
5194            ShowStatement::ShowCreateConnection(stmt) => f.write_node(stmt),
5195            ShowStatement::ShowCreateCluster(stmt) => f.write_node(stmt),
5196            ShowStatement::ShowCreateType(stmt) => f.write_node(stmt),
5197            ShowStatement::ShowVariable(stmt) => f.write_node(stmt),
5198            ShowStatement::InspectShard(stmt) => f.write_node(stmt),
5199        }
5200    }
5201}
5202impl_display_t!(ShowStatement);
5203
5204/// `GRANT ...`
5205#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5206pub struct GrantRoleStatement<T: AstInfo> {
5207    /// The roles that are gaining members.
5208    pub role_names: Vec<T::RoleName>,
5209    /// The roles that will be added to `role_name`.
5210    pub member_names: Vec<T::RoleName>,
5211}
5212
5213impl<T: AstInfo> AstDisplay for GrantRoleStatement<T> {
5214    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5215        f.write_str("GRANT ");
5216        f.write_node(&display::comma_separated(&self.role_names));
5217        f.write_str(" TO ");
5218        f.write_node(&display::comma_separated(&self.member_names));
5219    }
5220}
5221impl_display_t!(GrantRoleStatement);
5222
5223/// `REVOKE ...`
5224#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5225pub struct RevokeRoleStatement<T: AstInfo> {
5226    /// The roles that are losing members.
5227    pub role_names: Vec<T::RoleName>,
5228    /// The roles that will be removed from `role_name`.
5229    pub member_names: Vec<T::RoleName>,
5230}
5231
5232impl<T: AstInfo> AstDisplay for RevokeRoleStatement<T> {
5233    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5234        f.write_str("REVOKE ");
5235        f.write_node(&display::comma_separated(&self.role_names));
5236        f.write_str(" FROM ");
5237        f.write_node(&display::comma_separated(&self.member_names));
5238    }
5239}
5240impl_display_t!(RevokeRoleStatement);
5241
5242#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5243pub enum Privilege {
5244    SELECT,
5245    INSERT,
5246    UPDATE,
5247    DELETE,
5248    USAGE,
5249    CREATE,
5250    CREATEROLE,
5251    CREATEDB,
5252    CREATECLUSTER,
5253    CREATENETWORKPOLICY,
5254}
5255
5256impl AstDisplay for Privilege {
5257    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5258        f.write_str(match self {
5259            Privilege::SELECT => "SELECT",
5260            Privilege::INSERT => "INSERT",
5261            Privilege::UPDATE => "UPDATE",
5262            Privilege::DELETE => "DELETE",
5263            Privilege::CREATE => "CREATE",
5264            Privilege::USAGE => "USAGE",
5265            Privilege::CREATEROLE => "CREATEROLE",
5266            Privilege::CREATEDB => "CREATEDB",
5267            Privilege::CREATECLUSTER => "CREATECLUSTER",
5268            Privilege::CREATENETWORKPOLICY => "CREATENETWORKPOLICY",
5269        });
5270    }
5271}
5272impl_display!(Privilege);
5273
5274#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5275pub enum PrivilegeSpecification {
5276    All,
5277    Privileges(Vec<Privilege>),
5278}
5279
5280impl AstDisplay for PrivilegeSpecification {
5281    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5282        match self {
5283            PrivilegeSpecification::All => f.write_str("ALL"),
5284            PrivilegeSpecification::Privileges(privileges) => {
5285                f.write_node(&display::comma_separated(privileges))
5286            }
5287        }
5288    }
5289}
5290impl_display!(PrivilegeSpecification);
5291
5292#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5293pub enum GrantTargetSpecification<T: AstInfo> {
5294    Object {
5295        /// The type of object.
5296        ///
5297        /// Note: For views, materialized views, and sources this will be [`ObjectType::Table`].
5298        object_type: ObjectType,
5299        /// Specification of each object affected.
5300        object_spec_inner: GrantTargetSpecificationInner<T>,
5301    },
5302    System,
5303}
5304
5305#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5306pub enum GrantTargetSpecificationInner<T: AstInfo> {
5307    All(GrantTargetAllSpecification<T>),
5308    Objects { names: Vec<T::ObjectName> },
5309}
5310
5311#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5312pub enum GrantTargetAllSpecification<T: AstInfo> {
5313    All,
5314    AllDatabases { databases: Vec<T::DatabaseName> },
5315    AllSchemas { schemas: Vec<T::SchemaName> },
5316}
5317
5318impl<T: AstInfo> GrantTargetAllSpecification<T> {
5319    pub fn len(&self) -> usize {
5320        match self {
5321            GrantTargetAllSpecification::All => 1,
5322            GrantTargetAllSpecification::AllDatabases { databases } => databases.len(),
5323            GrantTargetAllSpecification::AllSchemas { schemas } => schemas.len(),
5324        }
5325    }
5326}
5327
5328impl<T: AstInfo> AstDisplay for GrantTargetSpecification<T> {
5329    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5330        match self {
5331            GrantTargetSpecification::Object {
5332                object_type,
5333                object_spec_inner,
5334            } => match object_spec_inner {
5335                GrantTargetSpecificationInner::All(all_spec) => match all_spec {
5336                    GrantTargetAllSpecification::All => {
5337                        f.write_str("ALL ");
5338                        f.write_node(object_type);
5339                        f.write_str("S");
5340                    }
5341                    GrantTargetAllSpecification::AllDatabases { databases } => {
5342                        f.write_str("ALL ");
5343                        f.write_node(object_type);
5344                        f.write_str("S IN DATABASE ");
5345                        f.write_node(&display::comma_separated(databases));
5346                    }
5347                    GrantTargetAllSpecification::AllSchemas { schemas } => {
5348                        f.write_str("ALL ");
5349                        f.write_node(object_type);
5350                        f.write_str("S IN SCHEMA ");
5351                        f.write_node(&display::comma_separated(schemas));
5352                    }
5353                },
5354                GrantTargetSpecificationInner::Objects { names } => {
5355                    f.write_node(object_type);
5356                    f.write_str(" ");
5357                    f.write_node(&display::comma_separated(names));
5358                }
5359            },
5360            GrantTargetSpecification::System => f.write_str("SYSTEM"),
5361        }
5362    }
5363}
5364impl_display_t!(GrantTargetSpecification);
5365
5366/// `GRANT ...`
5367#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5368pub struct GrantPrivilegesStatement<T: AstInfo> {
5369    /// The privileges being granted on an object.
5370    pub privileges: PrivilegeSpecification,
5371    /// The objects that are affected by the GRANT.
5372    pub target: GrantTargetSpecification<T>,
5373    /// The roles that will granted the privileges.
5374    pub roles: Vec<T::RoleName>,
5375}
5376
5377impl<T: AstInfo> AstDisplay for GrantPrivilegesStatement<T> {
5378    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5379        f.write_str("GRANT ");
5380        f.write_node(&self.privileges);
5381        f.write_str(" ON ");
5382        f.write_node(&self.target);
5383        f.write_str(" TO ");
5384        f.write_node(&display::comma_separated(&self.roles));
5385    }
5386}
5387impl_display_t!(GrantPrivilegesStatement);
5388
5389/// `REVOKE ...`
5390#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5391pub struct RevokePrivilegesStatement<T: AstInfo> {
5392    /// The privileges being revoked.
5393    pub privileges: PrivilegeSpecification,
5394    /// The objects that are affected by the REVOKE.
5395    pub target: GrantTargetSpecification<T>,
5396    /// The roles that will have privileges revoked.
5397    pub roles: Vec<T::RoleName>,
5398}
5399
5400impl<T: AstInfo> AstDisplay for RevokePrivilegesStatement<T> {
5401    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5402        f.write_str("REVOKE ");
5403        f.write_node(&self.privileges);
5404        f.write_str(" ON ");
5405        f.write_node(&self.target);
5406        f.write_str(" FROM ");
5407        f.write_node(&display::comma_separated(&self.roles));
5408    }
5409}
5410impl_display_t!(RevokePrivilegesStatement);
5411
5412#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5413pub enum TargetRoleSpecification<T: AstInfo> {
5414    /// Specific list of roles.
5415    Roles(Vec<T::RoleName>),
5416    /// All current and future roles.
5417    AllRoles,
5418}
5419
5420impl<T: AstInfo> AstDisplay for TargetRoleSpecification<T> {
5421    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5422        match self {
5423            TargetRoleSpecification::Roles(roles) => f.write_node(&display::comma_separated(roles)),
5424            TargetRoleSpecification::AllRoles => f.write_str("ALL ROLES"),
5425        }
5426    }
5427}
5428impl_display_t!(TargetRoleSpecification);
5429
5430#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5431pub struct AbbreviatedGrantStatement<T: AstInfo> {
5432    /// The privileges being granted.
5433    pub privileges: PrivilegeSpecification,
5434    /// The type of object.
5435    ///
5436    /// Note: For views, materialized views, and sources this will be [`ObjectType::Table`].
5437    pub object_type: ObjectType,
5438    /// The roles that will granted the privileges.
5439    pub grantees: Vec<T::RoleName>,
5440}
5441
5442impl<T: AstInfo> AstDisplay for AbbreviatedGrantStatement<T> {
5443    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5444        f.write_str("GRANT ");
5445        f.write_node(&self.privileges);
5446        f.write_str(" ON ");
5447        f.write_node(&self.object_type);
5448        f.write_str("S TO ");
5449        f.write_node(&display::comma_separated(&self.grantees));
5450    }
5451}
5452impl_display_t!(AbbreviatedGrantStatement);
5453
5454#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5455pub struct AbbreviatedRevokeStatement<T: AstInfo> {
5456    /// The privileges being revoked.
5457    pub privileges: PrivilegeSpecification,
5458    /// The type of object.
5459    ///
5460    /// Note: For views, materialized views, and sources this will be [`ObjectType::Table`].
5461    pub object_type: ObjectType,
5462    /// The roles that the privilege will be revoked from.
5463    pub revokees: Vec<T::RoleName>,
5464}
5465
5466impl<T: AstInfo> AstDisplay for AbbreviatedRevokeStatement<T> {
5467    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5468        f.write_str("REVOKE ");
5469        f.write_node(&self.privileges);
5470        f.write_str(" ON ");
5471        f.write_node(&self.object_type);
5472        f.write_str("S FROM ");
5473        f.write_node(&display::comma_separated(&self.revokees));
5474    }
5475}
5476impl_display_t!(AbbreviatedRevokeStatement);
5477
5478#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5479pub enum AbbreviatedGrantOrRevokeStatement<T: AstInfo> {
5480    Grant(AbbreviatedGrantStatement<T>),
5481    Revoke(AbbreviatedRevokeStatement<T>),
5482}
5483
5484impl<T: AstInfo> AbbreviatedGrantOrRevokeStatement<T> {
5485    pub fn privileges(&self) -> &PrivilegeSpecification {
5486        match self {
5487            AbbreviatedGrantOrRevokeStatement::Grant(grant) => &grant.privileges,
5488            AbbreviatedGrantOrRevokeStatement::Revoke(revoke) => &revoke.privileges,
5489        }
5490    }
5491
5492    pub fn object_type(&self) -> &ObjectType {
5493        match self {
5494            AbbreviatedGrantOrRevokeStatement::Grant(grant) => &grant.object_type,
5495            AbbreviatedGrantOrRevokeStatement::Revoke(revoke) => &revoke.object_type,
5496        }
5497    }
5498
5499    pub fn roles(&self) -> &Vec<T::RoleName> {
5500        match self {
5501            AbbreviatedGrantOrRevokeStatement::Grant(grant) => &grant.grantees,
5502            AbbreviatedGrantOrRevokeStatement::Revoke(revoke) => &revoke.revokees,
5503        }
5504    }
5505}
5506
5507impl<T: AstInfo> AstDisplay for AbbreviatedGrantOrRevokeStatement<T> {
5508    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5509        match self {
5510            AbbreviatedGrantOrRevokeStatement::Grant(grant) => f.write_node(grant),
5511            AbbreviatedGrantOrRevokeStatement::Revoke(revoke) => f.write_node(revoke),
5512        }
5513    }
5514}
5515impl_display_t!(AbbreviatedGrantOrRevokeStatement);
5516
5517/// `ALTER DEFAULT PRIVILEGES ...`
5518#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5519pub struct AlterDefaultPrivilegesStatement<T: AstInfo> {
5520    /// The roles for which created objects are affected.
5521    pub target_roles: TargetRoleSpecification<T>,
5522    /// The objects that are affected by the default privilege.
5523    pub target_objects: GrantTargetAllSpecification<T>,
5524    /// The privilege to grant or revoke.
5525    pub grant_or_revoke: AbbreviatedGrantOrRevokeStatement<T>,
5526}
5527
5528impl<T: AstInfo> AstDisplay for AlterDefaultPrivilegesStatement<T> {
5529    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5530        f.write_str("ALTER DEFAULT PRIVILEGES");
5531        match &self.target_roles {
5532            TargetRoleSpecification::Roles(_) => {
5533                f.write_str(" FOR ROLE ");
5534                f.write_node(&self.target_roles);
5535            }
5536            TargetRoleSpecification::AllRoles => {
5537                f.write_str(" FOR ");
5538                f.write_node(&self.target_roles);
5539            }
5540        }
5541        match &self.target_objects {
5542            GrantTargetAllSpecification::All => {}
5543            GrantTargetAllSpecification::AllDatabases { databases } => {
5544                f.write_str(" IN DATABASE ");
5545                f.write_node(&display::comma_separated(databases));
5546            }
5547            GrantTargetAllSpecification::AllSchemas { schemas } => {
5548                f.write_str(" IN SCHEMA ");
5549                f.write_node(&display::comma_separated(schemas));
5550            }
5551        }
5552        f.write_str(" ");
5553        f.write_node(&self.grant_or_revoke);
5554    }
5555}
5556impl_display_t!(AlterDefaultPrivilegesStatement);
5557
5558/// `REASSIGN OWNED ...`
5559#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5560pub struct ReassignOwnedStatement<T: AstInfo> {
5561    /// The roles whose owned objects are being reassigned.
5562    pub old_roles: Vec<T::RoleName>,
5563    /// The new owner of the objects.
5564    pub new_role: T::RoleName,
5565}
5566
5567impl<T: AstInfo> AstDisplay for ReassignOwnedStatement<T> {
5568    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5569        f.write_str("REASSIGN OWNED BY ");
5570        f.write_node(&display::comma_separated(&self.old_roles));
5571        f.write_str(" TO ");
5572        f.write_node(&self.new_role);
5573    }
5574}
5575impl_display_t!(ReassignOwnedStatement);
5576
5577/// `COMMENT ON ...`
5578#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5579pub struct CommentStatement<T: AstInfo> {
5580    pub object: CommentObjectType<T>,
5581    pub comment: Option<String>,
5582}
5583
5584impl<T: AstInfo> AstDisplay for CommentStatement<T> {
5585    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5586        f.write_str("COMMENT ON ");
5587        f.write_node(&self.object);
5588
5589        f.write_str(" IS ");
5590        match &self.comment {
5591            Some(s) => {
5592                f.write_str("'");
5593                f.write_node(&display::escape_single_quote_string(s));
5594                f.write_str("'");
5595            }
5596            None => f.write_str("NULL"),
5597        }
5598    }
5599}
5600impl_display_t!(CommentStatement);
5601
5602#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
5603pub struct ColumnName<T: AstInfo> {
5604    pub relation: T::ItemName,
5605    pub column: T::ColumnReference,
5606}
5607
5608impl<T: AstInfo> AstDisplay for ColumnName<T> {
5609    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5610        f.write_node(&self.relation);
5611        f.write_str(".");
5612        f.write_node(&self.column);
5613    }
5614}
5615impl_display_t!(ColumnName);
5616
5617#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5618pub enum CommentObjectType<T: AstInfo> {
5619    Table { name: T::ItemName },
5620    View { name: T::ItemName },
5621    Column { name: ColumnName<T> },
5622    MaterializedView { name: T::ItemName },
5623    Source { name: T::ItemName },
5624    Sink { name: T::ItemName },
5625    Index { name: T::ItemName },
5626    Func { name: T::ItemName },
5627    Connection { name: T::ItemName },
5628    Type { ty: T::DataType },
5629    Secret { name: T::ItemName },
5630    Role { name: T::RoleName },
5631    Database { name: T::DatabaseName },
5632    Schema { name: T::SchemaName },
5633    Cluster { name: T::ClusterName },
5634    ClusterReplica { name: QualifiedReplica },
5635    ContinualTask { name: T::ItemName },
5636    NetworkPolicy { name: T::NetworkPolicyName },
5637}
5638
5639impl<T: AstInfo> AstDisplay for CommentObjectType<T> {
5640    fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
5641        use CommentObjectType::*;
5642
5643        match self {
5644            Table { name } => {
5645                f.write_str("TABLE ");
5646                f.write_node(name);
5647            }
5648            View { name } => {
5649                f.write_str("VIEW ");
5650                f.write_node(name);
5651            }
5652            Column { name } => {
5653                f.write_str("COLUMN ");
5654                f.write_node(name);
5655            }
5656            MaterializedView { name } => {
5657                f.write_str("MATERIALIZED VIEW ");
5658                f.write_node(name);
5659            }
5660            Source { name } => {
5661                f.write_str("SOURCE ");
5662                f.write_node(name);
5663            }
5664            Sink { name } => {
5665                f.write_str("SINK ");
5666                f.write_node(name);
5667            }
5668            Index { name } => {
5669                f.write_str("INDEX ");
5670                f.write_node(name);
5671            }
5672            Func { name } => {
5673                f.write_str("FUNCTION ");
5674                f.write_node(name);
5675            }
5676            Connection { name } => {
5677                f.write_str("CONNECTION ");
5678                f.write_node(name);
5679            }
5680            Type { ty } => {
5681                f.write_str("TYPE ");
5682                f.write_node(ty);
5683            }
5684            Secret { name } => {
5685                f.write_str("SECRET ");
5686                f.write_node(name);
5687            }
5688            Role { name } => {
5689                f.write_str("ROLE ");
5690                f.write_node(name);
5691            }
5692            Database { name } => {
5693                f.write_str("DATABASE ");
5694                f.write_node(name);
5695            }
5696            Schema { name } => {
5697                f.write_str("SCHEMA ");
5698                f.write_node(name);
5699            }
5700            Cluster { name } => {
5701                f.write_str("CLUSTER ");
5702                f.write_node(name);
5703            }
5704            ClusterReplica { name } => {
5705                f.write_str("CLUSTER REPLICA ");
5706                f.write_node(name);
5707            }
5708            ContinualTask { name } => {
5709                f.write_str("CONTINUAL TASK ");
5710                f.write_node(name);
5711            }
5712            NetworkPolicy { name } => {
5713                f.write_str("NETWORK POLICY ");
5714                f.write_node(name);
5715            }
5716        }
5717    }
5718}
5719
5720impl_display_t!(CommentObjectType);
5721
5722// Include the `AstDisplay` implementations for simple options derived by the
5723// crate's build.rs script.
5724include!(concat!(env!("OUT_DIR"), "/display.simple_options.rs"));