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