mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-11-18 14:10:15 +00:00
Moving several struct variants out of Statement enum to allow for trait impls for specific sub-variants (#2057)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
This commit is contained in:
parent
e7d42f3d1a
commit
cc595cfd84
15 changed files with 1032 additions and 962 deletions
113
src/ast/dcl.rs
113
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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
412
src/ast/ddl.rs
412
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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
719
src/ast/mod.rs
719
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)
|
||||
|
|
|
|||
200
src/ast/spans.rs
200
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};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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() }]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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!(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue