diff --git a/src/binder/drop_view.rs b/src/binder/drop_view.rs new file mode 100644 index 00000000..9707f139 --- /dev/null +++ b/src/binder/drop_view.rs @@ -0,0 +1,26 @@ +use crate::binder::{lower_case_name, Binder}; +use crate::errors::DatabaseError; +use crate::planner::operator::drop_view::DropViewOperator; +use crate::planner::operator::Operator; +use crate::planner::LogicalPlan; +use crate::storage::Transaction; +use sqlparser::ast::ObjectName; +use std::sync::Arc; + +impl Binder<'_, '_, T> { + pub(crate) fn bind_drop_view( + &mut self, + name: &ObjectName, + if_exists: &bool, + ) -> Result { + let view_name = Arc::new(lower_case_name(name)?); + + Ok(LogicalPlan::new( + Operator::DropView(DropViewOperator { + view_name, + if_exists: *if_exists, + }), + vec![], + )) + } +} diff --git a/src/binder/mod.rs b/src/binder/mod.rs index 6c45ea9e..9114eefb 100644 --- a/src/binder/mod.rs +++ b/src/binder/mod.rs @@ -9,6 +9,7 @@ mod delete; mod describe; mod distinct; mod drop_table; +mod drop_view; mod explain; pub mod expr; mod insert; @@ -226,17 +227,11 @@ impl<'a, T: Transaction> BinderContext<'a, T> { pub fn view(&self, view_name: TableName) -> Result, DatabaseError> { if let Some(real_name) = self.table_aliases.get(view_name.as_ref()) { - self.transaction.view( - self.view_cache, - real_name.clone(), - (self.transaction, self.table_cache), - ) + self.transaction + .view(self.table_cache, self.view_cache, real_name.clone()) } else { - self.transaction.view( - self.view_cache, - view_name.clone(), - (self.transaction, self.table_cache), - ) + self.transaction + .view(self.table_cache, self.view_cache, view_name.clone()) } } @@ -259,17 +254,11 @@ impl<'a, T: Transaction> BinderContext<'a, T> { if source.is_none() && !only_table { source = if let Some(real_name) = self.table_aliases.get(table_name.as_ref()) { - self.transaction.view( - self.view_cache, - real_name.clone(), - (self.transaction, self.table_cache), - ) + self.transaction + .view(self.table_cache, self.view_cache, real_name.clone()) } else { - self.transaction.view( - self.view_cache, - table_name.clone(), - (self.transaction, self.table_cache), - ) + self.transaction + .view(self.table_cache, self.view_cache, table_name.clone()) }? .map(Source::View); } @@ -361,7 +350,10 @@ impl<'a, 'b, T: Transaction> Binder<'a, 'b, T> { if_exists, .. } => match object_type { + // todo handle all names ObjectType::Table => self.bind_drop_table(&names[0], if_exists)?, + // todo handle all names + ObjectType::View => self.bind_drop_view(&names[0], if_exists)?, _ => todo!(), }, Statement::Insert { diff --git a/src/errors.rs b/src/errors.rs index 86f0f48d..f5d7e753 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -163,4 +163,6 @@ pub enum DatabaseError { ValuesLenMismatch(usize, usize), #[error("the view already exists")] ViewExists, + #[error("the view not found")] + ViewNotFound, } diff --git a/src/execution/ddl/drop_view.rs b/src/execution/ddl/drop_view.rs new file mode 100644 index 00000000..798d7284 --- /dev/null +++ b/src/execution/ddl/drop_view.rs @@ -0,0 +1,42 @@ +use crate::execution::{Executor, WriteExecutor}; +use crate::planner::operator::drop_view::DropViewOperator; +use crate::storage::{StatisticsMetaCache, TableCache, Transaction, ViewCache}; +use crate::throw; +use crate::types::tuple_builder::TupleBuilder; + +pub struct DropView { + op: DropViewOperator, +} + +impl From for DropView { + fn from(op: DropViewOperator) -> Self { + DropView { op } + } +} + +impl<'a, T: Transaction + 'a> WriteExecutor<'a, T> for DropView { + fn execute_mut( + self, + (table_cache, view_cache, _): (&'a TableCache, &'a ViewCache, &'a StatisticsMetaCache), + transaction: &'a mut T, + ) -> Executor<'a> { + Box::new( + #[coroutine] + move || { + let DropViewOperator { + view_name, + if_exists, + } = self.op; + + throw!(transaction.drop_view( + view_cache, + table_cache, + view_name.clone(), + if_exists + )); + + yield Ok(TupleBuilder::build_result(format!("{}", view_name))); + }, + ) + } +} diff --git a/src/execution/ddl/mod.rs b/src/execution/ddl/mod.rs index 5ead54b6..23769f7c 100644 --- a/src/execution/ddl/mod.rs +++ b/src/execution/ddl/mod.rs @@ -2,6 +2,7 @@ pub mod add_column; pub(crate) mod create_index; pub(crate) mod create_table; pub(crate) mod create_view; -pub mod drop_column; +pub(crate) mod drop_column; pub(crate) mod drop_table; +pub(crate) mod drop_view; pub(crate) mod truncate; diff --git a/src/execution/mod.rs b/src/execution/mod.rs index 24fa8195..a6182f0c 100644 --- a/src/execution/mod.rs +++ b/src/execution/mod.rs @@ -11,6 +11,7 @@ use crate::execution::ddl::create_table::CreateTable; use crate::execution::ddl::create_view::CreateView; use crate::execution::ddl::drop_column::DropColumn; use crate::execution::ddl::drop_table::DropTable; +use crate::execution::ddl::drop_view::DropView; use crate::execution::ddl::truncate::Truncate; use crate::execution::dml::analyze::Analyze; use crate::execution::dml::copy_from_file::CopyFromFile; @@ -192,6 +193,7 @@ pub fn build_write<'a, T: Transaction + 'a>( } Operator::CreateView(op) => CreateView::from(op).execute_mut(cache, transaction), Operator::DropTable(op) => DropTable::from(op).execute_mut(cache, transaction), + Operator::DropView(op) => DropView::from(op).execute_mut(cache, transaction), Operator::Truncate(op) => Truncate::from(op).execute_mut(cache, transaction), Operator::CopyFromFile(op) => CopyFromFile::from(op).execute_mut(cache, transaction), #[warn(unused_assignments)] diff --git a/src/optimizer/rule/normalization/column_pruning.rs b/src/optimizer/rule/normalization/column_pruning.rs index 0dddba5c..cbdb5d25 100644 --- a/src/optimizer/rule/normalization/column_pruning.rs +++ b/src/optimizer/rule/normalization/column_pruning.rs @@ -147,6 +147,7 @@ impl ColumnPruning { | Operator::CreateIndex(_) | Operator::CreateView(_) | Operator::DropTable(_) + | Operator::DropView(_) | Operator::Truncate(_) | Operator::Show | Operator::CopyFromFile(_) diff --git a/src/optimizer/rule/normalization/compilation_in_advance.rs b/src/optimizer/rule/normalization/compilation_in_advance.rs index 8d5faddb..63afe35e 100644 --- a/src/optimizer/rule/normalization/compilation_in_advance.rs +++ b/src/optimizer/rule/normalization/compilation_in_advance.rs @@ -102,6 +102,7 @@ impl ExpressionRemapper { | Operator::CreateIndex(_) | Operator::CreateView(_) | Operator::DropTable(_) + | Operator::DropView(_) | Operator::Truncate(_) | Operator::CopyFromFile(_) | Operator::CopyToFile(_) @@ -208,6 +209,7 @@ impl EvaluatorBind { | Operator::CreateIndex(_) | Operator::CreateView(_) | Operator::DropTable(_) + | Operator::DropView(_) | Operator::Truncate(_) | Operator::CopyFromFile(_) | Operator::CopyToFile(_) diff --git a/src/planner/mod.rs b/src/planner/mod.rs index a1087f78..8d2ca2dd 100644 --- a/src/planner/mod.rs +++ b/src/planner/mod.rs @@ -156,6 +156,9 @@ impl LogicalPlan { Operator::DropTable(_) => SchemaOutput::Schema(vec![ColumnRef::from( ColumnCatalog::new_dummy("DROP TABLE SUCCESS".to_string()), )]), + Operator::DropView(_) => SchemaOutput::Schema(vec![ColumnRef::from( + ColumnCatalog::new_dummy("DROP VIEW SUCCESS".to_string()), + )]), Operator::Truncate(_) => SchemaOutput::Schema(vec![ColumnRef::from( ColumnCatalog::new_dummy("TRUNCATE TABLE SUCCESS".to_string()), )]), diff --git a/src/planner/operator/drop_view.rs b/src/planner/operator/drop_view.rs new file mode 100644 index 00000000..ee6d0d15 --- /dev/null +++ b/src/planner/operator/drop_view.rs @@ -0,0 +1,23 @@ +use crate::catalog::TableName; +use fnck_sql_serde_macros::ReferenceSerialization; +use std::fmt; +use std::fmt::Formatter; + +#[derive(Debug, PartialEq, Eq, Clone, Hash, ReferenceSerialization)] +pub struct DropViewOperator { + /// Table name to insert to + pub view_name: TableName, + pub if_exists: bool, +} + +impl fmt::Display for DropViewOperator { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!( + f, + "Drop View {}, If Exists: {}", + self.view_name, self.if_exists + )?; + + Ok(()) + } +} diff --git a/src/planner/operator/mod.rs b/src/planner/operator/mod.rs index 467b3883..b4462cd3 100644 --- a/src/planner/operator/mod.rs +++ b/src/planner/operator/mod.rs @@ -9,6 +9,7 @@ pub mod create_view; pub mod delete; pub mod describe; pub mod drop_table; +pub mod drop_view; pub mod filter; pub mod function_scan; pub mod insert; @@ -39,6 +40,7 @@ use crate::planner::operator::create_view::CreateViewOperator; use crate::planner::operator::delete::DeleteOperator; use crate::planner::operator::describe::DescribeOperator; use crate::planner::operator::drop_table::DropTableOperator; +use crate::planner::operator::drop_view::DropViewOperator; use crate::planner::operator::function_scan::FunctionScanOperator; use crate::planner::operator::insert::InsertOperator; use crate::planner::operator::join::JoinCondition; @@ -81,6 +83,7 @@ pub enum Operator { CreateIndex(CreateIndexOperator), CreateView(CreateViewOperator), DropTable(DropTableOperator), + DropView(DropViewOperator), Truncate(TruncateOperator), // Copy CopyFromFile(CopyFromFileOperator), @@ -169,6 +172,7 @@ impl Operator { | Operator::CreateIndex(_) | Operator::CreateView(_) | Operator::DropTable(_) + | Operator::DropView(_) | Operator::Truncate(_) | Operator::CopyFromFile(_) | Operator::CopyToFile(_) => None, @@ -246,6 +250,7 @@ impl Operator { | Operator::CreateIndex(_) | Operator::CreateView(_) | Operator::DropTable(_) + | Operator::DropView(_) | Operator::Truncate(_) | Operator::CopyFromFile(_) | Operator::CopyToFile(_) => vec![], @@ -279,6 +284,7 @@ impl fmt::Display for Operator { Operator::CreateIndex(op) => write!(f, "{}", op), Operator::CreateView(op) => write!(f, "{}", op), Operator::DropTable(op) => write!(f, "{}", op), + Operator::DropView(op) => write!(f, "{}", op), Operator::Truncate(op) => write!(f, "{}", op), Operator::CopyFromFile(op) => write!(f, "{}", op), Operator::CopyToFile(_) => todo!(), diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 22dfb671..a91891a0 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -345,6 +345,30 @@ pub trait Transaction: Sized { Ok(table_name) } + fn drop_view( + &mut self, + view_cache: &ViewCache, + table_cache: &TableCache, + view_name: TableName, + if_exists: bool, + ) -> Result<(), DatabaseError> { + if self + .view(table_cache, view_cache, view_name.clone())? + .is_none() + { + if if_exists { + return Ok(()); + } else { + return Err(DatabaseError::ViewNotFound); + } + } + + self.remove(&TableCodec::encode_view_key(view_name.as_str()))?; + view_cache.remove(&view_name); + + Ok(()) + } + fn drop_table( &mut self, table_cache: &TableCache, @@ -387,9 +411,9 @@ pub trait Transaction: Sized { fn view<'a>( &'a self, + table_cache: &'a TableCache, view_cache: &'a ViewCache, view_name: TableName, - drive: (&Self, &TableCache), ) -> Result, DatabaseError> { if let Some(view) = view_cache.get(&view_name) { return Ok(Some(view)); @@ -398,7 +422,7 @@ pub trait Transaction: Sized { return Ok(None); }; Ok(Some(view_cache.get_or_insert(view_name.clone(), |_| { - TableCodec::decode_view(&bytes, drive) + TableCodec::decode_view(&bytes, (self, table_cache)) })?)) } @@ -1623,9 +1647,9 @@ mod test { &view, transaction .view( + &table_state.table_cache, &table_state.view_cache, view_name.clone(), - (&transaction, &table_state.table_cache) )? .unwrap() ); @@ -1633,17 +1657,28 @@ mod test { &view, transaction .view( + &Arc::new(SharedLruCache::new(4, 1, RandomState::new())?), &table_state.view_cache, view_name.clone(), - ( - &transaction, - &Arc::new(SharedLruCache::new(4, 1, RandomState::new())?) - ) )? .unwrap() ); - // TODO: Drop View + transaction.drop_view( + &table_state.view_cache, + &table_state.table_cache, + view_name.clone(), + false, + )?; + transaction.drop_view( + &table_state.view_cache, + &table_state.table_cache, + view_name.clone(), + true, + )?; + assert!(transaction + .view(&table_state.table_cache, &table_state.view_cache, view_name)? + .is_none()); Ok(()) } diff --git a/tests/slt/crdb/delete.slt b/tests/slt/crdb/delete.slt index 32bc80a1..a8acb851 100644 --- a/tests/slt/crdb/delete.slt +++ b/tests/slt/crdb/delete.slt @@ -24,9 +24,8 @@ SELECT * FROM kv 5 6 7 8 -# TODO: Drop View -# statement ok -# drop view if exists kview +statement ok +drop view if exists kview statement ok CREATE VIEW kview AS SELECT k,v FROM kv diff --git a/tests/slt/sql_2016/F031_16.slt b/tests/slt/sql_2016/F031_16.slt index 92ef25dc..41dc3de6 100644 --- a/tests/slt/sql_2016/F031_16.slt +++ b/tests/slt/sql_2016/F031_16.slt @@ -1,11 +1,10 @@ # F031-16: DROP VIEW statement: RESTRICT clause -# TODO: Support `DROP VIEW` - statement ok CREATE TABLE TABLE_F031_16_01_01 ( ID INT PRIMARY KEY, A INTEGER ); statement ok CREATE VIEW VIEW_F031_16_01_01 AS SELECT A FROM TABLE_F031_16_01_01; -# DROP VIEW VIEW_F031_16_01_01 +statement ok +DROP VIEW VIEW_F031_16_01_01