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