From 8485f2c60c2db387492a75466b48f695797b3d33 Mon Sep 17 00:00:00 2001 From: Andrew Lamb Date: Wed, 26 Jan 2022 06:44:00 -0500 Subject: [PATCH 1/2] Move tests from context.rs to information_schema.rs --- datafusion/src/execution/context.rs | 470 -------------------- datafusion/tests/sql/information_schema.rs | 489 +++++++++++++++++++++ 2 files changed, 489 insertions(+), 470 deletions(-) create mode 100644 datafusion/tests/sql/information_schema.rs diff --git a/datafusion/src/execution/context.rs b/datafusion/src/execution/context.rs index 61cbf3abc8a1..44d04b31fc92 100644 --- a/datafusion/src/execution/context.rs +++ b/datafusion/src/execution/context.rs @@ -3551,476 +3551,6 @@ mod tests { Ok(()) } - #[tokio::test] - async fn information_schema_tables_not_exist_by_default() { - let mut ctx = ExecutionContext::new(); - - let err = plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") - .await - .unwrap_err(); - assert_eq!( - err.to_string(), - "Error during planning: Table or CTE with name 'information_schema.tables' not found" - ); - } - - #[tokio::test] - async fn information_schema_tables_no_tables() { - let mut ctx = ExecutionContext::with_config( - ExecutionConfig::new().with_information_schema(true), - ); - - let result = - plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") - .await - .unwrap(); - - let expected = vec![ - "+---------------+--------------------+------------+------------+", - "| table_catalog | table_schema | table_name | table_type |", - "+---------------+--------------------+------------+------------+", - "| datafusion | information_schema | columns | VIEW |", - "| datafusion | information_schema | tables | VIEW |", - "+---------------+--------------------+------------+------------+", - ]; - assert_batches_sorted_eq!(expected, &result); - } - - #[tokio::test] - async fn information_schema_tables_tables_default_catalog() { - let mut ctx = ExecutionContext::with_config( - ExecutionConfig::new().with_information_schema(true), - ); - - // Now, register an empty table - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - - let result = - plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") - .await - .unwrap(); - - let expected = vec![ - "+---------------+--------------------+------------+------------+", - "| table_catalog | table_schema | table_name | table_type |", - "+---------------+--------------------+------------+------------+", - "| datafusion | information_schema | tables | VIEW |", - "| datafusion | information_schema | columns | VIEW |", - "| datafusion | public | t | BASE TABLE |", - "+---------------+--------------------+------------+------------+", - ]; - assert_batches_sorted_eq!(expected, &result); - - // Newly added tables should appear - ctx.register_table("t2", test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - - let result = - plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") - .await - .unwrap(); - - let expected = vec![ - "+---------------+--------------------+------------+------------+", - "| table_catalog | table_schema | table_name | table_type |", - "+---------------+--------------------+------------+------------+", - "| datafusion | information_schema | columns | VIEW |", - "| datafusion | information_schema | tables | VIEW |", - "| datafusion | public | t | BASE TABLE |", - "| datafusion | public | t2 | BASE TABLE |", - "+---------------+--------------------+------------+------------+", - ]; - assert_batches_sorted_eq!(expected, &result); - } - - #[tokio::test] - async fn information_schema_tables_tables_with_multiple_catalogs() { - let mut ctx = ExecutionContext::with_config( - ExecutionConfig::new().with_information_schema(true), - ); - let catalog = MemoryCatalogProvider::new(); - let schema = MemorySchemaProvider::new(); - schema - .register_table("t1".to_owned(), test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - schema - .register_table("t2".to_owned(), test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - catalog.register_schema("my_schema", Arc::new(schema)); - ctx.register_catalog("my_catalog", Arc::new(catalog)); - - let catalog = MemoryCatalogProvider::new(); - let schema = MemorySchemaProvider::new(); - schema - .register_table("t3".to_owned(), test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - catalog.register_schema("my_other_schema", Arc::new(schema)); - ctx.register_catalog("my_other_catalog", Arc::new(catalog)); - - let result = - plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") - .await - .unwrap(); - - let expected = vec![ - "+------------------+--------------------+------------+------------+", - "| table_catalog | table_schema | table_name | table_type |", - "+------------------+--------------------+------------+------------+", - "| datafusion | information_schema | columns | VIEW |", - "| datafusion | information_schema | tables | VIEW |", - "| my_catalog | information_schema | columns | VIEW |", - "| my_catalog | information_schema | tables | VIEW |", - "| my_catalog | my_schema | t1 | BASE TABLE |", - "| my_catalog | my_schema | t2 | BASE TABLE |", - "| my_other_catalog | information_schema | columns | VIEW |", - "| my_other_catalog | information_schema | tables | VIEW |", - "| my_other_catalog | my_other_schema | t3 | BASE TABLE |", - "+------------------+--------------------+------------+------------+", - ]; - assert_batches_sorted_eq!(expected, &result); - } - - #[tokio::test] - async fn information_schema_tables_table_types() { - struct TestTable(TableType); - - #[async_trait] - impl TableProvider for TestTable { - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn table_type(&self) -> TableType { - self.0 - } - - fn schema(&self) -> SchemaRef { - unimplemented!() - } - - async fn scan( - &self, - _: &Option>, - _: &[Expr], - _: Option, - ) -> Result> { - unimplemented!() - } - } - - let mut ctx = ExecutionContext::with_config( - ExecutionConfig::new().with_information_schema(true), - ); - - ctx.register_table("physical", Arc::new(TestTable(TableType::Base))) - .unwrap(); - ctx.register_table("query", Arc::new(TestTable(TableType::View))) - .unwrap(); - ctx.register_table("temp", Arc::new(TestTable(TableType::Temporary))) - .unwrap(); - - let result = - plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") - .await - .unwrap(); - - let expected = vec![ - "+---------------+--------------------+------------+-----------------+", - "| table_catalog | table_schema | table_name | table_type |", - "+---------------+--------------------+------------+-----------------+", - "| datafusion | information_schema | tables | VIEW |", - "| datafusion | information_schema | columns | VIEW |", - "| datafusion | public | physical | BASE TABLE |", - "| datafusion | public | query | VIEW |", - "| datafusion | public | temp | LOCAL TEMPORARY |", - "+---------------+--------------------+------------+-----------------+", - ]; - assert_batches_sorted_eq!(expected, &result); - } - - #[tokio::test] - async fn information_schema_show_tables_no_information_schema() { - let mut ctx = ExecutionContext::with_config(ExecutionConfig::new()); - - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - - // use show tables alias - let err = plan_and_collect(&mut ctx, "SHOW TABLES").await.unwrap_err(); - - assert_eq!(err.to_string(), "Error during planning: SHOW TABLES is not supported unless information_schema is enabled"); - } - - #[tokio::test] - async fn information_schema_show_tables() { - let mut ctx = ExecutionContext::with_config( - ExecutionConfig::new().with_information_schema(true), - ); - - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - - // use show tables alias - let result = plan_and_collect(&mut ctx, "SHOW TABLES").await.unwrap(); - - let expected = vec![ - "+---------------+--------------------+------------+------------+", - "| table_catalog | table_schema | table_name | table_type |", - "+---------------+--------------------+------------+------------+", - "| datafusion | information_schema | columns | VIEW |", - "| datafusion | information_schema | tables | VIEW |", - "| datafusion | public | t | BASE TABLE |", - "+---------------+--------------------+------------+------------+", - ]; - assert_batches_sorted_eq!(expected, &result); - - let result = plan_and_collect(&mut ctx, "SHOW tables").await.unwrap(); - - assert_batches_sorted_eq!(expected, &result); - } - - #[tokio::test] - async fn information_schema_show_columns_no_information_schema() { - let mut ctx = ExecutionContext::with_config(ExecutionConfig::new()); - - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - - let err = plan_and_collect(&mut ctx, "SHOW COLUMNS FROM t") - .await - .unwrap_err(); - - assert_eq!(err.to_string(), "Error during planning: SHOW COLUMNS is not supported unless information_schema is enabled"); - } - - #[tokio::test] - async fn information_schema_show_columns_like_where() { - let mut ctx = ExecutionContext::with_config(ExecutionConfig::new()); - - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - - let expected = - "Error during planning: SHOW COLUMNS with WHERE or LIKE is not supported"; - - let err = plan_and_collect(&mut ctx, "SHOW COLUMNS FROM t LIKE 'f'") - .await - .unwrap_err(); - assert_eq!(err.to_string(), expected); - - let err = - plan_and_collect(&mut ctx, "SHOW COLUMNS FROM t WHERE column_name = 'bar'") - .await - .unwrap_err(); - assert_eq!(err.to_string(), expected); - } - - #[tokio::test] - async fn information_schema_show_columns() { - let mut ctx = ExecutionContext::with_config( - ExecutionConfig::new().with_information_schema(true), - ); - - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - - let result = plan_and_collect(&mut ctx, "SHOW COLUMNS FROM t") - .await - .unwrap(); - - let expected = vec![ - "+---------------+--------------+------------+-------------+-----------+-------------+", - "| table_catalog | table_schema | table_name | column_name | data_type | is_nullable |", - "+---------------+--------------+------------+-------------+-----------+-------------+", - "| datafusion | public | t | i | Int32 | YES |", - "+---------------+--------------+------------+-------------+-----------+-------------+", - ]; - assert_batches_sorted_eq!(expected, &result); - - let result = plan_and_collect(&mut ctx, "SHOW columns from t") - .await - .unwrap(); - assert_batches_sorted_eq!(expected, &result); - - // This isn't ideal but it is consistent behavior for `SELECT * from T` - let err = plan_and_collect(&mut ctx, "SHOW columns from T") - .await - .unwrap_err(); - assert_eq!( - err.to_string(), - "Error during planning: Unknown relation for SHOW COLUMNS: T" - ); - } - - // test errors with WHERE and LIKE - #[tokio::test] - async fn information_schema_show_columns_full_extended() { - let mut ctx = ExecutionContext::with_config( - ExecutionConfig::new().with_information_schema(true), - ); - - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - - let result = plan_and_collect(&mut ctx, "SHOW FULL COLUMNS FROM t") - .await - .unwrap(); - let expected = vec![ - "+---------------+--------------+------------+-------------+------------------+----------------+-------------+-----------+--------------------------+------------------------+-------------------+-------------------------+---------------+--------------------+---------------+", - "| table_catalog | table_schema | table_name | column_name | ordinal_position | column_default | is_nullable | data_type | character_maximum_length | character_octet_length | numeric_precision | numeric_precision_radix | numeric_scale | datetime_precision | interval_type |", - "+---------------+--------------+------------+-------------+------------------+----------------+-------------+-----------+--------------------------+------------------------+-------------------+-------------------------+---------------+--------------------+---------------+", - "| datafusion | public | t | i | 0 | | YES | Int32 | | | 32 | 2 | | | |", - "+---------------+--------------+------------+-------------+------------------+----------------+-------------+-----------+--------------------------+------------------------+-------------------+-------------------------+---------------+--------------------+---------------+", - ]; - assert_batches_sorted_eq!(expected, &result); - - let result = plan_and_collect(&mut ctx, "SHOW EXTENDED COLUMNS FROM t") - .await - .unwrap(); - assert_batches_sorted_eq!(expected, &result); - } - - #[tokio::test] - async fn information_schema_show_table_table_names() { - let mut ctx = ExecutionContext::with_config( - ExecutionConfig::new().with_information_schema(true), - ); - - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - - let result = plan_and_collect(&mut ctx, "SHOW COLUMNS FROM public.t") - .await - .unwrap(); - - let expected = vec![ - "+---------------+--------------+------------+-------------+-----------+-------------+", - "| table_catalog | table_schema | table_name | column_name | data_type | is_nullable |", - "+---------------+--------------+------------+-------------+-----------+-------------+", - "| datafusion | public | t | i | Int32 | YES |", - "+---------------+--------------+------------+-------------+-----------+-------------+", - ]; - assert_batches_sorted_eq!(expected, &result); - - let result = plan_and_collect(&mut ctx, "SHOW columns from datafusion.public.t") - .await - .unwrap(); - assert_batches_sorted_eq!(expected, &result); - - let err = plan_and_collect(&mut ctx, "SHOW columns from t2") - .await - .unwrap_err(); - assert_eq!( - err.to_string(), - "Error during planning: Unknown relation for SHOW COLUMNS: t2" - ); - - let err = plan_and_collect(&mut ctx, "SHOW columns from datafusion.public.t2") - .await - .unwrap_err(); - assert_eq!(err.to_string(), "Error during planning: Unknown relation for SHOW COLUMNS: datafusion.public.t2"); - } - - #[tokio::test] - async fn show_unsupported() { - let mut ctx = ExecutionContext::with_config(ExecutionConfig::new()); - - let err = plan_and_collect(&mut ctx, "SHOW SOMETHING_UNKNOWN") - .await - .unwrap_err(); - - assert_eq!(err.to_string(), "This feature is not implemented: SHOW SOMETHING_UNKNOWN not implemented. Supported syntax: SHOW "); - } - - #[tokio::test] - async fn information_schema_columns_not_exist_by_default() { - let mut ctx = ExecutionContext::new(); - - let err = plan_and_collect(&mut ctx, "SELECT * from information_schema.columns") - .await - .unwrap_err(); - assert_eq!( - err.to_string(), - "Error during planning: Table or CTE with name 'information_schema.columns' not found" - ); - } - - fn table_with_many_types() -> Arc { - let schema = Schema::new(vec![ - Field::new("int32_col", DataType::Int32, false), - Field::new("float64_col", DataType::Float64, true), - Field::new("utf8_col", DataType::Utf8, true), - Field::new("large_utf8_col", DataType::LargeUtf8, false), - Field::new("binary_col", DataType::Binary, false), - Field::new("large_binary_col", DataType::LargeBinary, false), - Field::new( - "timestamp_nanos", - DataType::Timestamp(TimeUnit::Nanosecond, None), - false, - ), - ]); - - let batch = RecordBatch::try_new( - Arc::new(schema.clone()), - vec![ - Arc::new(Int32Array::from_slice(&[1])), - Arc::new(Float64Array::from_slice(&[1.0])), - Arc::new(StringArray::from(vec![Some("foo")])), - Arc::new(LargeStringArray::from(vec![Some("bar")])), - Arc::new(BinaryArray::from_slice(&[b"foo" as &[u8]])), - Arc::new(LargeBinaryArray::from_slice(&[b"foo" as &[u8]])), - Arc::new(TimestampNanosecondArray::from_opt_vec( - vec![Some(123)], - None, - )), - ], - ) - .unwrap(); - let provider = MemTable::try_new(Arc::new(schema), vec![vec![batch]]).unwrap(); - Arc::new(provider) - } - - #[tokio::test] - async fn information_schema_columns() { - let mut ctx = ExecutionContext::with_config( - ExecutionConfig::new().with_information_schema(true), - ); - let catalog = MemoryCatalogProvider::new(); - let schema = MemorySchemaProvider::new(); - - schema - .register_table("t1".to_owned(), test::table_with_sequence(1, 1).unwrap()) - .unwrap(); - - schema - .register_table("t2".to_owned(), table_with_many_types()) - .unwrap(); - catalog.register_schema("my_schema", Arc::new(schema)); - ctx.register_catalog("my_catalog", Arc::new(catalog)); - - let result = - plan_and_collect(&mut ctx, "SELECT * from information_schema.columns") - .await - .unwrap(); - - let expected = vec![ - "+---------------+--------------+------------+------------------+------------------+----------------+-------------+-----------------------------+--------------------------+------------------------+-------------------+-------------------------+---------------+--------------------+---------------+", - "| table_catalog | table_schema | table_name | column_name | ordinal_position | column_default | is_nullable | data_type | character_maximum_length | character_octet_length | numeric_precision | numeric_precision_radix | numeric_scale | datetime_precision | interval_type |", - "+---------------+--------------+------------+------------------+------------------+----------------+-------------+-----------------------------+--------------------------+------------------------+-------------------+-------------------------+---------------+--------------------+---------------+", - "| my_catalog | my_schema | t1 | i | 0 | | YES | Int32 | | | 32 | 2 | | | |", - "| my_catalog | my_schema | t2 | binary_col | 4 | | NO | Binary | | 2147483647 | | | | | |", - "| my_catalog | my_schema | t2 | float64_col | 1 | | YES | Float64 | | | 24 | 2 | | | |", - "| my_catalog | my_schema | t2 | int32_col | 0 | | NO | Int32 | | | 32 | 2 | | | |", - "| my_catalog | my_schema | t2 | large_binary_col | 5 | | NO | LargeBinary | | 9223372036854775807 | | | | | |", - "| my_catalog | my_schema | t2 | large_utf8_col | 3 | | NO | LargeUtf8 | | 9223372036854775807 | | | | | |", - "| my_catalog | my_schema | t2 | timestamp_nanos | 6 | | NO | Timestamp(Nanosecond, None) | | | | | | | |", - "| my_catalog | my_schema | t2 | utf8_col | 2 | | YES | Utf8 | | 2147483647 | | | | | |", - "+---------------+--------------+------------+------------------+------------------+----------------+-------------+-----------------------------+--------------------------+------------------------+-------------------+-------------------------+---------------+--------------------+---------------+", - ]; - assert_batches_sorted_eq!(expected, &result); - } - #[tokio::test] async fn disabled_default_catalog_and_schema() -> Result<()> { let mut ctx = ExecutionContext::with_config( diff --git a/datafusion/tests/sql/information_schema.rs b/datafusion/tests/sql/information_schema.rs new file mode 100644 index 000000000000..83b1cdfd6ddf --- /dev/null +++ b/datafusion/tests/sql/information_schema.rs @@ -0,0 +1,489 @@ +// 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::*; + +#[tokio::test] +async fn information_schema_tables_not_exist_by_default() { + let mut ctx = ExecutionContext::new(); + + let err = plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + "Error during planning: Table or CTE with name 'information_schema.tables' not found" + ); +} + +#[tokio::test] +async fn information_schema_tables_no_tables() { + let mut ctx = ExecutionContext::with_config( + ExecutionConfig::new().with_information_schema(true), + ); + + let result = + plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") + .await + .unwrap(); + + let expected = vec![ + "+---------------+--------------------+------------+------------+", + "| table_catalog | table_schema | table_name | table_type |", + "+---------------+--------------------+------------+------------+", + "| datafusion | information_schema | columns | VIEW |", + "| datafusion | information_schema | tables | VIEW |", + "+---------------+--------------------+------------+------------+", + ]; + assert_batches_sorted_eq!(expected, &result); +} + +#[tokio::test] +async fn information_schema_tables_tables_default_catalog() { + let mut ctx = ExecutionContext::with_config( + ExecutionConfig::new().with_information_schema(true), + ); + + // Now, register an empty table + ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + + let result = + plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") + .await + .unwrap(); + + let expected = vec![ + "+---------------+--------------------+------------+------------+", + "| table_catalog | table_schema | table_name | table_type |", + "+---------------+--------------------+------------+------------+", + "| datafusion | information_schema | tables | VIEW |", + "| datafusion | information_schema | columns | VIEW |", + "| datafusion | public | t | BASE TABLE |", + "+---------------+--------------------+------------+------------+", + ]; + assert_batches_sorted_eq!(expected, &result); + + // Newly added tables should appear + ctx.register_table("t2", test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + + let result = + plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") + .await + .unwrap(); + + let expected = vec![ + "+---------------+--------------------+------------+------------+", + "| table_catalog | table_schema | table_name | table_type |", + "+---------------+--------------------+------------+------------+", + "| datafusion | information_schema | columns | VIEW |", + "| datafusion | information_schema | tables | VIEW |", + "| datafusion | public | t | BASE TABLE |", + "| datafusion | public | t2 | BASE TABLE |", + "+---------------+--------------------+------------+------------+", + ]; + assert_batches_sorted_eq!(expected, &result); +} + +#[tokio::test] +async fn information_schema_tables_tables_with_multiple_catalogs() { + let mut ctx = ExecutionContext::with_config( + ExecutionConfig::new().with_information_schema(true), + ); + let catalog = MemoryCatalogProvider::new(); + let schema = MemorySchemaProvider::new(); + schema + .register_table("t1".to_owned(), test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + schema + .register_table("t2".to_owned(), test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + catalog.register_schema("my_schema", Arc::new(schema)); + ctx.register_catalog("my_catalog", Arc::new(catalog)); + + let catalog = MemoryCatalogProvider::new(); + let schema = MemorySchemaProvider::new(); + schema + .register_table("t3".to_owned(), test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + catalog.register_schema("my_other_schema", Arc::new(schema)); + ctx.register_catalog("my_other_catalog", Arc::new(catalog)); + + let result = + plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") + .await + .unwrap(); + + let expected = vec![ + "+------------------+--------------------+------------+------------+", + "| table_catalog | table_schema | table_name | table_type |", + "+------------------+--------------------+------------+------------+", + "| datafusion | information_schema | columns | VIEW |", + "| datafusion | information_schema | tables | VIEW |", + "| my_catalog | information_schema | columns | VIEW |", + "| my_catalog | information_schema | tables | VIEW |", + "| my_catalog | my_schema | t1 | BASE TABLE |", + "| my_catalog | my_schema | t2 | BASE TABLE |", + "| my_other_catalog | information_schema | columns | VIEW |", + "| my_other_catalog | information_schema | tables | VIEW |", + "| my_other_catalog | my_other_schema | t3 | BASE TABLE |", + "+------------------+--------------------+------------+------------+", + ]; + assert_batches_sorted_eq!(expected, &result); +} + +#[tokio::test] +async fn information_schema_tables_table_types() { + struct TestTable(TableType); + + #[async_trait] + impl TableProvider for TestTable { + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn table_type(&self) -> TableType { + self.0 + } + + fn schema(&self) -> SchemaRef { + unimplemented!() + } + + async fn scan( + &self, + _: &Option>, + _: &[Expr], + _: Option, + ) -> Result> { + unimplemented!() + } + } + + let mut ctx = ExecutionContext::with_config( + ExecutionConfig::new().with_information_schema(true), + ); + + ctx.register_table("physical", Arc::new(TestTable(TableType::Base))) + .unwrap(); + ctx.register_table("query", Arc::new(TestTable(TableType::View))) + .unwrap(); + ctx.register_table("temp", Arc::new(TestTable(TableType::Temporary))) + .unwrap(); + + let result = + plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") + .await + .unwrap(); + + let expected = vec![ + "+---------------+--------------------+------------+-----------------+", + "| table_catalog | table_schema | table_name | table_type |", + "+---------------+--------------------+------------+-----------------+", + "| datafusion | information_schema | tables | VIEW |", + "| datafusion | information_schema | columns | VIEW |", + "| datafusion | public | physical | BASE TABLE |", + "| datafusion | public | query | VIEW |", + "| datafusion | public | temp | LOCAL TEMPORARY |", + "+---------------+--------------------+------------+-----------------+", + ]; + assert_batches_sorted_eq!(expected, &result); +} + +#[tokio::test] +async fn information_schema_show_tables_no_information_schema() { + let mut ctx = ExecutionContext::with_config(ExecutionConfig::new()); + + ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + + // use show tables alias + let err = plan_and_collect(&mut ctx, "SHOW TABLES").await.unwrap_err(); + + assert_eq!(err.to_string(), "Error during planning: SHOW TABLES is not supported unless information_schema is enabled"); +} + +#[tokio::test] +async fn information_schema_show_tables() { + let mut ctx = ExecutionContext::with_config( + ExecutionConfig::new().with_information_schema(true), + ); + + ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + + // use show tables alias + let result = plan_and_collect(&mut ctx, "SHOW TABLES").await.unwrap(); + + let expected = vec![ + "+---------------+--------------------+------------+------------+", + "| table_catalog | table_schema | table_name | table_type |", + "+---------------+--------------------+------------+------------+", + "| datafusion | information_schema | columns | VIEW |", + "| datafusion | information_schema | tables | VIEW |", + "| datafusion | public | t | BASE TABLE |", + "+---------------+--------------------+------------+------------+", + ]; + assert_batches_sorted_eq!(expected, &result); + + let result = plan_and_collect(&mut ctx, "SHOW tables").await.unwrap(); + + assert_batches_sorted_eq!(expected, &result); +} + +#[tokio::test] +async fn information_schema_show_columns_no_information_schema() { + let mut ctx = ExecutionContext::with_config(ExecutionConfig::new()); + + ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + + let err = plan_and_collect(&mut ctx, "SHOW COLUMNS FROM t") + .await + .unwrap_err(); + + assert_eq!(err.to_string(), "Error during planning: SHOW COLUMNS is not supported unless information_schema is enabled"); +} + +#[tokio::test] +async fn information_schema_show_columns_like_where() { + let mut ctx = ExecutionContext::with_config(ExecutionConfig::new()); + + ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + + let expected = + "Error during planning: SHOW COLUMNS with WHERE or LIKE is not supported"; + + let err = plan_and_collect(&mut ctx, "SHOW COLUMNS FROM t LIKE 'f'") + .await + .unwrap_err(); + assert_eq!(err.to_string(), expected); + + let err = + plan_and_collect(&mut ctx, "SHOW COLUMNS FROM t WHERE column_name = 'bar'") + .await + .unwrap_err(); + assert_eq!(err.to_string(), expected); +} + +#[tokio::test] +async fn information_schema_show_columns() { + let mut ctx = ExecutionContext::with_config( + ExecutionConfig::new().with_information_schema(true), + ); + + ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + + let result = plan_and_collect(&mut ctx, "SHOW COLUMNS FROM t") + .await + .unwrap(); + + let expected = vec![ + "+---------------+--------------+------------+-------------+-----------+-------------+", + "| table_catalog | table_schema | table_name | column_name | data_type | is_nullable |", + "+---------------+--------------+------------+-------------+-----------+-------------+", + "| datafusion | public | t | i | Int32 | YES |", + "+---------------+--------------+------------+-------------+-----------+-------------+", + ]; + assert_batches_sorted_eq!(expected, &result); + + let result = plan_and_collect(&mut ctx, "SHOW columns from t") + .await + .unwrap(); + assert_batches_sorted_eq!(expected, &result); + + // This isn't ideal but it is consistent behavior for `SELECT * from T` + let err = plan_and_collect(&mut ctx, "SHOW columns from T") + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + "Error during planning: Unknown relation for SHOW COLUMNS: T" + ); +} + +// test errors with WHERE and LIKE +#[tokio::test] +async fn information_schema_show_columns_full_extended() { + let mut ctx = ExecutionContext::with_config( + ExecutionConfig::new().with_information_schema(true), + ); + + ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + + let result = plan_and_collect(&mut ctx, "SHOW FULL COLUMNS FROM t") + .await + .unwrap(); + let expected = vec![ + "+---------------+--------------+------------+-------------+------------------+----------------+-------------+-----------+--------------------------+------------------------+-------------------+-------------------------+---------------+--------------------+---------------+", + "| table_catalog | table_schema | table_name | column_name | ordinal_position | column_default | is_nullable | data_type | character_maximum_length | character_octet_length | numeric_precision | numeric_precision_radix | numeric_scale | datetime_precision | interval_type |", + "+---------------+--------------+------------+-------------+------------------+----------------+-------------+-----------+--------------------------+------------------------+-------------------+-------------------------+---------------+--------------------+---------------+", + "| datafusion | public | t | i | 0 | | YES | Int32 | | | 32 | 2 | | | |", + "+---------------+--------------+------------+-------------+------------------+----------------+-------------+-----------+--------------------------+------------------------+-------------------+-------------------------+---------------+--------------------+---------------+", + ]; + assert_batches_sorted_eq!(expected, &result); + + let result = plan_and_collect(&mut ctx, "SHOW EXTENDED COLUMNS FROM t") + .await + .unwrap(); + assert_batches_sorted_eq!(expected, &result); +} + +#[tokio::test] +async fn information_schema_show_table_table_names() { + let mut ctx = ExecutionContext::with_config( + ExecutionConfig::new().with_information_schema(true), + ); + + ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + + let result = plan_and_collect(&mut ctx, "SHOW COLUMNS FROM public.t") + .await + .unwrap(); + + let expected = vec![ + "+---------------+--------------+------------+-------------+-----------+-------------+", + "| table_catalog | table_schema | table_name | column_name | data_type | is_nullable |", + "+---------------+--------------+------------+-------------+-----------+-------------+", + "| datafusion | public | t | i | Int32 | YES |", + "+---------------+--------------+------------+-------------+-----------+-------------+", + ]; + assert_batches_sorted_eq!(expected, &result); + + let result = plan_and_collect(&mut ctx, "SHOW columns from datafusion.public.t") + .await + .unwrap(); + assert_batches_sorted_eq!(expected, &result); + + let err = plan_and_collect(&mut ctx, "SHOW columns from t2") + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + "Error during planning: Unknown relation for SHOW COLUMNS: t2" + ); + + let err = plan_and_collect(&mut ctx, "SHOW columns from datafusion.public.t2") + .await + .unwrap_err(); + assert_eq!(err.to_string(), "Error during planning: Unknown relation for SHOW COLUMNS: datafusion.public.t2"); +} + +#[tokio::test] +async fn show_unsupported() { + let mut ctx = ExecutionContext::with_config(ExecutionConfig::new()); + + let err = plan_and_collect(&mut ctx, "SHOW SOMETHING_UNKNOWN") + .await + .unwrap_err(); + + assert_eq!(err.to_string(), "This feature is not implemented: SHOW SOMETHING_UNKNOWN not implemented. Supported syntax: SHOW "); +} + +#[tokio::test] +async fn information_schema_columns_not_exist_by_default() { + let mut ctx = ExecutionContext::new(); + + let err = plan_and_collect(&mut ctx, "SELECT * from information_schema.columns") + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + "Error during planning: Table or CTE with name 'information_schema.columns' not found" + ); +} + + +fn table_with_many_types() -> Arc { + let schema = Schema::new(vec![ + Field::new("int32_col", DataType::Int32, false), + Field::new("float64_col", DataType::Float64, true), + Field::new("utf8_col", DataType::Utf8, true), + Field::new("large_utf8_col", DataType::LargeUtf8, false), + Field::new("binary_col", DataType::Binary, false), + Field::new("large_binary_col", DataType::LargeBinary, false), + Field::new( + "timestamp_nanos", + DataType::Timestamp(TimeUnit::Nanosecond, None), + false, + ), + ]); + + let batch = RecordBatch::try_new( + Arc::new(schema.clone()), + vec![ + Arc::new(Int32Array::from_slice(&[1])), + Arc::new(Float64Array::from_slice(&[1.0])), + Arc::new(StringArray::from(vec![Some("foo")])), + Arc::new(LargeStringArray::from(vec![Some("bar")])), + Arc::new(BinaryArray::from_slice(&[b"foo" as &[u8]])), + Arc::new(LargeBinaryArray::from_slice(&[b"foo" as &[u8]])), + Arc::new(TimestampNanosecondArray::from_opt_vec( + vec![Some(123)], + None, + )), + ], + ) + .unwrap(); + let provider = MemTable::try_new(Arc::new(schema), vec![vec![batch]]).unwrap(); + Arc::new(provider) +} + +#[tokio::test] +async fn information_schema_columns() { + let mut ctx = ExecutionContext::with_config( + ExecutionConfig::new().with_information_schema(true), + ); + let catalog = MemoryCatalogProvider::new(); + let schema = MemorySchemaProvider::new(); + + schema + .register_table("t1".to_owned(), test::table_with_sequence(1, 1).unwrap()) + .unwrap(); + + schema + .register_table("t2".to_owned(), table_with_many_types()) + .unwrap(); + catalog.register_schema("my_schema", Arc::new(schema)); + ctx.register_catalog("my_catalog", Arc::new(catalog)); + + let result = + plan_and_collect(&mut ctx, "SELECT * from information_schema.columns") + .await + .unwrap(); + + let expected = vec![ + "+---------------+--------------+------------+------------------+------------------+----------------+-------------+-----------------------------+--------------------------+------------------------+-------------------+-------------------------+---------------+--------------------+---------------+", + "| table_catalog | table_schema | table_name | column_name | ordinal_position | column_default | is_nullable | data_type | character_maximum_length | character_octet_length | numeric_precision | numeric_precision_radix | numeric_scale | datetime_precision | interval_type |", + "+---------------+--------------+------------+------------------+------------------+----------------+-------------+-----------------------------+--------------------------+------------------------+-------------------+-------------------------+---------------+--------------------+---------------+", + "| my_catalog | my_schema | t1 | i | 0 | | YES | Int32 | | | 32 | 2 | | | |", + "| my_catalog | my_schema | t2 | binary_col | 4 | | NO | Binary | | 2147483647 | | | | | |", + "| my_catalog | my_schema | t2 | float64_col | 1 | | YES | Float64 | | | 24 | 2 | | | |", + "| my_catalog | my_schema | t2 | int32_col | 0 | | NO | Int32 | | | 32 | 2 | | | |", + "| my_catalog | my_schema | t2 | large_binary_col | 5 | | NO | LargeBinary | | 9223372036854775807 | | | | | |", + "| my_catalog | my_schema | t2 | large_utf8_col | 3 | | NO | LargeUtf8 | | 9223372036854775807 | | | | | |", + "| my_catalog | my_schema | t2 | timestamp_nanos | 6 | | NO | Timestamp(Nanosecond, None) | | | | | | | |", + "| my_catalog | my_schema | t2 | utf8_col | 2 | | YES | Utf8 | | 2147483647 | | | | | |", + "+---------------+--------------+------------+------------------+------------------+----------------+-------------+-----------------------------+--------------------------+------------------------+-------------------+-------------------------+---------------+--------------------+---------------+", + ]; + assert_batches_sorted_eq!(expected, &result); +} From d92e03fe1f00c6b7da1424795565f53237e10cd3 Mon Sep 17 00:00:00 2001 From: Andrew Lamb Date: Wed, 26 Jan 2022 06:52:33 -0500 Subject: [PATCH 2/2] Fix up tests to compile --- datafusion/src/execution/context.rs | 7 +-- datafusion/tests/sql/information_schema.rs | 73 +++++++++++++--------- datafusion/tests/sql/mod.rs | 17 +++++ 3 files changed, 63 insertions(+), 34 deletions(-) diff --git a/datafusion/src/execution/context.rs b/datafusion/src/execution/context.rs index 44d04b31fc92..9cc54dfe1f37 100644 --- a/datafusion/src/execution/context.rs +++ b/datafusion/src/execution/context.rs @@ -1277,14 +1277,13 @@ mod tests { logical_plan::{col, create_udf, sum, Expr}, }; use crate::{ - datasource::{empty::EmptyTable, MemTable, TableType}, + datasource::{empty::EmptyTable, MemTable}, logical_plan::create_udaf, physical_plan::expressions::AvgAccumulator, }; use arrow::array::{ - Array, ArrayRef, BinaryArray, DictionaryArray, Float32Array, Float64Array, - Int16Array, Int32Array, Int64Array, Int8Array, LargeBinaryArray, - LargeStringArray, StringArray, TimestampNanosecondArray, UInt16Array, + Array, ArrayRef, DictionaryArray, Float32Array, Float64Array, Int16Array, + Int32Array, Int64Array, Int8Array, LargeStringArray, StringArray, UInt16Array, UInt32Array, UInt64Array, UInt8Array, }; use arrow::compute::add; diff --git a/datafusion/tests/sql/information_schema.rs b/datafusion/tests/sql/information_schema.rs index 83b1cdfd6ddf..d93f0d7328d3 100644 --- a/datafusion/tests/sql/information_schema.rs +++ b/datafusion/tests/sql/information_schema.rs @@ -15,6 +15,16 @@ // specific language governing permissions and limitations // under the License. +use async_trait::async_trait; +use datafusion::{ + catalog::{ + catalog::MemoryCatalogProvider, + schema::{MemorySchemaProvider, SchemaProvider}, + }, + datasource::{TableProvider, TableType}, + logical_plan::Expr, +}; + use super::*; #[tokio::test] @@ -36,8 +46,7 @@ async fn information_schema_tables_no_tables() { ExecutionConfig::new().with_information_schema(true), ); - let result = - plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") + let result = plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") .await .unwrap(); @@ -59,11 +68,10 @@ async fn information_schema_tables_tables_default_catalog() { ); // Now, register an empty table - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + ctx.register_table("t", table_with_sequence(1, 1).unwrap()) .unwrap(); - let result = - plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") + let result = plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") .await .unwrap(); @@ -79,11 +87,10 @@ async fn information_schema_tables_tables_default_catalog() { assert_batches_sorted_eq!(expected, &result); // Newly added tables should appear - ctx.register_table("t2", test::table_with_sequence(1, 1).unwrap()) + ctx.register_table("t2", table_with_sequence(1, 1).unwrap()) .unwrap(); - let result = - plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") + let result = plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") .await .unwrap(); @@ -108,10 +115,10 @@ async fn information_schema_tables_tables_with_multiple_catalogs() { let catalog = MemoryCatalogProvider::new(); let schema = MemorySchemaProvider::new(); schema - .register_table("t1".to_owned(), test::table_with_sequence(1, 1).unwrap()) + .register_table("t1".to_owned(), table_with_sequence(1, 1).unwrap()) .unwrap(); schema - .register_table("t2".to_owned(), test::table_with_sequence(1, 1).unwrap()) + .register_table("t2".to_owned(), table_with_sequence(1, 1).unwrap()) .unwrap(); catalog.register_schema("my_schema", Arc::new(schema)); ctx.register_catalog("my_catalog", Arc::new(catalog)); @@ -119,13 +126,12 @@ async fn information_schema_tables_tables_with_multiple_catalogs() { let catalog = MemoryCatalogProvider::new(); let schema = MemorySchemaProvider::new(); schema - .register_table("t3".to_owned(), test::table_with_sequence(1, 1).unwrap()) + .register_table("t3".to_owned(), table_with_sequence(1, 1).unwrap()) .unwrap(); catalog.register_schema("my_other_schema", Arc::new(schema)); ctx.register_catalog("my_other_catalog", Arc::new(catalog)); - let result = - plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") + let result = plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") .await .unwrap(); @@ -186,8 +192,7 @@ async fn information_schema_tables_table_types() { ctx.register_table("temp", Arc::new(TestTable(TableType::Temporary))) .unwrap(); - let result = - plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") + let result = plan_and_collect(&mut ctx, "SELECT * from information_schema.tables") .await .unwrap(); @@ -209,7 +214,7 @@ async fn information_schema_tables_table_types() { async fn information_schema_show_tables_no_information_schema() { let mut ctx = ExecutionContext::with_config(ExecutionConfig::new()); - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + ctx.register_table("t", table_with_sequence(1, 1).unwrap()) .unwrap(); // use show tables alias @@ -224,7 +229,7 @@ async fn information_schema_show_tables() { ExecutionConfig::new().with_information_schema(true), ); - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + ctx.register_table("t", table_with_sequence(1, 1).unwrap()) .unwrap(); // use show tables alias @@ -250,7 +255,7 @@ async fn information_schema_show_tables() { async fn information_schema_show_columns_no_information_schema() { let mut ctx = ExecutionContext::with_config(ExecutionConfig::new()); - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + ctx.register_table("t", table_with_sequence(1, 1).unwrap()) .unwrap(); let err = plan_and_collect(&mut ctx, "SHOW COLUMNS FROM t") @@ -264,7 +269,7 @@ async fn information_schema_show_columns_no_information_schema() { async fn information_schema_show_columns_like_where() { let mut ctx = ExecutionContext::with_config(ExecutionConfig::new()); - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + ctx.register_table("t", table_with_sequence(1, 1).unwrap()) .unwrap(); let expected = @@ -275,8 +280,7 @@ async fn information_schema_show_columns_like_where() { .unwrap_err(); assert_eq!(err.to_string(), expected); - let err = - plan_and_collect(&mut ctx, "SHOW COLUMNS FROM t WHERE column_name = 'bar'") + let err = plan_and_collect(&mut ctx, "SHOW COLUMNS FROM t WHERE column_name = 'bar'") .await .unwrap_err(); assert_eq!(err.to_string(), expected); @@ -288,7 +292,7 @@ async fn information_schema_show_columns() { ExecutionConfig::new().with_information_schema(true), ); - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + ctx.register_table("t", table_with_sequence(1, 1).unwrap()) .unwrap(); let result = plan_and_collect(&mut ctx, "SHOW COLUMNS FROM t") @@ -326,7 +330,7 @@ async fn information_schema_show_columns_full_extended() { ExecutionConfig::new().with_information_schema(true), ); - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + ctx.register_table("t", table_with_sequence(1, 1).unwrap()) .unwrap(); let result = plan_and_collect(&mut ctx, "SHOW FULL COLUMNS FROM t") @@ -353,7 +357,7 @@ async fn information_schema_show_table_table_names() { ExecutionConfig::new().with_information_schema(true), ); - ctx.register_table("t", test::table_with_sequence(1, 1).unwrap()) + ctx.register_table("t", table_with_sequence(1, 1).unwrap()) .unwrap(); let result = plan_and_collect(&mut ctx, "SHOW COLUMNS FROM public.t") @@ -385,7 +389,10 @@ async fn information_schema_show_table_table_names() { let err = plan_and_collect(&mut ctx, "SHOW columns from datafusion.public.t2") .await .unwrap_err(); - assert_eq!(err.to_string(), "Error during planning: Unknown relation for SHOW COLUMNS: datafusion.public.t2"); + assert_eq!( + err.to_string(), + "Error during planning: Unknown relation for SHOW COLUMNS: datafusion.public.t2" + ); } #[tokio::test] @@ -412,7 +419,6 @@ async fn information_schema_columns_not_exist_by_default() { ); } - fn table_with_many_types() -> Arc { let schema = Schema::new(vec![ Field::new("int32_col", DataType::Int32, false), @@ -443,7 +449,7 @@ fn table_with_many_types() -> Arc { )), ], ) - .unwrap(); + .unwrap(); let provider = MemTable::try_new(Arc::new(schema), vec![vec![batch]]).unwrap(); Arc::new(provider) } @@ -457,7 +463,7 @@ async fn information_schema_columns() { let schema = MemorySchemaProvider::new(); schema - .register_table("t1".to_owned(), test::table_with_sequence(1, 1).unwrap()) + .register_table("t1".to_owned(), table_with_sequence(1, 1).unwrap()) .unwrap(); schema @@ -466,8 +472,7 @@ async fn information_schema_columns() { catalog.register_schema("my_schema", Arc::new(schema)); ctx.register_catalog("my_catalog", Arc::new(catalog)); - let result = - plan_and_collect(&mut ctx, "SELECT * from information_schema.columns") + let result = plan_and_collect(&mut ctx, "SELECT * from information_schema.columns") .await .unwrap(); @@ -487,3 +492,11 @@ async fn information_schema_columns() { ]; assert_batches_sorted_eq!(expected, &result); } + +/// Execute SQL and return results +async fn plan_and_collect( + ctx: &mut ExecutionContext, + sql: &str, +) -> Result> { + ctx.sql(sql).await?.collect().await +} diff --git a/datafusion/tests/sql/mod.rs b/datafusion/tests/sql/mod.rs index 55715af4f164..f2496c36814b 100644 --- a/datafusion/tests/sql/mod.rs +++ b/datafusion/tests/sql/mod.rs @@ -29,6 +29,7 @@ use datafusion::assert_batches_eq; use datafusion::assert_batches_sorted_eq; use datafusion::assert_contains; use datafusion::assert_not_contains; +use datafusion::datasource::TableProvider; use datafusion::from_slice::FromSlice; use datafusion::logical_plan::plan::{Aggregate, Projection}; use datafusion::logical_plan::LogicalPlan; @@ -95,6 +96,7 @@ pub mod udf; pub mod union; pub mod window; +pub mod information_schema; #[cfg_attr(not(feature = "unicode_expressions"), ignore)] pub mod unicode; @@ -693,6 +695,21 @@ fn make_timestamp_nano_table() -> Result> { make_timestamp_table::() } +/// Return a new table provider that has a single Int32 column with +/// values between `seq_start` and `seq_end` +pub fn table_with_sequence( + seq_start: i32, + seq_end: i32, +) -> Result> { + let schema = Arc::new(Schema::new(vec![Field::new("i", DataType::Int32, true)])); + let arr = Arc::new(Int32Array::from((seq_start..=seq_end).collect::>())); + let partitions = vec![vec![RecordBatch::try_new( + schema.clone(), + vec![arr as ArrayRef], + )?]]; + Ok(Arc::new(MemTable::try_new(schema, partitions)?)) +} + // Normalizes parts of an explain plan that vary from run to run (such as path) fn normalize_for_explain(s: &str) -> String { // Convert things like /Users/alamb/Software/arrow/testing/data/csv/aggregate_test_100.csv