Skip to content

Commit 25e037c

Browse files
feat: allow multiple actions in one ALTER TABLE statement (#960)
1 parent e0afd4b commit 25e037c

File tree

7 files changed

+349
-326
lines changed

7 files changed

+349
-326
lines changed

src/ast/mod.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,7 +1407,9 @@ pub enum Statement {
14071407
/// Table name
14081408
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
14091409
name: ObjectName,
1410-
operation: AlterTableOperation,
1410+
if_exists: bool,
1411+
only: bool,
1412+
operations: Vec<AlterTableOperation>,
14111413
},
14121414
AlterIndex {
14131415
name: ObjectName,
@@ -2618,8 +2620,24 @@ impl fmt::Display for Statement {
26182620
}
26192621
Ok(())
26202622
}
2621-
Statement::AlterTable { name, operation } => {
2622-
write!(f, "ALTER TABLE {name} {operation}")
2623+
Statement::AlterTable {
2624+
name,
2625+
if_exists,
2626+
only,
2627+
operations,
2628+
} => {
2629+
write!(f, "ALTER TABLE ")?;
2630+
if *if_exists {
2631+
write!(f, "IF EXISTS ")?;
2632+
}
2633+
if *only {
2634+
write!(f, "ONLY ")?;
2635+
}
2636+
write!(
2637+
f,
2638+
"{name} {operations}",
2639+
operations = display_comma_separated(operations)
2640+
)
26232641
}
26242642
Statement::AlterIndex { name, operation } => {
26252643
write!(f, "ALTER INDEX {name} {operation}")

src/parser/mod.rs

Lines changed: 174 additions & 168 deletions
Large diffs are not rendered by default.

src/test_utils.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,26 @@ pub fn expr_from_projection(item: &SelectItem) -> &Expr {
209209
}
210210
}
211211

212+
pub fn alter_table_op_with_name(stmt: Statement, expected_name: &str) -> AlterTableOperation {
213+
match stmt {
214+
Statement::AlterTable {
215+
name,
216+
if_exists,
217+
only: is_only,
218+
operations,
219+
} => {
220+
assert_eq!(name.to_string(), expected_name);
221+
assert!(!if_exists);
222+
assert!(!is_only);
223+
only(operations)
224+
}
225+
_ => panic!("Expected ALTER TABLE statement"),
226+
}
227+
}
228+
pub fn alter_table_op(stmt: Statement) -> AlterTableOperation {
229+
alter_table_op_with_name(stmt, "tab")
230+
}
231+
212232
/// Creates a `Value::Number`, panic'ing if n is not a number
213233
pub fn number(n: &str) -> Value {
214234
Value::Number(n.parse().unwrap(), false)

tests/sqlparser_common.rs

Lines changed: 67 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ use sqlparser::dialect::{
3030
use sqlparser::keywords::ALL_KEYWORDS;
3131
use sqlparser::parser::{Parser, ParserError, ParserOptions};
3232
use test_utils::{
33-
all_dialects, assert_eq_vec, expr_from_projection, join, number, only, table, table_alias,
34-
TestedDialects,
33+
all_dialects, alter_table_op, assert_eq_vec, expr_from_projection, join, number, only, table,
34+
table_alias, TestedDialects,
3535
};
3636

3737
#[macro_use]
@@ -2920,48 +2920,37 @@ fn parse_create_external_table_lowercase() {
29202920
#[test]
29212921
fn parse_alter_table() {
29222922
let add_column = "ALTER TABLE tab ADD COLUMN foo TEXT;";
2923-
match one_statement_parses_to(add_column, "ALTER TABLE tab ADD COLUMN foo TEXT") {
2924-
Statement::AlterTable {
2925-
name,
2926-
operation:
2927-
AlterTableOperation::AddColumn {
2928-
column_keyword,
2929-
if_not_exists,
2930-
column_def,
2931-
},
2923+
match alter_table_op(one_statement_parses_to(
2924+
add_column,
2925+
"ALTER TABLE tab ADD COLUMN foo TEXT",
2926+
)) {
2927+
AlterTableOperation::AddColumn {
2928+
column_keyword,
2929+
if_not_exists,
2930+
column_def,
29322931
} => {
29332932
assert!(column_keyword);
29342933
assert!(!if_not_exists);
2935-
assert_eq!("tab", name.to_string());
29362934
assert_eq!("foo", column_def.name.to_string());
29372935
assert_eq!("TEXT", column_def.data_type.to_string());
29382936
}
29392937
_ => unreachable!(),
29402938
};
29412939

29422940
let rename_table = "ALTER TABLE tab RENAME TO new_tab";
2943-
match verified_stmt(rename_table) {
2944-
Statement::AlterTable {
2945-
name,
2946-
operation: AlterTableOperation::RenameTable { table_name },
2947-
} => {
2948-
assert_eq!("tab", name.to_string());
2949-
assert_eq!("new_tab", table_name.to_string())
2941+
match alter_table_op(verified_stmt(rename_table)) {
2942+
AlterTableOperation::RenameTable { table_name } => {
2943+
assert_eq!("new_tab", table_name.to_string());
29502944
}
29512945
_ => unreachable!(),
29522946
};
29532947

29542948
let rename_column = "ALTER TABLE tab RENAME COLUMN foo TO new_foo";
2955-
match verified_stmt(rename_column) {
2956-
Statement::AlterTable {
2957-
name,
2958-
operation:
2959-
AlterTableOperation::RenameColumn {
2960-
old_column_name,
2961-
new_column_name,
2962-
},
2949+
match alter_table_op(verified_stmt(rename_column)) {
2950+
AlterTableOperation::RenameColumn {
2951+
old_column_name,
2952+
new_column_name,
29632953
} => {
2964-
assert_eq!("tab", name.to_string());
29652954
assert_eq!(old_column_name.to_string(), "foo");
29662955
assert_eq!(new_column_name.to_string(), "new_foo");
29672956
}
@@ -3047,21 +3036,15 @@ fn parse_alter_view_with_columns() {
30473036

30483037
#[test]
30493038
fn parse_alter_table_add_column() {
3050-
match verified_stmt("ALTER TABLE tab ADD foo TEXT") {
3051-
Statement::AlterTable {
3052-
operation: AlterTableOperation::AddColumn { column_keyword, .. },
3053-
..
3054-
} => {
3039+
match alter_table_op(verified_stmt("ALTER TABLE tab ADD foo TEXT")) {
3040+
AlterTableOperation::AddColumn { column_keyword, .. } => {
30553041
assert!(!column_keyword);
30563042
}
30573043
_ => unreachable!(),
30583044
};
30593045

3060-
match verified_stmt("ALTER TABLE tab ADD COLUMN foo TEXT") {
3061-
Statement::AlterTable {
3062-
operation: AlterTableOperation::AddColumn { column_keyword, .. },
3063-
..
3064-
} => {
3046+
match alter_table_op(verified_stmt("ALTER TABLE tab ADD COLUMN foo TEXT")) {
3047+
AlterTableOperation::AddColumn { column_keyword, .. } => {
30653048
assert!(column_keyword);
30663049
}
30673050
_ => unreachable!(),
@@ -3080,24 +3063,19 @@ fn parse_alter_table_add_column_if_not_exists() {
30803063
options: None,
30813064
};
30823065

3083-
match dialects.verified_stmt("ALTER TABLE tab ADD IF NOT EXISTS foo TEXT") {
3084-
Statement::AlterTable {
3085-
operation: AlterTableOperation::AddColumn { if_not_exists, .. },
3086-
..
3087-
} => {
3066+
match alter_table_op(dialects.verified_stmt("ALTER TABLE tab ADD IF NOT EXISTS foo TEXT")) {
3067+
AlterTableOperation::AddColumn { if_not_exists, .. } => {
30883068
assert!(if_not_exists);
30893069
}
30903070
_ => unreachable!(),
30913071
};
30923072

3093-
match dialects.verified_stmt("ALTER TABLE tab ADD COLUMN IF NOT EXISTS foo TEXT") {
3094-
Statement::AlterTable {
3095-
operation:
3096-
AlterTableOperation::AddColumn {
3097-
column_keyword,
3098-
if_not_exists,
3099-
..
3100-
},
3073+
match alter_table_op(
3074+
dialects.verified_stmt("ALTER TABLE tab ADD COLUMN IF NOT EXISTS foo TEXT"),
3075+
) {
3076+
AlterTableOperation::AddColumn {
3077+
column_keyword,
3078+
if_not_exists,
31013079
..
31023080
} => {
31033081
assert!(column_keyword);
@@ -3123,12 +3101,10 @@ fn parse_alter_table_constraints() {
31233101
check_one("CHECK (end_date > start_date OR end_date IS NULL)");
31243102

31253103
fn check_one(constraint_text: &str) {
3126-
match verified_stmt(&format!("ALTER TABLE tab ADD {constraint_text}")) {
3127-
Statement::AlterTable {
3128-
name,
3129-
operation: AlterTableOperation::AddConstraint(constraint),
3130-
} => {
3131-
assert_eq!("tab", name.to_string());
3104+
match alter_table_op(verified_stmt(&format!(
3105+
"ALTER TABLE tab ADD {constraint_text}"
3106+
))) {
3107+
AlterTableOperation::AddConstraint(constraint) => {
31323108
assert_eq!(constraint_text, constraint.to_string());
31333109
}
31343110
_ => unreachable!(),
@@ -3150,17 +3126,12 @@ fn parse_alter_table_drop_column() {
31503126
);
31513127

31523128
fn check_one(constraint_text: &str) {
3153-
match verified_stmt(&format!("ALTER TABLE tab {constraint_text}")) {
3154-
Statement::AlterTable {
3155-
name,
3156-
operation:
3157-
AlterTableOperation::DropColumn {
3158-
column_name,
3159-
if_exists,
3160-
cascade,
3161-
},
3129+
match alter_table_op(verified_stmt(&format!("ALTER TABLE tab {constraint_text}"))) {
3130+
AlterTableOperation::DropColumn {
3131+
column_name,
3132+
if_exists,
3133+
cascade,
31623134
} => {
3163-
assert_eq!("tab", name.to_string());
31643135
assert_eq!("is_active", column_name.to_string());
31653136
assert!(if_exists);
31663137
assert!(cascade);
@@ -3173,12 +3144,10 @@ fn parse_alter_table_drop_column() {
31733144
#[test]
31743145
fn parse_alter_table_alter_column() {
31753146
let alter_stmt = "ALTER TABLE tab";
3176-
match verified_stmt(&format!("{alter_stmt} ALTER COLUMN is_active SET NOT NULL")) {
3177-
Statement::AlterTable {
3178-
name,
3179-
operation: AlterTableOperation::AlterColumn { column_name, op },
3180-
} => {
3181-
assert_eq!("tab", name.to_string());
3147+
match alter_table_op(verified_stmt(&format!(
3148+
"{alter_stmt} ALTER COLUMN is_active SET NOT NULL"
3149+
))) {
3150+
AlterTableOperation::AlterColumn { column_name, op } => {
31823151
assert_eq!("is_active", column_name.to_string());
31833152
assert_eq!(op, AlterColumnOperation::SetNotNull {});
31843153
}
@@ -3190,14 +3159,10 @@ fn parse_alter_table_alter_column() {
31903159
"ALTER TABLE tab ALTER COLUMN is_active DROP NOT NULL",
31913160
);
31923161

3193-
match verified_stmt(&format!(
3162+
match alter_table_op(verified_stmt(&format!(
31943163
"{alter_stmt} ALTER COLUMN is_active SET DEFAULT false"
3195-
)) {
3196-
Statement::AlterTable {
3197-
name,
3198-
operation: AlterTableOperation::AlterColumn { column_name, op },
3199-
} => {
3200-
assert_eq!("tab", name.to_string());
3164+
))) {
3165+
AlterTableOperation::AlterColumn { column_name, op } => {
32013166
assert_eq!("is_active", column_name.to_string());
32023167
assert_eq!(
32033168
op,
@@ -3209,12 +3174,10 @@ fn parse_alter_table_alter_column() {
32093174
_ => unreachable!(),
32103175
}
32113176

3212-
match verified_stmt(&format!("{alter_stmt} ALTER COLUMN is_active DROP DEFAULT")) {
3213-
Statement::AlterTable {
3214-
name,
3215-
operation: AlterTableOperation::AlterColumn { column_name, op },
3216-
} => {
3217-
assert_eq!("tab", name.to_string());
3177+
match alter_table_op(verified_stmt(&format!(
3178+
"{alter_stmt} ALTER COLUMN is_active DROP DEFAULT"
3179+
))) {
3180+
AlterTableOperation::AlterColumn { column_name, op } => {
32183181
assert_eq!("is_active", column_name.to_string());
32193182
assert_eq!(op, AlterColumnOperation::DropDefault {});
32203183
}
@@ -3225,12 +3188,10 @@ fn parse_alter_table_alter_column() {
32253188
#[test]
32263189
fn parse_alter_table_alter_column_type() {
32273190
let alter_stmt = "ALTER TABLE tab";
3228-
match verified_stmt("ALTER TABLE tab ALTER COLUMN is_active SET DATA TYPE TEXT") {
3229-
Statement::AlterTable {
3230-
name,
3231-
operation: AlterTableOperation::AlterColumn { column_name, op },
3232-
} => {
3233-
assert_eq!("tab", name.to_string());
3191+
match alter_table_op(verified_stmt(
3192+
"ALTER TABLE tab ALTER COLUMN is_active SET DATA TYPE TEXT",
3193+
)) {
3194+
AlterTableOperation::AlterColumn { column_name, op } => {
32343195
assert_eq!("is_active", column_name.to_string());
32353196
assert_eq!(
32363197
op,
@@ -3267,34 +3228,28 @@ fn parse_alter_table_alter_column_type() {
32673228
#[test]
32683229
fn parse_alter_table_drop_constraint() {
32693230
let alter_stmt = "ALTER TABLE tab";
3270-
match verified_stmt("ALTER TABLE tab DROP CONSTRAINT constraint_name CASCADE") {
3271-
Statement::AlterTable {
3272-
name,
3273-
operation:
3274-
AlterTableOperation::DropConstraint {
3275-
name: constr_name,
3276-
if_exists,
3277-
cascade,
3278-
},
3231+
match alter_table_op(verified_stmt(
3232+
"ALTER TABLE tab DROP CONSTRAINT constraint_name CASCADE",
3233+
)) {
3234+
AlterTableOperation::DropConstraint {
3235+
name: constr_name,
3236+
if_exists,
3237+
cascade,
32793238
} => {
3280-
assert_eq!("tab", name.to_string());
32813239
assert_eq!("constraint_name", constr_name.to_string());
32823240
assert!(!if_exists);
32833241
assert!(cascade);
32843242
}
32853243
_ => unreachable!(),
32863244
}
3287-
match verified_stmt("ALTER TABLE tab DROP CONSTRAINT IF EXISTS constraint_name") {
3288-
Statement::AlterTable {
3289-
name,
3290-
operation:
3291-
AlterTableOperation::DropConstraint {
3292-
name: constr_name,
3293-
if_exists,
3294-
cascade,
3295-
},
3245+
match alter_table_op(verified_stmt(
3246+
"ALTER TABLE tab DROP CONSTRAINT IF EXISTS constraint_name",
3247+
)) {
3248+
AlterTableOperation::DropConstraint {
3249+
name: constr_name,
3250+
if_exists,
3251+
cascade,
32963252
} => {
3297-
assert_eq!("tab", name.to_string());
32983253
assert_eq!("constraint_name", constr_name.to_string());
32993254
assert!(if_exists);
33003255
assert!(!cascade);

0 commit comments

Comments
 (0)