This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-datafusion.git


The following commit(s) were added to refs/heads/master by this push:
     new 5621e3bbd implement `drop view` (#3267)
5621e3bbd is described below

commit 5621e3bbd050eeb79646240ec0a09426badfa162
Author: kmitchener <[email protected]>
AuthorDate: Sat Sep 3 05:25:52 2022 -0400

    implement `drop view` (#3267)
    
    * add initial support for 'drop view'
    
    * add tests
    
    * add very basic docs
    
    * add example to drop view doc
    
    * ran prettier on the doc
    
    * refactored, now done
    
    * removed typo
    
    * fix bad resolve merge conflict
---
 datafusion/core/src/execution/context.rs           |  93 ++++++++++++-------
 datafusion/core/src/physical_plan/planner.rs       |   2 +-
 datafusion/core/tests/sql/create_drop.rs           | 103 +++++++++++++++++++++
 datafusion/expr/src/logical_plan/mod.rs            |   8 +-
 datafusion/expr/src/logical_plan/plan.rs           |  28 +++++-
 datafusion/expr/src/utils.rs                       |   1 +
 .../optimizer/src/common_subexpr_eliminate.rs      |   1 +
 datafusion/optimizer/src/projection_push_down.rs   |   1 +
 datafusion/proto/src/logical_plan.rs               |   3 +
 datafusion/sql/src/planner.rs                      |  45 +++++----
 docs/source/user-guide/sql/ddl.md                  |  24 ++++-
 11 files changed, 243 insertions(+), 66 deletions(-)

diff --git a/datafusion/core/src/execution/context.rs 
b/datafusion/core/src/execution/context.rs
index 0b1618146..c5dcb7a59 100644
--- a/datafusion/core/src/execution/context.rs
+++ b/datafusion/core/src/execution/context.rs
@@ -102,7 +102,8 @@ use crate::variable::{VarProvider, VarType};
 use async_trait::async_trait;
 use chrono::{DateTime, Utc};
 use datafusion_common::ScalarValue;
-use datafusion_expr::TableSource;
+use datafusion_expr::logical_plan::DropView;
+use datafusion_expr::{TableSource, TableType};
 use datafusion_optimizer::decorrelate_where_exists::DecorrelateWhereExists;
 use datafusion_optimizer::decorrelate_where_in::DecorrelateWhereIn;
 use datafusion_optimizer::filter_null_join_keys::FilterNullJoinKeys;
@@ -269,10 +270,7 @@ impl SessionContext {
                 };
                 let table = self.table(name.as_str());
                 match (if_not_exists, table) {
-                    (true, Ok(_)) => {
-                        let plan = LogicalPlanBuilder::empty(false).build()?;
-                        Ok(Arc::new(DataFrame::new(self.state.clone(), &plan)))
-                    }
+                    (true, Ok(_)) => self.return_empty_dataframe(),
                     (_, Err(_)) => {
                         // TODO make schema in CreateExternalTable optional 
instead of empty
                         let provided_schema = if schema.fields().is_empty() {
@@ -294,8 +292,7 @@ impl SessionContext {
                             provided_schema,
                         )
                         .await?;
-                        let plan = LogicalPlanBuilder::empty(false).build()?;
-                        Ok(Arc::new(DataFrame::new(self.state.clone(), &plan)))
+                        self.return_empty_dataframe()
                     }
                     (false, Ok(_)) => Err(DataFusionError::Execution(format!(
                         "Table '{:?}' already exists",
@@ -313,10 +310,7 @@ impl SessionContext {
                 let table = self.table(name.as_str());
 
                 match (if_not_exists, or_replace, table) {
-                    (true, false, Ok(_)) => {
-                        let plan = LogicalPlanBuilder::empty(false).build()?;
-                        Ok(Arc::new(DataFrame::new(self.state.clone(), &plan)))
-                    }
+                    (true, false, Ok(_)) => self.return_empty_dataframe(),
                     (false, true, Ok(_)) => {
                         self.deregister_table(name.as_str())?;
                         let plan = self.optimize(&input)?;
@@ -371,16 +365,14 @@ impl SessionContext {
                             Arc::new(ViewTable::try_new((*input).clone(), 
definition)?);
 
                         self.register_table(name.as_str(), table)?;
-                        let plan = LogicalPlanBuilder::empty(false).build()?;
-                        Ok(Arc::new(DataFrame::new(self.state.clone(), &plan)))
+                        self.return_empty_dataframe()
                     }
                     (_, Err(_)) => {
                         let table =
                             Arc::new(ViewTable::try_new((*input).clone(), 
definition)?);
 
                         self.register_table(name.as_str(), table)?;
-                        let plan = LogicalPlanBuilder::empty(false).build()?;
-                        Ok(Arc::new(DataFrame::new(self.state.clone(), &plan)))
+                        self.return_empty_dataframe()
                     }
                     (false, Ok(_)) => Err(DataFusionError::Execution(format!(
                         "Table '{:?}' already exists",
@@ -392,15 +384,28 @@ impl SessionContext {
             LogicalPlan::DropTable(DropTable {
                 name, if_exists, ..
             }) => {
-                let returned = self.deregister_table(name.as_str())?;
-                if !if_exists && returned.is_none() {
-                    Err(DataFusionError::Execution(format!(
-                        "Memory table {:?} doesn't exist.",
+                let result = self.find_and_deregister(name.as_str(), 
TableType::Base);
+                match (result, if_exists) {
+                    (Ok(true), _) => self.return_empty_dataframe(),
+                    (_, true) => self.return_empty_dataframe(),
+                    (_, _) => Err(DataFusionError::Execution(format!(
+                        "Table {:?} doesn't exist.",
                         name
-                    )))
-                } else {
-                    let plan = LogicalPlanBuilder::empty(false).build()?;
-                    Ok(Arc::new(DataFrame::new(self.state.clone(), &plan)))
+                    ))),
+                }
+            }
+
+            LogicalPlan::DropView(DropView {
+                name, if_exists, ..
+            }) => {
+                let result = self.find_and_deregister(name.as_str(), 
TableType::View);
+                match (result, if_exists) {
+                    (Ok(true), _) => self.return_empty_dataframe(),
+                    (_, true) => self.return_empty_dataframe(),
+                    (_, _) => Err(DataFusionError::Execution(format!(
+                        "View {:?} doesn't exist.",
+                        name
+                    ))),
                 }
             }
             LogicalPlan::CreateCatalogSchema(CreateCatalogSchema {
@@ -429,15 +434,11 @@ impl SessionContext {
                 let schema = catalog.schema(schema_name);
 
                 match (if_not_exists, schema) {
-                    (true, Some(_)) => {
-                        let plan = LogicalPlanBuilder::empty(false).build()?;
-                        Ok(Arc::new(DataFrame::new(self.state.clone(), &plan)))
-                    }
+                    (true, Some(_)) => self.return_empty_dataframe(),
                     (true, None) | (false, None) => {
                         let schema = Arc::new(MemorySchemaProvider::new());
                         catalog.register_schema(schema_name, schema)?;
-                        let plan = LogicalPlanBuilder::empty(false).build()?;
-                        Ok(Arc::new(DataFrame::new(self.state.clone(), &plan)))
+                        self.return_empty_dataframe()
                     }
                     (false, Some(_)) => Err(DataFusionError::Execution(format!(
                         "Schema '{:?}' already exists",
@@ -453,18 +454,14 @@ impl SessionContext {
                 let catalog = self.catalog(catalog_name.as_str());
 
                 match (if_not_exists, catalog) {
-                    (true, Some(_)) => {
-                        let plan = LogicalPlanBuilder::empty(false).build()?;
-                        Ok(Arc::new(DataFrame::new(self.state.clone(), &plan)))
-                    }
+                    (true, Some(_)) => self.return_empty_dataframe(),
                     (true, None) | (false, None) => {
                         let new_catalog = 
Arc::new(MemoryCatalogProvider::new());
                         self.state
                             .write()
                             .catalog_list
                             .register_catalog(catalog_name, new_catalog);
-                        let plan = LogicalPlanBuilder::empty(false).build()?;
-                        Ok(Arc::new(DataFrame::new(self.state.clone(), &plan)))
+                        self.return_empty_dataframe()
                     }
                     (false, Some(_)) => Err(DataFusionError::Execution(format!(
                         "Catalog '{:?}' already exists",
@@ -477,6 +474,32 @@ impl SessionContext {
         }
     }
 
+    // return an empty dataframe
+    fn return_empty_dataframe(&self) -> Result<Arc<DataFrame>> {
+        let plan = LogicalPlanBuilder::empty(false).build()?;
+        Ok(Arc::new(DataFrame::new(self.state.clone(), &plan)))
+    }
+
+    fn find_and_deregister<'a>(
+        &self,
+        table_ref: impl Into<TableReference<'a>>,
+        table_type: TableType,
+    ) -> Result<bool> {
+        let table_ref = table_ref.into();
+        let table_provider = self
+            .state
+            .read()
+            .schema_for_ref(table_ref)?
+            .table(table_ref.table());
+
+        if let Some(table_provider) = table_provider {
+            if table_provider.table_type() == table_type {
+                self.deregister_table(table_ref)?;
+                return Ok(true);
+            }
+        }
+        Ok(false)
+    }
     /// Creates a logical plan.
     ///
     /// This function is intended for internal use and should not be called 
directly.
diff --git a/datafusion/core/src/physical_plan/planner.rs 
b/datafusion/core/src/physical_plan/planner.rs
index 2cdab3b0f..f727306ad 100644
--- a/datafusion/core/src/physical_plan/planner.rs
+++ b/datafusion/core/src/physical_plan/planner.rs
@@ -1042,7 +1042,7 @@ impl DefaultPhysicalPlanner {
                         "Unsupported logical plan: CreateCatalog".to_string(),
                     ))
                 }
-                | LogicalPlan::CreateMemoryTable(_) | LogicalPlan::DropTable 
(_) | LogicalPlan::CreateView(_) => {
+                | LogicalPlan::CreateMemoryTable(_) | 
LogicalPlan::DropTable(_) | LogicalPlan::DropView(_) | 
LogicalPlan::CreateView(_) => {
                     // Create a dummy exec.
                     Ok(Arc::new(EmptyExec::new(
                         false,
diff --git a/datafusion/core/tests/sql/create_drop.rs 
b/datafusion/core/tests/sql/create_drop.rs
index cca742c4a..820e570fa 100644
--- a/datafusion/core/tests/sql/create_drop.rs
+++ b/datafusion/core/tests/sql/create_drop.rs
@@ -112,6 +112,104 @@ async fn drop_table() -> Result<()> {
     Ok(())
 }
 
+#[tokio::test]
+async fn drop_view() -> Result<()> {
+    let ctx =
+        
SessionContext::with_config(SessionConfig::new().with_information_schema(true));
+    plan_and_collect(&ctx, "CREATE VIEW v AS SELECT 1").await?;
+    let rb = plan_and_collect(
+        &ctx,
+        "select * from information_schema.tables where table_name = 'v' and 
table_type = 'VIEW'",
+    )
+    .await?;
+    assert_eq!(rb[0].num_rows(), 1);
+
+    plan_and_collect(&ctx, "DROP VIEW v").await?;
+    let rb = plan_and_collect(
+        &ctx,
+        "select * from information_schema.tables where table_name = 'v' and 
table_type = 'VIEW'",
+    )
+    .await?;
+    assert!(rb.is_empty());
+    Ok(())
+}
+
+#[tokio::test]
+#[should_panic(expected = "doesn't exist")]
+async fn drop_view_nonexistent() {
+    let ctx = SessionContext::new();
+    ctx.sql("DROP VIEW non_existent_view")
+        .await
+        .unwrap()
+        .collect()
+        .await
+        .unwrap();
+}
+
+#[tokio::test]
+#[should_panic(expected = "doesn't exist")]
+async fn drop_view_cant_drop_table() {
+    let ctx = SessionContext::new();
+    ctx.sql("CREATE TABLE t AS SELECT 1")
+        .await
+        .unwrap()
+        .collect()
+        .await
+        .unwrap();
+    ctx.sql("DROP VIEW t")
+        .await
+        .unwrap()
+        .collect()
+        .await
+        .unwrap();
+}
+
+#[tokio::test]
+#[should_panic(expected = "doesn't exist")]
+async fn drop_table_cant_drop_view() {
+    let ctx = SessionContext::new();
+    ctx.sql("CREATE VIEW v AS SELECT 1")
+        .await
+        .unwrap()
+        .collect()
+        .await
+        .unwrap();
+    ctx.sql("DROP TABLE v")
+        .await
+        .unwrap()
+        .collect()
+        .await
+        .unwrap();
+}
+
+#[tokio::test]
+async fn drop_view_if_exists() -> Result<()> {
+    let ctx =
+        
SessionContext::with_config(SessionConfig::new().with_information_schema(true));
+    plan_and_collect(&ctx, "CREATE VIEW v AS SELECT 1").await?;
+    let rb = plan_and_collect(&ctx, "DROP VIEW IF EXISTS 
non_existent_view").await?;
+    // make sure we get an empty response back
+    assert!(rb.is_empty());
+
+    let rb = plan_and_collect(
+        &ctx,
+        "select * from information_schema.views where table_name = 'v'",
+    )
+    .await?;
+    // confirm view exists
+    assert_eq!(rb[0].num_rows(), 1);
+
+    plan_and_collect(&ctx, "DROP VIEW IF EXISTS v").await?;
+    let rb = plan_and_collect(
+        &ctx,
+        "select * from information_schema.views where table_name = 'v'",
+    )
+    .await?;
+    // confirm view is gone
+    assert!(rb.is_empty());
+    Ok(())
+}
+
 #[tokio::test]
 async fn csv_query_create_external_table() {
     let ctx = SessionContext::new();
@@ -287,3 +385,8 @@ async fn create_csv_table_empty_file() -> Result<()> {
 
     Ok(())
 }
+
+/// Execute SQL and return results
+async fn plan_and_collect(ctx: &SessionContext, sql: &str) -> 
Result<Vec<RecordBatch>> {
+    ctx.sql(sql).await?.collect().await
+}
diff --git a/datafusion/expr/src/logical_plan/mod.rs 
b/datafusion/expr/src/logical_plan/mod.rs
index ff0f59254..9917d69a7 100644
--- a/datafusion/expr/src/logical_plan/mod.rs
+++ b/datafusion/expr/src/logical_plan/mod.rs
@@ -23,10 +23,10 @@ mod plan;
 pub use builder::{table_scan, LogicalPlanBuilder};
 pub use plan::{
     Aggregate, Analyze, CreateCatalog, CreateCatalogSchema, 
CreateExternalTable,
-    CreateMemoryTable, CreateView, CrossJoin, Distinct, DropTable, 
EmptyRelation,
-    Explain, Extension, FileType, Filter, Join, JoinConstraint, JoinType, 
Limit,
-    LogicalPlan, Partitioning, PlanType, PlanVisitor, Projection, Repartition, 
Sort,
-    StringifiedPlan, Subquery, SubqueryAlias, TableScan, ToStringifiedPlan, 
Union,
+    CreateMemoryTable, CreateView, CrossJoin, Distinct, DropTable, DropView,
+    EmptyRelation, Explain, Extension, FileType, Filter, Join, JoinConstraint, 
JoinType,
+    Limit, LogicalPlan, Partitioning, PlanType, PlanVisitor, Projection, 
Repartition,
+    Sort, StringifiedPlan, Subquery, SubqueryAlias, TableScan, 
ToStringifiedPlan, Union,
     Values, Window,
 };
 
diff --git a/datafusion/expr/src/logical_plan/plan.rs 
b/datafusion/expr/src/logical_plan/plan.rs
index cec55bfc1..12e9e0738 100644
--- a/datafusion/expr/src/logical_plan/plan.rs
+++ b/datafusion/expr/src/logical_plan/plan.rs
@@ -86,6 +86,8 @@ pub enum LogicalPlan {
     CreateCatalog(CreateCatalog),
     /// Drops a table.
     DropTable(DropTable),
+    /// Drops a view.
+    DropView(DropView),
     /// Values expression. See
     /// [Postgres 
VALUES](https://www.postgresql.org/docs/current/queries-values.html)
     /// documentation for more details.
@@ -137,6 +139,7 @@ impl LogicalPlan {
             }
             LogicalPlan::CreateCatalog(CreateCatalog { schema, .. }) => schema,
             LogicalPlan::DropTable(DropTable { schema, .. }) => schema,
+            LogicalPlan::DropView(DropView { schema, .. }) => schema,
         }
     }
 
@@ -193,7 +196,7 @@ impl LogicalPlan {
             | LogicalPlan::CreateView(CreateView { input, .. })
             | LogicalPlan::Filter(Filter { input, .. }) => input.all_schemas(),
             LogicalPlan::Distinct(Distinct { input, .. }) => 
input.all_schemas(),
-            LogicalPlan::DropTable(_) => vec![],
+            LogicalPlan::DropTable(_) | LogicalPlan::DropView(_) => vec![],
         }
     }
 
@@ -253,6 +256,7 @@ impl LogicalPlan {
             | LogicalPlan::CreateCatalogSchema(_)
             | LogicalPlan::CreateCatalog(_)
             | LogicalPlan::DropTable(_)
+            | LogicalPlan::DropView(_)
             | LogicalPlan::CrossJoin(_)
             | LogicalPlan::Analyze { .. }
             | LogicalPlan::Explain { .. }
@@ -296,7 +300,8 @@ impl LogicalPlan {
             | LogicalPlan::CreateExternalTable(_)
             | LogicalPlan::CreateCatalogSchema(_)
             | LogicalPlan::CreateCatalog(_)
-            | LogicalPlan::DropTable(_) => vec![],
+            | LogicalPlan::DropTable(_)
+            | LogicalPlan::DropView(_) => vec![],
         }
     }
 
@@ -449,7 +454,8 @@ impl LogicalPlan {
             | LogicalPlan::CreateExternalTable(_)
             | LogicalPlan::CreateCatalogSchema(_)
             | LogicalPlan::CreateCatalog(_)
-            | LogicalPlan::DropTable(_) => true,
+            | LogicalPlan::DropTable(_)
+            | LogicalPlan::DropView(_) => true,
         };
         if !recurse {
             return Ok(false);
@@ -920,6 +926,11 @@ impl LogicalPlan {
                     }) => {
                         write!(f, "DropTable: {:?} if not exist:={}", name, 
if_exists)
                     }
+                    LogicalPlan::DropView(DropView {
+                        name, if_exists, ..
+                    }) => {
+                        write!(f, "DropView: {:?} if not exist:={}", name, 
if_exists)
+                    }
                     LogicalPlan::Distinct(Distinct { .. }) => {
                         write!(f, "Distinct:")
                     }
@@ -1019,6 +1030,17 @@ pub struct DropTable {
     pub schema: DFSchemaRef,
 }
 
+/// Drops a view.
+#[derive(Clone)]
+pub struct DropView {
+    /// The view name
+    pub name: String,
+    /// If the view exists
+    pub if_exists: bool,
+    /// Dummy schema
+    pub schema: DFSchemaRef,
+}
+
 /// Produces no rows: An empty relation with an empty schema
 #[derive(Clone)]
 pub struct EmptyRelation {
diff --git a/datafusion/expr/src/utils.rs b/datafusion/expr/src/utils.rs
index 4d3f1bc33..65c4be248 100644
--- a/datafusion/expr/src/utils.rs
+++ b/datafusion/expr/src/utils.rs
@@ -540,6 +540,7 @@ pub fn from_plan(
         | LogicalPlan::TableScan { .. }
         | LogicalPlan::CreateExternalTable(_)
         | LogicalPlan::DropTable(_)
+        | LogicalPlan::DropView(_)
         | LogicalPlan::CreateCatalogSchema(_)
         | LogicalPlan::CreateCatalog(_) => {
             // All of these plan types have no inputs / exprs so should not be 
called
diff --git a/datafusion/optimizer/src/common_subexpr_eliminate.rs 
b/datafusion/optimizer/src/common_subexpr_eliminate.rs
index fcefd8fa7..2d148a087 100644
--- a/datafusion/optimizer/src/common_subexpr_eliminate.rs
+++ b/datafusion/optimizer/src/common_subexpr_eliminate.rs
@@ -232,6 +232,7 @@ fn optimize(
         | LogicalPlan::CreateCatalogSchema(_)
         | LogicalPlan::CreateCatalog(_)
         | LogicalPlan::DropTable(_)
+        | LogicalPlan::DropView(_)
         | LogicalPlan::Distinct(_)
         | LogicalPlan::Extension { .. } => {
             // apply the optimization to all inputs of the plan
diff --git a/datafusion/optimizer/src/projection_push_down.rs 
b/datafusion/optimizer/src/projection_push_down.rs
index c458923e9..79364eb1f 100644
--- a/datafusion/optimizer/src/projection_push_down.rs
+++ b/datafusion/optimizer/src/projection_push_down.rs
@@ -497,6 +497,7 @@ fn optimize_plan(
         | LogicalPlan::CreateCatalogSchema(_)
         | LogicalPlan::CreateCatalog(_)
         | LogicalPlan::DropTable(_)
+        | LogicalPlan::DropView(_)
         | LogicalPlan::CrossJoin(_)
         | LogicalPlan::Distinct(_)
         | LogicalPlan::Extension { .. } => {
diff --git a/datafusion/proto/src/logical_plan.rs 
b/datafusion/proto/src/logical_plan.rs
index bcdb9796f..ca0487d39 100644
--- a/datafusion/proto/src/logical_plan.rs
+++ b/datafusion/proto/src/logical_plan.rs
@@ -1215,6 +1215,9 @@ impl AsLogicalPlan for LogicalPlanNode {
             LogicalPlan::DropTable(_) => Err(proto_error(
                 "LogicalPlan serde is not yet implemented for DropTable",
             )),
+            LogicalPlan::DropView(_) => Err(proto_error(
+                "LogicalPlan serde is not yet implemented for DropView",
+            )),
         }
     }
 }
diff --git a/datafusion/sql/src/planner.rs b/datafusion/sql/src/planner.rs
index 65e38973e..967272694 100644
--- a/datafusion/sql/src/planner.rs
+++ b/datafusion/sql/src/planner.rs
@@ -26,7 +26,7 @@ use 
datafusion_expr::expr_rewriter::normalize_col_with_schemas;
 use datafusion_expr::logical_plan::{
     Analyze, CreateCatalog, CreateCatalogSchema,
     CreateExternalTable as PlanCreateExternalTable, CreateMemoryTable, 
CreateView,
-    DropTable, Explain, FileType, JoinType, LogicalPlan, LogicalPlanBuilder,
+    DropTable, DropView, Explain, FileType, JoinType, LogicalPlan, 
LogicalPlanBuilder,
     Partitioning, PlanType, ToStringifiedPlan,
 };
 use datafusion_expr::utils::{
@@ -245,20 +245,29 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
                 schema: Arc::new(DFSchema::empty()),
             })),
             Statement::Drop {
-                object_type: ObjectType::Table,
+                object_type,
                 if_exists,
                 names,
                 cascade: _,
                 purge: _,
-            } =>
-            // We don't support cascade and purge for now.
-            {
-                Ok(LogicalPlan::DropTable(DropTable {
+                // We don't support cascade and purge for now.
+                // nor do we support multiple object names
+            } => match object_type {
+                ObjectType::Table => Ok(LogicalPlan::DropTable(DropTable {
                     name: names.get(0).unwrap().to_string(),
                     if_exists,
                     schema: DFSchemaRef::new(DFSchema::empty()),
-                }))
-            }
+                })),
+                ObjectType::View => Ok(LogicalPlan::DropView(DropView {
+                    name: names.get(0).unwrap().to_string(),
+                    if_exists,
+                    schema: DFSchemaRef::new(DFSchema::empty()),
+                })),
+                _ => Err(DataFusionError::NotImplemented(
+                    "Only `DROP TABLE/VIEW  ...` statement is supported 
currently"
+                        .to_string(),
+                )),
+            },
 
             Statement::ShowTables {
                 extended,
@@ -4170,7 +4179,7 @@ mod tests {
     }
 
     /// psql result
-    /// ```
+    /// ```text
     ///                               QUERY PLAN
     /// ----------------------------------------------------------------------
     /// WindowAgg  (cost=69.83..87.33 rows=1000 width=8)
@@ -4189,7 +4198,7 @@ mod tests {
     }
 
     /// psql result
-    /// ```
+    /// ```text
     ///                                     QUERY PLAN
     /// 
----------------------------------------------------------------------------------
     /// WindowAgg  (cost=137.16..154.66 rows=1000 width=12)
@@ -4277,7 +4286,7 @@ mod tests {
     }
 
     /// psql result
-    /// ```
+    /// ```text
     ///                                     QUERY PLAN
     /// 
-----------------------------------------------------------------------------------
     /// WindowAgg  (cost=142.16..162.16 rows=1000 width=16)
@@ -4300,7 +4309,7 @@ mod tests {
     }
 
     /// psql result
-    /// ```
+    /// ```text
     ///                                        QUERY PLAN
     /// 
----------------------------------------------------------------------------------------
     /// WindowAgg  (cost=139.66..172.16 rows=1000 width=24)
@@ -4325,7 +4334,7 @@ mod tests {
     }
 
     /// psql result
-    /// ```
+    /// ```text
     ///                                     QUERY PLAN
     /// 
----------------------------------------------------------------------------------
     /// WindowAgg  (cost=69.83..117.33 rows=1000 width=24)
@@ -4350,7 +4359,7 @@ mod tests {
     }
 
     /// psql result
-    /// ```
+    /// ```text
     ///                                        QUERY PLAN
     /// 
----------------------------------------------------------------------------------------
     /// WindowAgg  (cost=139.66..172.16 rows=1000 width=24)
@@ -4379,7 +4388,7 @@ mod tests {
     }
 
     /// psql result
-    /// ```
+    /// ```text
     ///                               QUERY PLAN
     /// ----------------------------------------------------------------------
     /// WindowAgg  (cost=69.83..89.83 rows=1000 width=12)
@@ -4399,7 +4408,7 @@ mod tests {
     }
 
     /// psql result
-    /// ```
+    /// ```text
     ///                               QUERY PLAN
     /// ----------------------------------------------------------------------
     /// WindowAgg  (cost=69.83..89.83 rows=1000 width=12)
@@ -4419,7 +4428,7 @@ mod tests {
     }
 
     /// psql result
-    /// ```
+    /// ```text
     ///                                     QUERY PLAN
     /// 
----------------------------------------------------------------------------------
     /// WindowAgg  (cost=142.16..162.16 rows=1000 width=16)
@@ -4443,7 +4452,7 @@ mod tests {
     }
 
     /// psql result
-    /// ```
+    /// ```text
     ///                                  QUERY PLAN
     /// 
-----------------------------------------------------------------------------
     /// WindowAgg  (cost=69.83..109.83 rows=1000 width=24)
diff --git a/docs/source/user-guide/sql/ddl.md 
b/docs/source/user-guide/sql/ddl.md
index ee73370e0..8d24a8e4c 100644
--- a/docs/source/user-guide/sql/ddl.md
+++ b/docs/source/user-guide/sql/ddl.md
@@ -94,14 +94,28 @@ CREATE TABLE memtable as select * from valuetable;
 
 ## DROP TABLE
 
-The table can be deleted.
+Removes the table from DataFusion's catalog.
 
-```
-DROP TABLE [ IF EXISTS ] name
-```
+<pre>
+DROP TABLE [ IF EXISTS ] <b><i>table_name</i></b>;
+</pre>
 
 ```sql
 CREATE TABLE users AS VALUES(1,2),(2,3);
-
 DROP TABLE users;
+-- or use 'if exists' to silently ignore if the table doesn't exist
+DROP TABLE IF EXISTS nonexistent_table;
+```
+
+## DROP VIEW
+
+Removes the view from DataFusion's catalog.
+
+<pre>
+DROP VIEW [ IF EXISTS ] <b><i>view_name</i></b>;
+</pre>
+
+```sql
+-- drop users_v view from the customer_a schema
+DROP VIEW IF EXISTS customer_a.users_v;
 ```

Reply via email to