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