mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-05-26 01:40:36 +00:00
feat: implement alter table (#218)
* feat: implement alter table * Currently we have no plans to support altering the primary keys (maybe never), so removed the related codes. * make `alter` a trait function in table * address other CR comments * cleanup * rebase develop * resolve code review comments Co-authored-by: luofucong <luofucong@greptime.com>
This commit is contained in:
@@ -77,6 +77,8 @@ impl<'a> ParserContext<'a> {
|
||||
|
||||
Keyword::SELECT | Keyword::WITH | Keyword::VALUES => self.parse_query(),
|
||||
|
||||
Keyword::ALTER => self.parse_alter(),
|
||||
|
||||
// todo(hl) support more statements.
|
||||
_ => self.unsupported(self.peek_token_as_string()),
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
mod alter_parser;
|
||||
pub(crate) mod create_parser;
|
||||
pub(crate) mod insert_parser;
|
||||
pub(crate) mod query_parser;
|
||||
|
||||
79
src/sql/src/parsers/alter_parser.rs
Normal file
79
src/sql/src/parsers/alter_parser.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use snafu::ResultExt;
|
||||
use sqlparser::keywords::Keyword;
|
||||
use sqlparser::parser::ParserError;
|
||||
|
||||
use crate::error;
|
||||
use crate::parser::ParserContext;
|
||||
use crate::parser::Result;
|
||||
use crate::statements::alter::{AlterTable, AlterTableOperation};
|
||||
use crate::statements::statement::Statement;
|
||||
|
||||
impl<'a> ParserContext<'a> {
|
||||
pub(crate) fn parse_alter(&mut self) -> Result<Statement> {
|
||||
let alter_table = self.parse().context(error::SyntaxSnafu { sql: self.sql })?;
|
||||
Ok(Statement::Alter(alter_table))
|
||||
}
|
||||
|
||||
fn parse(&mut self) -> std::result::Result<AlterTable, ParserError> {
|
||||
let parser = &mut self.parser;
|
||||
parser.expect_keywords(&[Keyword::ALTER, Keyword::TABLE])?;
|
||||
|
||||
let table_name = parser.parse_object_name()?;
|
||||
|
||||
let alter_operation = if parser.parse_keyword(Keyword::ADD) {
|
||||
if let Some(constraint) = parser.parse_optional_table_constraint()? {
|
||||
AlterTableOperation::AddConstraint(constraint)
|
||||
} else {
|
||||
let _ = parser.parse_keyword(Keyword::COLUMN);
|
||||
let column_def = parser.parse_column_def()?;
|
||||
AlterTableOperation::AddColumn { column_def }
|
||||
}
|
||||
} else {
|
||||
return Err(ParserError::ParserError(format!(
|
||||
"expect ADD or DROP after ALTER TABLE, found {}",
|
||||
parser.peek_token()
|
||||
)));
|
||||
};
|
||||
Ok(AlterTable::new(table_name, alter_operation))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::assert_matches::assert_matches;
|
||||
|
||||
use sqlparser::ast::{ColumnOption, DataType};
|
||||
use sqlparser::dialect::GenericDialect;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_alter_add_column() {
|
||||
let sql = "ALTER TABLE my_metric_1 ADD tagk_i STRING Null;";
|
||||
let mut result = ParserContext::create_with_dialect(sql, &GenericDialect {}).unwrap();
|
||||
assert_eq!(1, result.len());
|
||||
|
||||
let statement = result.remove(0);
|
||||
assert_matches!(statement, Statement::Alter { .. });
|
||||
match statement {
|
||||
Statement::Alter(alter_table) => {
|
||||
assert_eq!("my_metric_1", alter_table.table_name().0[0].value);
|
||||
|
||||
let alter_operation = alter_table.alter_operation();
|
||||
assert_matches!(alter_operation, AlterTableOperation::AddColumn { .. });
|
||||
match alter_operation {
|
||||
AlterTableOperation::AddColumn { column_def } => {
|
||||
assert_eq!("tagk_i", column_def.name.value);
|
||||
assert_eq!(DataType::String, column_def.data_type);
|
||||
assert!(column_def
|
||||
.options
|
||||
.iter()
|
||||
.any(|o| matches!(o.option, ColumnOption::Null)));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ impl<'a> ParserContext<'a> {
|
||||
mod tests {
|
||||
use sqlparser::dialect::GenericDialect;
|
||||
|
||||
use super::*;
|
||||
use crate::parser::ParserContext;
|
||||
|
||||
#[test]
|
||||
@@ -36,19 +35,13 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_parser_invalid_query() {
|
||||
// sql without selection
|
||||
let sql = "SELECT FROM table_1";
|
||||
|
||||
let parser = ParserContext::create_with_dialect(sql, &GenericDialect {}).unwrap();
|
||||
match &parser[0] {
|
||||
Statement::ShowDatabases(_) => {
|
||||
panic!("Not expected to be a show database statement")
|
||||
}
|
||||
Statement::Insert(_) => {
|
||||
panic!("Not expected to be a show database statement")
|
||||
}
|
||||
Statement::Create(_) | Statement::Query(_) => {}
|
||||
}
|
||||
pub fn test_parse_invalid_query() {
|
||||
let sql = "SELECT * FROM table_1 WHERE";
|
||||
let result = ParserContext::create_with_dialect(sql, &GenericDialect {});
|
||||
assert!(result.is_err());
|
||||
assert!(result
|
||||
.unwrap_err()
|
||||
.to_string()
|
||||
.contains("Expected an expression"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod alter;
|
||||
pub mod create_table;
|
||||
pub mod insert;
|
||||
pub mod query;
|
||||
|
||||
32
src/sql/src/statements/alter.rs
Normal file
32
src/sql/src/statements/alter.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use sqlparser::ast::{ColumnDef, ObjectName, TableConstraint};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct AlterTable {
|
||||
table_name: ObjectName,
|
||||
alter_operation: AlterTableOperation,
|
||||
}
|
||||
|
||||
impl AlterTable {
|
||||
pub(crate) fn new(table_name: ObjectName, alter_operation: AlterTableOperation) -> Self {
|
||||
Self {
|
||||
table_name,
|
||||
alter_operation,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn table_name(&self) -> &ObjectName {
|
||||
&self.table_name
|
||||
}
|
||||
|
||||
pub fn alter_operation(&self) -> &AlterTableOperation {
|
||||
&self.alter_operation
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum AlterTableOperation {
|
||||
/// `ADD <table_constraint>`
|
||||
AddConstraint(TableConstraint),
|
||||
/// `ADD [ COLUMN ] <column_def>`
|
||||
AddColumn { column_def: ColumnDef },
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use sqlparser::ast::Statement as SpStatement;
|
||||
use sqlparser::parser::ParserError;
|
||||
|
||||
use crate::statements::alter::AlterTable;
|
||||
use crate::statements::create_table::CreateTable;
|
||||
use crate::statements::insert::Insert;
|
||||
use crate::statements::query::Query;
|
||||
@@ -20,6 +21,9 @@ pub enum Statement {
|
||||
|
||||
/// CREATE TABLE
|
||||
Create(CreateTable),
|
||||
|
||||
/// ALTER TABLE
|
||||
Alter(AlterTable),
|
||||
}
|
||||
|
||||
/// Converts Statement to sqlparser statement
|
||||
@@ -33,7 +37,7 @@ impl TryFrom<Statement> for SpStatement {
|
||||
)),
|
||||
Statement::Query(s) => Ok(SpStatement::Query(Box::new(s.inner))),
|
||||
Statement::Insert(i) => Ok(i.inner),
|
||||
Statement::Create(_) => unimplemented!(),
|
||||
Statement::Create(_) | Statement::Alter(_) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user