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:
LFC
2022-09-06 13:44:34 +08:00
committed by GitHub
parent 119ff2fc2e
commit 5e67301c00
28 changed files with 956 additions and 216 deletions

View File

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

View File

@@ -1,3 +1,4 @@
mod alter_parser;
pub(crate) mod create_parser;
pub(crate) mod insert_parser;
pub(crate) mod query_parser;

View 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!(),
}
}
}

View File

@@ -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"));
}
}

View File

@@ -1,3 +1,4 @@
pub mod alter;
pub mod create_table;
pub mod insert;
pub mod query;

View 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 },
}

View File

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