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