Skip to content

Commit 8f70b00

Browse files
Moved AlterTable struct out of Statement
1 parent 112a96d commit 8f70b00

File tree

9 files changed

+140
-149
lines changed

9 files changed

+140
-149
lines changed

src/ast/ddl.rs

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,16 @@ use sqlparser_derive::{Visit, VisitMut};
3030

3131
use crate::ast::value::escape_single_quote_string;
3232
use crate::ast::{
33-
display_comma_separated, display_separated, ArgMode, CommentDef, ConditionalStatements,
34-
CreateFunctionBody, CreateFunctionUsing, CreateTableLikeKind, CreateTableOptions,
35-
CreateViewParams, DataType, Expr, FileFormat, FunctionBehavior, FunctionCalledOnNull,
36-
FunctionDeterminismSpecifier, FunctionParallel, HiveDistributionStyle, HiveFormat,
37-
HiveIOFormat, HiveRowFormat, Ident, InitializeKind, MySQLColumnPosition, ObjectName, OnCommit,
38-
OneOrManyWithParens, OperateFunctionArg, OrderByExpr, ProjectionSelect, Query, RefreshModeKind,
39-
RowAccessPolicy, SequenceOptions, Spanned, SqlOption, StorageSerializationPolicy, TableVersion,
40-
Tag, TriggerEvent, TriggerExecBody, TriggerObject, TriggerPeriod, TriggerReferencing, Value,
41-
ValueWithSpan, WrappedCollection,
33+
display_comma_separated, display_separated, ArgMode, AttachedToken, CommentDef,
34+
ConditionalStatements, CreateFunctionBody, CreateFunctionUsing, CreateTableLikeKind,
35+
CreateTableOptions, CreateViewParams, DataType, Expr, FileFormat, FunctionBehavior,
36+
FunctionCalledOnNull, FunctionDeterminismSpecifier, FunctionParallel, HiveDistributionStyle,
37+
HiveFormat, HiveIOFormat, HiveRowFormat, HiveSetLocation, Ident, InitializeKind,
38+
MySQLColumnPosition, ObjectName, OnCommit, OneOrManyWithParens, OperateFunctionArg,
39+
OrderByExpr, ProjectionSelect, Query, RefreshModeKind, RowAccessPolicy, SequenceOptions,
40+
Spanned, SqlOption, StorageSerializationPolicy, TableVersion, Tag, TriggerEvent,
41+
TriggerExecBody, TriggerObject, TriggerPeriod, TriggerReferencing, Value, ValueWithSpan,
42+
WrappedCollection,
4243
};
4344
use crate::display_utils::{DisplayCommaSeparated, Indent, NewLine, SpaceOrNewline};
4445
use crate::keywords::Keyword;
@@ -3749,3 +3750,52 @@ impl Spanned for DropExtension {
37493750
Span::empty()
37503751
}
37513752
}
3753+
3754+
/// ALTER TABLE statement
3755+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3756+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3757+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3758+
pub struct AlterTable {
3759+
/// Table name
3760+
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
3761+
pub name: ObjectName,
3762+
pub if_exists: bool,
3763+
pub only: bool,
3764+
pub operations: Vec<AlterTableOperation>,
3765+
pub location: Option<HiveSetLocation>,
3766+
/// ClickHouse dialect supports `ON CLUSTER` clause for ALTER TABLE
3767+
/// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
3768+
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
3769+
pub on_cluster: Option<Ident>,
3770+
/// Snowflake "ICEBERG" clause for Iceberg tables
3771+
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
3772+
pub iceberg: bool,
3773+
/// Token that represents the end of the statement (semicolon or EOF)
3774+
pub end_token: AttachedToken,
3775+
}
3776+
3777+
impl fmt::Display for AlterTable {
3778+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3779+
if self.iceberg {
3780+
write!(f, "ALTER ICEBERG TABLE ")?;
3781+
} else {
3782+
write!(f, "ALTER TABLE ")?;
3783+
}
3784+
3785+
if self.if_exists {
3786+
write!(f, "IF EXISTS ")?;
3787+
}
3788+
if self.only {
3789+
write!(f, "ONLY ")?;
3790+
}
3791+
write!(f, "{} ", &self.name)?;
3792+
if let Some(cluster) = &self.on_cluster {
3793+
write!(f, "ON CLUSTER {cluster} ")?;
3794+
}
3795+
write!(f, "{}", display_comma_separated(&self.operations))?;
3796+
if let Some(loc) = &self.location {
3797+
write!(f, " {loc}")?
3798+
}
3799+
Ok(())
3800+
}
3801+
}

src/ast/mod.rs

Lines changed: 21 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,18 @@ pub use self::dcl::{
6060
};
6161
pub use self::ddl::{
6262
AlterColumnOperation, AlterConnectorOwner, AlterIndexOperation, AlterPolicyOperation,
63-
AlterSchema, AlterSchemaOperation, AlterTableAlgorithm, AlterTableLock, AlterTableOperation,
64-
AlterType, AlterTypeAddValue, AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename,
65-
AlterTypeRenameValue, ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnOptions,
66-
ColumnPolicy, ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateDomain,
67-
CreateExtension, CreateFunction, CreateIndex, CreateTable, CreateTrigger, CreateView,
68-
Deduplicate, DeferrableInitial, DropBehavior, DropExtension, DropTrigger, GeneratedAs,
69-
GeneratedExpressionMode, IdentityParameters, IdentityProperty, IdentityPropertyFormatKind,
70-
IdentityPropertyKind, IdentityPropertyOrder, IndexColumn, IndexOption, IndexType,
71-
KeyOrIndexDisplay, Msck, NullsDistinctOption, Owner, Partition, ProcedureParam,
72-
ReferentialAction, RenameTableNameKind, ReplicaIdentity, TableConstraint, TagsColumnOption,
73-
Truncate, UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation, ViewColumnDef,
63+
AlterSchema, AlterSchemaOperation, AlterTable, AlterTableAlgorithm, AlterTableLock,
64+
AlterTableOperation, AlterType, AlterTypeAddValue, AlterTypeAddValuePosition,
65+
AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue, ClusteredBy, ColumnDef,
66+
ColumnOption, ColumnOptionDef, ColumnOptions, ColumnPolicy, ColumnPolicyProperty,
67+
ConstraintCharacteristics, CreateConnector, CreateDomain, CreateExtension, CreateFunction,
68+
CreateIndex, CreateTable, CreateTrigger, CreateView, Deduplicate, DeferrableInitial,
69+
DropBehavior, DropExtension, DropTrigger, GeneratedAs, GeneratedExpressionMode,
70+
IdentityParameters, IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind,
71+
IdentityPropertyOrder, IndexColumn, IndexOption, IndexType, KeyOrIndexDisplay, Msck,
72+
NullsDistinctOption, Owner, Partition, ProcedureParam, ReferentialAction, RenameTableNameKind,
73+
ReplicaIdentity, TableConstraint, TagsColumnOption, Truncate,
74+
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation, ViewColumnDef,
7475
};
7576
pub use self::dml::{Delete, Insert, Update};
7677
pub use self::operator::{BinaryOperator, UnaryOperator};
@@ -3311,24 +3312,7 @@ pub enum Statement {
33113312
/// ```sql
33123313
/// ALTER TABLE
33133314
/// ```
3314-
AlterTable {
3315-
/// Table name
3316-
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
3317-
name: ObjectName,
3318-
if_exists: bool,
3319-
only: bool,
3320-
operations: Vec<AlterTableOperation>,
3321-
location: Option<HiveSetLocation>,
3322-
/// ClickHouse dialect supports `ON CLUSTER` clause for ALTER TABLE
3323-
/// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
3324-
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
3325-
on_cluster: Option<Ident>,
3326-
/// Snowflake "ICEBERG" clause for Iceberg tables
3327-
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
3328-
iceberg: bool,
3329-
/// Token that represents the end of the statement (semicolon or EOF)
3330-
end_token: AttachedToken,
3331-
},
3315+
AlterTable(AlterTable),
33323316
/// ```sql
33333317
/// ALTER SCHEMA
33343318
/// ```
@@ -3537,10 +3521,9 @@ pub enum Statement {
35373521
CreateExtension(CreateExtension),
35383522
/// ```sql
35393523
/// DROP EXTENSION [ IF EXISTS ] name [, ...] [ CASCADE | RESTRICT ]
3540-
///
3524+
/// ```
35413525
/// Note: this is a PostgreSQL-specific statement.
35423526
/// https://www.postgresql.org/docs/current/sql-dropextension.html
3543-
/// ```
35443527
DropExtension(DropExtension),
35453528
/// ```sql
35463529
/// FETCH
@@ -4879,42 +4862,7 @@ impl fmt::Display for Statement {
48794862
Ok(())
48804863
}
48814864
Statement::CreateConnector(create_connector) => create_connector.fmt(f),
4882-
Statement::AlterTable {
4883-
name,
4884-
if_exists,
4885-
only,
4886-
operations,
4887-
location,
4888-
on_cluster,
4889-
iceberg,
4890-
end_token: _,
4891-
} => {
4892-
if *iceberg {
4893-
write!(f, "ALTER ICEBERG TABLE ")?;
4894-
} else {
4895-
write!(f, "ALTER TABLE ")?;
4896-
}
4897-
4898-
if *if_exists {
4899-
write!(f, "IF EXISTS ")?;
4900-
}
4901-
if *only {
4902-
write!(f, "ONLY ")?;
4903-
}
4904-
write!(f, "{name} ")?;
4905-
if let Some(cluster) = on_cluster {
4906-
write!(f, "ON CLUSTER {cluster} ")?;
4907-
}
4908-
write!(
4909-
f,
4910-
"{operations}",
4911-
operations = display_comma_separated(operations)
4912-
)?;
4913-
if let Some(loc) = location {
4914-
write!(f, " {loc}")?
4915-
}
4916-
Ok(())
4917-
}
4865+
Statement::AlterTable(alter_table) => write!(f, "{alter_table}"),
49184866
Statement::AlterIndex { name, operation } => {
49194867
write!(f, "ALTER INDEX {name} {operation}")
49204868
}
@@ -10570,6 +10518,12 @@ impl From<CreateRole> for Statement {
1057010518
}
1057110519
}
1057210520

10521+
impl From<AlterTable> for Statement {
10522+
fn from(at: AlterTable) -> Self {
10523+
Self::AlterTable(at)
10524+
}
10525+
}
10526+
1057310527
impl From<CreateExtension> for Statement {
1057410528
fn from(ce: CreateExtension) -> Self {
1057510529
Self::CreateExtension(ce)

src/ast/spans.rs

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
// under the License.
1717

1818
use crate::ast::{
19-
ddl::AlterSchema, query::SelectItemQualifiedWildcardKind, AlterSchemaOperation, ColumnOptions,
20-
ExportData, Owner, TypedString,
19+
ddl::AlterSchema, query::SelectItemQualifiedWildcardKind, AlterSchemaOperation, AlterTable,
20+
ColumnOptions, ExportData, Owner, TypedString,
2121
};
2222
use core::iter;
2323

@@ -367,21 +367,7 @@ impl Spanned for Statement {
367367
Statement::CreateSecret { .. } => Span::empty(),
368368
Statement::CreateServer { .. } => Span::empty(),
369369
Statement::CreateConnector { .. } => Span::empty(),
370-
Statement::AlterTable {
371-
name,
372-
if_exists: _,
373-
only: _,
374-
operations,
375-
location: _,
376-
on_cluster,
377-
iceberg: _,
378-
end_token,
379-
} => union_spans(
380-
core::iter::once(name.span())
381-
.chain(operations.iter().map(|i| i.span()))
382-
.chain(on_cluster.iter().map(|i| i.span))
383-
.chain(core::iter::once(end_token.0.span)),
384-
),
370+
Statement::AlterTable(alter_table) => alter_table.span(),
385371
Statement::AlterIndex { name, operation } => name.span().union(&operation.span()),
386372
Statement::AlterView {
387373
name,
@@ -2416,6 +2402,17 @@ impl Spanned for AlterSchema {
24162402
}
24172403
}
24182404

2405+
impl Spanned for AlterTable {
2406+
fn span(&self) -> Span {
2407+
union_spans(
2408+
core::iter::once(self.name.span())
2409+
.chain(self.operations.iter().map(|i| i.span()))
2410+
.chain(self.on_cluster.iter().map(|i| i.span))
2411+
.chain(core::iter::once(self.end_token.0.span)),
2412+
)
2413+
}
2414+
}
2415+
24192416
#[cfg(test)]
24202417
pub mod tests {
24212418
use crate::dialect::{Dialect, GenericDialect, SnowflakeDialect};

src/parser/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9359,7 +9359,7 @@ impl<'a> Parser<'a> {
93599359
self.get_current_token().clone()
93609360
};
93619361

9362-
Ok(Statement::AlterTable {
9362+
Ok(AlterTable {
93639363
name: table_name,
93649364
if_exists,
93659365
only,
@@ -9368,7 +9368,8 @@ impl<'a> Parser<'a> {
93689368
on_cluster,
93699369
iceberg,
93709370
end_token: AttachedToken(end_token),
9371-
})
9371+
}
9372+
.into())
93729373
}
93739374

93749375
pub fn parse_alter_view(&mut self) -> Result<Statement, ParserError> {

src/test_utils.rs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -343,21 +343,12 @@ pub fn expr_from_projection(item: &SelectItem) -> &Expr {
343343

344344
pub fn alter_table_op_with_name(stmt: Statement, expected_name: &str) -> AlterTableOperation {
345345
match stmt {
346-
Statement::AlterTable {
347-
name,
348-
if_exists,
349-
only: is_only,
350-
operations,
351-
on_cluster: _,
352-
location: _,
353-
iceberg,
354-
end_token: _,
355-
} => {
356-
assert_eq!(name.to_string(), expected_name);
357-
assert!(!if_exists);
358-
assert!(!is_only);
359-
assert!(!iceberg);
360-
only(operations)
346+
Statement::AlterTable(alter_table) => {
347+
assert_eq!(alter_table.name.to_string(), expected_name);
348+
assert!(!alter_table.if_exists);
349+
assert!(!alter_table.only);
350+
assert!(!alter_table.iceberg);
351+
only(alter_table.operations)
361352
}
362353
_ => panic!("Expected ALTER TABLE statement"),
363354
}
@@ -484,7 +475,7 @@ pub fn index_column(stmt: Statement) -> Expr {
484475
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
485476
}
486477
}
487-
Statement::AlterTable { operations, .. } => match operations.first().unwrap() {
478+
Statement::AlterTable(alter_table) => match alter_table.operations.first().unwrap() {
488479
AlterTableOperation::AddConstraint { constraint, .. } => {
489480
match constraint {
490481
TableConstraint::Index { columns, .. } => {

tests/sqlparser_clickhouse.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,10 @@ fn parse_alter_table_attach_and_detach_partition() {
243243
match clickhouse_and_generic()
244244
.verified_stmt(format!("ALTER TABLE t0 {operation} PARTITION part").as_str())
245245
{
246-
Statement::AlterTable {
247-
name, operations, ..
248-
} => {
249-
pretty_assertions::assert_eq!("t0", name.to_string());
246+
Statement::AlterTable(alter_table) => {
247+
pretty_assertions::assert_eq!("t0", alter_table.name.to_string());
250248
pretty_assertions::assert_eq!(
251-
operations[0],
249+
alter_table.operations[0],
252250
if operation == &"ATTACH" {
253251
AlterTableOperation::AttachPartition {
254252
partition: Partition::Expr(Identifier(Ident::new("part"))),
@@ -266,9 +264,9 @@ fn parse_alter_table_attach_and_detach_partition() {
266264
match clickhouse_and_generic()
267265
.verified_stmt(format!("ALTER TABLE t1 {operation} PART part").as_str())
268266
{
269-
Statement::AlterTable {
267+
Statement::AlterTable(AlterTable {
270268
name, operations, ..
271-
} => {
269+
}) => {
272270
pretty_assertions::assert_eq!("t1", name.to_string());
273271
pretty_assertions::assert_eq!(
274272
operations[0],
@@ -308,9 +306,9 @@ fn parse_alter_table_add_projection() {
308306
"ALTER TABLE t0 ADD PROJECTION IF NOT EXISTS my_name",
309307
" (SELECT a, b GROUP BY a ORDER BY b)",
310308
)) {
311-
Statement::AlterTable {
309+
Statement::AlterTable(AlterTable {
312310
name, operations, ..
313-
} => {
311+
}) => {
314312
assert_eq!(name, ObjectName::from(vec!["t0".into()]));
315313
assert_eq!(1, operations.len());
316314
assert_eq!(
@@ -380,9 +378,9 @@ fn parse_alter_table_add_projection() {
380378
fn parse_alter_table_drop_projection() {
381379
match clickhouse_and_generic().verified_stmt("ALTER TABLE t0 DROP PROJECTION IF EXISTS my_name")
382380
{
383-
Statement::AlterTable {
381+
Statement::AlterTable(AlterTable {
384382
name, operations, ..
385-
} => {
383+
}) => {
386384
assert_eq!(name, ObjectName::from(vec!["t0".into()]));
387385
assert_eq!(1, operations.len());
388386
assert_eq!(
@@ -413,9 +411,9 @@ fn parse_alter_table_clear_and_materialize_projection() {
413411
format!("ALTER TABLE t0 {keyword} PROJECTION IF EXISTS my_name IN PARTITION p0",)
414412
.as_str(),
415413
) {
416-
Statement::AlterTable {
414+
Statement::AlterTable(AlterTable {
417415
name, operations, ..
418-
} => {
416+
}) => {
419417
assert_eq!(name, ObjectName::from(vec!["t0".into()]));
420418
assert_eq!(1, operations.len());
421419
assert_eq!(
@@ -1518,7 +1516,7 @@ fn parse_freeze_and_unfreeze_partition() {
15181516
Value::SingleQuotedString("2024-08-14".to_string()).with_empty_span(),
15191517
));
15201518
match clickhouse_and_generic().verified_stmt(&sql) {
1521-
Statement::AlterTable { operations, .. } => {
1519+
Statement::AlterTable(AlterTable { operations, .. }) => {
15221520
assert_eq!(operations.len(), 1);
15231521
let expected_operation = if operation_name == &"FREEZE" {
15241522
AlterTableOperation::FreezePartition {
@@ -1542,7 +1540,7 @@ fn parse_freeze_and_unfreeze_partition() {
15421540
let sql =
15431541
format!("ALTER TABLE t {operation_name} PARTITION '2024-08-14' WITH NAME 'hello'");
15441542
match clickhouse_and_generic().verified_stmt(&sql) {
1545-
Statement::AlterTable { operations, .. } => {
1543+
Statement::AlterTable(AlterTable { operations, .. }) => {
15461544
assert_eq!(operations.len(), 1);
15471545
let expected_partition = Partition::Expr(Expr::Value(
15481546
Value::SingleQuotedString("2024-08-14".to_string()).with_empty_span(),

0 commit comments

Comments
 (0)