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 25ab1f937 [sqllogictest] Create empty tables (#5026)
25ab1f937 is described below

commit 25ab1f93718296fad8e41bd2ef2ab731d7034444
Author: Yevhenii Melnyk <[email protected]>
AuthorDate: Mon Jan 23 13:12:03 2023 +0100

    [sqllogictest] Create empty tables (#5026)
---
 .../src/engines/datafusion/create_table.rs         | 68 ++++++++++++++++++++++
 .../datafusion/{insert/mod.rs => insert.rs}        |  4 +-
 .../sqllogictests/src/engines/datafusion/mod.rs    | 28 ++++++++-
 .../src/engines/datafusion/{insert => }/util.rs    |  0
 .../core/tests/sqllogictests/test_files/ddl.slt    | 46 +++++++++++++++
 datafusion/sql/src/planner.rs                      |  2 +-
 6 files changed, 141 insertions(+), 7 deletions(-)

diff --git 
a/datafusion/core/tests/sqllogictests/src/engines/datafusion/create_table.rs 
b/datafusion/core/tests/sqllogictests/src/engines/datafusion/create_table.rs
new file mode 100644
index 000000000..d7ef8469e
--- /dev/null
+++ b/datafusion/core/tests/sqllogictests/src/engines/datafusion/create_table.rs
@@ -0,0 +1,68 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use super::error::Result;
+use crate::engines::datafusion::error::DFSqlLogicTestError;
+use crate::engines::datafusion::util::LogicTestContextProvider;
+use datafusion::datasource::MemTable;
+use datafusion::prelude::SessionContext;
+use datafusion_common::{DataFusionError, OwnedTableReference};
+use datafusion_sql::planner::{object_name_to_table_reference, SqlToRel};
+use sqllogictest::DBOutput;
+use sqlparser::ast::{ColumnDef, ObjectName};
+use std::sync::Arc;
+
+pub async fn create_table(
+    ctx: &SessionContext,
+    name: ObjectName,
+    columns: Vec<ColumnDef>,
+    if_not_exists: bool,
+    or_replace: bool,
+) -> Result<DBOutput> {
+    let table_reference = object_name_to_table_reference(name)?;
+    let existing_table = ctx.table(&table_reference).await;
+    match (if_not_exists, or_replace, existing_table) {
+        (true, false, Ok(_)) => Ok(DBOutput::StatementComplete(0)),
+        (false, true, Ok(_)) => {
+            ctx.deregister_table(&table_reference)?;
+            create_new_table(ctx, table_reference, columns)
+        }
+        (true, true, Ok(_)) => {
+            Err(DFSqlLogicTestError::from(DataFusionError::Execution(
+                "'IF NOT EXISTS' cannot coexist with 'REPLACE'".to_string(),
+            )))
+        }
+        (_, _, Err(_)) => create_new_table(ctx, table_reference, columns),
+        (false, false, Ok(_)) => {
+            Err(DFSqlLogicTestError::from(DataFusionError::Execution(
+                format!("Table '{table_reference}' already exists"),
+            )))
+        }
+    }
+}
+
+fn create_new_table(
+    ctx: &SessionContext,
+    table_reference: OwnedTableReference,
+    columns: Vec<ColumnDef>,
+) -> Result<DBOutput> {
+    let sql_to_rel = SqlToRel::new(&LogicTestContextProvider {});
+    let schema = Arc::new(sql_to_rel.build_schema(columns)?);
+    let table_provider = Arc::new(MemTable::try_new(schema, vec![])?);
+    ctx.register_table(&table_reference, table_provider)?;
+    Ok(DBOutput::StatementComplete(0))
+}
diff --git 
a/datafusion/core/tests/sqllogictests/src/engines/datafusion/insert/mod.rs 
b/datafusion/core/tests/sqllogictests/src/engines/datafusion/insert.rs
similarity index 98%
rename from 
datafusion/core/tests/sqllogictests/src/engines/datafusion/insert/mod.rs
rename to datafusion/core/tests/sqllogictests/src/engines/datafusion/insert.rs
index ee18851c2..aa0d563e1 100644
--- a/datafusion/core/tests/sqllogictests/src/engines/datafusion/insert/mod.rs
+++ b/datafusion/core/tests/sqllogictests/src/engines/datafusion/insert.rs
@@ -15,10 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
-mod util;
-
-use self::util::LogicTestContextProvider;
 use super::error::Result;
+use crate::engines::datafusion::util::LogicTestContextProvider;
 use arrow::record_batch::RecordBatch;
 use datafusion::datasource::MemTable;
 use datafusion::prelude::SessionContext;
diff --git a/datafusion/core/tests/sqllogictests/src/engines/datafusion/mod.rs 
b/datafusion/core/tests/sqllogictests/src/engines/datafusion/mod.rs
index 4acdcae76..cb4990a42 100644
--- a/datafusion/core/tests/sqllogictests/src/engines/datafusion/mod.rs
+++ b/datafusion/core/tests/sqllogictests/src/engines/datafusion/mod.rs
@@ -21,15 +21,18 @@ use sqllogictest::DBOutput;
 
 use self::error::{DFSqlLogicTestError, Result};
 use async_trait::async_trait;
+use create_table::create_table;
 use datafusion::arrow::record_batch::RecordBatch;
 use datafusion::prelude::SessionContext;
 use datafusion_sql::parser::{DFParser, Statement};
 use insert::insert;
 use sqlparser::ast::Statement as SQLStatement;
 
+mod create_table;
 mod error;
 mod insert;
 mod normalize;
+mod util;
 
 pub struct DataFusion {
     ctx: SessionContext,
@@ -74,9 +77,28 @@ async fn run_query(ctx: &SessionContext, sql: impl 
Into<String>) -> Result<DBOut
         let statement0 = statements.pop_front().expect("at least one SQL 
statement");
         if let Statement::Statement(statement) = statement0 {
             let statement = *statement;
-            if matches!(&statement, SQLStatement::Insert { .. }) {
-                return insert(ctx, statement).await;
-            }
+            match statement {
+                SQLStatement::Insert { .. } => return insert(ctx, 
statement).await,
+                SQLStatement::CreateTable {
+                    query,
+                    constraints,
+                    table_properties,
+                    with_options,
+                    name,
+                    columns,
+                    if_not_exists,
+                    or_replace,
+                    ..
+                } if query.is_none()
+                    && constraints.is_empty()
+                    && table_properties.is_empty()
+                    && with_options.is_empty() =>
+                {
+                    return create_table(ctx, name, columns, if_not_exists, 
or_replace)
+                        .await
+                }
+                _ => {}
+            };
         }
     }
     let df = ctx.sql(sql.as_str()).await?;
diff --git 
a/datafusion/core/tests/sqllogictests/src/engines/datafusion/insert/util.rs 
b/datafusion/core/tests/sqllogictests/src/engines/datafusion/util.rs
similarity index 100%
rename from 
datafusion/core/tests/sqllogictests/src/engines/datafusion/insert/util.rs
rename to datafusion/core/tests/sqllogictests/src/engines/datafusion/util.rs
diff --git a/datafusion/core/tests/sqllogictests/test_files/ddl.slt 
b/datafusion/core/tests/sqllogictests/test_files/ddl.slt
index cb7db95e9..2b49bcd03 100644
--- a/datafusion/core/tests/sqllogictests/test_files/ddl.slt
+++ b/datafusion/core/tests/sqllogictests/test_files/ddl.slt
@@ -419,3 +419,49 @@ SELECT * FROM aggregate_simple order by c1 DESC LIMIT 1;
 
 statement ok
 DROP TABLE aggregate_simple
+
+
+# Should create an empty table
+statement ok
+CREATE TABLE table_without_values(field1 BIGINT, field2 BIGINT);
+
+
+# Should skip existing table
+statement ok
+CREATE TABLE IF NOT EXISTS table_without_values(field1 BIGINT, field2 BIGINT);
+
+
+# Should not recreate the same table
+statement error Table 'table_without_values' already exists
+CREATE TABLE table_without_values(field1 BIGINT, field2 BIGINT);
+
+
+# 'IF NOT EXISTS' cannot coexist with 'REPLACE'
+statement error Execution error: 'IF NOT EXISTS' cannot coexist with 'REPLACE'
+CREATE OR REPLACE TABLE IF NOT EXISTS table_without_values(field1 BIGINT, 
field2 BIGINT);
+
+# Should insert into an empty table
+statement ok
+insert into table_without_values values (1, 2), (2, 3), (2, 4);
+
+query II rowsort
+select * from table_without_values;
+----
+1 2
+2 3
+2 4
+
+
+# Should recreate existing table
+statement ok
+CREATE OR REPLACE TABLE table_without_values(field1 BIGINT, field2 BIGINT);
+
+
+# Should insert into a recreated table
+statement ok
+insert into table_without_values values (10, 20);
+
+query II rowsort
+select * from table_without_values;
+----
+10 20
diff --git a/datafusion/sql/src/planner.rs b/datafusion/sql/src/planner.rs
index 4b93f26f9..5ccbbc09f 100644
--- a/datafusion/sql/src/planner.rs
+++ b/datafusion/sql/src/planner.rs
@@ -114,7 +114,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
         }
     }
 
-    pub(crate) fn build_schema(&self, columns: Vec<SQLColumnDef>) -> 
Result<Schema> {
+    pub fn build_schema(&self, columns: Vec<SQLColumnDef>) -> Result<Schema> {
         let mut fields = Vec::with_capacity(columns.len());
 
         for column in columns {

Reply via email to