Skip to main content

mz_sql_parser/ast/defs/
statement.rs

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