Skip to main content

mz_sql_parser/ast/defs/
statement.rs

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