Skip to content

Commit

Permalink
Support Modify Column for MySQL dialect (apache#1216)
Browse files Browse the repository at this point in the history
  • Loading branch information
KKould authored and JichaoS committed May 7, 2024
1 parent 76bfa87 commit 905a3f2
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,14 @@ pub enum AlterTableOperation {
/// MySQL `ALTER TABLE` only [FIRST | AFTER column_name]
column_position: Option<MySQLColumnPosition>,
},
// CHANGE [ COLUMN ] <col_name> <data_type> [ <options> ]
ModifyColumn {
col_name: Ident,
data_type: DataType,
options: Vec<ColumnOption>,
/// MySQL `ALTER TABLE` only [FIRST | AFTER column_name]
column_position: Option<MySQLColumnPosition>,
},
/// `RENAME CONSTRAINT <old_constraint_name> TO <new_constraint_name>`
///
/// Note: this is a PostgreSQL-specific operation.
Expand Down Expand Up @@ -292,6 +300,22 @@ impl fmt::Display for AlterTableOperation {

Ok(())
}
AlterTableOperation::ModifyColumn {
col_name,
data_type,
options,
column_position,
} => {
write!(f, "MODIFY COLUMN {col_name} {data_type}")?;
if !options.is_empty() {
write!(f, " {}", display_separated(options, " "))?;
}
if let Some(position) = column_position {
write!(f, " {position}")?;
}

Ok(())
}
AlterTableOperation::RenameConstraint { old_name, new_name } => {
write!(f, "RENAME CONSTRAINT {old_name} TO {new_name}")
}
Expand Down
1 change: 1 addition & 0 deletions src/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ define_keywords!(
MOD,
MODE,
MODIFIES,
MODIFY,
MODULE,
MONTH,
MSCK,
Expand Down
17 changes: 17 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5757,6 +5757,23 @@ impl<'a> Parser<'a> {
options,
column_position,
}
} else if self.parse_keyword(Keyword::MODIFY) {
let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ]
let col_name = self.parse_identifier(false)?;
let data_type = self.parse_data_type()?;
let mut options = vec![];
while let Some(option) = self.parse_optional_column_option()? {
options.push(option);
}

let column_position = self.parse_column_position()?;

AlterTableOperation::ModifyColumn {
col_name,
data_type,
options,
column_position,
}
} else if self.parse_keyword(Keyword::ALTER) {
let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ]
let column_name = self.parse_identifier(false)?;
Expand Down
93 changes: 93 additions & 0 deletions tests/sqlparser_mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2218,6 +2218,99 @@ fn parse_alter_table_change_column_with_column_position() {
assert_eq!(expected_operation_after, operation);
}

#[test]
fn parse_alter_table_modify_column() {
let expected_name = ObjectName(vec![Ident::new("orders")]);
let expected_operation = AlterTableOperation::ModifyColumn {
col_name: Ident::new("description"),
data_type: DataType::Text,
options: vec![ColumnOption::NotNull],
column_position: None,
};

let sql1 = "ALTER TABLE orders MODIFY COLUMN description TEXT NOT NULL";
let operation =
alter_table_op_with_name(mysql().verified_stmt(sql1), &expected_name.to_string());
assert_eq!(expected_operation, operation);

let sql2 = "ALTER TABLE orders MODIFY description TEXT NOT NULL";
let operation = alter_table_op_with_name(
mysql().one_statement_parses_to(sql2, sql1),
&expected_name.to_string(),
);
assert_eq!(expected_operation, operation);

let expected_operation = AlterTableOperation::ModifyColumn {
col_name: Ident::new("description"),
data_type: DataType::Text,
options: vec![ColumnOption::NotNull],
column_position: Some(MySQLColumnPosition::First),
};
let sql3 = "ALTER TABLE orders MODIFY COLUMN description TEXT NOT NULL FIRST";
let operation =
alter_table_op_with_name(mysql().verified_stmt(sql3), &expected_name.to_string());
assert_eq!(expected_operation, operation);

let expected_operation = AlterTableOperation::ModifyColumn {
col_name: Ident::new("description"),
data_type: DataType::Text,
options: vec![ColumnOption::NotNull],
column_position: Some(MySQLColumnPosition::After(Ident {
value: String::from("foo"),
quote_style: None,
})),
};
let sql4 = "ALTER TABLE orders MODIFY COLUMN description TEXT NOT NULL AFTER foo";
let operation =
alter_table_op_with_name(mysql().verified_stmt(sql4), &expected_name.to_string());
assert_eq!(expected_operation, operation);
}

#[test]
fn parse_alter_table_modify_column_with_column_position() {
let expected_name = ObjectName(vec![Ident::new("orders")]);
let expected_operation_first = AlterTableOperation::ModifyColumn {
col_name: Ident::new("description"),
data_type: DataType::Text,
options: vec![ColumnOption::NotNull],
column_position: Some(MySQLColumnPosition::First),
};

let sql1 = "ALTER TABLE orders MODIFY COLUMN description TEXT NOT NULL FIRST";
let operation =
alter_table_op_with_name(mysql().verified_stmt(sql1), &expected_name.to_string());
assert_eq!(expected_operation_first, operation);

let sql2 = "ALTER TABLE orders MODIFY description TEXT NOT NULL FIRST";
let operation = alter_table_op_with_name(
mysql().one_statement_parses_to(sql2, sql1),
&expected_name.to_string(),
);
assert_eq!(expected_operation_first, operation);

let expected_operation_after = AlterTableOperation::ModifyColumn {
col_name: Ident::new("description"),
data_type: DataType::Text,
options: vec![ColumnOption::NotNull],
column_position: Some(MySQLColumnPosition::After(Ident {
value: String::from("total_count"),
quote_style: None,
})),
};

let sql1 = "ALTER TABLE orders MODIFY COLUMN description TEXT NOT NULL AFTER total_count";
let operation =
alter_table_op_with_name(mysql().verified_stmt(sql1), &expected_name.to_string());
assert_eq!(expected_operation_after, operation);

let sql2 = "ALTER TABLE orders MODIFY description TEXT NOT NULL AFTER total_count";
let operation = alter_table_op_with_name(
mysql().one_statement_parses_to(sql2, sql1),
&expected_name.to_string(),
);
assert_eq!(expected_operation_after, operation);
}

#[test]
fn parse_substring_in_select() {
let sql = "SELECT DISTINCT SUBSTRING(description, 0, 1) FROM test";
Expand Down

0 comments on commit 905a3f2

Please sign in to comment.