feat: impl drop view (#4231)

* feat: impl drop view

* fix: metric name

* fix: comments

* test: add DropViewProcedure test

* test: drop view meets a table

* test: update sqlness tests by drop view

* feat: apply suggestion from AI

* chore: apply suggestion

Co-authored-by: Jeremyhi <jiachun_feng@proton.me>

* chore: apply suggestion

Co-authored-by: Jeremyhi <jiachun_feng@proton.me>

* chore: apply suggestion

Co-authored-by: Jeremyhi <jiachun_feng@proton.me>

* fix: TYPE_NAME for DropFlowProcedure

---------

Co-authored-by: Jeremyhi <jiachun_feng@proton.me>
This commit is contained in:
dennis zhuang
2024-07-11 12:53:54 -07:00
committed by GitHub
parent 7ad248d6f6
commit ab22bbac84
25 changed files with 830 additions and 137 deletions

View File

@@ -16,9 +16,9 @@ use snafu::{ensure, ResultExt};
use sqlparser::dialect::keywords::Keyword;
use sqlparser::tokenizer::Token;
use crate::error::{self, InvalidTableNameSnafu, Result};
use crate::error::{self, InvalidFlowNameSnafu, InvalidTableNameSnafu, Result};
use crate::parser::{ParserContext, FLOW};
use crate::statements::drop::{DropDatabase, DropFlow, DropTable};
use crate::statements::drop::{DropDatabase, DropFlow, DropTable, DropView};
use crate::statements::statement::Statement;
/// DROP statement parser implementation
@@ -28,6 +28,7 @@ impl<'a> ParserContext<'a> {
match self.parser.peek_token().token {
Token::Word(w) => match w.keyword {
Keyword::TABLE => self.parse_drop_table(),
Keyword::VIEW => self.parse_drop_view(),
Keyword::SCHEMA | Keyword::DATABASE => self.parse_drop_database(),
Keyword::NoKeyword => {
let uppercase = w.value.to_uppercase();
@@ -42,6 +43,31 @@ impl<'a> ParserContext<'a> {
}
}
fn parse_drop_view(&mut self) -> Result<Statement> {
let _ = self.parser.next_token();
let if_exists = self.parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
let raw_view_ident = self
.parse_object_name()
.with_context(|_| error::UnexpectedSnafu {
sql: self.sql,
expected: "a view name",
actual: self.peek_token_as_string(),
})?;
let view_ident = Self::canonicalize_object_name(raw_view_ident);
ensure!(
!view_ident.0.is_empty(),
InvalidTableNameSnafu {
name: view_ident.to_string()
}
);
Ok(Statement::DropView(DropView {
view_name: view_ident,
drop_if_exists: if_exists,
}))
}
fn parse_drop_flow(&mut self) -> Result<Statement> {
let _ = self.parser.next_token();
@@ -56,7 +82,7 @@ impl<'a> ParserContext<'a> {
let flow_ident = Self::canonicalize_object_name(raw_flow_ident);
ensure!(
!flow_ident.0.is_empty(),
InvalidTableNameSnafu {
InvalidFlowNameSnafu {
name: flow_ident.to_string()
}
);
@@ -263,4 +289,53 @@ mod tests {
))
)
}
#[test]
pub fn test_drop_view() {
let sql = "DROP VIEW foo";
let result =
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
let mut stmts: Vec<Statement> = result.unwrap();
let stmt = stmts.pop().unwrap();
assert_eq!(
stmt,
Statement::DropView(DropView {
view_name: ObjectName(vec![Ident::new("foo")]),
drop_if_exists: false,
})
);
assert_eq!(sql, stmt.to_string());
let sql = "DROP VIEW greptime.public.foo";
let result =
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
let mut stmts: Vec<Statement> = result.unwrap();
let stmt = stmts.pop().unwrap();
assert_eq!(
stmt,
Statement::DropView(DropView {
view_name: ObjectName(vec![
Ident::new("greptime"),
Ident::new("public"),
Ident::new("foo")
]),
drop_if_exists: false,
})
);
assert_eq!(sql, stmt.to_string());
let sql = "DROP VIEW IF EXISTS foo";
let result =
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
let mut stmts: Vec<Statement> = result.unwrap();
let stmt = stmts.pop().unwrap();
assert_eq!(
stmt,
Statement::DropView(DropView {
view_name: ObjectName(vec![Ident::new("foo")]),
drop_if_exists: true,
})
);
assert_eq!(sql, stmt.to_string());
}
}

View File

@@ -137,6 +137,30 @@ impl Display for DropFlow {
}
}
/// `DROP VIEW` statement.
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
pub struct DropView {
// The view name
pub view_name: ObjectName,
// drop view if exists
pub drop_if_exists: bool,
}
impl Display for DropView {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"DROP VIEW{} {}",
if self.drop_if_exists {
" IF EXISTS"
} else {
""
},
self.view_name
)
}
}
#[cfg(test)]
mod tests {
use std::assert_matches::assert_matches;

View File

@@ -25,7 +25,7 @@ use crate::statements::create::{
};
use crate::statements::delete::Delete;
use crate::statements::describe::DescribeTable;
use crate::statements::drop::{DropDatabase, DropFlow, DropTable};
use crate::statements::drop::{DropDatabase, DropFlow, DropTable, DropView};
use crate::statements::explain::Explain;
use crate::statements::insert::Insert;
use crate::statements::query::Query;
@@ -55,14 +55,16 @@ pub enum Statement {
CreateTableLike(CreateTableLike),
// CREATE FLOW
CreateFlow(CreateFlow),
// DROP FLOW
DropFlow(DropFlow),
// CREATE VIEW ... AS
CreateView(CreateView),
// DROP TABLE
DropTable(DropTable),
// DROP DATABASE
DropDatabase(DropDatabase),
// DROP FLOW
DropFlow(DropFlow),
// DROP View
DropView(DropView),
// CREATE DATABASE
CreateDatabase(CreateDatabase),
/// ALTER TABLE
@@ -119,6 +121,7 @@ impl Display for Statement {
Statement::DropFlow(s) => s.fmt(f),
Statement::DropTable(s) => s.fmt(f),
Statement::DropDatabase(s) => s.fmt(f),
Statement::DropView(s) => s.fmt(f),
Statement::CreateDatabase(s) => s.fmt(f),
Statement::Alter(s) => s.fmt(f),
Statement::ShowDatabases(s) => s.fmt(f),