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 d11e28a33 feat(catalog): Implement information_schema.views (#2934)
d11e28a33 is described below
commit d11e28a333992ffe71303a19a4891a354c8af240
Author: BaymaxHWY <[email protected]>
AuthorDate: Wed Jul 20 21:23:33 2022 +0800
feat(catalog): Implement information_schema.views (#2934)
---
datafusion/core/src/catalog/information_schema.rs | 126 +++++++++++++++++---
datafusion/core/tests/sql/information_schema.rs | 138 ++++++++++++----------
datafusion/sql/src/planner.rs | 4 +-
3 files changed, 183 insertions(+), 85 deletions(-)
diff --git a/datafusion/core/src/catalog/information_schema.rs
b/datafusion/core/src/catalog/information_schema.rs
index fd8e250fe..0467dffa7 100644
--- a/datafusion/core/src/catalog/information_schema.rs
+++ b/datafusion/core/src/catalog/information_schema.rs
@@ -41,6 +41,7 @@ use super::{
const INFORMATION_SCHEMA: &str = "information_schema";
const TABLES: &str = "tables";
+const VIEWS: &str = "views";
const COLUMNS: &str = "columns";
/// Wraps another [`CatalogProvider`] and adds a "information_schema"
@@ -124,28 +125,21 @@ impl InformationSchemaProvider {
builder.add_table(
&catalog_name,
&schema_name,
- table_name,
+ &table_name,
table.table_type(),
- table.get_table_definition(),
);
}
}
}
// Add a final list for the information schema tables themselves
- builder.add_table(
- &catalog_name,
- INFORMATION_SCHEMA,
- TABLES,
- TableType::View,
- None::<&str>,
- );
+ builder.add_table(&catalog_name, INFORMATION_SCHEMA, TABLES,
TableType::View);
+ builder.add_table(&catalog_name, INFORMATION_SCHEMA, VIEWS,
TableType::View);
builder.add_table(
&catalog_name,
INFORMATION_SCHEMA,
COLUMNS,
TableType::View,
- None::<&str>,
);
}
@@ -154,6 +148,32 @@ impl InformationSchemaProvider {
Arc::new(mem_table)
}
+ fn make_views(&self) -> Arc<dyn TableProvider> {
+ let mut builder = InformationSchemaViewBuilder::new();
+
+ for catalog_name in self.catalog_list.catalog_names() {
+ let catalog = self.catalog_list.catalog(&catalog_name).unwrap();
+
+ for schema_name in catalog.schema_names() {
+ if schema_name != INFORMATION_SCHEMA {
+ let schema = catalog.schema(&schema_name).unwrap();
+ for table_name in schema.table_names() {
+ let table = schema.table(&table_name).unwrap();
+ builder.add_view(
+ &catalog_name,
+ &schema_name,
+ &table_name,
+ table.get_table_definition(),
+ )
+ }
+ }
+ }
+ }
+
+ let mem_table: MemTable = builder.into();
+ Arc::new(mem_table)
+ }
+
/// Construct the `information_schema.columns` virtual table
fn make_columns(&self) -> Arc<dyn TableProvider> {
let mut builder = InformationSchemaColumnsBuilder::new();
@@ -194,7 +214,7 @@ impl SchemaProvider for InformationSchemaProvider {
}
fn table_names(&self) -> Vec<String> {
- vec![TABLES.to_string(), COLUMNS.to_string()]
+ vec![TABLES.to_string(), VIEWS.to_string(), COLUMNS.to_string()]
}
fn table(&self, name: &str) -> Option<Arc<dyn TableProvider>> {
@@ -202,13 +222,15 @@ impl SchemaProvider for InformationSchemaProvider {
Some(self.make_tables())
} else if name.eq_ignore_ascii_case("columns") {
Some(self.make_columns())
+ } else if name.eq_ignore_ascii_case("views") {
+ Some(self.make_views())
} else {
None
}
}
fn table_exist(&self, name: &str) -> bool {
- return matches!(name.to_ascii_lowercase().as_str(), TABLES | COLUMNS);
+ return matches!(name.to_ascii_lowercase().as_str(), TABLES | VIEWS |
COLUMNS);
}
}
@@ -220,7 +242,6 @@ struct InformationSchemaTablesBuilder {
schema_names: StringBuilder,
table_names: StringBuilder,
table_types: StringBuilder,
- definitions: StringBuilder,
}
impl InformationSchemaTablesBuilder {
@@ -234,7 +255,6 @@ impl InformationSchemaTablesBuilder {
schema_names: StringBuilder::new(default_capacity),
table_names: StringBuilder::new(default_capacity),
table_types: StringBuilder::new(default_capacity),
- definitions: StringBuilder::new(default_capacity),
}
}
@@ -244,7 +264,6 @@ impl InformationSchemaTablesBuilder {
schema_name: impl AsRef<str>,
table_name: impl AsRef<str>,
table_type: TableType,
- definition: Option<impl AsRef<str>>,
) {
// Note: append_value is actually infallable.
self.catalog_names
@@ -261,7 +280,6 @@ impl InformationSchemaTablesBuilder {
TableType::Temporary => "LOCAL TEMPORARY",
})
.unwrap();
- self.definitions.append_option(definition.as_ref()).unwrap();
}
}
@@ -272,7 +290,6 @@ impl From<InformationSchemaTablesBuilder> for MemTable {
Field::new("table_schema", DataType::Utf8, false),
Field::new("table_name", DataType::Utf8, false),
Field::new("table_type", DataType::Utf8, false),
- Field::new("definition", DataType::Utf8, true),
]);
let InformationSchemaTablesBuilder {
@@ -280,7 +297,6 @@ impl From<InformationSchemaTablesBuilder> for MemTable {
mut schema_names,
mut table_names,
mut table_types,
- mut definitions,
} = value;
let schema = Arc::new(schema);
@@ -291,6 +307,80 @@ impl From<InformationSchemaTablesBuilder> for MemTable {
Arc::new(schema_names.finish()),
Arc::new(table_names.finish()),
Arc::new(table_types.finish()),
+ ],
+ )
+ .unwrap();
+
+ MemTable::try_new(schema, vec![vec![batch]]).unwrap()
+ }
+}
+
+/// Builds the `information_schema.VIEWS` table row by row
+///
+/// Columns are based on
<https://www.postgresql.org/docs/current/infoschema-columns.html>
+struct InformationSchemaViewBuilder {
+ catalog_names: StringBuilder,
+ schema_names: StringBuilder,
+ table_names: StringBuilder,
+ definitions: StringBuilder,
+}
+
+impl InformationSchemaViewBuilder {
+ fn new() -> Self {
+ // StringBuilder requires providing an initial capacity, so
+ // pick 10 here arbitrarily as this is not performance
+ // critical code and the number of tables is unavailable here.
+ let default_capacity = 10;
+ Self {
+ catalog_names: StringBuilder::new(default_capacity),
+ schema_names: StringBuilder::new(default_capacity),
+ table_names: StringBuilder::new(default_capacity),
+ definitions: StringBuilder::new(default_capacity),
+ }
+ }
+
+ fn add_view(
+ &mut self,
+ catalog_name: impl AsRef<str>,
+ schema_name: impl AsRef<str>,
+ table_name: impl AsRef<str>,
+ definition: Option<impl AsRef<str>>,
+ ) {
+ // Note: append_value is actually infallable.
+ self.catalog_names
+ .append_value(catalog_name.as_ref())
+ .unwrap();
+ self.schema_names
+ .append_value(schema_name.as_ref())
+ .unwrap();
+ self.table_names.append_value(table_name.as_ref()).unwrap();
+ self.definitions.append_option(definition.as_ref()).unwrap();
+ }
+}
+
+impl From<InformationSchemaViewBuilder> for MemTable {
+ fn from(value: InformationSchemaViewBuilder) -> Self {
+ let schema = Schema::new(vec![
+ Field::new("table_catalog", DataType::Utf8, false),
+ Field::new("table_schema", DataType::Utf8, false),
+ Field::new("table_name", DataType::Utf8, false),
+ Field::new("definition", DataType::Utf8, true),
+ ]);
+
+ let InformationSchemaViewBuilder {
+ mut catalog_names,
+ mut schema_names,
+ mut table_names,
+ mut definitions,
+ } = value;
+
+ let schema = Arc::new(schema);
+ let batch = RecordBatch::try_new(
+ schema.clone(),
+ vec![
+ Arc::new(catalog_names.finish()),
+ Arc::new(schema_names.finish()),
+ Arc::new(table_names.finish()),
Arc::new(definitions.finish()),
],
)
diff --git a/datafusion/core/tests/sql/information_schema.rs
b/datafusion/core/tests/sql/information_schema.rs
index f528c3c3c..5a4aa297f 100644
--- a/datafusion/core/tests/sql/information_schema.rs
+++ b/datafusion/core/tests/sql/information_schema.rs
@@ -52,12 +52,13 @@ async fn information_schema_tables_no_tables() {
.unwrap();
let expected = vec![
-
"+---------------+--------------------+------------+------------+------------+",
- "| table_catalog | table_schema | table_name | table_type |
definition |",
-
"+---------------+--------------------+------------+------------+------------+",
- "| datafusion | information_schema | columns | VIEW |
|",
- "| datafusion | information_schema | tables | VIEW |
|",
-
"+---------------+--------------------+------------+------------+------------+",
+ "+---------------+--------------------+------------+------------+",
+ "| table_catalog | table_schema | table_name | table_type |",
+ "+---------------+--------------------+------------+------------+",
+ "| datafusion | information_schema | columns | VIEW |",
+ "| datafusion | information_schema | tables | VIEW |",
+ "| datafusion | information_schema | views | VIEW |",
+ "+---------------+--------------------+------------+------------+",
];
assert_batches_sorted_eq!(expected, &result);
}
@@ -76,13 +77,14 @@ async fn information_schema_tables_tables_default_catalog()
{
.unwrap();
let expected = vec![
-
"+---------------+--------------------+------------+------------+------------+",
- "| table_catalog | table_schema | table_name | table_type |
definition |",
-
"+---------------+--------------------+------------+------------+------------+",
- "| datafusion | information_schema | columns | VIEW |
|",
- "| datafusion | information_schema | tables | VIEW |
|",
- "| datafusion | public | t | BASE TABLE |
|",
-
"+---------------+--------------------+------------+------------+------------+",
+ "+---------------+--------------------+------------+------------+",
+ "| table_catalog | table_schema | table_name | table_type |",
+ "+---------------+--------------------+------------+------------+",
+ "| datafusion | information_schema | columns | VIEW |",
+ "| datafusion | information_schema | tables | VIEW |",
+ "| datafusion | information_schema | views | VIEW |",
+ "| datafusion | public | t | BASE TABLE |",
+ "+---------------+--------------------+------------+------------+",
];
assert_batches_sorted_eq!(expected, &result);
@@ -95,14 +97,15 @@ async fn information_schema_tables_tables_default_catalog()
{
.unwrap();
let expected = vec![
-
"+---------------+--------------------+------------+------------+------------+",
- "| table_catalog | table_schema | table_name | table_type |
definition |",
-
"+---------------+--------------------+------------+------------+------------+",
- "| datafusion | information_schema | columns | VIEW |
|",
- "| datafusion | information_schema | tables | VIEW |
|",
- "| datafusion | public | t | BASE TABLE |
|",
- "| datafusion | public | t2 | BASE TABLE |
|",
-
"+---------------+--------------------+------------+------------+------------+",
+ "+---------------+--------------------+------------+------------+",
+ "| table_catalog | table_schema | table_name | table_type |",
+ "+---------------+--------------------+------------+------------+",
+ "| datafusion | information_schema | columns | VIEW |",
+ "| datafusion | information_schema | tables | VIEW |",
+ "| datafusion | information_schema | views | VIEW |",
+ "| datafusion | public | t | BASE TABLE |",
+ "| datafusion | public | t2 | BASE TABLE |",
+ "+---------------+--------------------+------------+------------+",
];
assert_batches_sorted_eq!(expected, &result);
}
@@ -139,19 +142,22 @@ async fn
information_schema_tables_tables_with_multiple_catalogs() {
.unwrap();
let expected = vec![
-
"+------------------+--------------------+------------+------------+------------+",
- "| table_catalog | table_schema | table_name | table_type |
definition |",
-
"+------------------+--------------------+------------+------------+------------+",
- "| 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 |
|",
-
"+------------------+--------------------+------------+------------+------------+",
+ "+------------------+--------------------+------------+------------+",
+ "| table_catalog | table_schema | table_name | table_type |",
+ "+------------------+--------------------+------------+------------+",
+ "| datafusion | information_schema | columns | VIEW |",
+ "| datafusion | information_schema | tables | VIEW |",
+ "| datafusion | information_schema | views | VIEW |",
+ "| my_catalog | information_schema | columns | VIEW |",
+ "| my_catalog | information_schema | tables | VIEW |",
+ "| my_catalog | information_schema | views | 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 | information_schema | views | VIEW |",
+ "| my_other_catalog | my_other_schema | t3 | BASE TABLE |",
+ "+------------------+--------------------+------------+------------+",
];
assert_batches_sorted_eq!(expected, &result);
}
@@ -200,15 +206,16 @@ async fn information_schema_tables_table_types() {
.unwrap();
let expected = vec![
-
"+---------------+--------------------+------------+-----------------+------------+",
- "| table_catalog | table_schema | table_name | table_type |
definition |",
-
"+---------------+--------------------+------------+-----------------+------------+",
- "| datafusion | information_schema | columns | VIEW |
|",
- "| datafusion | information_schema | tables | VIEW |
|",
- "| datafusion | public | physical | BASE TABLE |
|",
- "| datafusion | public | query | VIEW |
|",
- "| datafusion | public | temp | LOCAL TEMPORARY |
|",
-
"+---------------+--------------------+------------+-----------------+------------+",
+
"+---------------+--------------------+------------+-----------------+",
+ "| table_catalog | table_schema | table_name | table_type
|",
+
"+---------------+--------------------+------------+-----------------+",
+ "| datafusion | information_schema | columns | VIEW
|",
+ "| datafusion | information_schema | tables | VIEW
|",
+ "| datafusion | information_schema | views | VIEW
|",
+ "| datafusion | public | physical | BASE TABLE
|",
+ "| datafusion | public | query | VIEW
|",
+ "| datafusion | public | temp | LOCAL TEMPORARY
|",
+
"+---------------+--------------------+------------+-----------------+",
];
assert_batches_sorted_eq!(expected, &result);
}
@@ -273,13 +280,14 @@ async fn information_schema_show_tables() {
let result = plan_and_collect(&ctx, "SHOW TABLES").await.unwrap();
let expected = vec![
-
"+---------------+--------------------+------------+------------+------------+",
- "| table_catalog | table_schema | table_name | table_type |
definition |",
-
"+---------------+--------------------+------------+------------+------------+",
- "| datafusion | information_schema | columns | VIEW |
|",
- "| datafusion | information_schema | tables | VIEW |
|",
- "| datafusion | public | t | BASE TABLE |
|",
-
"+---------------+--------------------+------------+------------+------------+",
+ "+---------------+--------------------+------------+------------+",
+ "| table_catalog | table_schema | table_name | table_type |",
+ "+---------------+--------------------+------------+------------+",
+ "| datafusion | information_schema | columns | VIEW |",
+ "| datafusion | information_schema | tables | VIEW |",
+ "| datafusion | information_schema | views | VIEW |",
+ "| datafusion | public | t | BASE TABLE |",
+ "+---------------+--------------------+------------+------------+",
];
assert_batches_sorted_eq!(expected, &result);
@@ -542,11 +550,11 @@ async fn show_create_view() {
assert_eq!(results[0].num_rows(), 1);
let expected = vec![
- "+------+--------------------------------------+",
- "| name | definition |",
- "+------+--------------------------------------+",
- "| xyz | CREATE VIEW xyz AS SELECT * FROM abc |",
- "+------+--------------------------------------+",
+
"+---------------+--------------+------------+--------------------------------------+",
+ "| table_catalog | table_schema | table_name | definition
|",
+
"+---------------+--------------+------------+--------------------------------------+",
+ "| datafusion | public | xyz | CREATE VIEW xyz AS
SELECT * FROM abc |",
+
"+---------------+--------------+------------+--------------------------------------+",
];
assert_batches_eq!(expected, &results);
}
@@ -567,11 +575,11 @@ async fn show_create_view_in_catalog() {
assert_eq!(results[0].num_rows(), 1);
let expected = vec![
- "+----------+-------------------------------------------+",
- "| name | definition |",
- "+----------+-------------------------------------------+",
- "| test.xyz | CREATE VIEW test.xyz AS SELECT * FROM abc |",
- "+----------+-------------------------------------------+",
+
"+---------------+--------------+------------+-------------------------------------------+",
+ "| table_catalog | table_schema | table_name | definition
|",
+
"+---------------+--------------+------------+-------------------------------------------+",
+ "| datafusion | test | xyz | CREATE VIEW test.xyz AS
SELECT * FROM abc |",
+
"+---------------+--------------+------------+-------------------------------------------+",
];
assert_batches_eq!(expected, &results);
}
@@ -587,11 +595,11 @@ async fn show_create_table() {
let results = plan_and_collect(&ctx, result_sql).await.unwrap();
let expected = vec![
- "+------+------------+",
- "| name | definition |",
- "+------+------------+",
- "| abc | |",
- "+------+------------+",
+ "+---------------+--------------+------------+------------+",
+ "| table_catalog | table_schema | table_name | definition |",
+ "+---------------+--------------+------------+------------+",
+ "| datafusion | public | abc | |",
+ "+---------------+--------------+------------+------------+",
];
assert_batches_eq!(expected, &results);
diff --git a/datafusion/sql/src/planner.rs b/datafusion/sql/src/planner.rs
index 2dfd24777..9bab96927 100644
--- a/datafusion/sql/src/planner.rs
+++ b/datafusion/sql/src/planner.rs
@@ -2463,8 +2463,8 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
.join(" AND ");
let query = format!(
- "SELECT '{}' as name, definition FROM information_schema.tables
WHERE {}",
- table_name, where_clause
+ "SELECT table_catalog, table_schema, table_name, definition FROM
information_schema.views WHERE {}",
+ where_clause
);
let mut rewrite = DFParser::parse_sql(&query)?;