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