You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2025/10/10 14:08:47 UTC

(datafusion-sqlparser-rs) 01/01: Moving several struct variants out of `Statement` enum to allow for trait impls for specific sub-variants (#2057)

This is an automated email from the ASF dual-hosted git repository.

github-bot pushed a commit to branch gh-readonly-queue/main/pr-2057-e7d42f3d1a3fb6a542b70d8bef945db2c67bcf06
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git

commit cc595cfd847f6e4b8edb6def67535e0a499b8845
Author: Luca Cappelletti <ca...@gmail.com>
AuthorDate: Fri Oct 10 16:08:20 2025 +0200

    Moving several struct variants out of `Statement` enum to allow for trait impls for specific sub-variants (#2057)
---
 src/ast/dcl.rs                | 113 ++++++-
 src/ast/ddl.rs                | 412 +++++++++++++++++++++++-
 src/ast/dml.rs                |  65 +++-
 src/ast/mod.rs                | 719 +++++++++---------------------------------
 src/ast/spans.rs              | 200 ++++++------
 src/parser/mod.rs             |  48 +--
 src/test_utils.rs             |  23 +-
 tests/sqlparser_bigquery.rs   |  12 +-
 tests/sqlparser_clickhouse.rs |  30 +-
 tests/sqlparser_common.rs     | 111 +++----
 tests/sqlparser_mssql.rs      |  10 +-
 tests/sqlparser_mysql.rs      |  38 +--
 tests/sqlparser_postgres.rs   | 193 +++++-------
 tests/sqlparser_snowflake.rs  |  10 +-
 tests/sqlparser_sqlite.rs     |  10 +-
 15 files changed, 1032 insertions(+), 962 deletions(-)

diff --git a/src/ast/dcl.rs b/src/ast/dcl.rs
index 07989407..d04875a7 100644
--- a/src/ast/dcl.rs
+++ b/src/ast/dcl.rs
@@ -28,8 +28,9 @@ use serde::{Deserialize, Serialize};
 #[cfg(feature = "visitor")]
 use sqlparser_derive::{Visit, VisitMut};
 
-use super::{display_comma_separated, Expr, Ident, Password};
+use super::{display_comma_separated, Expr, Ident, Password, Spanned};
 use crate::ast::{display_separated, ObjectName};
+use crate::tokenizer::Span;
 
 /// An option in `ROLE` statement.
 ///
@@ -252,3 +253,113 @@ impl fmt::Display for SecondaryRoles {
         }
     }
 }
+
+/// CREATE ROLE statement
+/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createrole.html)
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct CreateRole {
+    pub names: Vec<ObjectName>,
+    pub if_not_exists: bool,
+    // Postgres
+    pub login: Option<bool>,
+    pub inherit: Option<bool>,
+    pub bypassrls: Option<bool>,
+    pub password: Option<Password>,
+    pub superuser: Option<bool>,
+    pub create_db: Option<bool>,
+    pub create_role: Option<bool>,
+    pub replication: Option<bool>,
+    pub connection_limit: Option<Expr>,
+    pub valid_until: Option<Expr>,
+    pub in_role: Vec<Ident>,
+    pub in_group: Vec<Ident>,
+    pub role: Vec<Ident>,
+    pub user: Vec<Ident>,
+    pub admin: Vec<Ident>,
+    // MSSQL
+    pub authorization_owner: Option<ObjectName>,
+}
+
+impl fmt::Display for CreateRole {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "CREATE ROLE {if_not_exists}{names}{superuser}{create_db}{create_role}{inherit}{login}{replication}{bypassrls}",
+            if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
+            names = display_separated(&self.names, ", "),
+            superuser = match self.superuser {
+                Some(true) => " SUPERUSER",
+                Some(false) => " NOSUPERUSER",
+                None => ""
+            },
+            create_db = match self.create_db {
+                Some(true) => " CREATEDB",
+                Some(false) => " NOCREATEDB",
+                None => ""
+            },
+            create_role = match self.create_role {
+                Some(true) => " CREATEROLE",
+                Some(false) => " NOCREATEROLE",
+                None => ""
+            },
+            inherit = match self.inherit {
+                Some(true) => " INHERIT",
+                Some(false) => " NOINHERIT",
+                None => ""
+            },
+            login = match self.login {
+                Some(true) => " LOGIN",
+                Some(false) => " NOLOGIN",
+                None => ""
+            },
+            replication = match self.replication {
+                Some(true) => " REPLICATION",
+                Some(false) => " NOREPLICATION",
+                None => ""
+            },
+            bypassrls = match self.bypassrls {
+                Some(true) => " BYPASSRLS",
+                Some(false) => " NOBYPASSRLS",
+                None => ""
+            }
+        )?;
+        if let Some(limit) = &self.connection_limit {
+            write!(f, " CONNECTION LIMIT {limit}")?;
+        }
+        match &self.password {
+            Some(Password::Password(pass)) => write!(f, " PASSWORD {pass}")?,
+            Some(Password::NullPassword) => write!(f, " PASSWORD NULL")?,
+            None => {}
+        };
+        if let Some(until) = &self.valid_until {
+            write!(f, " VALID UNTIL {until}")?;
+        }
+        if !self.in_role.is_empty() {
+            write!(f, " IN ROLE {}", display_comma_separated(&self.in_role))?;
+        }
+        if !self.in_group.is_empty() {
+            write!(f, " IN GROUP {}", display_comma_separated(&self.in_group))?;
+        }
+        if !self.role.is_empty() {
+            write!(f, " ROLE {}", display_comma_separated(&self.role))?;
+        }
+        if !self.user.is_empty() {
+            write!(f, " USER {}", display_comma_separated(&self.user))?;
+        }
+        if !self.admin.is_empty() {
+            write!(f, " ADMIN {}", display_comma_separated(&self.admin))?;
+        }
+        if let Some(owner) = &self.authorization_owner {
+            write!(f, " AUTHORIZATION {owner}")?;
+        }
+        Ok(())
+    }
+}
+
+impl Spanned for CreateRole {
+    fn span(&self) -> Span {
+        Span::empty()
+    }
+}
diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
index c6ab7ad1..aafa8e64 100644
--- a/src/ast/ddl.rs
+++ b/src/ast/ddl.rs
@@ -19,7 +19,7 @@
 //! (commonly referred to as Data Definition Language, or DDL)
 
 #[cfg(not(feature = "std"))]
-use alloc::{boxed::Box, string::String, vec::Vec};
+use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
 use core::fmt::{self, Display, Write};
 
 #[cfg(feature = "serde")]
@@ -30,15 +30,16 @@ use sqlparser_derive::{Visit, VisitMut};
 
 use crate::ast::value::escape_single_quote_string;
 use crate::ast::{
-    display_comma_separated, display_separated, table_constraints::TableConstraint, ArgMode,
-    CommentDef, ConditionalStatements, CreateFunctionBody, CreateFunctionUsing,
-    CreateTableLikeKind, CreateTableOptions, DataType, Expr, FileFormat, FunctionBehavior,
-    FunctionCalledOnNull, FunctionDeterminismSpecifier, FunctionParallel, HiveDistributionStyle,
-    HiveFormat, HiveIOFormat, HiveRowFormat, Ident, InitializeKind, MySQLColumnPosition,
-    ObjectName, OnCommit, OneOrManyWithParens, OperateFunctionArg, OrderByExpr, ProjectionSelect,
-    Query, RefreshModeKind, RowAccessPolicy, SequenceOptions, Spanned, SqlOption,
-    StorageSerializationPolicy, TableVersion, Tag, TriggerEvent, TriggerExecBody, TriggerObject,
-    TriggerPeriod, TriggerReferencing, Value, ValueWithSpan, WrappedCollection,
+    display_comma_separated, display_separated, ArgMode, AttachedToken, CommentDef,
+    ConditionalStatements, CreateFunctionBody, CreateFunctionUsing, CreateTableLikeKind,
+    CreateTableOptions, CreateViewParams, DataType, Expr, FileFormat, FunctionBehavior,
+    FunctionCalledOnNull, FunctionDesc, FunctionDeterminismSpecifier, FunctionParallel,
+    HiveDistributionStyle, HiveFormat, HiveIOFormat, HiveRowFormat, HiveSetLocation, Ident,
+    InitializeKind, MySQLColumnPosition, ObjectName, OnCommit, OneOrManyWithParens,
+    OperateFunctionArg, OrderByExpr, ProjectionSelect, Query, RefreshModeKind, RowAccessPolicy,
+    SequenceOptions, Spanned, SqlOption, StorageSerializationPolicy, TableConstraint, TableVersion,
+    Tag, TriggerEvent, TriggerExecBody, TriggerObject, TriggerPeriod, TriggerReferencing, Value,
+    ValueWithSpan, WrappedCollection,
 };
 use crate::display_utils::{DisplayCommaSeparated, Indent, NewLine, SpaceOrNewline};
 use crate::keywords::Keyword;
@@ -3138,3 +3139,394 @@ impl fmt::Display for DropTrigger {
         Ok(())
     }
 }
+
+/// A `TRUNCATE` statement.
+///
+/// ```sql
+/// TRUNCATE TABLE table_names [PARTITION (partitions)] [RESTART IDENTITY | CONTINUE IDENTITY] [CASCADE | RESTRICT] [ON CLUSTER cluster_name]
+/// ```
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct Truncate {
+    /// Table names to truncate
+    pub table_names: Vec<super::TruncateTableTarget>,
+    /// Optional partition specification
+    pub partitions: Option<Vec<Expr>>,
+    /// TABLE - optional keyword
+    pub table: bool,
+    /// Postgres-specific option: [ RESTART IDENTITY | CONTINUE IDENTITY ]
+    pub identity: Option<super::TruncateIdentityOption>,
+    /// Postgres-specific option: [ CASCADE | RESTRICT ]
+    pub cascade: Option<super::CascadeOption>,
+    /// ClickHouse-specific option: [ ON CLUSTER cluster_name ]
+    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/truncate/)
+    pub on_cluster: Option<Ident>,
+}
+
+impl fmt::Display for Truncate {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let table = if self.table { "TABLE " } else { "" };
+
+        write!(
+            f,
+            "TRUNCATE {table}{table_names}",
+            table_names = display_comma_separated(&self.table_names)
+        )?;
+
+        if let Some(identity) = &self.identity {
+            match identity {
+                super::TruncateIdentityOption::Restart => write!(f, " RESTART IDENTITY")?,
+                super::TruncateIdentityOption::Continue => write!(f, " CONTINUE IDENTITY")?,
+            }
+        }
+        if let Some(cascade) = &self.cascade {
+            match cascade {
+                super::CascadeOption::Cascade => write!(f, " CASCADE")?,
+                super::CascadeOption::Restrict => write!(f, " RESTRICT")?,
+            }
+        }
+
+        if let Some(ref parts) = &self.partitions {
+            if !parts.is_empty() {
+                write!(f, " PARTITION ({})", display_comma_separated(parts))?;
+            }
+        }
+        if let Some(on_cluster) = &self.on_cluster {
+            write!(f, " ON CLUSTER {on_cluster}")?;
+        }
+        Ok(())
+    }
+}
+
+impl Spanned for Truncate {
+    fn span(&self) -> Span {
+        Span::union_iter(
+            self.table_names.iter().map(|i| i.name.span()).chain(
+                self.partitions
+                    .iter()
+                    .flat_map(|i| i.iter().map(|k| k.span())),
+            ),
+        )
+    }
+}
+
+/// An `MSCK` statement.
+///
+/// ```sql
+/// MSCK [REPAIR] TABLE table_name [ADD|DROP|SYNC PARTITIONS]
+/// ```
+/// MSCK (Hive) - MetaStore Check command
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct Msck {
+    /// Table name to check
+    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
+    pub table_name: ObjectName,
+    /// Whether to repair the table
+    pub repair: bool,
+    /// Partition action (ADD, DROP, or SYNC)
+    pub partition_action: Option<super::AddDropSync>,
+}
+
+impl fmt::Display for Msck {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "MSCK {repair}TABLE {table}",
+            repair = if self.repair { "REPAIR " } else { "" },
+            table = self.table_name
+        )?;
+        if let Some(pa) = &self.partition_action {
+            write!(f, " {pa}")?;
+        }
+        Ok(())
+    }
+}
+
+impl Spanned for Msck {
+    fn span(&self) -> Span {
+        self.table_name.span()
+    }
+}
+
+/// CREATE VIEW statement.
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct CreateView {
+    /// True if this is a `CREATE OR ALTER VIEW` statement
+    ///
+    /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-view-transact-sql)
+    pub or_alter: bool,
+    pub or_replace: bool,
+    pub materialized: bool,
+    /// Snowflake: SECURE view modifier
+    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
+    pub secure: bool,
+    /// View name
+    pub name: ObjectName,
+    /// If `if_not_exists` is true, this flag is set to true if the view name comes before the `IF NOT EXISTS` clause.
+    /// Example:
+    /// ```sql
+    /// CREATE VIEW myview IF NOT EXISTS AS SELECT 1`
+    ///  ```
+    /// Otherwise, the flag is set to false if the view name comes after the clause
+    /// Example:
+    /// ```sql
+    /// CREATE VIEW IF NOT EXISTS myview AS SELECT 1`
+    ///  ```
+    pub name_before_not_exists: bool,
+    pub columns: Vec<ViewColumnDef>,
+    pub query: Box<Query>,
+    pub options: CreateTableOptions,
+    pub cluster_by: Vec<Ident>,
+    /// Snowflake: Views can have comments in Snowflake.
+    /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
+    pub comment: Option<String>,
+    /// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_VIEW.html>
+    pub with_no_schema_binding: bool,
+    /// if true, has SQLite `IF NOT EXISTS` clause <https://www.sqlite.org/lang_createview.html>
+    pub if_not_exists: bool,
+    /// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html>
+    pub temporary: bool,
+    /// if not None, has Clickhouse `TO` clause, specify the table into which to insert results
+    /// <https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view>
+    pub to: Option<ObjectName>,
+    /// MySQL: Optional parameters for the view algorithm, definer, and security context
+    pub params: Option<CreateViewParams>,
+}
+
+impl fmt::Display for CreateView {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "CREATE {or_alter}{or_replace}",
+            or_alter = if self.or_alter { "OR ALTER " } else { "" },
+            or_replace = if self.or_replace { "OR REPLACE " } else { "" },
+        )?;
+        if let Some(ref params) = self.params {
+            params.fmt(f)?;
+        }
+        write!(
+            f,
+            "{secure}{materialized}{temporary}VIEW {if_not_and_name}{to}",
+            if_not_and_name = if self.if_not_exists {
+                if self.name_before_not_exists {
+                    format!("{} IF NOT EXISTS", self.name)
+                } else {
+                    format!("IF NOT EXISTS {}", self.name)
+                }
+            } else {
+                format!("{}", self.name)
+            },
+            secure = if self.secure { "SECURE " } else { "" },
+            materialized = if self.materialized {
+                "MATERIALIZED "
+            } else {
+                ""
+            },
+            temporary = if self.temporary { "TEMPORARY " } else { "" },
+            to = self
+                .to
+                .as_ref()
+                .map(|to| format!(" TO {to}"))
+                .unwrap_or_default()
+        )?;
+        if !self.columns.is_empty() {
+            write!(f, " ({})", display_comma_separated(&self.columns))?;
+        }
+        if matches!(self.options, CreateTableOptions::With(_)) {
+            write!(f, " {}", self.options)?;
+        }
+        if let Some(ref comment) = self.comment {
+            write!(f, " COMMENT = '{}'", escape_single_quote_string(comment))?;
+        }
+        if !self.cluster_by.is_empty() {
+            write!(
+                f,
+                " CLUSTER BY ({})",
+                display_comma_separated(&self.cluster_by)
+            )?;
+        }
+        if matches!(self.options, CreateTableOptions::Options(_)) {
+            write!(f, " {}", self.options)?;
+        }
+        f.write_str(" AS")?;
+        SpaceOrNewline.fmt(f)?;
+        self.query.fmt(f)?;
+        if self.with_no_schema_binding {
+            write!(f, " WITH NO SCHEMA BINDING")?;
+        }
+        Ok(())
+    }
+}
+
+/// CREATE EXTENSION statement
+/// Note: this is a PostgreSQL-specific statement
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct CreateExtension {
+    pub name: Ident,
+    pub if_not_exists: bool,
+    pub cascade: bool,
+    pub schema: Option<Ident>,
+    pub version: Option<Ident>,
+}
+
+impl fmt::Display for CreateExtension {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "CREATE EXTENSION {if_not_exists}{name}",
+            if_not_exists = if self.if_not_exists {
+                "IF NOT EXISTS "
+            } else {
+                ""
+            },
+            name = self.name
+        )?;
+        if self.cascade || self.schema.is_some() || self.version.is_some() {
+            write!(f, " WITH")?;
+
+            if let Some(name) = &self.schema {
+                write!(f, " SCHEMA {name}")?;
+            }
+            if let Some(version) = &self.version {
+                write!(f, " VERSION {version}")?;
+            }
+            if self.cascade {
+                write!(f, " CASCADE")?;
+            }
+        }
+
+        Ok(())
+    }
+}
+
+impl Spanned for CreateExtension {
+    fn span(&self) -> Span {
+        Span::empty()
+    }
+}
+
+/// DROP EXTENSION statement  
+/// Note: this is a PostgreSQL-specific statement
+///
+/// # References
+///
+/// PostgreSQL Documentation:
+/// <https://www.postgresql.org/docs/current/sql-dropextension.html>
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct DropExtension {
+    pub names: Vec<Ident>,
+    pub if_exists: bool,
+    /// `CASCADE` or `RESTRICT`
+    pub cascade_or_restrict: Option<ReferentialAction>,
+}
+
+impl fmt::Display for DropExtension {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "DROP EXTENSION")?;
+        if self.if_exists {
+            write!(f, " IF EXISTS")?;
+        }
+        write!(f, " {}", display_comma_separated(&self.names))?;
+        if let Some(cascade_or_restrict) = &self.cascade_or_restrict {
+            write!(f, " {cascade_or_restrict}")?;
+        }
+        Ok(())
+    }
+}
+
+impl Spanned for DropExtension {
+    fn span(&self) -> Span {
+        Span::empty()
+    }
+}
+
+/// ALTER TABLE statement
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct AlterTable {
+    /// Table name
+    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
+    pub name: ObjectName,
+    pub if_exists: bool,
+    pub only: bool,
+    pub operations: Vec<AlterTableOperation>,
+    pub location: Option<HiveSetLocation>,
+    /// ClickHouse dialect supports `ON CLUSTER` clause for ALTER TABLE
+    /// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
+    /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
+    pub on_cluster: Option<Ident>,
+    /// Snowflake "ICEBERG" clause for Iceberg tables
+    /// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
+    pub iceberg: bool,
+    /// Token that represents the end of the statement (semicolon or EOF)
+    pub end_token: AttachedToken,
+}
+
+impl fmt::Display for AlterTable {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if self.iceberg {
+            write!(f, "ALTER ICEBERG TABLE ")?;
+        } else {
+            write!(f, "ALTER TABLE ")?;
+        }
+
+        if self.if_exists {
+            write!(f, "IF EXISTS ")?;
+        }
+        if self.only {
+            write!(f, "ONLY ")?;
+        }
+        write!(f, "{} ", &self.name)?;
+        if let Some(cluster) = &self.on_cluster {
+            write!(f, "ON CLUSTER {cluster} ")?;
+        }
+        write!(f, "{}", display_comma_separated(&self.operations))?;
+        if let Some(loc) = &self.location {
+            write!(f, " {loc}")?
+        }
+        Ok(())
+    }
+}
+
+/// DROP FUNCTION statement
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct DropFunction {
+    pub if_exists: bool,
+    /// One or more functions to drop
+    pub func_desc: Vec<FunctionDesc>,
+    /// `CASCADE` or `RESTRICT`
+    pub drop_behavior: Option<DropBehavior>,
+}
+
+impl fmt::Display for DropFunction {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "DROP FUNCTION{} {}",
+            if self.if_exists { " IF EXISTS" } else { "" },
+            display_comma_separated(&self.func_desc),
+        )?;
+        if let Some(op) = &self.drop_behavior {
+            write!(f, " {op}")?;
+        }
+        Ok(())
+    }
+}
+
+impl Spanned for DropFunction {
+    fn span(&self) -> Span {
+        Span::empty()
+    }
+}
diff --git a/src/ast/dml.rs b/src/ast/dml.rs
index e4d99bcf..c0bfcb19 100644
--- a/src/ast/dml.rs
+++ b/src/ast/dml.rs
@@ -29,7 +29,7 @@ use crate::display_utils::{indented_list, Indent, SpaceOrNewline};
 use super::{
     display_comma_separated, query::InputFormatClause, Assignment, Expr, FromTable, Ident,
     InsertAliases, MysqlInsertPriority, ObjectName, OnInsert, OrderByExpr, Query, SelectItem,
-    Setting, SqliteOnConflict, TableObject, TableWithJoins,
+    Setting, SqliteOnConflict, TableObject, TableWithJoins, UpdateTableFromKind,
 };
 
 /// INSERT statement.
@@ -240,3 +240,66 @@ impl Display for Delete {
         Ok(())
     }
 }
+
+/// UPDATE statement.
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct Update {
+    /// TABLE
+    pub table: TableWithJoins,
+    /// Column assignments
+    pub assignments: Vec<Assignment>,
+    /// Table which provide value to be set
+    pub from: Option<UpdateTableFromKind>,
+    /// WHERE
+    pub selection: Option<Expr>,
+    /// RETURNING
+    pub returning: Option<Vec<SelectItem>>,
+    /// SQLite-specific conflict resolution clause
+    pub or: Option<SqliteOnConflict>,
+    /// LIMIT
+    pub limit: Option<Expr>,
+}
+
+impl Display for Update {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str("UPDATE ")?;
+        if let Some(or) = &self.or {
+            or.fmt(f)?;
+            f.write_str(" ")?;
+        }
+        self.table.fmt(f)?;
+        if let Some(UpdateTableFromKind::BeforeSet(from)) = &self.from {
+            SpaceOrNewline.fmt(f)?;
+            f.write_str("FROM")?;
+            indented_list(f, from)?;
+        }
+        if !self.assignments.is_empty() {
+            SpaceOrNewline.fmt(f)?;
+            f.write_str("SET")?;
+            indented_list(f, &self.assignments)?;
+        }
+        if let Some(UpdateTableFromKind::AfterSet(from)) = &self.from {
+            SpaceOrNewline.fmt(f)?;
+            f.write_str("FROM")?;
+            indented_list(f, from)?;
+        }
+        if let Some(selection) = &self.selection {
+            SpaceOrNewline.fmt(f)?;
+            f.write_str("WHERE")?;
+            SpaceOrNewline.fmt(f)?;
+            Indent(selection).fmt(f)?;
+        }
+        if let Some(returning) = &self.returning {
+            SpaceOrNewline.fmt(f)?;
+            f.write_str("RETURNING")?;
+            indented_list(f, returning)?;
+        }
+        if let Some(limit) = &self.limit {
+            SpaceOrNewline.fmt(f)?;
+            write!(f, "LIMIT {limit}")?;
+        }
+        Ok(())
+    }
+}
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index 52968d7d..0c83b320 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -43,7 +43,7 @@ use serde::{Deserialize, Serialize};
 use sqlparser_derive::{Visit, VisitMut};
 
 use crate::{
-    display_utils::{indented_list, SpaceOrNewline},
+    display_utils::SpaceOrNewline,
     tokenizer::{Span, Token},
 };
 use crate::{
@@ -56,22 +56,24 @@ pub use self::data_type::{
     ExactNumberInfo, IntervalFields, StructBracketKind, TimezoneInfo,
 };
 pub use self::dcl::{
-    AlterRoleOperation, ResetConfig, RoleOption, SecondaryRoles, SetConfigValue, Use,
+    AlterRoleOperation, CreateRole, ResetConfig, RoleOption, SecondaryRoles, SetConfigValue, Use,
 };
 pub use self::ddl::{
     AlterColumnOperation, AlterConnectorOwner, AlterIndexOperation, AlterPolicyOperation,
-    AlterSchema, AlterSchemaOperation, AlterTableAlgorithm, AlterTableLock, AlterTableOperation,
-    AlterType, AlterTypeAddValue, AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename,
-    AlterTypeRenameValue, ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnOptions,
-    ColumnPolicy, ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateDomain,
-    CreateFunction, CreateIndex, CreateTable, CreateTrigger, Deduplicate, DeferrableInitial,
-    DropBehavior, DropTrigger, GeneratedAs, GeneratedExpressionMode, IdentityParameters,
-    IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder,
-    IndexColumn, IndexOption, IndexType, KeyOrIndexDisplay, NullsDistinctOption, Owner, Partition,
-    ProcedureParam, ReferentialAction, RenameTableNameKind, ReplicaIdentity, TagsColumnOption,
-    UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation, ViewColumnDef,
+    AlterSchema, AlterSchemaOperation, AlterTable, AlterTableAlgorithm, AlterTableLock,
+    AlterTableOperation, AlterType, AlterTypeAddValue, AlterTypeAddValuePosition,
+    AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue, ClusteredBy, ColumnDef,
+    ColumnOption, ColumnOptionDef, ColumnOptions, ColumnPolicy, ColumnPolicyProperty,
+    ConstraintCharacteristics, CreateConnector, CreateDomain, CreateExtension, CreateFunction,
+    CreateIndex, CreateTable, CreateTrigger, CreateView, Deduplicate, DeferrableInitial,
+    DropBehavior, DropExtension, DropFunction, DropTrigger, GeneratedAs, GeneratedExpressionMode,
+    IdentityParameters, IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind,
+    IdentityPropertyOrder, IndexColumn, IndexOption, IndexType, KeyOrIndexDisplay, Msck,
+    NullsDistinctOption, Owner, Partition, ProcedureParam, ReferentialAction, RenameTableNameKind,
+    ReplicaIdentity, TagsColumnOption, Truncate, UserDefinedTypeCompositeAttributeDef,
+    UserDefinedTypeRepresentation, ViewColumnDef,
 };
-pub use self::dml::{Delete, Insert};
+pub use self::dml::{Delete, Insert, Update};
 pub use self::operator::{BinaryOperator, UnaryOperator};
 pub use self::query::{
     AfterMatchSkip, ConnectBy, Cte, CteAsMaterialized, Distinct, EmptyMatchesMode,
@@ -3064,6 +3066,59 @@ impl Display for ExceptionWhen {
     }
 }
 
+/// ANALYZE TABLE statement (Hive-specific)
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct Analyze {
+    #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
+    pub table_name: ObjectName,
+    pub partitions: Option<Vec<Expr>>,
+    pub for_columns: bool,
+    pub columns: Vec<Ident>,
+    pub cache_metadata: bool,
+    pub noscan: bool,
+    pub compute_statistics: bool,
+    pub has_table_keyword: bool,
+}
+
+impl fmt::Display for Analyze {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "ANALYZE{}{table_name}",
+            if self.has_table_keyword {
+                " TABLE "
+            } else {
+                " "
+            },
+            table_name = self.table_name
+        )?;
+        if let Some(ref parts) = self.partitions {
+            if !parts.is_empty() {
+                write!(f, " PARTITION ({})", display_comma_separated(parts))?;
+            }
+        }
+
+        if self.compute_statistics {
+            write!(f, " COMPUTE STATISTICS")?;
+        }
+        if self.noscan {
+            write!(f, " NOSCAN")?;
+        }
+        if self.cache_metadata {
+            write!(f, " CACHE METADATA")?;
+        }
+        if self.for_columns {
+            write!(f, " FOR COLUMNS")?;
+            if !self.columns.is_empty() {
+                write!(f, " {}", display_comma_separated(&self.columns))?;
+            }
+        }
+        Ok(())
+    }
+}
+
 /// A top-level statement (SELECT, INSERT, CREATE, etc.)
 #[allow(clippy::large_enum_variant)]
 #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
@@ -3078,49 +3133,18 @@ pub enum Statement {
     /// ANALYZE
     /// ```
     /// Analyze (Hive)
-    Analyze {
-        #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
-        table_name: ObjectName,
-        partitions: Option<Vec<Expr>>,
-        for_columns: bool,
-        columns: Vec<Ident>,
-        cache_metadata: bool,
-        noscan: bool,
-        compute_statistics: bool,
-        has_table_keyword: bool,
-    },
+    Analyze(Analyze),
     Set(Set),
     /// ```sql
     /// TRUNCATE
     /// ```
     /// Truncate (Hive)
-    Truncate {
-        table_names: Vec<TruncateTableTarget>,
-        partitions: Option<Vec<Expr>>,
-        /// TABLE - optional keyword;
-        table: bool,
-        /// Postgres-specific option
-        /// [ RESTART IDENTITY | CONTINUE IDENTITY ]
-        identity: Option<TruncateIdentityOption>,
-        /// Postgres-specific option
-        /// [ CASCADE | RESTRICT ]
-        cascade: Option<CascadeOption>,
-        /// ClickHouse-specific option
-        /// [ ON CLUSTER cluster_name ]
-        ///
-        /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/truncate/)
-        on_cluster: Option<Ident>,
-    },
+    Truncate(Truncate),
     /// ```sql
     /// MSCK
     /// ```
     /// Msck (Hive)
-    Msck {
-        #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
-        table_name: ObjectName,
-        repair: bool,
-        partition_action: Option<AddDropSync>,
-    },
+    Msck(Msck),
     /// ```sql
     /// SELECT
     /// ```
@@ -3223,22 +3247,7 @@ pub enum Statement {
     /// ```sql
     /// UPDATE
     /// ```
-    Update {
-        /// TABLE
-        table: TableWithJoins,
-        /// Column assignments
-        assignments: Vec<Assignment>,
-        /// Table which provide value to be set
-        from: Option<UpdateTableFromKind>,
-        /// WHERE
-        selection: Option<Expr>,
-        /// RETURNING
-        returning: Option<Vec<SelectItem>>,
-        /// SQLite-specific conflict resolution clause
-        or: Option<SqliteOnConflict>,
-        /// LIMIT
-        limit: Option<Expr>,
-    },
+    Update(Update),
     /// ```sql
     /// DELETE
     /// ```
@@ -3246,48 +3255,7 @@ pub enum Statement {
     /// ```sql
     /// CREATE VIEW
     /// ```
-    CreateView {
-        /// True if this is a `CREATE OR ALTER VIEW` statement
-        ///
-        /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-view-transact-sql)
-        or_alter: bool,
-        or_replace: bool,
-        materialized: bool,
-        /// Snowflake: SECURE view modifier
-        /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
-        secure: bool,
-        /// View name
-        name: ObjectName,
-        /// If `if_not_exists` is true, this flag is set to true if the view name comes before the `IF NOT EXISTS` clause.
-        /// Example:
-        /// ```sql
-        /// CREATE VIEW myview IF NOT EXISTS AS SELECT 1`
-        ///  ```
-        /// Otherwise, the flag is set to false if the view name comes after the clause
-        /// Example:
-        /// ```sql
-        /// CREATE VIEW IF NOT EXISTS myview AS SELECT 1`
-        ///  ```
-        name_before_not_exists: bool,
-        columns: Vec<ViewColumnDef>,
-        query: Box<Query>,
-        options: CreateTableOptions,
-        cluster_by: Vec<Ident>,
-        /// Snowflake: Views can have comments in Snowflake.
-        /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
-        comment: Option<String>,
-        /// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_VIEW.html>
-        with_no_schema_binding: bool,
-        /// if true, has SQLite `IF NOT EXISTS` clause <https://www.sqlite.org/lang_createview.html>
-        if_not_exists: bool,
-        /// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html>
-        temporary: bool,
-        /// if not None, has Clickhouse `TO` clause, specify the table into which to insert results
-        /// <https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view>
-        to: Option<ObjectName>,
-        /// MySQL: Optional parameters for the view algorithm, definer, and security context
-        params: Option<CreateViewParams>,
-    },
+    CreateView(CreateView),
     /// ```sql
     /// CREATE TABLE
     /// ```
@@ -3311,28 +3279,7 @@ pub enum Statement {
     /// CREATE ROLE
     /// ```
     /// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createrole.html)
-    CreateRole {
-        names: Vec<ObjectName>,
-        if_not_exists: bool,
-        // Postgres
-        login: Option<bool>,
-        inherit: Option<bool>,
-        bypassrls: Option<bool>,
-        password: Option<Password>,
-        superuser: Option<bool>,
-        create_db: Option<bool>,
-        create_role: Option<bool>,
-        replication: Option<bool>,
-        connection_limit: Option<Expr>,
-        valid_until: Option<Expr>,
-        in_role: Vec<Ident>,
-        in_group: Vec<Ident>,
-        role: Vec<Ident>,
-        user: Vec<Ident>,
-        admin: Vec<Ident>,
-        // MSSQL
-        authorization_owner: Option<ObjectName>,
-    },
+    CreateRole(CreateRole),
     /// ```sql
     /// CREATE SECRET
     /// ```
@@ -3370,24 +3317,7 @@ pub enum Statement {
     /// ```sql
     /// ALTER TABLE
     /// ```
-    AlterTable {
-        /// Table name
-        #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
-        name: ObjectName,
-        if_exists: bool,
-        only: bool,
-        operations: Vec<AlterTableOperation>,
-        location: Option<HiveSetLocation>,
-        /// ClickHouse dialect supports `ON CLUSTER` clause for ALTER TABLE
-        /// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
-        /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
-        on_cluster: Option<Ident>,
-        /// Snowflake "ICEBERG" clause for Iceberg tables
-        /// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
-        iceberg: bool,
-        /// Token that represents the end of the statement (semicolon or EOF)
-        end_token: AttachedToken,
-    },
+    AlterTable(AlterTable),
     /// ```sql
     /// ALTER SCHEMA
     /// ```
@@ -3523,13 +3453,7 @@ pub enum Statement {
     /// ```sql
     /// DROP FUNCTION
     /// ```
-    DropFunction {
-        if_exists: bool,
-        /// One or more function to drop
-        func_desc: Vec<FunctionDesc>,
-        /// `CASCADE` or `RESTRICT`
-        drop_behavior: Option<DropBehavior>,
-    },
+    DropFunction(DropFunction),
     /// ```sql
     /// DROP DOMAIN
     /// ```
@@ -3593,25 +3517,13 @@ pub enum Statement {
     /// ```
     ///
     /// Note: this is a PostgreSQL-specific statement,
-    CreateExtension {
-        name: Ident,
-        if_not_exists: bool,
-        cascade: bool,
-        schema: Option<Ident>,
-        version: Option<Ident>,
-    },
+    CreateExtension(CreateExtension),
     /// ```sql
     /// DROP EXTENSION [ IF EXISTS ] name [, ...] [ CASCADE | RESTRICT ]
-    ///
-    /// Note: this is a PostgreSQL-specific statement.
-    /// https://www.postgresql.org/docs/current/sql-dropextension.html
     /// ```
-    DropExtension {
-        names: Vec<Ident>,
-        if_exists: bool,
-        /// `CASCADE` or `RESTRICT`
-        cascade_or_restrict: Option<ReferentialAction>,
-    },
+    /// Note: this is a PostgreSQL-specific statement.
+    /// <https://www.postgresql.org/docs/current/sql-dropextension.html>
+    DropExtension(DropExtension),
     /// ```sql
     /// FETCH
     /// ```
@@ -4328,6 +4240,24 @@ pub enum Statement {
     Vacuum(VacuumStatement),
 }
 
+impl From<Analyze> for Statement {
+    fn from(analyze: Analyze) -> Self {
+        Statement::Analyze(analyze)
+    }
+}
+
+impl From<ddl::Truncate> for Statement {
+    fn from(truncate: ddl::Truncate) -> Self {
+        Statement::Truncate(truncate)
+    }
+}
+
+impl From<ddl::Msck> for Statement {
+    fn from(msck: ddl::Msck) -> Self {
+        Statement::Msck(msck)
+    }
+}
+
 /// ```sql
 /// {COPY | REVOKE} CURRENT GRANTS
 /// ```
@@ -4528,61 +4458,8 @@ impl fmt::Display for Statement {
                 }
                 write!(f, " {source}")
             }
-            Statement::Msck {
-                table_name,
-                repair,
-                partition_action,
-            } => {
-                write!(
-                    f,
-                    "MSCK {repair}TABLE {table}",
-                    repair = if *repair { "REPAIR " } else { "" },
-                    table = table_name
-                )?;
-                if let Some(pa) = partition_action {
-                    write!(f, " {pa}")?;
-                }
-                Ok(())
-            }
-            Statement::Truncate {
-                table_names,
-                partitions,
-                table,
-                identity,
-                cascade,
-                on_cluster,
-            } => {
-                let table = if *table { "TABLE " } else { "" };
-
-                write!(
-                    f,
-                    "TRUNCATE {table}{table_names}",
-                    table_names = display_comma_separated(table_names)
-                )?;
-
-                if let Some(identity) = identity {
-                    match identity {
-                        TruncateIdentityOption::Restart => write!(f, " RESTART IDENTITY")?,
-                        TruncateIdentityOption::Continue => write!(f, " CONTINUE IDENTITY")?,
-                    }
-                }
-                if let Some(cascade) = cascade {
-                    match cascade {
-                        CascadeOption::Cascade => write!(f, " CASCADE")?,
-                        CascadeOption::Restrict => write!(f, " RESTRICT")?,
-                    }
-                }
-
-                if let Some(ref parts) = partitions {
-                    if !parts.is_empty() {
-                        write!(f, " PARTITION ({})", display_comma_separated(parts))?;
-                    }
-                }
-                if let Some(on_cluster) = on_cluster {
-                    write!(f, " ON CLUSTER {on_cluster}")?;
-                }
-                Ok(())
-            }
+            Statement::Msck(msck) => msck.fmt(f),
+            Statement::Truncate(truncate) => truncate.fmt(f),
             Statement::Case(stmt) => {
                 write!(f, "{stmt}")
             }
@@ -4637,44 +4514,7 @@ impl fmt::Display for Statement {
                 )?;
                 Ok(())
             }
-            Statement::Analyze {
-                table_name,
-                partitions,
-                for_columns,
-                columns,
-                cache_metadata,
-                noscan,
-                compute_statistics,
-                has_table_keyword,
-            } => {
-                write!(
-                    f,
-                    "ANALYZE{}{table_name}",
-                    if *has_table_keyword { " TABLE " } else { " " }
-                )?;
-                if let Some(ref parts) = partitions {
-                    if !parts.is_empty() {
-                        write!(f, " PARTITION ({})", display_comma_separated(parts))?;
-                    }
-                }
-
-                if *compute_statistics {
-                    write!(f, " COMPUTE STATISTICS")?;
-                }
-                if *noscan {
-                    write!(f, " NOSCAN")?;
-                }
-                if *cache_metadata {
-                    write!(f, " CACHE METADATA")?;
-                }
-                if *for_columns {
-                    write!(f, " FOR COLUMNS")?;
-                    if !columns.is_empty() {
-                        write!(f, " {}", display_comma_separated(columns))?;
-                    }
-                }
-                Ok(())
-            }
+            Statement::Analyze(analyze) => analyze.fmt(f),
             Statement::Insert(insert) => insert.fmt(f),
             Statement::Install {
                 extension_name: name,
@@ -4730,53 +4570,7 @@ impl fmt::Display for Statement {
                 }
                 Ok(())
             }
-            Statement::Update {
-                table,
-                assignments,
-                from,
-                selection,
-                returning,
-                or,
-                limit,
-            } => {
-                f.write_str("UPDATE ")?;
-                if let Some(or) = or {
-                    or.fmt(f)?;
-                    f.write_str(" ")?;
-                }
-                table.fmt(f)?;
-                if let Some(UpdateTableFromKind::BeforeSet(from)) = from {
-                    SpaceOrNewline.fmt(f)?;
-                    f.write_str("FROM")?;
-                    indented_list(f, from)?;
-                }
-                if !assignments.is_empty() {
-                    SpaceOrNewline.fmt(f)?;
-                    f.write_str("SET")?;
-                    indented_list(f, assignments)?;
-                }
-                if let Some(UpdateTableFromKind::AfterSet(from)) = from {
-                    SpaceOrNewline.fmt(f)?;
-                    f.write_str("FROM")?;
-                    indented_list(f, from)?;
-                }
-                if let Some(selection) = selection {
-                    SpaceOrNewline.fmt(f)?;
-                    f.write_str("WHERE")?;
-                    SpaceOrNewline.fmt(f)?;
-                    Indent(selection).fmt(f)?;
-                }
-                if let Some(returning) = returning {
-                    SpaceOrNewline.fmt(f)?;
-                    f.write_str("RETURNING")?;
-                    indented_list(f, returning)?;
-                }
-                if let Some(limit) = limit {
-                    SpaceOrNewline.fmt(f)?;
-                    write!(f, "LIMIT {limit}")?;
-                }
-                Ok(())
-            }
+            Statement::Update(update) => update.fmt(f),
             Statement::Delete(delete) => delete.fmt(f),
             Statement::Open(open) => open.fmt(f),
             Statement::Close { cursor } => {
@@ -4932,80 +4726,7 @@ impl fmt::Display for Statement {
                 }
                 Ok(())
             }
-            Statement::CreateView {
-                or_alter,
-                name,
-                or_replace,
-                columns,
-                query,
-                materialized,
-                secure,
-                options,
-                cluster_by,
-                comment,
-                with_no_schema_binding,
-                if_not_exists,
-                temporary,
-                to,
-                params,
-                name_before_not_exists,
-            } => {
-                write!(
-                    f,
-                    "CREATE {or_alter}{or_replace}",
-                    or_alter = if *or_alter { "OR ALTER " } else { "" },
-                    or_replace = if *or_replace { "OR REPLACE " } else { "" },
-                )?;
-                if let Some(params) = params {
-                    params.fmt(f)?;
-                }
-                write!(
-                    f,
-                    "{secure}{materialized}{temporary}VIEW {if_not_and_name}{to}",
-                    if_not_and_name = if *if_not_exists {
-                        if *name_before_not_exists {
-                            format!("{name} IF NOT EXISTS")
-                        } else {
-                            format!("IF NOT EXISTS {name}")
-                        }
-                    } else {
-                        format!("{name}")
-                    },
-                    secure = if *secure { "SECURE " } else { "" },
-                    materialized = if *materialized { "MATERIALIZED " } else { "" },
-                    temporary = if *temporary { "TEMPORARY " } else { "" },
-                    to = to
-                        .as_ref()
-                        .map(|to| format!(" TO {to}"))
-                        .unwrap_or_default()
-                )?;
-                if !columns.is_empty() {
-                    write!(f, " ({})", display_comma_separated(columns))?;
-                }
-                if matches!(options, CreateTableOptions::With(_)) {
-                    write!(f, " {options}")?;
-                }
-                if let Some(comment) = comment {
-                    write!(
-                        f,
-                        " COMMENT = '{}'",
-                        value::escape_single_quote_string(comment)
-                    )?;
-                }
-                if !cluster_by.is_empty() {
-                    write!(f, " CLUSTER BY ({})", display_comma_separated(cluster_by))?;
-                }
-                if matches!(options, CreateTableOptions::Options(_)) {
-                    write!(f, " {options}")?;
-                }
-                f.write_str(" AS")?;
-                SpaceOrNewline.fmt(f)?;
-                query.fmt(f)?;
-                if *with_no_schema_binding {
-                    write!(f, " WITH NO SCHEMA BINDING")?;
-                }
-                Ok(())
-            }
+            Statement::CreateView(create_view) => create_view.fmt(f),
             Statement::CreateTable(create_table) => create_table.fmt(f),
             Statement::LoadData {
                 local,
@@ -5056,141 +4777,9 @@ impl fmt::Display for Statement {
                 Ok(())
             }
             Statement::CreateIndex(create_index) => create_index.fmt(f),
-            Statement::CreateExtension {
-                name,
-                if_not_exists,
-                cascade,
-                schema,
-                version,
-            } => {
-                write!(
-                    f,
-                    "CREATE EXTENSION {if_not_exists}{name}",
-                    if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" }
-                )?;
-                if *cascade || schema.is_some() || version.is_some() {
-                    write!(f, " WITH")?;
-
-                    if let Some(name) = schema {
-                        write!(f, " SCHEMA {name}")?;
-                    }
-                    if let Some(version) = version {
-                        write!(f, " VERSION {version}")?;
-                    }
-                    if *cascade {
-                        write!(f, " CASCADE")?;
-                    }
-                }
-
-                Ok(())
-            }
-            Statement::DropExtension {
-                names,
-                if_exists,
-                cascade_or_restrict,
-            } => {
-                write!(f, "DROP EXTENSION")?;
-                if *if_exists {
-                    write!(f, " IF EXISTS")?;
-                }
-                write!(f, " {}", display_comma_separated(names))?;
-                if let Some(cascade_or_restrict) = cascade_or_restrict {
-                    write!(f, " {cascade_or_restrict}")?;
-                }
-                Ok(())
-            }
-            Statement::CreateRole {
-                names,
-                if_not_exists,
-                inherit,
-                login,
-                bypassrls,
-                password,
-                create_db,
-                create_role,
-                superuser,
-                replication,
-                connection_limit,
-                valid_until,
-                in_role,
-                in_group,
-                role,
-                user,
-                admin,
-                authorization_owner,
-            } => {
-                write!(
-                    f,
-                    "CREATE ROLE {if_not_exists}{names}{superuser}{create_db}{create_role}{inherit}{login}{replication}{bypassrls}",
-                    if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
-                    names = display_separated(names, ", "),
-                    superuser = match *superuser {
-                        Some(true) => " SUPERUSER",
-                        Some(false) => " NOSUPERUSER",
-                        None => ""
-                    },
-                    create_db = match *create_db {
-                        Some(true) => " CREATEDB",
-                        Some(false) => " NOCREATEDB",
-                        None => ""
-                    },
-                    create_role = match *create_role {
-                        Some(true) => " CREATEROLE",
-                        Some(false) => " NOCREATEROLE",
-                        None => ""
-                    },
-                    inherit = match *inherit {
-                        Some(true) => " INHERIT",
-                        Some(false) => " NOINHERIT",
-                        None => ""
-                    },
-                    login = match *login {
-                        Some(true) => " LOGIN",
-                        Some(false) => " NOLOGIN",
-                        None => ""
-                    },
-                    replication = match *replication {
-                        Some(true) => " REPLICATION",
-                        Some(false) => " NOREPLICATION",
-                        None => ""
-                    },
-                    bypassrls = match *bypassrls {
-                        Some(true) => " BYPASSRLS",
-                        Some(false) => " NOBYPASSRLS",
-                        None => ""
-                    }
-                )?;
-                if let Some(limit) = connection_limit {
-                    write!(f, " CONNECTION LIMIT {limit}")?;
-                }
-                match password {
-                    Some(Password::Password(pass)) => write!(f, " PASSWORD {pass}"),
-                    Some(Password::NullPassword) => write!(f, " PASSWORD NULL"),
-                    None => Ok(()),
-                }?;
-                if let Some(until) = valid_until {
-                    write!(f, " VALID UNTIL {until}")?;
-                }
-                if !in_role.is_empty() {
-                    write!(f, " IN ROLE {}", display_comma_separated(in_role))?;
-                }
-                if !in_group.is_empty() {
-                    write!(f, " IN GROUP {}", display_comma_separated(in_group))?;
-                }
-                if !role.is_empty() {
-                    write!(f, " ROLE {}", display_comma_separated(role))?;
-                }
-                if !user.is_empty() {
-                    write!(f, " USER {}", display_comma_separated(user))?;
-                }
-                if !admin.is_empty() {
-                    write!(f, " ADMIN {}", display_comma_separated(admin))?;
-                }
-                if let Some(owner) = authorization_owner {
-                    write!(f, " AUTHORIZATION {owner}")?;
-                }
-                Ok(())
-            }
+            Statement::CreateExtension(create_extension) => write!(f, "{create_extension}"),
+            Statement::DropExtension(drop_extension) => write!(f, "{drop_extension}"),
+            Statement::CreateRole(create_role) => write!(f, "{create_role}"),
             Statement::CreateSecret {
                 or_replace,
                 temporary,
@@ -5272,42 +4861,7 @@ impl fmt::Display for Statement {
                 Ok(())
             }
             Statement::CreateConnector(create_connector) => create_connector.fmt(f),
-            Statement::AlterTable {
-                name,
-                if_exists,
-                only,
-                operations,
-                location,
-                on_cluster,
-                iceberg,
-                end_token: _,
-            } => {
-                if *iceberg {
-                    write!(f, "ALTER ICEBERG TABLE ")?;
-                } else {
-                    write!(f, "ALTER TABLE ")?;
-                }
-
-                if *if_exists {
-                    write!(f, "IF EXISTS ")?;
-                }
-                if *only {
-                    write!(f, "ONLY ")?;
-                }
-                write!(f, "{name} ")?;
-                if let Some(cluster) = on_cluster {
-                    write!(f, "ON CLUSTER {cluster} ")?;
-                }
-                write!(
-                    f,
-                    "{operations}",
-                    operations = display_comma_separated(operations)
-                )?;
-                if let Some(loc) = location {
-                    write!(f, " {loc}")?
-                }
-                Ok(())
-            }
+            Statement::AlterTable(alter_table) => write!(f, "{alter_table}"),
             Statement::AlterIndex { name, operation } => {
                 write!(f, "ALTER INDEX {name} {operation}")
             }
@@ -5410,22 +4964,7 @@ impl fmt::Display for Statement {
                 };
                 Ok(())
             }
-            Statement::DropFunction {
-                if_exists,
-                func_desc,
-                drop_behavior,
-            } => {
-                write!(
-                    f,
-                    "DROP FUNCTION{} {}",
-                    if *if_exists { " IF EXISTS" } else { "" },
-                    display_comma_separated(func_desc),
-                )?;
-                if let Some(op) = drop_behavior {
-                    write!(f, " {op}")?;
-                }
-                Ok(())
-            }
+            Statement::DropFunction(drop_function) => write!(f, "{drop_function}"),
             Statement::DropDomain(DropDomain {
                 if_exists,
                 name,
@@ -10945,6 +10484,48 @@ impl From<Insert> for Statement {
     }
 }
 
+impl From<Update> for Statement {
+    fn from(u: Update) -> Self {
+        Self::Update(u)
+    }
+}
+
+impl From<CreateView> for Statement {
+    fn from(cv: CreateView) -> Self {
+        Self::CreateView(cv)
+    }
+}
+
+impl From<CreateRole> for Statement {
+    fn from(cr: CreateRole) -> Self {
+        Self::CreateRole(cr)
+    }
+}
+
+impl From<AlterTable> for Statement {
+    fn from(at: AlterTable) -> Self {
+        Self::AlterTable(at)
+    }
+}
+
+impl From<DropFunction> for Statement {
+    fn from(df: DropFunction) -> Self {
+        Self::DropFunction(df)
+    }
+}
+
+impl From<CreateExtension> for Statement {
+    fn from(ce: CreateExtension) -> Self {
+        Self::CreateExtension(ce)
+    }
+}
+
+impl From<DropExtension> for Statement {
+    fn from(de: DropExtension) -> Self {
+        Self::DropExtension(de)
+    }
+}
+
 impl From<CaseStatement> for Statement {
     fn from(c: CaseStatement) -> Self {
         Self::Case(c)
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index 0a303fcf..de3439cf 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -16,8 +16,8 @@
 // under the License.
 
 use crate::ast::{
-    ddl::AlterSchema, query::SelectItemQualifiedWildcardKind, AlterSchemaOperation, ColumnOptions,
-    ExportData, Owner, TypedString,
+    ddl::AlterSchema, query::SelectItemQualifiedWildcardKind, AlterSchemaOperation, AlterTable,
+    ColumnOptions, CreateView, ExportData, Owner, TypedString,
 };
 use core::iter;
 
@@ -25,23 +25,23 @@ use crate::tokenizer::Span;
 
 use super::{
     dcl::SecondaryRoles, value::ValueWithSpan, AccessExpr, AlterColumnOperation,
-    AlterIndexOperation, AlterTableOperation, Array, Assignment, AssignmentTarget, AttachedToken,
-    BeginEndStatements, CaseStatement, CloseCursor, ClusteredIndex, ColumnDef, ColumnOption,
-    ColumnOptionDef, ConditionalStatementBlock, ConditionalStatements, ConflictTarget, ConnectBy,
-    ConstraintCharacteristics, CopySource, CreateIndex, CreateTable, CreateTableOptions, Cte,
-    Delete, DoUpdate, ExceptSelectItem, ExcludeSelectItem, Expr, ExprWithAlias, Fetch, FromTable,
-    Function, FunctionArg, FunctionArgExpr, FunctionArgumentClause, FunctionArgumentList,
-    FunctionArguments, GroupByExpr, HavingBound, IfStatement, IlikeSelectItem, IndexColumn, Insert,
-    Interpolate, InterpolateExpr, Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem,
-    LateralView, LimitClause, MatchRecognizePattern, Measure, NamedParenthesizedList,
-    NamedWindowDefinition, ObjectName, ObjectNamePart, Offset, OnConflict, OnConflictAction,
-    OnInsert, OpenStatement, OrderBy, OrderByExpr, OrderByKind, Partition, PivotValueSource,
-    ProjectionSelect, Query, RaiseStatement, RaiseStatementValue, ReferentialAction,
-    RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem,
-    SetExpr, SqlOption, Statement, Subscript, SymbolDefinition, TableAlias, TableAliasColumnDef,
-    TableConstraint, TableFactor, TableObject, TableOptionsClustered, TableWithJoins,
-    UpdateTableFromKind, Use, Value, Values, ViewColumnDef, WhileStatement,
-    WildcardAdditionalOptions, With, WithFill,
+    AlterIndexOperation, AlterTableOperation, Analyze, Array, Assignment, AssignmentTarget,
+    AttachedToken, BeginEndStatements, CaseStatement, CloseCursor, ClusteredIndex, ColumnDef,
+    ColumnOption, ColumnOptionDef, ConditionalStatementBlock, ConditionalStatements,
+    ConflictTarget, ConnectBy, ConstraintCharacteristics, CopySource, CreateIndex, CreateTable,
+    CreateTableOptions, Cte, Delete, DoUpdate, ExceptSelectItem, ExcludeSelectItem, Expr,
+    ExprWithAlias, Fetch, FromTable, Function, FunctionArg, FunctionArgExpr,
+    FunctionArgumentClause, FunctionArgumentList, FunctionArguments, GroupByExpr, HavingBound,
+    IfStatement, IlikeSelectItem, IndexColumn, Insert, Interpolate, InterpolateExpr, Join,
+    JoinConstraint, JoinOperator, JsonPath, JsonPathElem, LateralView, LimitClause,
+    MatchRecognizePattern, Measure, NamedParenthesizedList, NamedWindowDefinition, ObjectName,
+    ObjectNamePart, Offset, OnConflict, OnConflictAction, OnInsert, OpenStatement, OrderBy,
+    OrderByExpr, OrderByKind, Partition, PivotValueSource, ProjectionSelect, Query, RaiseStatement,
+    RaiseStatementValue, ReferentialAction, RenameSelectItem, ReplaceSelectElement,
+    ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SqlOption, Statement, Subscript,
+    SymbolDefinition, TableAlias, TableAliasColumnDef, TableConstraint, TableFactor, TableObject,
+    TableOptionsClustered, TableWithJoins, Update, UpdateTableFromKind, Use, Value, Values,
+    ViewColumnDef, WhileStatement, WildcardAdditionalOptions, With, WithFill,
 };
 
 /// Given an iterator of spans, return the [Span::union] of all spans.
@@ -298,38 +298,9 @@ impl Spanned for Values {
 impl Spanned for Statement {
     fn span(&self) -> Span {
         match self {
-            Statement::Analyze {
-                table_name,
-                partitions,
-                for_columns: _,
-                columns,
-                cache_metadata: _,
-                noscan: _,
-                compute_statistics: _,
-                has_table_keyword: _,
-            } => union_spans(
-                core::iter::once(table_name.span())
-                    .chain(partitions.iter().flat_map(|i| i.iter().map(|k| k.span())))
-                    .chain(columns.iter().map(|i| i.span)),
-            ),
-            Statement::Truncate {
-                table_names,
-                partitions,
-                table: _,
-                identity: _,
-                cascade: _,
-                on_cluster: _,
-            } => union_spans(
-                table_names
-                    .iter()
-                    .map(|i| i.name.span())
-                    .chain(partitions.iter().flat_map(|i| i.iter().map(|k| k.span()))),
-            ),
-            Statement::Msck {
-                table_name,
-                repair: _,
-                partition_action: _,
-            } => table_name.span(),
+            Statement::Analyze(analyze) => analyze.span(),
+            Statement::Truncate(truncate) => truncate.span(),
+            Statement::Msck(msck) => msck.span(),
             Statement::Query(query) => query.span(),
             Statement::Insert(insert) => insert.span(),
             Statement::Install { extension_name } => extension_name.span,
@@ -375,47 +346,9 @@ impl Spanned for Statement {
                 CloseCursor::All => Span::empty(),
                 CloseCursor::Specific { name } => name.span,
             },
-            Statement::Update {
-                table,
-                assignments,
-                from,
-                selection,
-                returning,
-                or: _,
-                limit: _,
-            } => union_spans(
-                core::iter::once(table.span())
-                    .chain(assignments.iter().map(|i| i.span()))
-                    .chain(from.iter().map(|i| i.span()))
-                    .chain(selection.iter().map(|i| i.span()))
-                    .chain(returning.iter().flat_map(|i| i.iter().map(|k| k.span()))),
-            ),
+            Statement::Update(update) => update.span(),
             Statement::Delete(delete) => delete.span(),
-            Statement::CreateView {
-                or_alter: _,
-                or_replace: _,
-                materialized: _,
-                secure: _,
-                name,
-                columns,
-                query,
-                options,
-                cluster_by,
-                comment: _,
-                with_no_schema_binding: _,
-                if_not_exists: _,
-                temporary: _,
-                to,
-                name_before_not_exists: _,
-                params: _,
-            } => union_spans(
-                core::iter::once(name.span())
-                    .chain(columns.iter().map(|i| i.span()))
-                    .chain(core::iter::once(query.span()))
-                    .chain(core::iter::once(options.span()))
-                    .chain(cluster_by.iter().map(|i| i.span))
-                    .chain(to.iter().map(|i| i.span())),
-            ),
+            Statement::CreateView(create_view) => create_view.span(),
             Statement::CreateTable(create_table) => create_table.span(),
             Statement::CreateVirtualTable {
                 name,
@@ -428,25 +361,13 @@ impl Spanned for Statement {
                     .chain(module_args.iter().map(|i| i.span)),
             ),
             Statement::CreateIndex(create_index) => create_index.span(),
-            Statement::CreateRole { .. } => Span::empty(),
+            Statement::CreateRole(create_role) => create_role.span(),
+            Statement::CreateExtension(create_extension) => create_extension.span(),
+            Statement::DropExtension(drop_extension) => drop_extension.span(),
             Statement::CreateSecret { .. } => Span::empty(),
             Statement::CreateServer { .. } => Span::empty(),
             Statement::CreateConnector { .. } => Span::empty(),
-            Statement::AlterTable {
-                name,
-                if_exists: _,
-                only: _,
-                operations,
-                location: _,
-                on_cluster,
-                iceberg: _,
-                end_token,
-            } => union_spans(
-                core::iter::once(name.span())
-                    .chain(operations.iter().map(|i| i.span()))
-                    .chain(on_cluster.iter().map(|i| i.span))
-                    .chain(core::iter::once(end_token.0.span)),
-            ),
+            Statement::AlterTable(alter_table) => alter_table.span(),
             Statement::AlterIndex { name, operation } => name.span().union(&operation.span()),
             Statement::AlterView {
                 name,
@@ -467,13 +388,11 @@ impl Spanned for Statement {
             Statement::AttachDuckDBDatabase { .. } => Span::empty(),
             Statement::DetachDuckDBDatabase { .. } => Span::empty(),
             Statement::Drop { .. } => Span::empty(),
-            Statement::DropFunction { .. } => Span::empty(),
+            Statement::DropFunction(drop_function) => drop_function.span(),
             Statement::DropDomain { .. } => Span::empty(),
             Statement::DropProcedure { .. } => Span::empty(),
             Statement::DropSecret { .. } => Span::empty(),
             Statement::Declare { .. } => Span::empty(),
-            Statement::CreateExtension { .. } => Span::empty(),
-            Statement::DropExtension { .. } => Span::empty(),
             Statement::Fetch { .. } => Span::empty(),
             Statement::Flush { .. } => Span::empty(),
             Statement::Discard { .. } => Span::empty(),
@@ -873,6 +792,20 @@ impl Spanned for ConstraintCharacteristics {
     }
 }
 
+impl Spanned for Analyze {
+    fn span(&self) -> Span {
+        union_spans(
+            core::iter::once(self.table_name.span())
+                .chain(
+                    self.partitions
+                        .iter()
+                        .flat_map(|i| i.iter().map(|k| k.span())),
+                )
+                .chain(self.columns.iter().map(|i| i.span)),
+        )
+    }
+}
+
 /// # partial span
 ///
 /// Missing spans:
@@ -941,6 +874,29 @@ impl Spanned for Delete {
     }
 }
 
+impl Spanned for Update {
+    fn span(&self) -> Span {
+        let Update {
+            table,
+            assignments,
+            from,
+            selection,
+            returning,
+            or: _,
+            limit,
+        } = self;
+
+        union_spans(
+            core::iter::once(table.span())
+                .chain(assignments.iter().map(|i| i.span()))
+                .chain(from.iter().map(|i| i.span()))
+                .chain(selection.iter().map(|i| i.span()))
+                .chain(returning.iter().flat_map(|i| i.iter().map(|k| k.span())))
+                .chain(limit.iter().map(|i| i.span())),
+        )
+    }
+}
+
 impl Spanned for FromTable {
     fn span(&self) -> Span {
         match self {
@@ -2375,6 +2331,30 @@ impl Spanned for AlterSchema {
     }
 }
 
+impl Spanned for CreateView {
+    fn span(&self) -> Span {
+        union_spans(
+            core::iter::once(self.name.span())
+                .chain(self.columns.iter().map(|i| i.span()))
+                .chain(core::iter::once(self.query.span()))
+                .chain(core::iter::once(self.options.span()))
+                .chain(self.cluster_by.iter().map(|i| i.span))
+                .chain(self.to.iter().map(|i| i.span())),
+        )
+    }
+}
+
+impl Spanned for AlterTable {
+    fn span(&self) -> Span {
+        union_spans(
+            core::iter::once(self.name.span())
+                .chain(self.operations.iter().map(|i| i.span()))
+                .chain(self.on_cluster.iter().map(|i| i.span))
+                .chain(core::iter::once(self.end_token.0.span)),
+        )
+    }
+}
+
 #[cfg(test)]
 pub mod tests {
     use crate::dialect::{Dialect, GenericDialect, SnowflakeDialect};
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index d1e9b1e7..2b365e29 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -982,11 +982,12 @@ impl<'a> Parser<'a> {
                 Ok(pa)
             })?
             .unwrap_or_default();
-        Ok(Statement::Msck {
+        Ok(Msck {
             repair,
             table_name,
             partition_action,
-        })
+        }
+        .into())
     }
 
     pub fn parse_truncate(&mut self) -> Result<Statement, ParserError> {
@@ -1024,14 +1025,15 @@ impl<'a> Parser<'a> {
 
         let on_cluster = self.parse_optional_on_cluster()?;
 
-        Ok(Statement::Truncate {
+        Ok(Truncate {
             table_names,
             partitions,
             table,
             identity,
             cascade,
             on_cluster,
-        })
+        }
+        .into())
     }
 
     fn parse_cascade_option(&mut self) -> Option<CascadeOption> {
@@ -1167,7 +1169,7 @@ impl<'a> Parser<'a> {
             }
         }
 
-        Ok(Statement::Analyze {
+        Ok(Analyze {
             has_table_keyword,
             table_name,
             for_columns,
@@ -1176,7 +1178,8 @@ impl<'a> Parser<'a> {
             cache_metadata,
             noscan,
             compute_statistics,
-        })
+        }
+        .into())
     }
 
     /// Parse a new expression including wildcard & qualified wildcard.
@@ -5926,7 +5929,7 @@ impl<'a> Parser<'a> {
                 Keyword::BINDING,
             ]);
 
-        Ok(Statement::CreateView {
+        Ok(CreateView {
             or_alter,
             name,
             columns,
@@ -5943,7 +5946,8 @@ impl<'a> Parser<'a> {
             to,
             params: create_view_params,
             name_before_not_exists,
-        })
+        }
+        .into())
     }
 
     /// Parse optional parameters for the `CREATE VIEW` statement supported by [MySQL].
@@ -6206,7 +6210,7 @@ impl<'a> Parser<'a> {
             }?
         }
 
-        Ok(Statement::CreateRole {
+        Ok(CreateRole {
             names,
             if_not_exists,
             login,
@@ -6225,7 +6229,8 @@ impl<'a> Parser<'a> {
             user,
             admin,
             authorization_owner,
-        })
+        }
+        .into())
     }
 
     pub fn parse_owner(&mut self) -> Result<Owner, ParserError> {
@@ -6503,11 +6508,11 @@ impl<'a> Parser<'a> {
         let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
         let func_desc = self.parse_comma_separated(Parser::parse_function_desc)?;
         let drop_behavior = self.parse_optional_drop_behavior();
-        Ok(Statement::DropFunction {
+        Ok(Statement::DropFunction(DropFunction {
             if_exists,
             func_desc,
             drop_behavior,
-        })
+        }))
     }
 
     /// ```sql
@@ -7175,13 +7180,14 @@ impl<'a> Parser<'a> {
             (None, None, false)
         };
 
-        Ok(Statement::CreateExtension {
+        Ok(CreateExtension {
             name,
             if_not_exists,
             schema,
             version,
             cascade,
-        })
+        }
+        .into())
     }
 
     /// Parse a PostgreSQL-specific [Statement::DropExtension] statement.
@@ -7190,7 +7196,7 @@ impl<'a> Parser<'a> {
         let names = self.parse_comma_separated(|p| p.parse_identifier())?;
         let cascade_or_restrict =
             self.parse_one_of_keywords(&[Keyword::CASCADE, Keyword::RESTRICT]);
-        Ok(Statement::DropExtension {
+        Ok(Statement::DropExtension(DropExtension {
             names,
             if_exists,
             cascade_or_restrict: cascade_or_restrict
@@ -7200,7 +7206,7 @@ impl<'a> Parser<'a> {
                     _ => self.expected("CASCADE or RESTRICT", self.peek_token()),
                 })
                 .transpose()?,
-        })
+        }))
     }
 
     //TODO: Implement parsing for Skewed
@@ -9378,7 +9384,7 @@ impl<'a> Parser<'a> {
             self.get_current_token().clone()
         };
 
-        Ok(Statement::AlterTable {
+        Ok(AlterTable {
             name: table_name,
             if_exists,
             only,
@@ -9387,7 +9393,8 @@ impl<'a> Parser<'a> {
             on_cluster,
             iceberg,
             end_token: AttachedToken(end_token),
-        })
+        }
+        .into())
     }
 
     pub fn parse_alter_view(&mut self) -> Result<Statement, ParserError> {
@@ -15662,7 +15669,7 @@ impl<'a> Parser<'a> {
         } else {
             None
         };
-        Ok(Statement::Update {
+        Ok(Update {
             table,
             assignments,
             from,
@@ -15670,7 +15677,8 @@ impl<'a> Parser<'a> {
             returning,
             or,
             limit,
-        })
+        }
+        .into())
     }
 
     /// Parse a `var = expr` assignment, used in an UPDATE statement
diff --git a/src/test_utils.rs b/src/test_utils.rs
index 03fdee8a..a8c8afd5 100644
--- a/src/test_utils.rs
+++ b/src/test_utils.rs
@@ -343,21 +343,12 @@ pub fn expr_from_projection(item: &SelectItem) -> &Expr {
 
 pub fn alter_table_op_with_name(stmt: Statement, expected_name: &str) -> AlterTableOperation {
     match stmt {
-        Statement::AlterTable {
-            name,
-            if_exists,
-            only: is_only,
-            operations,
-            on_cluster: _,
-            location: _,
-            iceberg,
-            end_token: _,
-        } => {
-            assert_eq!(name.to_string(), expected_name);
-            assert!(!if_exists);
-            assert!(!is_only);
-            assert!(!iceberg);
-            only(operations)
+        Statement::AlterTable(alter_table) => {
+            assert_eq!(alter_table.name.to_string(), expected_name);
+            assert!(!alter_table.if_exists);
+            assert!(!alter_table.only);
+            assert!(!alter_table.iceberg);
+            only(alter_table.operations)
         }
         _ => panic!("Expected ALTER TABLE statement"),
     }
@@ -484,7 +475,7 @@ pub fn index_column(stmt: Statement) -> Expr {
                 _ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
             }
         }
-        Statement::AlterTable { operations, .. } => match operations.first().unwrap() {
+        Statement::AlterTable(alter_table) => match alter_table.operations.first().unwrap() {
             AlterTableOperation::AddConstraint { constraint, .. } => {
                 match constraint {
                     TableConstraint::Index(constraint) => {
diff --git a/tests/sqlparser_bigquery.rs b/tests/sqlparser_bigquery.rs
index 4f0cfa3e..03a0ac81 100644
--- a/tests/sqlparser_bigquery.rs
+++ b/tests/sqlparser_bigquery.rs
@@ -332,13 +332,13 @@ fn parse_create_view_with_options() {
         "AS SELECT column_1, column_2, column_3 FROM myproject.mydataset.mytable",
     );
     match bigquery().verified_stmt(sql) {
-        Statement::CreateView {
+        Statement::CreateView(CreateView {
             name,
             query,
             options,
             columns,
             ..
-        } => {
+        }) => {
             assert_eq!(
                 name,
                 ObjectName::from(vec![
@@ -401,7 +401,7 @@ fn parse_create_view_with_options() {
 fn parse_create_view_if_not_exists() {
     let sql = "CREATE VIEW IF NOT EXISTS mydataset.newview AS SELECT foo FROM bar";
     match bigquery().verified_stmt(sql) {
-        Statement::CreateView {
+        Statement::CreateView(CreateView {
             name,
             columns,
             query,
@@ -414,7 +414,7 @@ fn parse_create_view_if_not_exists() {
             if_not_exists,
             temporary,
             ..
-        } => {
+        }) => {
             assert_eq!("mydataset.newview", name.to_string());
             assert_eq!(Vec::<ViewColumnDef>::new(), columns);
             assert_eq!("SELECT foo FROM bar", query.to_string());
@@ -435,12 +435,12 @@ fn parse_create_view_if_not_exists() {
 fn parse_create_view_with_unquoted_hyphen() {
     let sql = "CREATE VIEW IF NOT EXISTS my-pro-ject.mydataset.myview AS SELECT 1";
     match bigquery().verified_stmt(sql) {
-        Statement::CreateView {
+        Statement::CreateView(CreateView {
             name,
             query,
             if_not_exists,
             ..
-        } => {
+        }) => {
             assert_eq!("my-pro-ject.mydataset.myview", name.to_string());
             assert_eq!("SELECT 1", query.to_string());
             assert!(if_not_exists);
diff --git a/tests/sqlparser_clickhouse.rs b/tests/sqlparser_clickhouse.rs
index bc1431f9..44bfcda4 100644
--- a/tests/sqlparser_clickhouse.rs
+++ b/tests/sqlparser_clickhouse.rs
@@ -243,12 +243,10 @@ fn parse_alter_table_attach_and_detach_partition() {
         match clickhouse_and_generic()
             .verified_stmt(format!("ALTER TABLE t0 {operation} PARTITION part").as_str())
         {
-            Statement::AlterTable {
-                name, operations, ..
-            } => {
-                pretty_assertions::assert_eq!("t0", name.to_string());
+            Statement::AlterTable(alter_table) => {
+                pretty_assertions::assert_eq!("t0", alter_table.name.to_string());
                 pretty_assertions::assert_eq!(
-                    operations[0],
+                    alter_table.operations[0],
                     if operation == &"ATTACH" {
                         AlterTableOperation::AttachPartition {
                             partition: Partition::Expr(Identifier(Ident::new("part"))),
@@ -266,9 +264,9 @@ fn parse_alter_table_attach_and_detach_partition() {
         match clickhouse_and_generic()
             .verified_stmt(format!("ALTER TABLE t1 {operation} PART part").as_str())
         {
-            Statement::AlterTable {
+            Statement::AlterTable(AlterTable {
                 name, operations, ..
-            } => {
+            }) => {
                 pretty_assertions::assert_eq!("t1", name.to_string());
                 pretty_assertions::assert_eq!(
                     operations[0],
@@ -308,9 +306,9 @@ fn parse_alter_table_add_projection() {
         "ALTER TABLE t0 ADD PROJECTION IF NOT EXISTS my_name",
         " (SELECT a, b GROUP BY a ORDER BY b)",
     )) {
-        Statement::AlterTable {
+        Statement::AlterTable(AlterTable {
             name, operations, ..
-        } => {
+        }) => {
             assert_eq!(name, ObjectName::from(vec!["t0".into()]));
             assert_eq!(1, operations.len());
             assert_eq!(
@@ -380,9 +378,9 @@ fn parse_alter_table_add_projection() {
 fn parse_alter_table_drop_projection() {
     match clickhouse_and_generic().verified_stmt("ALTER TABLE t0 DROP PROJECTION IF EXISTS my_name")
     {
-        Statement::AlterTable {
+        Statement::AlterTable(AlterTable {
             name, operations, ..
-        } => {
+        }) => {
             assert_eq!(name, ObjectName::from(vec!["t0".into()]));
             assert_eq!(1, operations.len());
             assert_eq!(
@@ -413,9 +411,9 @@ fn parse_alter_table_clear_and_materialize_projection() {
             format!("ALTER TABLE t0 {keyword} PROJECTION IF EXISTS my_name IN PARTITION p0",)
                 .as_str(),
         ) {
-            Statement::AlterTable {
+            Statement::AlterTable(AlterTable {
                 name, operations, ..
-            } => {
+            }) => {
                 assert_eq!(name, ObjectName::from(vec!["t0".into()]));
                 assert_eq!(1, operations.len());
                 assert_eq!(
@@ -904,7 +902,7 @@ fn parse_create_table_with_variant_default_expressions() {
 #[test]
 fn parse_create_view_with_fields_data_types() {
     match clickhouse().verified_stmt(r#"CREATE VIEW v (i "int", f "String") AS SELECT * FROM t"#) {
-        Statement::CreateView { name, columns, .. } => {
+        Statement::CreateView(CreateView { name, columns, .. }) => {
             assert_eq!(name, ObjectName::from(vec!["v".into()]));
             assert_eq!(
                 columns,
@@ -1518,7 +1516,7 @@ fn parse_freeze_and_unfreeze_partition() {
             Value::SingleQuotedString("2024-08-14".to_string()).with_empty_span(),
         ));
         match clickhouse_and_generic().verified_stmt(&sql) {
-            Statement::AlterTable { operations, .. } => {
+            Statement::AlterTable(AlterTable { operations, .. }) => {
                 assert_eq!(operations.len(), 1);
                 let expected_operation = if operation_name == &"FREEZE" {
                     AlterTableOperation::FreezePartition {
@@ -1542,7 +1540,7 @@ fn parse_freeze_and_unfreeze_partition() {
         let sql =
             format!("ALTER TABLE t {operation_name} PARTITION '2024-08-14' WITH NAME 'hello'");
         match clickhouse_and_generic().verified_stmt(&sql) {
-            Statement::AlterTable { operations, .. } => {
+            Statement::AlterTable(AlterTable { operations, .. }) => {
                 assert_eq!(operations.len(), 1);
                 let expected_partition = Partition::Expr(Expr::Value(
                     Value::SingleQuotedString("2024-08-14".to_string()).with_empty_span(),
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index a1fd48d3..773937c5 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -377,12 +377,12 @@ fn parse_insert_sqlite() {
 fn parse_update() {
     let sql = "UPDATE t SET a = 1, b = 2, c = 3 WHERE d";
     match verified_stmt(sql) {
-        Statement::Update {
+        Statement::Update(Update {
             table,
             assignments,
             selection,
             ..
-        } => {
+        }) => {
             assert_eq!(table.to_string(), "t".to_string());
             assert_eq!(
                 assignments,
@@ -439,7 +439,7 @@ fn parse_update_set_from() {
     let stmt = dialects.verified_stmt(sql);
     assert_eq!(
         stmt,
-        Statement::Update {
+        Statement::Update(Update {
             table: TableWithJoins {
                 relation: table_from_name(ObjectName::from(vec![Ident::new("t1")])),
                 joins: vec![],
@@ -516,7 +516,7 @@ fn parse_update_set_from() {
             returning: None,
             or: None,
             limit: None
-        }
+        })
     );
 
     let sql = "UPDATE T SET a = b FROM U, (SELECT foo FROM V) AS W WHERE 1 = 1";
@@ -527,7 +527,7 @@ fn parse_update_set_from() {
 fn parse_update_with_table_alias() {
     let sql = "UPDATE users AS u SET u.username = 'new_user' WHERE u.username = 'old_user'";
     match verified_stmt(sql) {
-        Statement::Update {
+        Statement::Update(Update {
             table,
             assignments,
             from: _from,
@@ -535,7 +535,7 @@ fn parse_update_with_table_alias() {
             returning,
             or: None,
             limit: None,
-        } => {
+        }) => {
             assert_eq!(
                 TableWithJoins {
                     relation: TableFactor::Table {
@@ -591,7 +591,7 @@ fn parse_update_with_table_alias() {
 #[test]
 fn parse_update_or() {
     let expect_or_clause = |sql: &str, expected_action: SqliteOnConflict| match verified_stmt(sql) {
-        Statement::Update { or, .. } => assert_eq!(or, Some(expected_action)),
+        Statement::Update(Update { or, .. }) => assert_eq!(or, Some(expected_action)),
         other => unreachable!("Expected update with or, got {:?}", other),
     };
     expect_or_clause(
@@ -4846,9 +4846,9 @@ fn test_alter_table_with_on_cluster() {
     match all_dialects()
         .verified_stmt("ALTER TABLE t ON CLUSTER 'cluster' ADD CONSTRAINT bar PRIMARY KEY (baz)")
     {
-        Statement::AlterTable {
+        Statement::AlterTable(AlterTable {
             name, on_cluster, ..
-        } => {
+        }) => {
             assert_eq!(name.to_string(), "t");
             assert_eq!(on_cluster, Some(Ident::with_quote('\'', "cluster")));
         }
@@ -4858,9 +4858,9 @@ fn test_alter_table_with_on_cluster() {
     match all_dialects()
         .verified_stmt("ALTER TABLE t ON CLUSTER cluster_name ADD CONSTRAINT bar PRIMARY KEY (baz)")
     {
-        Statement::AlterTable {
+        Statement::AlterTable(AlterTable {
             name, on_cluster, ..
-        } => {
+        }) => {
             assert_eq!(name.to_string(), "t");
             assert_eq!(on_cluster, Some(Ident::new("cluster_name")));
         }
@@ -7615,7 +7615,7 @@ fn parse_ctes() {
     // CTE in a view
     let sql = &format!("CREATE VIEW v AS {with}");
     match verified_stmt(sql) {
-        Statement::CreateView { query, .. } => assert_ctes_in_select(&cte_sqls, &query),
+        Statement::CreateView(create_view) => assert_ctes_in_select(&cte_sqls, &create_view.query),
         _ => panic!("Expected: CREATE VIEW"),
     }
     // CTE in a CTE...
@@ -8103,7 +8103,7 @@ fn parse_drop_database_if_exists() {
 fn parse_create_view() {
     let sql = "CREATE VIEW myschema.myview AS SELECT foo FROM bar";
     match verified_stmt(sql) {
-        Statement::CreateView {
+        Statement::CreateView(CreateView {
             or_alter,
             name,
             columns,
@@ -8120,7 +8120,7 @@ fn parse_create_view() {
             params,
             name_before_not_exists: _,
             secure: _,
-        } => {
+        }) => {
             assert_eq!(or_alter, false);
             assert_eq!("myschema.myview", name.to_string());
             assert_eq!(Vec::<ViewColumnDef>::new(), columns);
@@ -8146,7 +8146,7 @@ fn parse_create_view() {
 fn parse_create_view_with_options() {
     let sql = "CREATE VIEW v WITH (foo = 'bar', a = 123) AS SELECT 1";
     match verified_stmt(sql) {
-        Statement::CreateView { options, .. } => {
+        Statement::CreateView(create_view) => {
             assert_eq!(
                 CreateTableOptions::With(vec![
                     SqlOption::KeyValue {
@@ -8160,7 +8160,7 @@ fn parse_create_view_with_options() {
                         value: Expr::value(number("123")),
                     },
                 ]),
-                options
+                create_view.options
             );
         }
         _ => unreachable!(),
@@ -8173,24 +8173,21 @@ fn parse_create_view_with_columns() {
     // TODO: why does this fail for ClickHouseDialect? (#1449)
     // match all_dialects().verified_stmt(sql) {
     match all_dialects_except(|d| d.is::<ClickHouseDialect>()).verified_stmt(sql) {
-        Statement::CreateView {
-            or_alter,
-            name,
-            columns,
-            or_replace,
-            options,
-            query,
-            materialized,
-            cluster_by,
-            comment,
-            with_no_schema_binding: late_binding,
-            if_not_exists,
-            temporary,
-            to,
-            params,
-            name_before_not_exists: _,
-            secure: _,
-        } => {
+        Statement::CreateView(create_view) => {
+            let or_alter = create_view.or_alter;
+            let name = create_view.name;
+            let columns = create_view.columns;
+            let or_replace = create_view.or_replace;
+            let options = create_view.options;
+            let query = create_view.query;
+            let materialized = create_view.materialized;
+            let cluster_by = create_view.cluster_by;
+            let comment = create_view.comment;
+            let late_binding = create_view.with_no_schema_binding;
+            let if_not_exists = create_view.if_not_exists;
+            let temporary = create_view.temporary;
+            let to = create_view.to;
+            let params = create_view.params;
             assert_eq!(or_alter, false);
             assert_eq!("v", name.to_string());
             assert_eq!(
@@ -8224,7 +8221,7 @@ fn parse_create_view_with_columns() {
 fn parse_create_view_temporary() {
     let sql = "CREATE TEMPORARY VIEW myschema.myview AS SELECT foo FROM bar";
     match verified_stmt(sql) {
-        Statement::CreateView {
+        Statement::CreateView(CreateView {
             or_alter,
             name,
             columns,
@@ -8241,7 +8238,7 @@ fn parse_create_view_temporary() {
             params,
             name_before_not_exists: _,
             secure: _,
-        } => {
+        }) => {
             assert_eq!(or_alter, false);
             assert_eq!("myschema.myview", name.to_string());
             assert_eq!(Vec::<ViewColumnDef>::new(), columns);
@@ -8265,7 +8262,7 @@ fn parse_create_view_temporary() {
 fn parse_create_or_replace_view() {
     let sql = "CREATE OR REPLACE VIEW v AS SELECT 1";
     match verified_stmt(sql) {
-        Statement::CreateView {
+        Statement::CreateView(CreateView {
             or_alter,
             name,
             columns,
@@ -8282,7 +8279,7 @@ fn parse_create_or_replace_view() {
             params,
             name_before_not_exists: _,
             secure: _,
-        } => {
+        }) => {
             assert_eq!(or_alter, false);
             assert_eq!("v", name.to_string());
             assert_eq!(columns, vec![]);
@@ -8310,7 +8307,7 @@ fn parse_create_or_replace_materialized_view() {
     // https://docs.snowflake.com/en/sql-reference/sql/create-materialized-view.html
     let sql = "CREATE OR REPLACE MATERIALIZED VIEW v AS SELECT 1";
     match verified_stmt(sql) {
-        Statement::CreateView {
+        Statement::CreateView(CreateView {
             or_alter,
             name,
             columns,
@@ -8327,7 +8324,7 @@ fn parse_create_or_replace_materialized_view() {
             params,
             name_before_not_exists: _,
             secure: _,
-        } => {
+        }) => {
             assert_eq!(or_alter, false);
             assert_eq!("v", name.to_string());
             assert_eq!(columns, vec![]);
@@ -8351,7 +8348,7 @@ fn parse_create_or_replace_materialized_view() {
 fn parse_create_materialized_view() {
     let sql = "CREATE MATERIALIZED VIEW myschema.myview AS SELECT foo FROM bar";
     match verified_stmt(sql) {
-        Statement::CreateView {
+        Statement::CreateView(CreateView {
             or_alter,
             name,
             or_replace,
@@ -8368,7 +8365,7 @@ fn parse_create_materialized_view() {
             params,
             name_before_not_exists: _,
             secure: _,
-        } => {
+        }) => {
             assert_eq!(or_alter, false);
             assert_eq!("myschema.myview", name.to_string());
             assert_eq!(Vec::<ViewColumnDef>::new(), columns);
@@ -8392,7 +8389,7 @@ fn parse_create_materialized_view() {
 fn parse_create_materialized_view_with_cluster_by() {
     let sql = "CREATE MATERIALIZED VIEW myschema.myview CLUSTER BY (foo) AS SELECT foo FROM bar";
     match verified_stmt(sql) {
-        Statement::CreateView {
+        Statement::CreateView(CreateView {
             or_alter,
             name,
             or_replace,
@@ -8409,7 +8406,7 @@ fn parse_create_materialized_view_with_cluster_by() {
             params,
             name_before_not_exists: _,
             secure: _,
-        } => {
+        }) => {
             assert_eq!(or_alter, false);
             assert_eq!("myschema.myview", name.to_string());
             assert_eq!(Vec::<ViewColumnDef>::new(), columns);
@@ -9417,21 +9414,17 @@ fn parse_drop_index() {
 fn parse_create_role() {
     let sql = "CREATE ROLE consultant";
     match verified_stmt(sql) {
-        Statement::CreateRole { names, .. } => {
-            assert_eq_vec(&["consultant"], &names);
+        Statement::CreateRole(create_role) => {
+            assert_eq_vec(&["consultant"], &create_role.names);
         }
         _ => unreachable!(),
     }
 
     let sql = "CREATE ROLE IF NOT EXISTS mysql_a, mysql_b";
     match verified_stmt(sql) {
-        Statement::CreateRole {
-            names,
-            if_not_exists,
-            ..
-        } => {
-            assert_eq_vec(&["mysql_a", "mysql_b"], &names);
-            assert!(if_not_exists);
+        Statement::CreateRole(create_role) => {
+            assert_eq_vec(&["mysql_a", "mysql_b"], &create_role.names);
+            assert!(create_role.if_not_exists);
         }
         _ => unreachable!(),
     }
@@ -13351,8 +13344,8 @@ fn test_extract_seconds_single_quote_err() {
 fn test_truncate_table_with_on_cluster() {
     let sql = "TRUNCATE TABLE t ON CLUSTER cluster_name";
     match all_dialects().verified_stmt(sql) {
-        Statement::Truncate { on_cluster, .. } => {
-            assert_eq!(on_cluster, Some(Ident::new("cluster_name")));
+        Statement::Truncate(truncate) => {
+            assert_eq!(truncate.on_cluster, Some(Ident::new("cluster_name")));
         }
         _ => panic!("Expected: TRUNCATE TABLE statement"),
     }
@@ -16407,14 +16400,14 @@ fn parse_truncate_only() {
     ];
 
     assert_eq!(
-        Statement::Truncate {
+        Statement::Truncate(Truncate {
             table_names,
             partitions: None,
             table: true,
             identity: None,
             cascade: None,
             on_cluster: None,
-        },
+        }),
         truncate
     );
 }
@@ -17288,9 +17281,9 @@ fn parse_invisible_column() {
     let sql = r#"ALTER TABLE t ADD COLUMN bar INT INVISIBLE"#;
     let stmt = verified_stmt(sql);
     match stmt {
-        Statement::AlterTable { operations, .. } => {
+        Statement::AlterTable(alter_table) => {
             assert_eq!(
-                operations,
+                alter_table.operations,
                 vec![AlterTableOperation::AddColumn {
                     column_keyword: true,
                     if_not_exists: false,
diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs
index 18189917..9dccce49 100644
--- a/tests/sqlparser_mssql.rs
+++ b/tests/sqlparser_mssql.rs
@@ -778,14 +778,10 @@ fn parse_mssql_bin_literal() {
 fn parse_mssql_create_role() {
     let sql = "CREATE ROLE mssql AUTHORIZATION helena";
     match ms().verified_stmt(sql) {
-        Statement::CreateRole {
-            names,
-            authorization_owner,
-            ..
-        } => {
-            assert_eq_vec(&["mssql"], &names);
+        Statement::CreateRole(create_role) => {
+            assert_eq_vec(&["mssql"], &create_role.names);
             assert_eq!(
-                authorization_owner,
+                create_role.authorization_owner,
                 Some(ObjectName::from(vec![Ident {
                     value: "helena".into(),
                     quote_style: None,
diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs
index 35bac548..9aaa35ba 100644
--- a/tests/sqlparser_mysql.rs
+++ b/tests/sqlparser_mysql.rs
@@ -2603,7 +2603,7 @@ fn parse_insert_with_numeric_prefix_column_name() {
 fn parse_update_with_joins() {
     let sql = "UPDATE orders AS o JOIN customers AS c ON o.customer_id = c.id SET o.completed = true WHERE c.firstname = 'Peter'";
     match mysql().verified_stmt(sql) {
-        Statement::Update {
+        Statement::Update(Update {
             table,
             assignments,
             from: _from,
@@ -2611,7 +2611,7 @@ fn parse_update_with_joins() {
             returning,
             or: None,
             limit: None,
-        } => {
+        }) => {
             assert_eq!(
                 TableWithJoins {
                     relation: TableFactor::Table {
@@ -2729,7 +2729,7 @@ fn parse_delete_with_limit() {
 #[test]
 fn parse_alter_table_add_column() {
     match mysql().verified_stmt("ALTER TABLE tab ADD COLUMN b INT FIRST") {
-        Statement::AlterTable {
+        Statement::AlterTable(AlterTable {
             name,
             if_exists,
             only,
@@ -2738,7 +2738,7 @@ fn parse_alter_table_add_column() {
             location: _,
             on_cluster: _,
             end_token: _,
-        } => {
+        }) => {
             assert_eq!(name.to_string(), "tab");
             assert!(!if_exists);
             assert!(!iceberg);
@@ -2761,13 +2761,13 @@ fn parse_alter_table_add_column() {
     }
 
     match mysql().verified_stmt("ALTER TABLE tab ADD COLUMN b INT AFTER foo") {
-        Statement::AlterTable {
+        Statement::AlterTable(AlterTable {
             name,
             if_exists,
             only,
             operations,
             ..
-        } => {
+        }) => {
             assert_eq!(name.to_string(), "tab");
             assert!(!if_exists);
             assert!(!only);
@@ -2798,13 +2798,13 @@ fn parse_alter_table_add_columns() {
     match mysql()
         .verified_stmt("ALTER TABLE tab ADD COLUMN a TEXT FIRST, ADD COLUMN b INT AFTER foo")
     {
-        Statement::AlterTable {
+        Statement::AlterTable(AlterTable {
             name,
             if_exists,
             only,
             operations,
             ..
-        } => {
+        }) => {
             assert_eq!(name.to_string(), "tab");
             assert!(!if_exists);
             assert!(!only);
@@ -3026,7 +3026,7 @@ fn parse_alter_table_with_algorithm() {
         "ALTER TABLE users DROP COLUMN password_digest, ALGORITHM = COPY, RENAME COLUMN name TO username";
     let stmt = mysql_and_generic().verified_stmt(sql);
     match stmt {
-        Statement::AlterTable { operations, .. } => {
+        Statement::AlterTable(AlterTable { operations, .. }) => {
             assert_eq!(
                 operations,
                 vec![
@@ -3074,7 +3074,7 @@ fn parse_alter_table_with_lock() {
         "ALTER TABLE users DROP COLUMN password_digest, LOCK = EXCLUSIVE, RENAME COLUMN name TO username";
     let stmt = mysql_and_generic().verified_stmt(sql);
     match stmt {
-        Statement::AlterTable { operations, .. } => {
+        Statement::AlterTable(AlterTable { operations, .. }) => {
             assert_eq!(
                 operations,
                 vec![
@@ -3857,7 +3857,7 @@ fn parse_revoke() {
 fn parse_create_view_algorithm_param() {
     let sql = "CREATE ALGORITHM = MERGE VIEW foo AS SELECT 1";
     let stmt = mysql().verified_stmt(sql);
-    if let Statement::CreateView {
+    if let Statement::CreateView(CreateView {
         params:
             Some(CreateViewParams {
                 algorithm,
@@ -3865,7 +3865,7 @@ fn parse_create_view_algorithm_param() {
                 security,
             }),
         ..
-    } = stmt
+    }) = stmt
     {
         assert_eq!(algorithm, Some(CreateViewAlgorithm::Merge));
         assert!(definer.is_none());
@@ -3881,7 +3881,7 @@ fn parse_create_view_algorithm_param() {
 fn parse_create_view_definer_param() {
     let sql = "CREATE DEFINER = 'jeffrey'@'localhost' VIEW foo AS SELECT 1";
     let stmt = mysql().verified_stmt(sql);
-    if let Statement::CreateView {
+    if let Statement::CreateView(CreateView {
         params:
             Some(CreateViewParams {
                 algorithm,
@@ -3889,7 +3889,7 @@ fn parse_create_view_definer_param() {
                 security,
             }),
         ..
-    } = stmt
+    }) = stmt
     {
         assert!(algorithm.is_none());
         if let Some(GranteeName::UserHost { user, host }) = definer {
@@ -3910,7 +3910,7 @@ fn parse_create_view_definer_param() {
 fn parse_create_view_security_param() {
     let sql = "CREATE SQL SECURITY DEFINER VIEW foo AS SELECT 1";
     let stmt = mysql().verified_stmt(sql);
-    if let Statement::CreateView {
+    if let Statement::CreateView(CreateView {
         params:
             Some(CreateViewParams {
                 algorithm,
@@ -3918,7 +3918,7 @@ fn parse_create_view_security_param() {
                 security,
             }),
         ..
-    } = stmt
+    }) = stmt
     {
         assert!(algorithm.is_none());
         assert!(definer.is_none());
@@ -3933,7 +3933,7 @@ fn parse_create_view_security_param() {
 fn parse_create_view_multiple_params() {
     let sql = "CREATE ALGORITHM = UNDEFINED DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW foo AS SELECT 1";
     let stmt = mysql().verified_stmt(sql);
-    if let Statement::CreateView {
+    if let Statement::CreateView(CreateView {
         params:
             Some(CreateViewParams {
                 algorithm,
@@ -3941,7 +3941,7 @@ fn parse_create_view_multiple_params() {
                 security,
             }),
         ..
-    } = stmt
+    }) = stmt
     {
         assert_eq!(algorithm, Some(CreateViewAlgorithm::Undefined));
         if let Some(GranteeName::UserHost { user, host }) = definer {
@@ -4179,7 +4179,7 @@ fn test_variable_assignment_using_colon_equal() {
     let stmt = mysql().verified_stmt(sql_update);
 
     match stmt {
-        Statement::Update { assignments, .. } => {
+        Statement::Update(Update { assignments, .. }) => {
             assert_eq!(
                 assignments,
                 vec![Assignment {
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index 45ae32da..3c2a98e1 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -605,7 +605,7 @@ fn parse_alter_table_constraints_unique_nulls_distinct() {
     match pg_and_generic()
         .verified_stmt("ALTER TABLE t ADD CONSTRAINT b UNIQUE NULLS NOT DISTINCT (c)")
     {
-        Statement::AlterTable { operations, .. } => match &operations[0] {
+        Statement::AlterTable(alter_table) => match &alter_table.operations[0] {
             AlterTableOperation::AddConstraint {
                 constraint: TableConstraint::Unique(constraint),
                 ..
@@ -674,93 +674,93 @@ fn parse_create_extension() {
 fn parse_drop_extension() {
     assert_eq!(
         pg_and_generic().verified_stmt("DROP EXTENSION extension_name"),
-        Statement::DropExtension {
+        Statement::DropExtension(DropExtension {
             names: vec!["extension_name".into()],
             if_exists: false,
             cascade_or_restrict: None,
-        }
+        })
     );
     assert_eq!(
         pg_and_generic().verified_stmt("DROP EXTENSION extension_name CASCADE"),
-        Statement::DropExtension {
+        Statement::DropExtension(DropExtension {
             names: vec!["extension_name".into()],
             if_exists: false,
             cascade_or_restrict: Some(ReferentialAction::Cascade),
-        }
+        })
     );
 
     assert_eq!(
         pg_and_generic().verified_stmt("DROP EXTENSION extension_name RESTRICT"),
-        Statement::DropExtension {
+        Statement::DropExtension(DropExtension {
             names: vec!["extension_name".into()],
             if_exists: false,
             cascade_or_restrict: Some(ReferentialAction::Restrict),
-        }
+        })
     );
 
     assert_eq!(
         pg_and_generic().verified_stmt("DROP EXTENSION extension_name, extension_name2 CASCADE"),
-        Statement::DropExtension {
+        Statement::DropExtension(DropExtension {
             names: vec!["extension_name".into(), "extension_name2".into()],
             if_exists: false,
             cascade_or_restrict: Some(ReferentialAction::Cascade),
-        }
+        })
     );
 
     assert_eq!(
         pg_and_generic().verified_stmt("DROP EXTENSION extension_name, extension_name2 RESTRICT"),
-        Statement::DropExtension {
+        Statement::DropExtension(DropExtension {
             names: vec!["extension_name".into(), "extension_name2".into()],
             if_exists: false,
             cascade_or_restrict: Some(ReferentialAction::Restrict),
-        }
+        })
     );
 
     assert_eq!(
         pg_and_generic().verified_stmt("DROP EXTENSION IF EXISTS extension_name"),
-        Statement::DropExtension {
+        Statement::DropExtension(DropExtension {
             names: vec!["extension_name".into()],
             if_exists: true,
             cascade_or_restrict: None,
-        }
+        })
     );
 
     assert_eq!(
         pg_and_generic().verified_stmt("DROP EXTENSION IF EXISTS extension_name CASCADE"),
-        Statement::DropExtension {
+        Statement::DropExtension(DropExtension {
             names: vec!["extension_name".into()],
             if_exists: true,
             cascade_or_restrict: Some(ReferentialAction::Cascade),
-        }
+        })
     );
 
     assert_eq!(
         pg_and_generic().verified_stmt("DROP EXTENSION IF EXISTS extension_name RESTRICT"),
-        Statement::DropExtension {
+        Statement::DropExtension(DropExtension {
             names: vec!["extension_name".into()],
             if_exists: true,
             cascade_or_restrict: Some(ReferentialAction::Restrict),
-        }
+        })
     );
 
     assert_eq!(
         pg_and_generic()
             .verified_stmt("DROP EXTENSION IF EXISTS extension_name1, extension_name2 CASCADE"),
-        Statement::DropExtension {
+        Statement::DropExtension(DropExtension {
             names: vec!["extension_name1".into(), "extension_name2".into()],
             if_exists: true,
             cascade_or_restrict: Some(ReferentialAction::Cascade),
-        }
+        })
     );
 
     assert_eq!(
         pg_and_generic()
             .verified_stmt("DROP EXTENSION IF EXISTS extension_name1, extension_name2 RESTRICT"),
-        Statement::DropExtension {
+        Statement::DropExtension(DropExtension {
             names: vec!["extension_name1".into(), "extension_name2".into()],
             if_exists: true,
             cascade_or_restrict: Some(ReferentialAction::Restrict),
-        }
+        })
     );
 }
 
@@ -829,13 +829,13 @@ fn parse_alter_table_alter_column_add_generated() {
 #[test]
 fn parse_alter_table_add_columns() {
     match pg().verified_stmt("ALTER TABLE IF EXISTS ONLY tab ADD COLUMN a TEXT, ADD COLUMN b INT") {
-        Statement::AlterTable {
+        Statement::AlterTable(AlterTable {
             name,
             if_exists,
             only,
             operations,
             ..
-        } => {
+        }) => {
             assert_eq!(name.to_string(), "tab");
             assert!(if_exists);
             assert!(only);
@@ -909,13 +909,13 @@ fn parse_alter_table_owner_to() {
 
     for case in test_cases {
         match pg_and_generic().verified_stmt(case.sql) {
-            Statement::AlterTable {
+            Statement::AlterTable(AlterTable {
                 name,
                 if_exists: _,
                 only: _,
                 operations,
                 ..
-            } => {
+            }) => {
                 assert_eq!(name.to_string(), "tab");
                 assert_eq!(
                     operations,
@@ -2009,7 +2009,7 @@ fn parse_pg_returning() {
              RETURNING temp_lo AS lo, temp_hi AS hi, prcp",
     );
     match stmt {
-        Statement::Update { returning, .. } => {
+        Statement::Update(Update { returning, .. }) => {
             assert_eq!(
                 Some(vec![
                     SelectItem::ExprWithAlias {
@@ -3833,47 +3833,29 @@ fn parse_custom_operator() {
 fn parse_create_role() {
     let sql = "CREATE ROLE IF NOT EXISTS mysql_a, mysql_b";
     match pg().verified_stmt(sql) {
-        Statement::CreateRole {
-            names,
-            if_not_exists,
-            ..
-        } => {
-            assert_eq_vec(&["mysql_a", "mysql_b"], &names);
-            assert!(if_not_exists);
+        Statement::CreateRole(create_role) => {
+            assert_eq_vec(&["mysql_a", "mysql_b"], &create_role.names);
+            assert!(create_role.if_not_exists);
         }
         _ => unreachable!(),
     }
 
     let sql = "CREATE ROLE abc LOGIN PASSWORD NULL";
     match pg().parse_sql_statements(sql).as_deref() {
-        Ok(
-            [Statement::CreateRole {
-                names,
-                login,
-                password,
-                ..
-            }],
-        ) => {
-            assert_eq_vec(&["abc"], names);
-            assert_eq!(*login, Some(true));
-            assert_eq!(*password, Some(Password::NullPassword));
+        Ok([Statement::CreateRole(create_role)]) => {
+            assert_eq_vec(&["abc"], &create_role.names);
+            assert_eq!(create_role.login, Some(true));
+            assert_eq!(create_role.password, Some(Password::NullPassword));
         }
         err => panic!("Failed to parse CREATE ROLE test case: {err:?}"),
     }
 
     let sql = "CREATE ROLE abc WITH LOGIN PASSWORD NULL";
     match pg().parse_sql_statements(sql).as_deref() {
-        Ok(
-            [Statement::CreateRole {
-                names,
-                login,
-                password,
-                ..
-            }],
-        ) => {
-            assert_eq_vec(&["abc"], names);
-            assert_eq!(*login, Some(true));
-            assert_eq!(*password, Some(Password::NullPassword));
+        Ok([Statement::CreateRole(create_role)]) => {
+            assert_eq_vec(&["abc"], &create_role.names);
+            assert_eq!(create_role.login, Some(true));
+            assert_eq!(create_role.password, Some(Password::NullPassword));
         }
         err => panic!("Failed to parse CREATE ROLE test case: {err:?}"),
     }
@@ -3881,69 +3863,44 @@ fn parse_create_role() {
     let sql = "CREATE ROLE magician WITH SUPERUSER CREATEROLE NOCREATEDB BYPASSRLS INHERIT PASSWORD 'abcdef' LOGIN VALID UNTIL '2025-01-01' IN ROLE role1, role2 ROLE role3 ADMIN role4, role5 REPLICATION";
     // Roundtrip order of optional parameters is not preserved
     match pg().parse_sql_statements(sql).as_deref() {
-        Ok(
-            [Statement::CreateRole {
-                names,
-                if_not_exists,
-                bypassrls,
-                login,
-                inherit,
-                password,
-                superuser,
-                create_db,
-                create_role,
-                replication,
-                connection_limit,
-                valid_until,
-                in_role,
-                in_group,
-                role,
-                user: _,
-                admin,
-                authorization_owner,
-            }],
-        ) => {
-            assert_eq_vec(&["magician"], names);
-            assert!(!*if_not_exists);
-            assert_eq!(*login, Some(true));
-            assert_eq!(*inherit, Some(true));
-            assert_eq!(*bypassrls, Some(true));
+        Ok([Statement::CreateRole(create_role)]) => {
+            assert_eq_vec(&["magician"], &create_role.names);
+            assert!(!create_role.if_not_exists);
+            assert_eq!(create_role.login, Some(true));
+            assert_eq!(create_role.inherit, Some(true));
+            assert_eq!(create_role.bypassrls, Some(true));
             assert_eq!(
-                *password,
+                create_role.password,
                 Some(Password::Password(Expr::Value(
                     (Value::SingleQuotedString("abcdef".into())).with_empty_span()
                 )))
             );
-            assert_eq!(*superuser, Some(true));
-            assert_eq!(*create_db, Some(false));
-            assert_eq!(*create_role, Some(true));
-            assert_eq!(*replication, Some(true));
-            assert_eq!(*connection_limit, None);
+            assert_eq!(create_role.superuser, Some(true));
+            assert_eq!(create_role.create_db, Some(false));
+            assert_eq!(create_role.create_role, Some(true));
+            assert_eq!(create_role.replication, Some(true));
+            assert_eq!(create_role.connection_limit, None);
             assert_eq!(
-                *valid_until,
+                create_role.valid_until,
                 Some(Expr::Value(
                     (Value::SingleQuotedString("2025-01-01".into())).with_empty_span()
                 ))
             );
-            assert_eq_vec(&["role1", "role2"], in_role);
-            assert!(in_group.is_empty());
-            assert_eq_vec(&["role3"], role);
-            assert_eq_vec(&["role4", "role5"], admin);
-            assert_eq!(*authorization_owner, None);
+            assert_eq_vec(&["role1", "role2"], &create_role.in_role);
+            assert!(create_role.in_group.is_empty());
+            assert_eq_vec(&["role3"], &create_role.role);
+            assert_eq_vec(&["role4", "role5"], &create_role.admin);
+            assert_eq!(create_role.authorization_owner, None);
         }
         err => panic!("Failed to parse CREATE ROLE test case: {err:?}"),
     }
 
     let sql = "CREATE ROLE abc WITH USER foo, bar ROLE baz ";
     match pg().parse_sql_statements(sql).as_deref() {
-        Ok(
-            [Statement::CreateRole {
-                names, user, role, ..
-            }],
-        ) => {
-            assert_eq_vec(&["abc"], names);
-            assert_eq_vec(&["foo", "bar"], user);
-            assert_eq_vec(&["baz"], role);
+        Ok([Statement::CreateRole(create_role)]) => {
+            assert_eq_vec(&["abc"], &create_role.names);
+            assert_eq_vec(&["foo", "bar"], &create_role.user);
+            assert_eq_vec(&["baz"], &create_role.role);
         }
         err => panic!("Failed to parse CREATE ROLE test case: {err:?}"),
     }
@@ -4532,7 +4489,7 @@ fn parse_drop_function() {
     let sql = "DROP FUNCTION IF EXISTS test_func";
     assert_eq!(
         pg().verified_stmt(sql),
-        Statement::DropFunction {
+        Statement::DropFunction(DropFunction {
             if_exists: true,
             func_desc: vec![FunctionDesc {
                 name: ObjectName::from(vec![Ident {
@@ -4543,13 +4500,13 @@ fn parse_drop_function() {
                 args: None
             }],
             drop_behavior: None
-        }
+        })
     );
 
     let sql = "DROP FUNCTION IF EXISTS test_func(a INTEGER, IN b INTEGER = 1)";
     assert_eq!(
         pg().verified_stmt(sql),
-        Statement::DropFunction {
+        Statement::DropFunction(DropFunction {
             if_exists: true,
             func_desc: vec![FunctionDesc {
                 name: ObjectName::from(vec![Ident {
@@ -4570,13 +4527,13 @@ fn parse_drop_function() {
                 ]),
             }],
             drop_behavior: None
-        }
+        })
     );
 
     let sql = "DROP FUNCTION IF EXISTS test_func1(a INTEGER, IN b INTEGER = 1), test_func2(a VARCHAR, IN b INTEGER = 1)";
     assert_eq!(
         pg().verified_stmt(sql),
-        Statement::DropFunction {
+        Statement::DropFunction(DropFunction {
             if_exists: true,
             func_desc: vec![
                 FunctionDesc {
@@ -4617,7 +4574,7 @@ fn parse_drop_function() {
                 }
             ],
             drop_behavior: None
-        }
+        })
     );
 }
 
@@ -4957,14 +4914,14 @@ fn parse_truncate() {
         only: false,
     }];
     assert_eq!(
-        Statement::Truncate {
+        Statement::Truncate(Truncate {
             table_names,
             partitions: None,
             table: false,
             identity: None,
             cascade: None,
             on_cluster: None,
-        },
+        }),
         truncate
     );
 }
@@ -4981,14 +4938,14 @@ fn parse_truncate_with_options() {
     }];
 
     assert_eq!(
-        Statement::Truncate {
+        Statement::Truncate(Truncate {
             table_names,
             partitions: None,
             table: true,
             identity: Some(TruncateIdentityOption::Restart),
             cascade: Some(CascadeOption::Cascade),
             on_cluster: None,
-        },
+        }),
         truncate
     );
 }
@@ -5014,14 +4971,14 @@ fn parse_truncate_with_table_list() {
     ];
 
     assert_eq!(
-        Statement::Truncate {
+        Statement::Truncate(Truncate {
             table_names,
             partitions: None,
             table: true,
             identity: Some(TruncateIdentityOption::Restart),
             cascade: Some(CascadeOption::Cascade),
             on_cluster: None,
-        },
+        }),
         truncate
     );
 }
@@ -6409,7 +6366,7 @@ fn parse_varbit_datatype() {
 #[test]
 fn parse_alter_table_replica_identity() {
     match pg_and_generic().verified_stmt("ALTER TABLE foo REPLICA IDENTITY FULL") {
-        Statement::AlterTable { operations, .. } => {
+        Statement::AlterTable(AlterTable { operations, .. }) => {
             assert_eq!(
                 operations,
                 vec![AlterTableOperation::ReplicaIdentity {
@@ -6421,7 +6378,7 @@ fn parse_alter_table_replica_identity() {
     }
 
     match pg_and_generic().verified_stmt("ALTER TABLE foo REPLICA IDENTITY USING INDEX foo_idx") {
-        Statement::AlterTable { operations, .. } => {
+        Statement::AlterTable(AlterTable { operations, .. }) => {
             assert_eq!(
                 operations,
                 vec![AlterTableOperation::ReplicaIdentity {
@@ -6469,7 +6426,7 @@ fn parse_alter_table_constraint_not_valid() {
     match pg_and_generic().verified_stmt(
         "ALTER TABLE foo ADD CONSTRAINT bar FOREIGN KEY (baz) REFERENCES other(ref) NOT VALID",
     ) {
-        Statement::AlterTable { operations, .. } => {
+        Statement::AlterTable(AlterTable { operations, .. }) => {
             assert_eq!(
                 operations,
                 vec![AlterTableOperation::AddConstraint {
@@ -6495,7 +6452,7 @@ fn parse_alter_table_constraint_not_valid() {
 #[test]
 fn parse_alter_table_validate_constraint() {
     match pg_and_generic().verified_stmt("ALTER TABLE foo VALIDATE CONSTRAINT bar") {
-        Statement::AlterTable { operations, .. } => {
+        Statement::AlterTable(AlterTable { operations, .. }) => {
             assert_eq!(
                 operations,
                 vec![AlterTableOperation::ValidateConstraint { name: "bar".into() }]
diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs
index e04bfaf5..e7a12834 100644
--- a/tests/sqlparser_snowflake.rs
+++ b/tests/sqlparser_snowflake.rs
@@ -53,11 +53,11 @@ fn parse_sf_create_secure_view_and_materialized_view() {
         "CREATE OR REPLACE SECURE MATERIALIZED VIEW v AS SELECT 1",
     ] {
         match snowflake().verified_stmt(sql) {
-            Statement::CreateView {
+            Statement::CreateView(CreateView {
                 secure,
                 materialized,
                 ..
-            } => {
+            }) => {
                 assert!(secure);
                 if sql.contains("MATERIALIZED") {
                     assert!(materialized);
@@ -1047,7 +1047,7 @@ fn parse_sf_create_or_replace_with_comment_for_snowflake() {
         test_utils::TestedDialects::new(vec![Box::new(SnowflakeDialect {}) as Box<dyn Dialect>]);
 
     match dialect.verified_stmt(sql) {
-        Statement::CreateView {
+        Statement::CreateView(CreateView {
             name,
             columns,
             or_replace,
@@ -1060,7 +1060,7 @@ fn parse_sf_create_or_replace_with_comment_for_snowflake() {
             if_not_exists,
             temporary,
             ..
-        } => {
+        }) => {
             assert_eq!("v", name.to_string());
             assert_eq!(columns, vec![]);
             assert_eq!(options, CreateTableOptions::None);
@@ -3281,7 +3281,7 @@ fn parse_view_column_descriptions() {
     let sql = "CREATE OR REPLACE VIEW v (a COMMENT 'Comment', b) AS SELECT a, b FROM table1";
 
     match snowflake().verified_stmt(sql) {
-        Statement::CreateView { name, columns, .. } => {
+        Statement::CreateView(CreateView { name, columns, .. }) => {
             assert_eq!(name.to_string(), "v");
             assert_eq!(
                 columns,
diff --git a/tests/sqlparser_sqlite.rs b/tests/sqlparser_sqlite.rs
index 114aca03..5083ecd0 100644
--- a/tests/sqlparser_sqlite.rs
+++ b/tests/sqlparser_sqlite.rs
@@ -166,7 +166,7 @@ fn parse_create_virtual_table() {
 fn parse_create_view_temporary_if_not_exists() {
     let sql = "CREATE TEMPORARY VIEW IF NOT EXISTS myschema.myview AS SELECT foo FROM bar";
     match sqlite_and_generic().verified_stmt(sql) {
-        Statement::CreateView {
+        Statement::CreateView(CreateView {
             name,
             columns,
             query,
@@ -179,7 +179,7 @@ fn parse_create_view_temporary_if_not_exists() {
             if_not_exists,
             temporary,
             ..
-        } => {
+        }) => {
             assert_eq!("myschema.myview", name.to_string());
             assert_eq!(Vec::<ViewColumnDef>::new(), columns);
             assert_eq!("SELECT foo FROM bar", query.to_string());
@@ -467,7 +467,7 @@ fn parse_update_tuple_row_values() {
     // See https://github.com/sqlparser-rs/sqlparser-rs/issues/1311
     assert_eq!(
         sqlite().verified_stmt("UPDATE x SET (a, b) = (1, 2)"),
-        Statement::Update {
+        Statement::Update(Update {
             or: None,
             assignments: vec![Assignment {
                 target: AssignmentTarget::Tuple(vec![
@@ -487,7 +487,7 @@ fn parse_update_tuple_row_values() {
             from: None,
             returning: None,
             limit: None
-        }
+        })
     );
 }
 
@@ -596,7 +596,7 @@ fn test_regexp_operator() {
 #[test]
 fn test_update_delete_limit() {
     match sqlite().verified_stmt("UPDATE foo SET bar = 1 LIMIT 99") {
-        Statement::Update { limit, .. } => {
+        Statement::Update(Update { limit, .. }) => {
             assert_eq!(limit, Some(Expr::value(number("99"))));
         }
         _ => unreachable!(),


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org