Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions datafusion-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,9 @@ fn get_session_config(args: &Args) -> Result<SessionConfig> {
config_options.sql_parser.dialect = Dialect::Spark;
}

let mut session_config =
SessionConfig::from(config_options).with_information_schema(true);
let mut session_config = SessionConfig::from(config_options)
.with_system_catalog(Some(String::from("system")))
.with_information_schema(true);

if args.reads_sql_from_stdin() {
// When stdin carries the session's SQL — the REPL (including any rc
Expand Down
146 changes: 116 additions & 30 deletions datafusion/catalog/src/information_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ impl InformationSchemaProvider {
pub fn new(catalog_list: Arc<dyn CatalogProviderList>) -> Self {
Self {
config: InformationSchemaConfig {
system_catalog_name: None,
catalog_list,
table_functions: HashMap::new(),
},
Expand All @@ -98,10 +99,16 @@ impl InformationSchemaProvider {
self.config.table_functions = table_functions;
self
}

pub fn with_system_catalog(mut self, catalog_name: String) -> Self {
self.config.system_catalog_name = Some(catalog_name);
self
}
}

#[derive(Clone, Debug)]
struct InformationSchemaConfig {
system_catalog_name: Option<String>,
catalog_list: Arc<dyn CatalogProviderList>,
table_functions: HashMap<String, Arc<TableFunction>>,
}
Expand Down Expand Up @@ -148,6 +155,17 @@ impl InformationSchemaConfig {
}
}

if let Some(system_catalog_name) = &self.system_catalog_name {
for table_name in INFORMATION_SCHEMA_TABLES {
builder.add_table(
system_catalog_name,
INFORMATION_SCHEMA,
table_name,
TableType::View,
);
}
}

Ok(())
}

Expand Down Expand Up @@ -177,21 +195,46 @@ impl InformationSchemaConfig {
if schema_name != INFORMATION_SCHEMA {
// schema name may not exist in the catalog, so we need to check
if let Some(schema) = catalog.schema(&schema_name) {
for table_name in schema.table_names() {
if let Some(table) = schema.table(&table_name).await? {
builder.add_view(
&catalog_name,
&schema_name,
&table_name,
table.get_table_definition(),
)
}
}
Self::add_views(
builder,
&catalog_name,
&schema_name,
schema.as_ref(),
)
.await?;
}
}

// Add the information schema views themselves
Self::add_views(builder, &catalog_name, INFORMATION_SCHEMA, self).await?;
}
}

// Add the system information schema
if let Some(system_catalog_name) = &self.system_catalog_name {
Self::add_views(builder, system_catalog_name, INFORMATION_SCHEMA, self)
.await?;
}

Ok(())
}

async fn add_views(
builder: &mut InformationSchemaViewBuilder,
catalog_name: &str,
schema_name: &str,
schema: &dyn SchemaProvider,
) -> Result<(), DataFusionError> {
for table_name in schema.table_names() {
if let Some(table) = schema.table(&table_name).await? {
builder.add_view(
catalog_name,
schema_name,
&table_name,
table.get_table_definition(),
)
}
}
Ok(())
}

Expand All @@ -207,21 +250,13 @@ impl InformationSchemaConfig {
if schema_name != INFORMATION_SCHEMA {
// schema name may not exist in the catalog, so we need to check
if let Some(schema) = catalog.schema(&schema_name) {
for table_name in schema.table_names() {
if let Some(table) = schema.table(&table_name).await? {
for (field_position, field) in
table.schema().fields().iter().enumerate()
{
builder.add_column(
&catalog_name,
&schema_name,
&table_name,
field_position,
field,
)
}
}
}
Self::add_columns(
builder,
&catalog_name,
&schema_name,
schema.as_ref(),
)
.await?;
}
}
}
Expand All @@ -230,6 +265,29 @@ impl InformationSchemaConfig {
Ok(())
}

async fn add_columns(
builder: &mut InformationSchemaColumnsBuilder,
catalog_name: &str,
schema_name: &str,
schema: &dyn SchemaProvider,
) -> Result<(), DataFusionError> {
for table_name in schema.table_names() {
if let Some(table) = schema.table(&table_name).await? {
for (field_position, field) in table.schema().fields().iter().enumerate()
{
builder.add_column(
catalog_name,
schema_name,
&table_name,
field_position,
field,
)
}
}
}
Ok(())
}

/// Construct the `information_schema.df_settings` virtual table
fn make_df_settings(
&self,
Expand Down Expand Up @@ -575,6 +633,24 @@ fn remove_native_type_prefix(native_type: &NativeType) -> String {

#[async_trait]
impl SchemaProvider for InformationSchemaProvider {
fn table_names(&self) -> Vec<String> {
self.config.table_names()
}

async fn table(
&self,
name: &str,
) -> Result<Option<Arc<dyn TableProvider>>, DataFusionError> {
self.config.get_table(name)
}

fn table_exist(&self, name: &str) -> bool {
self.config.table_exist(name)
}
}

#[async_trait]
impl SchemaProvider for InformationSchemaConfig {
fn table_names(&self) -> Vec<String> {
INFORMATION_SCHEMA_TABLES
.iter()
Expand All @@ -586,7 +662,20 @@ impl SchemaProvider for InformationSchemaProvider {
&self,
name: &str,
) -> Result<Option<Arc<dyn TableProvider>>, DataFusionError> {
let config = self.config.clone();
self.get_table(name)
}

fn table_exist(&self, name: &str) -> bool {
INFORMATION_SCHEMA_TABLES.contains(&name.to_ascii_lowercase().as_str())
}
}

impl InformationSchemaConfig {
fn get_table(
&self,
name: &str,
) -> Result<Option<Arc<dyn TableProvider>>, DataFusionError> {
let config = self.clone();
let table: Arc<dyn PartitionStream> = match name.to_ascii_lowercase().as_str() {
TABLES => Arc::new(InformationSchemaTables::new(config)),
COLUMNS => Arc::new(InformationSchemaColumns::new(config)),
Expand All @@ -602,10 +691,6 @@ impl SchemaProvider for InformationSchemaProvider {
StreamingTable::try_new(Arc::clone(table.schema()), vec![table]).unwrap(),
)))
}

fn table_exist(&self, name: &str) -> bool {
INFORMATION_SCHEMA_TABLES.contains(&name.to_ascii_lowercase().as_str())
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -1564,6 +1649,7 @@ mod tests {
#[tokio::test]
async fn make_tables_uses_table_type() {
let config = InformationSchemaConfig {
system_catalog_name: None,
catalog_list: Arc::new(Fixture),
table_functions: HashMap::new(),
};
Expand Down
3 changes: 3 additions & 0 deletions datafusion/common/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ config_namespace! {
/// The default schema name - this impacts what SQL queries use if not specified
pub default_schema: String, default = "public".to_string()

/// The system schema name - when set a global system and `information_schema` catalog will be available
pub system_catalog: Option<String>, default = None

/// Should DataFusion provide access to `information_schema`
/// virtual tables for displaying schema information
pub information_schema: bool, default = false
Expand Down
6 changes: 4 additions & 2 deletions datafusion/core/src/execution/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2846,7 +2846,9 @@ mod tests {
async fn sql_create_catalog() -> Result<()> {
// the information schema used to introduce cyclic Arcs
let ctx = SessionContext::new_with_config(
SessionConfig::new().with_information_schema(true),
SessionConfig::new()
.with_information_schema(true)
.with_system_catalog(Some(String::from("system"))),
);

// Create catalog
Expand All @@ -2862,7 +2864,7 @@ mod tests {
.await?;

// Check table exists in schema
let results = ctx.sql("SELECT * FROM information_schema.tables WHERE table_catalog='test' AND table_schema='abc' AND table_name = 'y'").await.unwrap().collect().await.unwrap();
let results = ctx.sql("SELECT * FROM system.information_schema.tables WHERE table_catalog='test' AND table_schema='abc' AND table_name = 'y'").await.unwrap().collect().await.unwrap();

assert_eq!(results[0].num_rows(), 1);
Ok(())
Expand Down
Loading
Loading