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