feat: Add DROP DEFAULT (#6290)

* feat: Add `DROP DEFAULT`

Signed-off-by: Yihai Lin <yihai-lin@foxmail.com>

* chore: use `next_token`

Signed-off-by: Yihai Lin <yihai-lin@foxmail.com>

---------

Signed-off-by: Yihai Lin <yihai-lin@foxmail.com>
This commit is contained in:
Lin Yihai
2025-06-17 17:33:56 +08:00
committed by GitHub
parent 50e4c916e7
commit 438791b3e4
14 changed files with 474 additions and 11 deletions

View File

@@ -30,7 +30,7 @@ use crate::parsers::utils::{
};
use crate::statements::alter::{
AddColumn, AlterDatabase, AlterDatabaseOperation, AlterTable, AlterTableOperation,
KeyValueOption, SetIndexOperation, UnsetIndexOperation,
DropDefaultsOperation, KeyValueOption, SetIndexOperation, UnsetIndexOperation,
};
use crate::statements::statement::Statement;
use crate::util::parse_option_string;
@@ -156,6 +156,7 @@ impl ParserContext<'_> {
.collect();
AlterTableOperation::SetTableOptions { options }
}
Keyword::ALTER => self.parse_alter_columns()?,
_ => self.expected(
"ADD or DROP or MODIFY or RENAME or SET after ALTER TABLE",
self.parser.peek_token(),
@@ -168,6 +169,29 @@ impl ParserContext<'_> {
Ok(AlterTable::new(table_name, alter_operation))
}
// Parse the following: ALTER TABLE table_name ALTER ...
fn parse_alter_columns(&mut self) -> Result<AlterTableOperation> {
let _ = self.parser.next_token();
let _ = self.parser.next_token();
let ts = self.parser.next_token();
match ts.token {
// Parse `DROP DEFAULT`: ALTER TABLE `table_name` ALTER `a` DROP DEFAULT, ALTER `b` DROP DEFAULT, ...
Token::Word(w) if w.keyword == Keyword::DROP => {
let ts = self.parser.peek_token();
match ts.token {
Token::Word(w) if w.keyword == Keyword::DEFAULT => {
self.parser.prev_token();
self.parser.prev_token();
self.parser.prev_token();
self.parse_alter_table_drop_default()
}
_ => self.expected("DEFAULT is expecting after DROP", ts),
}
}
_ => self.expected("DROP after ALTER COLUMN", ts),
}
}
fn parse_alter_table_unset(&mut self) -> Result<AlterTableOperation> {
let _ = self.parser.next_token();
let keys = self
@@ -198,6 +222,14 @@ impl ParserContext<'_> {
}
}
fn parse_alter_table_drop_default(&mut self) -> Result<AlterTableOperation> {
let columns = self
.parser
.parse_comma_separated(parse_alter_column_drop_default)
.context(error::SyntaxSnafu)?;
Ok(AlterTableOperation::DropDefaults { columns })
}
fn parse_alter_table_modify(&mut self) -> Result<AlterTableOperation> {
let _ = self.parser.next_token();
self.parser
@@ -385,6 +417,23 @@ impl ParserContext<'_> {
}
}
fn parse_alter_column_drop_default(
parser: &mut Parser,
) -> std::result::Result<DropDefaultsOperation, ParserError> {
parser.next_token();
let column_name = ParserContext::canonicalize_identifier(parser.parse_identifier()?);
if parser.parse_keywords(&[Keyword::DROP, Keyword::DEFAULT]) {
Ok(DropDefaultsOperation(column_name))
} else {
let not_drop = parser.peek_token();
parser.next_token();
let not_default = parser.peek_token();
Err(ParserError::ParserError(format!(
"Unexpected keyword, expect DROP DEFAULT, got: `{not_drop} {not_default}`"
)))
}
}
/// Parses a string literal and an optional string literal value.
fn parse_string_options(parser: &mut Parser) -> std::result::Result<(String, String), ParserError> {
let name = parser.parse_literal_string()?;
@@ -1125,4 +1174,42 @@ mod tests {
}
}
}
#[test]
fn test_parse_alter_drop_default() {
let columns = vec![vec!["a"], vec!["a", "b", "c"]];
for col in columns {
let sql = col
.iter()
.map(|x| format!("ALTER {x} DROP DEFAULT"))
.collect::<Vec<String>>()
.join(",");
let sql = format!("ALTER TABLE test_table {sql}");
let mut result = ParserContext::create_with_dialect(
&sql,
&GreptimeDbDialect {},
ParseOptions::default(),
)
.unwrap();
assert_eq!(1, result.len());
let statement = result.remove(0);
assert_matches!(statement, Statement::AlterTable { .. });
match statement {
Statement::AlterTable(alter_table) => {
assert_eq!("test_table", alter_table.table_name().0[0].value);
let alter_operation = alter_table.alter_operation();
match alter_operation {
AlterTableOperation::DropDefaults { columns } => {
assert_eq!(col.len(), columns.len());
for i in 0..columns.len() {
assert_eq!(col[i], columns[i].0.value);
}
}
_ => unreachable!(),
}
}
_ => unreachable!(),
}
}
}
}

View File

@@ -92,8 +92,15 @@ pub enum AlterTableOperation {
UnsetIndex {
options: UnsetIndexOperation,
},
DropDefaults {
columns: Vec<DropDefaultsOperation>,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
/// `ALTER <column_name> DROP DEFAULT`
pub struct DropDefaultsOperation(pub Ident);
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
pub enum SetIndexOperation {
/// `MODIFY COLUMN <column_name> SET FULLTEXT INDEX [WITH <options>]`
@@ -204,6 +211,13 @@ impl Display for AlterTableOperation {
write!(f, "MODIFY COLUMN {column_name} UNSET SKIPPING INDEX")
}
},
AlterTableOperation::DropDefaults { columns } => {
let columns = columns
.iter()
.map(|column| format!("ALTER {} DROP DEFAULT", column.0))
.join(", ");
write!(f, "{columns}")
}
}
}
}
@@ -487,5 +501,26 @@ ALTER TABLE monitor MODIFY COLUMN a SET INVERTED INDEX"#,
unreachable!();
}
}
let sql = "ALTER TABLE monitor ALTER a DROP DEFAULT";
let stmts =
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
.unwrap();
assert_eq!(1, stmts.len());
assert_matches!(&stmts[0], Statement::AlterTable { .. });
match &stmts[0] {
Statement::AlterTable(set) => {
let new_sql = format!("\n{}", set);
assert_eq!(
r#"
ALTER TABLE monitor ALTER a DROP DEFAULT"#,
&new_sql
);
}
_ => {
unreachable!();
}
}
}
}