From 678ca8d33b59b2d928d622a93e3649d1f3b4a0db Mon Sep 17 00:00:00 2001 From: "Levy A." Date: Wed, 27 Aug 2025 15:45:03 -0300 Subject: [PATCH] feat(parser): add `ALTER COLUMN` --- core/translate/alter.rs | 3 +++ parser/src/ast.rs | 2 ++ parser/src/ast/fmt.rs | 7 +++++++ parser/src/lexer.rs | 2 +- parser/src/parser.rs | 36 ++++++++++++++++++++++++++++++++++-- 5 files changed, 47 insertions(+), 3 deletions(-) diff --git a/core/translate/alter.rs b/core/translate/alter.rs index 0990e90ac..3699fdce8 100644 --- a/core/translate/alter.rs +++ b/core/translate/alter.rs @@ -411,5 +411,8 @@ pub fn translate_alter_table( program } + ast::AlterTableBody::AlterColumn { .. } => { + todo!("`ALTER COLUMN` not implemented") + } }) } diff --git a/parser/src/ast.rs b/parser/src/ast.rs index a0640aac5..d1b429a1e 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -982,6 +982,8 @@ pub enum AlterTableBody { RenameTo(Name), /// `ADD COLUMN` AddColumn(ColumnDefinition), // TODO distinction between ADD and ADD COLUMN + /// `ALTER COLUMN` + AlterColumn { old: Name, new: ColumnDefinition }, /// `RENAME COLUMN` RenameColumn { /// old name diff --git a/parser/src/ast/fmt.rs b/parser/src/ast/fmt.rs index ee0b6716e..0e46cb680 100644 --- a/parser/src/ast/fmt.rs +++ b/parser/src/ast/fmt.rs @@ -1409,6 +1409,13 @@ impl ToTokens for AlterTableBody { s.append(TK_COLUMNKW, None)?; def.to_tokens_with_context(s, context) } + Self::AlterColumn { old, new } => { + s.append(TK_ALTER, None)?; + s.append(TK_COLUMNKW, None)?; + old.to_tokens_with_context(s, context)?; + s.append(TK_TO, None)?; + new.to_tokens_with_context(s, context) + } Self::RenameColumn { old, new } => { s.append(TK_RENAME, None)?; s.append(TK_COLUMNKW, None)?; diff --git a/parser/src/lexer.rs b/parser/src/lexer.rs index 1ea608e14..70240a42d 100644 --- a/parser/src/lexer.rs +++ b/parser/src/lexer.rs @@ -17,7 +17,7 @@ pub fn is_identifier_continue(b: u8) -> bool { || b > b'\x7F' } -#[derive(Clone, PartialEq, Eq)] // do not derive Copy for Token, just use .clone() when needed +#[derive(Clone, PartialEq, Eq, Debug)] // do not derive Copy for Token, just use .clone() when needed pub struct Token<'a> { pub value: &'a [u8], pub token_type: Option, // None means Token is whitespaces or comments diff --git a/parser/src/parser.rs b/parser/src/parser.rs index 124058fc9..4de88dbd7 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -425,7 +425,8 @@ impl<'a> Parser<'a> { } TK_COLUMNKW => { let prev_tt = self.current_token.token_type.unwrap_or(TK_EOF); - let can_be_columnkw = matches!(prev_tt, TK_ADD | TK_RENAME | TK_DROP); + let can_be_columnkw = + matches!(prev_tt, TK_ADD | TK_RENAME | TK_DROP | TK_ALTER); if !can_be_columnkw { tok.token_type = Some(TK_ID); @@ -3437,7 +3438,7 @@ impl<'a> Parser<'a> { eat_assert!(self, TK_ALTER); eat_expect!(self, TK_TABLE); let tbl_name = self.parse_fullname(false)?; - let tok = eat_expect!(self, TK_ADD, TK_DROP, TK_RENAME); + let tok = eat_expect!(self, TK_ADD, TK_DROP, TK_RENAME, TK_ALTER); match tok.token_type.unwrap() { TK_ADD => { @@ -3488,6 +3489,19 @@ impl<'a> Parser<'a> { })) } } + TK_ALTER => { + eat_expect!(self, TK_COLUMNKW); + let col_name = self.parse_nm()?; + + eat_expect!(self, TK_TO); + + let new = self.parse_column_definition(true)?; + + Ok(Stmt::AlterTable(AlterTable { + name: tbl_name, + body: AlterTableBody::AlterColumn { old: col_name, new }, + })) + } _ => unreachable!(), } } @@ -9855,6 +9869,24 @@ mod tests { }), }))], ), + ( + b"ALTER TABLE foo ALTER COLUMN bar TO baz INTEGER".as_slice(), + vec![Cmd::Stmt(Stmt::AlterTable (AlterTable { + name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None }, + body: AlterTableBody::AlterColumn { + old: Name::Ident("bar".to_owned()), + new: ColumnDefinition { + col_name: Name::Ident("baz".to_owned()), + col_type: Some(Type { + name: "INTEGER".to_owned(), + size: None, + }), + constraints: vec![], + }, + + }, + }))], + ), // parse create index ( b"CREATE INDEX idx_foo ON foo (bar)".as_slice(),