Add LOCK operation for ALTER TABLE (#1768)

This commit is contained in:
Mohamed Abdeen 2025-03-18 08:22:37 +02:00 committed by GitHub
parent 10cf7c164e
commit da5892802f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 104 additions and 1 deletions

View file

@ -288,6 +288,16 @@ pub enum AlterTableOperation {
equals: bool,
algorithm: AlterTableAlgorithm,
},
/// `LOCK [=] { DEFAULT | NONE | SHARED | EXCLUSIVE }`
///
/// [MySQL]-specific table alter lock.
///
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
Lock {
equals: bool,
lock: AlterTableLock,
},
/// `AUTO_INCREMENT [=] <value>`
///
/// [MySQL]-specific table option for raising current auto increment value.
@ -366,6 +376,30 @@ impl fmt::Display for AlterTableAlgorithm {
}
}
/// [MySQL] `ALTER TABLE` lock.
///
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/alter-table.html
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum AlterTableLock {
Default,
None,
Shared,
Exclusive,
}
impl fmt::Display for AlterTableLock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self {
Self::Default => "DEFAULT",
Self::None => "NONE",
Self::Shared => "SHARED",
Self::Exclusive => "EXCLUSIVE",
})
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@ -692,6 +726,9 @@ impl fmt::Display for AlterTableOperation {
value
)
}
AlterTableOperation::Lock { equals, lock } => {
write!(f, "LOCK {}{}", if *equals { "= " } else { "" }, lock)
}
}
}
}

View file

@ -48,7 +48,7 @@ pub use self::dcl::{
};
pub use self::ddl::{
AlterColumnOperation, AlterConnectorOwner, AlterIndexOperation, AlterPolicyOperation,
AlterTableAlgorithm, AlterTableOperation, AlterType, AlterTypeAddValue,
AlterTableAlgorithm, AlterTableLock, AlterTableOperation, AlterType, AlterTypeAddValue,
AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue,
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnPolicy, ColumnPolicyProperty,
ConstraintCharacteristics, CreateConnector, CreateFunction, Deduplicate, DeferrableInitial,

View file

@ -1119,6 +1119,7 @@ impl Spanned for AlterTableOperation {
AlterTableOperation::ResumeRecluster => Span::empty(),
AlterTableOperation::Algorithm { .. } => Span::empty(),
AlterTableOperation::AutoIncrement { value, .. } => value.span(),
AlterTableOperation::Lock { .. } => Span::empty(),
}
}
}

View file

@ -797,6 +797,7 @@ define_keywords!(
SETS,
SETTINGS,
SHARE,
SHARED,
SHARING,
SHOW,
SIGNED,

View file

@ -8311,6 +8311,24 @@ impl<'a> Parser<'a> {
AlterTableOperation::SuspendRecluster
} else if self.parse_keywords(&[Keyword::RESUME, Keyword::RECLUSTER]) {
AlterTableOperation::ResumeRecluster
} else if self.parse_keyword(Keyword::LOCK) {
let equals = self.consume_token(&Token::Eq);
let lock = match self.parse_one_of_keywords(&[
Keyword::DEFAULT,
Keyword::EXCLUSIVE,
Keyword::NONE,
Keyword::SHARED,
]) {
Some(Keyword::DEFAULT) => AlterTableLock::Default,
Some(Keyword::EXCLUSIVE) => AlterTableLock::Exclusive,
Some(Keyword::NONE) => AlterTableLock::None,
Some(Keyword::SHARED) => AlterTableLock::Shared,
_ => self.expected(
"DEFAULT, EXCLUSIVE, NONE or SHARED after LOCK [=]",
self.peek_token(),
)?,
};
AlterTableOperation::Lock { equals, lock }
} else if self.parse_keyword(Keyword::ALGORITHM) {
let equals = self.consume_token(&Token::Eq);
let algorithm = match self.parse_one_of_keywords(&[

View file

@ -2454,6 +2454,52 @@ fn parse_alter_table_with_algorithm() {
mysql_and_generic().verified_stmt("ALTER TABLE `users` ALGORITHM = COPY");
}
#[test]
fn parse_alter_table_with_lock() {
let sql = "ALTER TABLE tab LOCK = SHARED";
let expected_operation = AlterTableOperation::Lock {
equals: true,
lock: AlterTableLock::Shared,
};
let operation = alter_table_op(mysql_and_generic().verified_stmt(sql));
assert_eq!(expected_operation, operation);
let sql =
"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, .. } => {
assert_eq!(
operations,
vec![
AlterTableOperation::DropColumn {
column_name: Ident::new("password_digest"),
if_exists: false,
drop_behavior: None,
},
AlterTableOperation::Lock {
equals: true,
lock: AlterTableLock::Exclusive,
},
AlterTableOperation::RenameColumn {
old_column_name: Ident::new("name"),
new_column_name: Ident::new("username")
},
]
)
}
_ => panic!("Unexpected statement {stmt}"),
}
mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK DEFAULT");
mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK SHARED");
mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK NONE");
mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK EXCLUSIVE");
mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK = DEFAULT");
mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK = SHARED");
mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK = NONE");
mysql_and_generic().verified_stmt("ALTER TABLE `users` LOCK = EXCLUSIVE");
}
#[test]
fn parse_alter_table_auto_increment() {
let sql = "ALTER TABLE tab AUTO_INCREMENT = 42";