feat(parser): add ALTER COLUMN

This commit is contained in:
Levy A.
2025-08-27 15:45:03 -03:00
parent e1b5f2d948
commit 678ca8d33b
5 changed files with 47 additions and 3 deletions

View File

@@ -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

View File

@@ -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)?;

View File

@@ -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<TokenType>, // None means Token is whitespaces or comments

View File

@@ -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(),