ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing - #9762

Closed
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog
Closed

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing#9762
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog

Conversation

@returnString

@returnStringreturnString commented Mar 21, 2021

Copy link
Copy Markdown
Contributor

This is an implementation of catalog and schema providers to support table namespacing (see the design doc).

I'm creating this draft PR as a supporting implementation for the proposal, to prove out that the work can be done whilst minimising API churn and still allowing for use cases that don't care at all about the notion of catalogs or schemas; in this new setup, the default namespace is datafusion.public, which will be created automatically with the default execution context config and allow for table registration.

Highlights

  • Datasource map removed in execution context state, replaced with catalog map
  • Execution context allows for registering new catalog providers
  • Catalog providers can be queried for their constituent schema providers
  • Schema providers can be queried for table providers, similarly to the old datasource map
  • Includes basic implementations of CatalogProvider and SchemaProvider backed by hashmaps
  • New TableReference enum maps to various ways of referring to a table in sql
    • Bare: my_table
    • Partial: schema.my_table
    • Full: catalog.schema.my_table
  • Given a default catalog and schema, TableReference instances of any variant can be converted to a ResolvedTableReference, which always include all three components

@github-actions

Copy link
Copy Markdown

@Dandandan

Copy link
Copy Markdown
Contributor

This is truly awesome @returnString !
Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

@andygrove

Copy link
Copy Markdown
Member

Thanks @returnString and I appreciate the well-written design doc to explain the PR. I didn't go through the code in great detail but I like the design. I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

@returnString

returnString commented Mar 21, 2021

Copy link
Copy Markdown
ContributorAuthor

Thanks both :)

I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

I've just audited all the unwraps that are introduced in these commits, and they fall into two categories:

  • test cases that aren't already set up to return Result<()>
  • unwrapping guard objects for Mutex/RwLock - afaik these only error if the lock is poisoned and this usage is consistent with existing lock usage e.g. state access in the ExecutionContext

Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

I think the quick hack (context: retrieving a list of table names from the execution ctx, assuming a flat namespace) can probably be removed outright, as ctx.catalog("my_db")?.schema("my_schema")?.table_names() would be a much more explicit way of doing this going forward. As far as I can tell, ExecutionContext::tables isn't referenced at all in the codebase internally, but this would introduce a bit more API breakage.

As for tests, yes, the coverage so far is basically "didn't break anything" and "all three types of reference to a given table in the default catalog/schema resolve correctly", so I'll try and plan out some more in-depth testing covering e.g. tables of the same name in multiple schemas/catalogs.

@codecov-io

codecov-io commented Mar 21, 2021

Copy link
Copy Markdown

Codecov Report

Merging #9762 (03048c6) into master (29feea0) will increase coverage by 0.00%.
The diff coverage is 80.36%.

Impacted file tree graph

@@ Coverage Diff @@## master #9762 +/- ##
========================================
Coverage 82.59% 82.59% ========================================
Files 248 252 +4 Lines 58294 59004 +710 ========================================
+ Hits 48149 48737 +588 - Misses 10145 10267 +122 
Impacted FilesCoverage Δ
rust/datafusion/examples/flight_server.rs0.00% <0.00%> (ø)
rust/datafusion/examples/simple_udaf.rs0.00% <ø> (ø)
rust/datafusion/src/datasource/datasource.rs100.00% <ø> (ø)
rust/datafusion/src/datasource/memory.rs85.15% <ø> (ø)
rust/datafusion/src/execution/dataframe_impl.rs89.10% <0.00%> (-1.03%)⬇️
rust/datafusion/src/optimizer/constant_folding.rs92.30% <0.00%> (-0.36%)⬇️
...datafusion/src/optimizer/hash_build_probe_order.rs53.60% <0.00%> (-1.72%)⬇️
...t/datafusion/src/optimizer/projection_push_down.rs98.66% <ø> (ø)
rust/datafusion/src/physical_plan/mod.rs88.00% <ø> (ø)
rust/parquet/src/basic.rs88.59% <ø> (+1.36%)⬆️
... and 35 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 81d6724...03048c6. Read the comment docs.

@returnString
returnString marked this pull request as ready for review March 21, 2021 22:02
@returnString

Copy link
Copy Markdown
ContributorAuthor

Whilst I still want to try and conjure up a few more test cases, I think this PR is now in a state where I'm happy to receive actual code reviews, so I've removed the draft status :)

@alamb

Copy link
Copy Markdown
Contributor

I plan to review this PR later today

@alambalamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all this looks great. Thank you @returnString !

I went through it fairly carefully and I have some suggestions but nothing that would prevent us from merging this in my opinion.

start.elapsed().as_millis()
);
ctx.register_table(table, Arc::new(memtable));
ctx.register_table(*table, Arc::new(memtable))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change to make register_table fallible is a breaking change, but a very reasonable one I think.

// specific language governing permissions and limitations
// under the License.

//! Describes the interface and built-in implementations of catalogs,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

fn as_any(&self) -> &dyn Any;

/// Retrieves the list of available schema names in this catalog.
fn schema_names(&self) -> Vec<String>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about returning something more like Vec<&str> to prevent requiring a copy?

Ideally it would be nice if we could do something like

fn schema_names(&self) -> impl Iterator<Item=&str>

As all uses of the results here will need to iterate over the names I suspect

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I iniitally tried to implement these returning &[&str] but with the threading requirements I struggled to get anything working that way. I think this would require a larger refactoring to enable, but I'm not 100% sure on that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vec<&str> might be possible

}

/// Simple in-memory implementation of a catalog.
pub struct MemoryCatalogProvider {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some other PR perhaps we can put the concrete implementations into their own modules. I don't think this one is big enough to warrant that yet, however; I just wanted to point it out

impl<'a> TryFrom<&'a sqlparser::ast::ObjectName> for TableReference<'a> {
type Error = DataFusionError;

fn try_from(value: &'a sqlparser::ast::ObjectName) -> Result<Self, Self::Error> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

/// Selects a name for the default catalog and schema
pub fn with_default_catalog_and_schema(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this API. 👍

I wonder if we need an API for getting default_catalog and default_schema?

Comment threadrust/datafusion/src/execution/context.rs Outdated
@@ -1922,6 +2035,114 @@ mod tests {
Ok(())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are excellent tests . 👍

&mut ctx,
"SELECT cat, SUM(i) AS total FROM (
SELECT i, 'a' AS cat FROM catalog_a.schema_a.table_a
UNION ALL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DandandanUNION is already being used!

for table_ref in &[
"nonexistentschema.aggregate_test_100",
"nonexistentcatalog.public.aggregate_test_100",
"way.too.many.namespaces.as.ident.prefixes.aggregate_test_100",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
@alamb

Copy link
Copy Markdown
Contributor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

@returnString

Copy link
Copy Markdown
ContributorAuthor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

I was looking to see if I could improve the test setup any further, but on reflection I'm actually pretty happy with the state of things; I don't think we're missing any use cases in the coverage (at least, ones I can conceive of right now). So from my side, happy with things as they are :)

@alambalamb closed this in 14441dbMar 23, 2021
@alamb

Copy link
Copy Markdown
Contributor

Thanks again @returnString ! This is a great feature

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@returnString@Dandandan@andygrove@codecov-io@alamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing - #9762

Closed
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog
Closed

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing#9762
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog

Conversation

@returnString

@returnStringreturnString commented Mar 21, 2021

Copy link
Copy Markdown
Contributor

This is an implementation of catalog and schema providers to support table namespacing (see the design doc).

I'm creating this draft PR as a supporting implementation for the proposal, to prove out that the work can be done whilst minimising API churn and still allowing for use cases that don't care at all about the notion of catalogs or schemas; in this new setup, the default namespace is datafusion.public, which will be created automatically with the default execution context config and allow for table registration.

Highlights

  • Datasource map removed in execution context state, replaced with catalog map
  • Execution context allows for registering new catalog providers
  • Catalog providers can be queried for their constituent schema providers
  • Schema providers can be queried for table providers, similarly to the old datasource map
  • Includes basic implementations of CatalogProvider and SchemaProvider backed by hashmaps
  • New TableReference enum maps to various ways of referring to a table in sql
    • Bare: my_table
    • Partial: schema.my_table
    • Full: catalog.schema.my_table
  • Given a default catalog and schema, TableReference instances of any variant can be converted to a ResolvedTableReference, which always include all three components

@github-actions

Copy link
Copy Markdown

@Dandandan

Copy link
Copy Markdown
Contributor

This is truly awesome @returnString !
Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

@andygrove

Copy link
Copy Markdown
Member

Thanks @returnString and I appreciate the well-written design doc to explain the PR. I didn't go through the code in great detail but I like the design. I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

@returnString

returnString commented Mar 21, 2021

Copy link
Copy Markdown
ContributorAuthor

Thanks both :)

I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

I've just audited all the unwraps that are introduced in these commits, and they fall into two categories:

  • test cases that aren't already set up to return Result<()>
  • unwrapping guard objects for Mutex/RwLock - afaik these only error if the lock is poisoned and this usage is consistent with existing lock usage e.g. state access in the ExecutionContext

Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

I think the quick hack (context: retrieving a list of table names from the execution ctx, assuming a flat namespace) can probably be removed outright, as ctx.catalog("my_db")?.schema("my_schema")?.table_names() would be a much more explicit way of doing this going forward. As far as I can tell, ExecutionContext::tables isn't referenced at all in the codebase internally, but this would introduce a bit more API breakage.

As for tests, yes, the coverage so far is basically "didn't break anything" and "all three types of reference to a given table in the default catalog/schema resolve correctly", so I'll try and plan out some more in-depth testing covering e.g. tables of the same name in multiple schemas/catalogs.

@codecov-io

codecov-io commented Mar 21, 2021

Copy link
Copy Markdown

Codecov Report

Merging #9762 (03048c6) into master (29feea0) will increase coverage by 0.00%.
The diff coverage is 80.36%.

Impacted file tree graph

@@ Coverage Diff @@## master #9762 +/- ##
========================================
Coverage 82.59% 82.59% ========================================
Files 248 252 +4 Lines 58294 59004 +710 ========================================
+ Hits 48149 48737 +588 - Misses 10145 10267 +122 
Impacted FilesCoverage Δ
rust/datafusion/examples/flight_server.rs0.00% <0.00%> (ø)
rust/datafusion/examples/simple_udaf.rs0.00% <ø> (ø)
rust/datafusion/src/datasource/datasource.rs100.00% <ø> (ø)
rust/datafusion/src/datasource/memory.rs85.15% <ø> (ø)
rust/datafusion/src/execution/dataframe_impl.rs89.10% <0.00%> (-1.03%)⬇️
rust/datafusion/src/optimizer/constant_folding.rs92.30% <0.00%> (-0.36%)⬇️
...datafusion/src/optimizer/hash_build_probe_order.rs53.60% <0.00%> (-1.72%)⬇️
...t/datafusion/src/optimizer/projection_push_down.rs98.66% <ø> (ø)
rust/datafusion/src/physical_plan/mod.rs88.00% <ø> (ø)
rust/parquet/src/basic.rs88.59% <ø> (+1.36%)⬆️
... and 35 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 81d6724...03048c6. Read the comment docs.

@returnString
returnString marked this pull request as ready for review March 21, 2021 22:02
@returnString

Copy link
Copy Markdown
ContributorAuthor

Whilst I still want to try and conjure up a few more test cases, I think this PR is now in a state where I'm happy to receive actual code reviews, so I've removed the draft status :)

@alamb

Copy link
Copy Markdown
Contributor

I plan to review this PR later today

@alambalamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all this looks great. Thank you @returnString !

I went through it fairly carefully and I have some suggestions but nothing that would prevent us from merging this in my opinion.

start.elapsed().as_millis()
);
ctx.register_table(table, Arc::new(memtable));
ctx.register_table(*table, Arc::new(memtable))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change to make register_table fallible is a breaking change, but a very reasonable one I think.

// specific language governing permissions and limitations
// under the License.

//! Describes the interface and built-in implementations of catalogs,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

fn as_any(&self) -> &dyn Any;

/// Retrieves the list of available schema names in this catalog.
fn schema_names(&self) -> Vec<String>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about returning something more like Vec<&str> to prevent requiring a copy?

Ideally it would be nice if we could do something like

fn schema_names(&self) -> impl Iterator<Item=&str>

As all uses of the results here will need to iterate over the names I suspect

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I iniitally tried to implement these returning &[&str] but with the threading requirements I struggled to get anything working that way. I think this would require a larger refactoring to enable, but I'm not 100% sure on that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vec<&str> might be possible

}

/// Simple in-memory implementation of a catalog.
pub struct MemoryCatalogProvider {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some other PR perhaps we can put the concrete implementations into their own modules. I don't think this one is big enough to warrant that yet, however; I just wanted to point it out

impl<'a> TryFrom<&'a sqlparser::ast::ObjectName> for TableReference<'a> {
type Error = DataFusionError;

fn try_from(value: &'a sqlparser::ast::ObjectName) -> Result<Self, Self::Error> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

/// Selects a name for the default catalog and schema
pub fn with_default_catalog_and_schema(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this API. 👍

I wonder if we need an API for getting default_catalog and default_schema?

Comment threadrust/datafusion/src/execution/context.rs Outdated
@@ -1922,6 +2035,114 @@ mod tests {
Ok(())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are excellent tests . 👍

&mut ctx,
"SELECT cat, SUM(i) AS total FROM (
SELECT i, 'a' AS cat FROM catalog_a.schema_a.table_a
UNION ALL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DandandanUNION is already being used!

for table_ref in &[
"nonexistentschema.aggregate_test_100",
"nonexistentcatalog.public.aggregate_test_100",
"way.too.many.namespaces.as.ident.prefixes.aggregate_test_100",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
@alamb

Copy link
Copy Markdown
Contributor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

@returnString

Copy link
Copy Markdown
ContributorAuthor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

I was looking to see if I could improve the test setup any further, but on reflection I'm actually pretty happy with the state of things; I don't think we're missing any use cases in the coverage (at least, ones I can conceive of right now). So from my side, happy with things as they are :)

@alambalamb closed this in 14441dbMar 23, 2021
@alamb

Copy link
Copy Markdown
Contributor

Thanks again @returnString ! This is a great feature

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@returnString@Dandandan@andygrove@codecov-io@alamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing - #9762

Closed
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog
Closed

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing#9762
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog

Conversation

@returnString

@returnStringreturnString commented Mar 21, 2021

Copy link
Copy Markdown
Contributor

This is an implementation of catalog and schema providers to support table namespacing (see the design doc).

I'm creating this draft PR as a supporting implementation for the proposal, to prove out that the work can be done whilst minimising API churn and still allowing for use cases that don't care at all about the notion of catalogs or schemas; in this new setup, the default namespace is datafusion.public, which will be created automatically with the default execution context config and allow for table registration.

Highlights

  • Datasource map removed in execution context state, replaced with catalog map
  • Execution context allows for registering new catalog providers
  • Catalog providers can be queried for their constituent schema providers
  • Schema providers can be queried for table providers, similarly to the old datasource map
  • Includes basic implementations of CatalogProvider and SchemaProvider backed by hashmaps
  • New TableReference enum maps to various ways of referring to a table in sql
    • Bare: my_table
    • Partial: schema.my_table
    • Full: catalog.schema.my_table
  • Given a default catalog and schema, TableReference instances of any variant can be converted to a ResolvedTableReference, which always include all three components

@github-actions

Copy link
Copy Markdown

@Dandandan

Copy link
Copy Markdown
Contributor

This is truly awesome @returnString !
Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

@andygrove

Copy link
Copy Markdown
Member

Thanks @returnString and I appreciate the well-written design doc to explain the PR. I didn't go through the code in great detail but I like the design. I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

@returnString

returnString commented Mar 21, 2021

Copy link
Copy Markdown
ContributorAuthor

Thanks both :)

I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

I've just audited all the unwraps that are introduced in these commits, and they fall into two categories:

  • test cases that aren't already set up to return Result<()>
  • unwrapping guard objects for Mutex/RwLock - afaik these only error if the lock is poisoned and this usage is consistent with existing lock usage e.g. state access in the ExecutionContext

Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

I think the quick hack (context: retrieving a list of table names from the execution ctx, assuming a flat namespace) can probably be removed outright, as ctx.catalog("my_db")?.schema("my_schema")?.table_names() would be a much more explicit way of doing this going forward. As far as I can tell, ExecutionContext::tables isn't referenced at all in the codebase internally, but this would introduce a bit more API breakage.

As for tests, yes, the coverage so far is basically "didn't break anything" and "all three types of reference to a given table in the default catalog/schema resolve correctly", so I'll try and plan out some more in-depth testing covering e.g. tables of the same name in multiple schemas/catalogs.

@codecov-io

codecov-io commented Mar 21, 2021

Copy link
Copy Markdown

Codecov Report

Merging #9762 (03048c6) into master (29feea0) will increase coverage by 0.00%.
The diff coverage is 80.36%.

Impacted file tree graph

@@ Coverage Diff @@## master #9762 +/- ##
========================================
Coverage 82.59% 82.59% ========================================
Files 248 252 +4 Lines 58294 59004 +710 ========================================
+ Hits 48149 48737 +588 - Misses 10145 10267 +122 
Impacted FilesCoverage Δ
rust/datafusion/examples/flight_server.rs0.00% <0.00%> (ø)
rust/datafusion/examples/simple_udaf.rs0.00% <ø> (ø)
rust/datafusion/src/datasource/datasource.rs100.00% <ø> (ø)
rust/datafusion/src/datasource/memory.rs85.15% <ø> (ø)
rust/datafusion/src/execution/dataframe_impl.rs89.10% <0.00%> (-1.03%)⬇️
rust/datafusion/src/optimizer/constant_folding.rs92.30% <0.00%> (-0.36%)⬇️
...datafusion/src/optimizer/hash_build_probe_order.rs53.60% <0.00%> (-1.72%)⬇️
...t/datafusion/src/optimizer/projection_push_down.rs98.66% <ø> (ø)
rust/datafusion/src/physical_plan/mod.rs88.00% <ø> (ø)
rust/parquet/src/basic.rs88.59% <ø> (+1.36%)⬆️
... and 35 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 81d6724...03048c6. Read the comment docs.

@returnString
returnString marked this pull request as ready for review March 21, 2021 22:02
@returnString

Copy link
Copy Markdown
ContributorAuthor

Whilst I still want to try and conjure up a few more test cases, I think this PR is now in a state where I'm happy to receive actual code reviews, so I've removed the draft status :)

@alamb

Copy link
Copy Markdown
Contributor

I plan to review this PR later today

@alambalamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all this looks great. Thank you @returnString !

I went through it fairly carefully and I have some suggestions but nothing that would prevent us from merging this in my opinion.

start.elapsed().as_millis()
);
ctx.register_table(table, Arc::new(memtable));
ctx.register_table(*table, Arc::new(memtable))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change to make register_table fallible is a breaking change, but a very reasonable one I think.

// specific language governing permissions and limitations
// under the License.

//! Describes the interface and built-in implementations of catalogs,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

fn as_any(&self) -> &dyn Any;

/// Retrieves the list of available schema names in this catalog.
fn schema_names(&self) -> Vec<String>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about returning something more like Vec<&str> to prevent requiring a copy?

Ideally it would be nice if we could do something like

fn schema_names(&self) -> impl Iterator<Item=&str>

As all uses of the results here will need to iterate over the names I suspect

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I iniitally tried to implement these returning &[&str] but with the threading requirements I struggled to get anything working that way. I think this would require a larger refactoring to enable, but I'm not 100% sure on that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vec<&str> might be possible

}

/// Simple in-memory implementation of a catalog.
pub struct MemoryCatalogProvider {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some other PR perhaps we can put the concrete implementations into their own modules. I don't think this one is big enough to warrant that yet, however; I just wanted to point it out

impl<'a> TryFrom<&'a sqlparser::ast::ObjectName> for TableReference<'a> {
type Error = DataFusionError;

fn try_from(value: &'a sqlparser::ast::ObjectName) -> Result<Self, Self::Error> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

/// Selects a name for the default catalog and schema
pub fn with_default_catalog_and_schema(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this API. 👍

I wonder if we need an API for getting default_catalog and default_schema?

Comment threadrust/datafusion/src/execution/context.rs Outdated
@@ -1922,6 +2035,114 @@ mod tests {
Ok(())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are excellent tests . 👍

&mut ctx,
"SELECT cat, SUM(i) AS total FROM (
SELECT i, 'a' AS cat FROM catalog_a.schema_a.table_a
UNION ALL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DandandanUNION is already being used!

for table_ref in &[
"nonexistentschema.aggregate_test_100",
"nonexistentcatalog.public.aggregate_test_100",
"way.too.many.namespaces.as.ident.prefixes.aggregate_test_100",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
@alamb

Copy link
Copy Markdown
Contributor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

@returnString

Copy link
Copy Markdown
ContributorAuthor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

I was looking to see if I could improve the test setup any further, but on reflection I'm actually pretty happy with the state of things; I don't think we're missing any use cases in the coverage (at least, ones I can conceive of right now). So from my side, happy with things as they are :)

@alambalamb closed this in 14441dbMar 23, 2021
@alamb

Copy link
Copy Markdown
Contributor

Thanks again @returnString ! This is a great feature

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@returnString@Dandandan@andygrove@codecov-io@alamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing - #9762

Closed
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog
Closed

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing#9762
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog

Conversation

@returnString

@returnStringreturnString commented Mar 21, 2021

Copy link
Copy Markdown
Contributor

This is an implementation of catalog and schema providers to support table namespacing (see the design doc).

I'm creating this draft PR as a supporting implementation for the proposal, to prove out that the work can be done whilst minimising API churn and still allowing for use cases that don't care at all about the notion of catalogs or schemas; in this new setup, the default namespace is datafusion.public, which will be created automatically with the default execution context config and allow for table registration.

Highlights

  • Datasource map removed in execution context state, replaced with catalog map
  • Execution context allows for registering new catalog providers
  • Catalog providers can be queried for their constituent schema providers
  • Schema providers can be queried for table providers, similarly to the old datasource map
  • Includes basic implementations of CatalogProvider and SchemaProvider backed by hashmaps
  • New TableReference enum maps to various ways of referring to a table in sql
    • Bare: my_table
    • Partial: schema.my_table
    • Full: catalog.schema.my_table
  • Given a default catalog and schema, TableReference instances of any variant can be converted to a ResolvedTableReference, which always include all three components

@github-actions

Copy link
Copy Markdown

@Dandandan

Copy link
Copy Markdown
Contributor

This is truly awesome @returnString !
Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

@andygrove

Copy link
Copy Markdown
Member

Thanks @returnString and I appreciate the well-written design doc to explain the PR. I didn't go through the code in great detail but I like the design. I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

@returnString

returnString commented Mar 21, 2021

Copy link
Copy Markdown
ContributorAuthor

Thanks both :)

I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

I've just audited all the unwraps that are introduced in these commits, and they fall into two categories:

  • test cases that aren't already set up to return Result<()>
  • unwrapping guard objects for Mutex/RwLock - afaik these only error if the lock is poisoned and this usage is consistent with existing lock usage e.g. state access in the ExecutionContext

Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

I think the quick hack (context: retrieving a list of table names from the execution ctx, assuming a flat namespace) can probably be removed outright, as ctx.catalog("my_db")?.schema("my_schema")?.table_names() would be a much more explicit way of doing this going forward. As far as I can tell, ExecutionContext::tables isn't referenced at all in the codebase internally, but this would introduce a bit more API breakage.

As for tests, yes, the coverage so far is basically "didn't break anything" and "all three types of reference to a given table in the default catalog/schema resolve correctly", so I'll try and plan out some more in-depth testing covering e.g. tables of the same name in multiple schemas/catalogs.

@codecov-io

codecov-io commented Mar 21, 2021

Copy link
Copy Markdown

Codecov Report

Merging #9762 (03048c6) into master (29feea0) will increase coverage by 0.00%.
The diff coverage is 80.36%.

Impacted file tree graph

@@ Coverage Diff @@## master #9762 +/- ##
========================================
Coverage 82.59% 82.59% ========================================
Files 248 252 +4 Lines 58294 59004 +710 ========================================
+ Hits 48149 48737 +588 - Misses 10145 10267 +122 
Impacted FilesCoverage Δ
rust/datafusion/examples/flight_server.rs0.00% <0.00%> (ø)
rust/datafusion/examples/simple_udaf.rs0.00% <ø> (ø)
rust/datafusion/src/datasource/datasource.rs100.00% <ø> (ø)
rust/datafusion/src/datasource/memory.rs85.15% <ø> (ø)
rust/datafusion/src/execution/dataframe_impl.rs89.10% <0.00%> (-1.03%)⬇️
rust/datafusion/src/optimizer/constant_folding.rs92.30% <0.00%> (-0.36%)⬇️
...datafusion/src/optimizer/hash_build_probe_order.rs53.60% <0.00%> (-1.72%)⬇️
...t/datafusion/src/optimizer/projection_push_down.rs98.66% <ø> (ø)
rust/datafusion/src/physical_plan/mod.rs88.00% <ø> (ø)
rust/parquet/src/basic.rs88.59% <ø> (+1.36%)⬆️
... and 35 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 81d6724...03048c6. Read the comment docs.

@returnString
returnString marked this pull request as ready for review March 21, 2021 22:02
@returnString

Copy link
Copy Markdown
ContributorAuthor

Whilst I still want to try and conjure up a few more test cases, I think this PR is now in a state where I'm happy to receive actual code reviews, so I've removed the draft status :)

@alamb

Copy link
Copy Markdown
Contributor

I plan to review this PR later today

@alambalamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all this looks great. Thank you @returnString !

I went through it fairly carefully and I have some suggestions but nothing that would prevent us from merging this in my opinion.

start.elapsed().as_millis()
);
ctx.register_table(table, Arc::new(memtable));
ctx.register_table(*table, Arc::new(memtable))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change to make register_table fallible is a breaking change, but a very reasonable one I think.

// specific language governing permissions and limitations
// under the License.

//! Describes the interface and built-in implementations of catalogs,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

fn as_any(&self) -> &dyn Any;

/// Retrieves the list of available schema names in this catalog.
fn schema_names(&self) -> Vec<String>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about returning something more like Vec<&str> to prevent requiring a copy?

Ideally it would be nice if we could do something like

fn schema_names(&self) -> impl Iterator<Item=&str>

As all uses of the results here will need to iterate over the names I suspect

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I iniitally tried to implement these returning &[&str] but with the threading requirements I struggled to get anything working that way. I think this would require a larger refactoring to enable, but I'm not 100% sure on that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vec<&str> might be possible

}

/// Simple in-memory implementation of a catalog.
pub struct MemoryCatalogProvider {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some other PR perhaps we can put the concrete implementations into their own modules. I don't think this one is big enough to warrant that yet, however; I just wanted to point it out

impl<'a> TryFrom<&'a sqlparser::ast::ObjectName> for TableReference<'a> {
type Error = DataFusionError;

fn try_from(value: &'a sqlparser::ast::ObjectName) -> Result<Self, Self::Error> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

/// Selects a name for the default catalog and schema
pub fn with_default_catalog_and_schema(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this API. 👍

I wonder if we need an API for getting default_catalog and default_schema?

Comment threadrust/datafusion/src/execution/context.rs Outdated
@@ -1922,6 +2035,114 @@ mod tests {
Ok(())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are excellent tests . 👍

&mut ctx,
"SELECT cat, SUM(i) AS total FROM (
SELECT i, 'a' AS cat FROM catalog_a.schema_a.table_a
UNION ALL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DandandanUNION is already being used!

for table_ref in &[
"nonexistentschema.aggregate_test_100",
"nonexistentcatalog.public.aggregate_test_100",
"way.too.many.namespaces.as.ident.prefixes.aggregate_test_100",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
@alamb

Copy link
Copy Markdown
Contributor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

@returnString

Copy link
Copy Markdown
ContributorAuthor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

I was looking to see if I could improve the test setup any further, but on reflection I'm actually pretty happy with the state of things; I don't think we're missing any use cases in the coverage (at least, ones I can conceive of right now). So from my side, happy with things as they are :)

@alambalamb closed this in 14441dbMar 23, 2021
@alamb

Copy link
Copy Markdown
Contributor

Thanks again @returnString ! This is a great feature

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@returnString@Dandandan@andygrove@codecov-io@alamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing - #9762

Closed
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog
Closed

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing#9762
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog

Conversation

@returnString

@returnStringreturnString commented Mar 21, 2021

Copy link
Copy Markdown
Contributor

This is an implementation of catalog and schema providers to support table namespacing (see the design doc).

I'm creating this draft PR as a supporting implementation for the proposal, to prove out that the work can be done whilst minimising API churn and still allowing for use cases that don't care at all about the notion of catalogs or schemas; in this new setup, the default namespace is datafusion.public, which will be created automatically with the default execution context config and allow for table registration.

Highlights

  • Datasource map removed in execution context state, replaced with catalog map
  • Execution context allows for registering new catalog providers
  • Catalog providers can be queried for their constituent schema providers
  • Schema providers can be queried for table providers, similarly to the old datasource map
  • Includes basic implementations of CatalogProvider and SchemaProvider backed by hashmaps
  • New TableReference enum maps to various ways of referring to a table in sql
    • Bare: my_table
    • Partial: schema.my_table
    • Full: catalog.schema.my_table
  • Given a default catalog and schema, TableReference instances of any variant can be converted to a ResolvedTableReference, which always include all three components

@github-actions

Copy link
Copy Markdown

@Dandandan

Copy link
Copy Markdown
Contributor

This is truly awesome @returnString !
Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

@andygrove

Copy link
Copy Markdown
Member

Thanks @returnString and I appreciate the well-written design doc to explain the PR. I didn't go through the code in great detail but I like the design. I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

@returnString

returnString commented Mar 21, 2021

Copy link
Copy Markdown
ContributorAuthor

Thanks both :)

I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

I've just audited all the unwraps that are introduced in these commits, and they fall into two categories:

  • test cases that aren't already set up to return Result<()>
  • unwrapping guard objects for Mutex/RwLock - afaik these only error if the lock is poisoned and this usage is consistent with existing lock usage e.g. state access in the ExecutionContext

Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

I think the quick hack (context: retrieving a list of table names from the execution ctx, assuming a flat namespace) can probably be removed outright, as ctx.catalog("my_db")?.schema("my_schema")?.table_names() would be a much more explicit way of doing this going forward. As far as I can tell, ExecutionContext::tables isn't referenced at all in the codebase internally, but this would introduce a bit more API breakage.

As for tests, yes, the coverage so far is basically "didn't break anything" and "all three types of reference to a given table in the default catalog/schema resolve correctly", so I'll try and plan out some more in-depth testing covering e.g. tables of the same name in multiple schemas/catalogs.

@codecov-io

codecov-io commented Mar 21, 2021

Copy link
Copy Markdown

Codecov Report

Merging #9762 (03048c6) into master (29feea0) will increase coverage by 0.00%.
The diff coverage is 80.36%.

Impacted file tree graph

@@ Coverage Diff @@## master #9762 +/- ##
========================================
Coverage 82.59% 82.59% ========================================
Files 248 252 +4 Lines 58294 59004 +710 ========================================
+ Hits 48149 48737 +588 - Misses 10145 10267 +122 
Impacted FilesCoverage Δ
rust/datafusion/examples/flight_server.rs0.00% <0.00%> (ø)
rust/datafusion/examples/simple_udaf.rs0.00% <ø> (ø)
rust/datafusion/src/datasource/datasource.rs100.00% <ø> (ø)
rust/datafusion/src/datasource/memory.rs85.15% <ø> (ø)
rust/datafusion/src/execution/dataframe_impl.rs89.10% <0.00%> (-1.03%)⬇️
rust/datafusion/src/optimizer/constant_folding.rs92.30% <0.00%> (-0.36%)⬇️
...datafusion/src/optimizer/hash_build_probe_order.rs53.60% <0.00%> (-1.72%)⬇️
...t/datafusion/src/optimizer/projection_push_down.rs98.66% <ø> (ø)
rust/datafusion/src/physical_plan/mod.rs88.00% <ø> (ø)
rust/parquet/src/basic.rs88.59% <ø> (+1.36%)⬆️
... and 35 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 81d6724...03048c6. Read the comment docs.

@returnString
returnString marked this pull request as ready for review March 21, 2021 22:02
@returnString

Copy link
Copy Markdown
ContributorAuthor

Whilst I still want to try and conjure up a few more test cases, I think this PR is now in a state where I'm happy to receive actual code reviews, so I've removed the draft status :)

@alamb

Copy link
Copy Markdown
Contributor

I plan to review this PR later today

@alambalamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all this looks great. Thank you @returnString !

I went through it fairly carefully and I have some suggestions but nothing that would prevent us from merging this in my opinion.

start.elapsed().as_millis()
);
ctx.register_table(table, Arc::new(memtable));
ctx.register_table(*table, Arc::new(memtable))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change to make register_table fallible is a breaking change, but a very reasonable one I think.

// specific language governing permissions and limitations
// under the License.

//! Describes the interface and built-in implementations of catalogs,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

fn as_any(&self) -> &dyn Any;

/// Retrieves the list of available schema names in this catalog.
fn schema_names(&self) -> Vec<String>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about returning something more like Vec<&str> to prevent requiring a copy?

Ideally it would be nice if we could do something like

fn schema_names(&self) -> impl Iterator<Item=&str>

As all uses of the results here will need to iterate over the names I suspect

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I iniitally tried to implement these returning &[&str] but with the threading requirements I struggled to get anything working that way. I think this would require a larger refactoring to enable, but I'm not 100% sure on that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vec<&str> might be possible

}

/// Simple in-memory implementation of a catalog.
pub struct MemoryCatalogProvider {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some other PR perhaps we can put the concrete implementations into their own modules. I don't think this one is big enough to warrant that yet, however; I just wanted to point it out

impl<'a> TryFrom<&'a sqlparser::ast::ObjectName> for TableReference<'a> {
type Error = DataFusionError;

fn try_from(value: &'a sqlparser::ast::ObjectName) -> Result<Self, Self::Error> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

/// Selects a name for the default catalog and schema
pub fn with_default_catalog_and_schema(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this API. 👍

I wonder if we need an API for getting default_catalog and default_schema?

Comment threadrust/datafusion/src/execution/context.rs Outdated
@@ -1922,6 +2035,114 @@ mod tests {
Ok(())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are excellent tests . 👍

&mut ctx,
"SELECT cat, SUM(i) AS total FROM (
SELECT i, 'a' AS cat FROM catalog_a.schema_a.table_a
UNION ALL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DandandanUNION is already being used!

for table_ref in &[
"nonexistentschema.aggregate_test_100",
"nonexistentcatalog.public.aggregate_test_100",
"way.too.many.namespaces.as.ident.prefixes.aggregate_test_100",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
@alamb

Copy link
Copy Markdown
Contributor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

@returnString

Copy link
Copy Markdown
ContributorAuthor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

I was looking to see if I could improve the test setup any further, but on reflection I'm actually pretty happy with the state of things; I don't think we're missing any use cases in the coverage (at least, ones I can conceive of right now). So from my side, happy with things as they are :)

@alambalamb closed this in 14441dbMar 23, 2021
@alamb

Copy link
Copy Markdown
Contributor

Thanks again @returnString ! This is a great feature

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@returnString@Dandandan@andygrove@codecov-io@alamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing - #9762

Closed
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog
Closed

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing#9762
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog

Conversation

@returnString

@returnStringreturnString commented Mar 21, 2021

Copy link
Copy Markdown
Contributor

This is an implementation of catalog and schema providers to support table namespacing (see the design doc).

I'm creating this draft PR as a supporting implementation for the proposal, to prove out that the work can be done whilst minimising API churn and still allowing for use cases that don't care at all about the notion of catalogs or schemas; in this new setup, the default namespace is datafusion.public, which will be created automatically with the default execution context config and allow for table registration.

Highlights

  • Datasource map removed in execution context state, replaced with catalog map
  • Execution context allows for registering new catalog providers
  • Catalog providers can be queried for their constituent schema providers
  • Schema providers can be queried for table providers, similarly to the old datasource map
  • Includes basic implementations of CatalogProvider and SchemaProvider backed by hashmaps
  • New TableReference enum maps to various ways of referring to a table in sql
    • Bare: my_table
    • Partial: schema.my_table
    • Full: catalog.schema.my_table
  • Given a default catalog and schema, TableReference instances of any variant can be converted to a ResolvedTableReference, which always include all three components

@github-actions

Copy link
Copy Markdown

@Dandandan

Copy link
Copy Markdown
Contributor

This is truly awesome @returnString !
Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

@andygrove

Copy link
Copy Markdown
Member

Thanks @returnString and I appreciate the well-written design doc to explain the PR. I didn't go through the code in great detail but I like the design. I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

@returnString

returnString commented Mar 21, 2021

Copy link
Copy Markdown
ContributorAuthor

Thanks both :)

I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

I've just audited all the unwraps that are introduced in these commits, and they fall into two categories:

  • test cases that aren't already set up to return Result<()>
  • unwrapping guard objects for Mutex/RwLock - afaik these only error if the lock is poisoned and this usage is consistent with existing lock usage e.g. state access in the ExecutionContext

Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

I think the quick hack (context: retrieving a list of table names from the execution ctx, assuming a flat namespace) can probably be removed outright, as ctx.catalog("my_db")?.schema("my_schema")?.table_names() would be a much more explicit way of doing this going forward. As far as I can tell, ExecutionContext::tables isn't referenced at all in the codebase internally, but this would introduce a bit more API breakage.

As for tests, yes, the coverage so far is basically "didn't break anything" and "all three types of reference to a given table in the default catalog/schema resolve correctly", so I'll try and plan out some more in-depth testing covering e.g. tables of the same name in multiple schemas/catalogs.

@codecov-io

codecov-io commented Mar 21, 2021

Copy link
Copy Markdown

Codecov Report

Merging #9762 (03048c6) into master (29feea0) will increase coverage by 0.00%.
The diff coverage is 80.36%.

Impacted file tree graph

@@ Coverage Diff @@## master #9762 +/- ##
========================================
Coverage 82.59% 82.59% ========================================
Files 248 252 +4 Lines 58294 59004 +710 ========================================
+ Hits 48149 48737 +588 - Misses 10145 10267 +122 
Impacted FilesCoverage Δ
rust/datafusion/examples/flight_server.rs0.00% <0.00%> (ø)
rust/datafusion/examples/simple_udaf.rs0.00% <ø> (ø)
rust/datafusion/src/datasource/datasource.rs100.00% <ø> (ø)
rust/datafusion/src/datasource/memory.rs85.15% <ø> (ø)
rust/datafusion/src/execution/dataframe_impl.rs89.10% <0.00%> (-1.03%)⬇️
rust/datafusion/src/optimizer/constant_folding.rs92.30% <0.00%> (-0.36%)⬇️
...datafusion/src/optimizer/hash_build_probe_order.rs53.60% <0.00%> (-1.72%)⬇️
...t/datafusion/src/optimizer/projection_push_down.rs98.66% <ø> (ø)
rust/datafusion/src/physical_plan/mod.rs88.00% <ø> (ø)
rust/parquet/src/basic.rs88.59% <ø> (+1.36%)⬆️
... and 35 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 81d6724...03048c6. Read the comment docs.

@returnString
returnString marked this pull request as ready for review March 21, 2021 22:02
@returnString

Copy link
Copy Markdown
ContributorAuthor

Whilst I still want to try and conjure up a few more test cases, I think this PR is now in a state where I'm happy to receive actual code reviews, so I've removed the draft status :)

@alamb

Copy link
Copy Markdown
Contributor

I plan to review this PR later today

@alambalamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all this looks great. Thank you @returnString !

I went through it fairly carefully and I have some suggestions but nothing that would prevent us from merging this in my opinion.

start.elapsed().as_millis()
);
ctx.register_table(table, Arc::new(memtable));
ctx.register_table(*table, Arc::new(memtable))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change to make register_table fallible is a breaking change, but a very reasonable one I think.

// specific language governing permissions and limitations
// under the License.

//! Describes the interface and built-in implementations of catalogs,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

fn as_any(&self) -> &dyn Any;

/// Retrieves the list of available schema names in this catalog.
fn schema_names(&self) -> Vec<String>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about returning something more like Vec<&str> to prevent requiring a copy?

Ideally it would be nice if we could do something like

fn schema_names(&self) -> impl Iterator<Item=&str>

As all uses of the results here will need to iterate over the names I suspect

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I iniitally tried to implement these returning &[&str] but with the threading requirements I struggled to get anything working that way. I think this would require a larger refactoring to enable, but I'm not 100% sure on that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vec<&str> might be possible

}

/// Simple in-memory implementation of a catalog.
pub struct MemoryCatalogProvider {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some other PR perhaps we can put the concrete implementations into their own modules. I don't think this one is big enough to warrant that yet, however; I just wanted to point it out

impl<'a> TryFrom<&'a sqlparser::ast::ObjectName> for TableReference<'a> {
type Error = DataFusionError;

fn try_from(value: &'a sqlparser::ast::ObjectName) -> Result<Self, Self::Error> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

/// Selects a name for the default catalog and schema
pub fn with_default_catalog_and_schema(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this API. 👍

I wonder if we need an API for getting default_catalog and default_schema?

Comment threadrust/datafusion/src/execution/context.rs Outdated
@@ -1922,6 +2035,114 @@ mod tests {
Ok(())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are excellent tests . 👍

&mut ctx,
"SELECT cat, SUM(i) AS total FROM (
SELECT i, 'a' AS cat FROM catalog_a.schema_a.table_a
UNION ALL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DandandanUNION is already being used!

for table_ref in &[
"nonexistentschema.aggregate_test_100",
"nonexistentcatalog.public.aggregate_test_100",
"way.too.many.namespaces.as.ident.prefixes.aggregate_test_100",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
@alamb

Copy link
Copy Markdown
Contributor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

@returnString

Copy link
Copy Markdown
ContributorAuthor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

I was looking to see if I could improve the test setup any further, but on reflection I'm actually pretty happy with the state of things; I don't think we're missing any use cases in the coverage (at least, ones I can conceive of right now). So from my side, happy with things as they are :)

@alambalamb closed this in 14441dbMar 23, 2021
@alamb

Copy link
Copy Markdown
Contributor

Thanks again @returnString ! This is a great feature

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@returnString@Dandandan@andygrove@codecov-io@alamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing - #9762

Closed
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog
Closed

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing#9762
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog

Conversation

@returnString

@returnStringreturnString commented Mar 21, 2021

Copy link
Copy Markdown
Contributor

This is an implementation of catalog and schema providers to support table namespacing (see the design doc).

I'm creating this draft PR as a supporting implementation for the proposal, to prove out that the work can be done whilst minimising API churn and still allowing for use cases that don't care at all about the notion of catalogs or schemas; in this new setup, the default namespace is datafusion.public, which will be created automatically with the default execution context config and allow for table registration.

Highlights

  • Datasource map removed in execution context state, replaced with catalog map
  • Execution context allows for registering new catalog providers
  • Catalog providers can be queried for their constituent schema providers
  • Schema providers can be queried for table providers, similarly to the old datasource map
  • Includes basic implementations of CatalogProvider and SchemaProvider backed by hashmaps
  • New TableReference enum maps to various ways of referring to a table in sql
    • Bare: my_table
    • Partial: schema.my_table
    • Full: catalog.schema.my_table
  • Given a default catalog and schema, TableReference instances of any variant can be converted to a ResolvedTableReference, which always include all three components

@github-actions

Copy link
Copy Markdown

@Dandandan

Copy link
Copy Markdown
Contributor

This is truly awesome @returnString !
Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

@andygrove

Copy link
Copy Markdown
Member

Thanks @returnString and I appreciate the well-written design doc to explain the PR. I didn't go through the code in great detail but I like the design. I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

@returnString

returnString commented Mar 21, 2021

Copy link
Copy Markdown
ContributorAuthor

Thanks both :)

I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

I've just audited all the unwraps that are introduced in these commits, and they fall into two categories:

  • test cases that aren't already set up to return Result<()>
  • unwrapping guard objects for Mutex/RwLock - afaik these only error if the lock is poisoned and this usage is consistent with existing lock usage e.g. state access in the ExecutionContext

Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

I think the quick hack (context: retrieving a list of table names from the execution ctx, assuming a flat namespace) can probably be removed outright, as ctx.catalog("my_db")?.schema("my_schema")?.table_names() would be a much more explicit way of doing this going forward. As far as I can tell, ExecutionContext::tables isn't referenced at all in the codebase internally, but this would introduce a bit more API breakage.

As for tests, yes, the coverage so far is basically "didn't break anything" and "all three types of reference to a given table in the default catalog/schema resolve correctly", so I'll try and plan out some more in-depth testing covering e.g. tables of the same name in multiple schemas/catalogs.

@codecov-io

codecov-io commented Mar 21, 2021

Copy link
Copy Markdown

Codecov Report

Merging #9762 (03048c6) into master (29feea0) will increase coverage by 0.00%.
The diff coverage is 80.36%.

Impacted file tree graph

@@ Coverage Diff @@## master #9762 +/- ##
========================================
Coverage 82.59% 82.59% ========================================
Files 248 252 +4 Lines 58294 59004 +710 ========================================
+ Hits 48149 48737 +588 - Misses 10145 10267 +122 
Impacted FilesCoverage Δ
rust/datafusion/examples/flight_server.rs0.00% <0.00%> (ø)
rust/datafusion/examples/simple_udaf.rs0.00% <ø> (ø)
rust/datafusion/src/datasource/datasource.rs100.00% <ø> (ø)
rust/datafusion/src/datasource/memory.rs85.15% <ø> (ø)
rust/datafusion/src/execution/dataframe_impl.rs89.10% <0.00%> (-1.03%)⬇️
rust/datafusion/src/optimizer/constant_folding.rs92.30% <0.00%> (-0.36%)⬇️
...datafusion/src/optimizer/hash_build_probe_order.rs53.60% <0.00%> (-1.72%)⬇️
...t/datafusion/src/optimizer/projection_push_down.rs98.66% <ø> (ø)
rust/datafusion/src/physical_plan/mod.rs88.00% <ø> (ø)
rust/parquet/src/basic.rs88.59% <ø> (+1.36%)⬆️
... and 35 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 81d6724...03048c6. Read the comment docs.

@returnString
returnString marked this pull request as ready for review March 21, 2021 22:02
@returnString

Copy link
Copy Markdown
ContributorAuthor

Whilst I still want to try and conjure up a few more test cases, I think this PR is now in a state where I'm happy to receive actual code reviews, so I've removed the draft status :)

@alamb

Copy link
Copy Markdown
Contributor

I plan to review this PR later today

@alambalamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all this looks great. Thank you @returnString !

I went through it fairly carefully and I have some suggestions but nothing that would prevent us from merging this in my opinion.

start.elapsed().as_millis()
);
ctx.register_table(table, Arc::new(memtable));
ctx.register_table(*table, Arc::new(memtable))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change to make register_table fallible is a breaking change, but a very reasonable one I think.

// specific language governing permissions and limitations
// under the License.

//! Describes the interface and built-in implementations of catalogs,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

fn as_any(&self) -> &dyn Any;

/// Retrieves the list of available schema names in this catalog.
fn schema_names(&self) -> Vec<String>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about returning something more like Vec<&str> to prevent requiring a copy?

Ideally it would be nice if we could do something like

fn schema_names(&self) -> impl Iterator<Item=&str>

As all uses of the results here will need to iterate over the names I suspect

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I iniitally tried to implement these returning &[&str] but with the threading requirements I struggled to get anything working that way. I think this would require a larger refactoring to enable, but I'm not 100% sure on that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vec<&str> might be possible

}

/// Simple in-memory implementation of a catalog.
pub struct MemoryCatalogProvider {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some other PR perhaps we can put the concrete implementations into their own modules. I don't think this one is big enough to warrant that yet, however; I just wanted to point it out

impl<'a> TryFrom<&'a sqlparser::ast::ObjectName> for TableReference<'a> {
type Error = DataFusionError;

fn try_from(value: &'a sqlparser::ast::ObjectName) -> Result<Self, Self::Error> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

/// Selects a name for the default catalog and schema
pub fn with_default_catalog_and_schema(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this API. 👍

I wonder if we need an API for getting default_catalog and default_schema?

Comment threadrust/datafusion/src/execution/context.rs Outdated
@@ -1922,6 +2035,114 @@ mod tests {
Ok(())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are excellent tests . 👍

&mut ctx,
"SELECT cat, SUM(i) AS total FROM (
SELECT i, 'a' AS cat FROM catalog_a.schema_a.table_a
UNION ALL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DandandanUNION is already being used!

for table_ref in &[
"nonexistentschema.aggregate_test_100",
"nonexistentcatalog.public.aggregate_test_100",
"way.too.many.namespaces.as.ident.prefixes.aggregate_test_100",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
@alamb

Copy link
Copy Markdown
Contributor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

@returnString

Copy link
Copy Markdown
ContributorAuthor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

I was looking to see if I could improve the test setup any further, but on reflection I'm actually pretty happy with the state of things; I don't think we're missing any use cases in the coverage (at least, ones I can conceive of right now). So from my side, happy with things as they are :)

@alambalamb closed this in 14441dbMar 23, 2021
@alamb

Copy link
Copy Markdown
Contributor

Thanks again @returnString ! This is a great feature

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@returnString@Dandandan@andygrove@codecov-io@alamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing - #9762

Closed
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog
Closed

ARROW-12037: [Rust] [DataFusion] Support catalogs and schemas for table namespacing#9762
returnString wants to merge 17 commits into
apache:masterfrom
reservoirdb:catalog

Conversation

@returnString

@returnStringreturnString commented Mar 21, 2021

Copy link
Copy Markdown
Contributor

This is an implementation of catalog and schema providers to support table namespacing (see the design doc).

I'm creating this draft PR as a supporting implementation for the proposal, to prove out that the work can be done whilst minimising API churn and still allowing for use cases that don't care at all about the notion of catalogs or schemas; in this new setup, the default namespace is datafusion.public, which will be created automatically with the default execution context config and allow for table registration.

Highlights

  • Datasource map removed in execution context state, replaced with catalog map
  • Execution context allows for registering new catalog providers
  • Catalog providers can be queried for their constituent schema providers
  • Schema providers can be queried for table providers, similarly to the old datasource map
  • Includes basic implementations of CatalogProvider and SchemaProvider backed by hashmaps
  • New TableReference enum maps to various ways of referring to a table in sql
    • Bare: my_table
    • Partial: schema.my_table
    • Full: catalog.schema.my_table
  • Given a default catalog and schema, TableReference instances of any variant can be converted to a ResolvedTableReference, which always include all three components

@github-actions

Copy link
Copy Markdown

@Dandandan

Copy link
Copy Markdown
Contributor

This is truly awesome @returnString !
Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

@andygrove

Copy link
Copy Markdown
Member

Thanks @returnString and I appreciate the well-written design doc to explain the PR. I didn't go through the code in great detail but I like the design. I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

@returnString

returnString commented Mar 21, 2021

Copy link
Copy Markdown
ContributorAuthor

Thanks both :)

I noted a couple of unwraps in the code. It would be good to document why they are safe or consider having those methods return Result if they are not safe.

I've just audited all the unwraps that are introduced in these commits, and they fall into two categories:

  • test cases that aren't already set up to return Result<()>
  • unwrapping guard objects for Mutex/RwLock - afaik these only error if the lock is poisoned and this usage is consistent with existing lock usage e.g. state access in the ExecutionContext

Apart from some tests & remaining cleanup (e.g. of the "quick hack") I really like the direction this is going!

I think the quick hack (context: retrieving a list of table names from the execution ctx, assuming a flat namespace) can probably be removed outright, as ctx.catalog("my_db")?.schema("my_schema")?.table_names() would be a much more explicit way of doing this going forward. As far as I can tell, ExecutionContext::tables isn't referenced at all in the codebase internally, but this would introduce a bit more API breakage.

As for tests, yes, the coverage so far is basically "didn't break anything" and "all three types of reference to a given table in the default catalog/schema resolve correctly", so I'll try and plan out some more in-depth testing covering e.g. tables of the same name in multiple schemas/catalogs.

@codecov-io

codecov-io commented Mar 21, 2021

Copy link
Copy Markdown

Codecov Report

Merging #9762 (03048c6) into master (29feea0) will increase coverage by 0.00%.
The diff coverage is 80.36%.

Impacted file tree graph

@@ Coverage Diff @@## master #9762 +/- ##
========================================
Coverage 82.59% 82.59% ========================================
Files 248 252 +4 Lines 58294 59004 +710 ========================================
+ Hits 48149 48737 +588 - Misses 10145 10267 +122 
Impacted FilesCoverage Δ
rust/datafusion/examples/flight_server.rs0.00% <0.00%> (ø)
rust/datafusion/examples/simple_udaf.rs0.00% <ø> (ø)
rust/datafusion/src/datasource/datasource.rs100.00% <ø> (ø)
rust/datafusion/src/datasource/memory.rs85.15% <ø> (ø)
rust/datafusion/src/execution/dataframe_impl.rs89.10% <0.00%> (-1.03%)⬇️
rust/datafusion/src/optimizer/constant_folding.rs92.30% <0.00%> (-0.36%)⬇️
...datafusion/src/optimizer/hash_build_probe_order.rs53.60% <0.00%> (-1.72%)⬇️
...t/datafusion/src/optimizer/projection_push_down.rs98.66% <ø> (ø)
rust/datafusion/src/physical_plan/mod.rs88.00% <ø> (ø)
rust/parquet/src/basic.rs88.59% <ø> (+1.36%)⬆️
... and 35 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 81d6724...03048c6. Read the comment docs.

@returnString
returnString marked this pull request as ready for review March 21, 2021 22:02
@returnString

Copy link
Copy Markdown
ContributorAuthor

Whilst I still want to try and conjure up a few more test cases, I think this PR is now in a state where I'm happy to receive actual code reviews, so I've removed the draft status :)

@alamb

Copy link
Copy Markdown
Contributor

I plan to review this PR later today

@alambalamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all this looks great. Thank you @returnString !

I went through it fairly carefully and I have some suggestions but nothing that would prevent us from merging this in my opinion.

start.elapsed().as_millis()
);
ctx.register_table(table, Arc::new(memtable));
ctx.register_table(*table, Arc::new(memtable))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change to make register_table fallible is a breaking change, but a very reasonable one I think.

// specific language governing permissions and limitations
// under the License.

//! Describes the interface and built-in implementations of catalogs,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

fn as_any(&self) -> &dyn Any;

/// Retrieves the list of available schema names in this catalog.
fn schema_names(&self) -> Vec<String>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about returning something more like Vec<&str> to prevent requiring a copy?

Ideally it would be nice if we could do something like

fn schema_names(&self) -> impl Iterator<Item=&str>

As all uses of the results here will need to iterate over the names I suspect

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I iniitally tried to implement these returning &[&str] but with the threading requirements I struggled to get anything working that way. I think this would require a larger refactoring to enable, but I'm not 100% sure on that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vec<&str> might be possible

}

/// Simple in-memory implementation of a catalog.
pub struct MemoryCatalogProvider {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some other PR perhaps we can put the concrete implementations into their own modules. I don't think this one is big enough to warrant that yet, however; I just wanted to point it out

impl<'a> TryFrom<&'a sqlparser::ast::ObjectName> for TableReference<'a> {
type Error = DataFusionError;

fn try_from(value: &'a sqlparser::ast::ObjectName) -> Result<Self, Self::Error> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

/// Selects a name for the default catalog and schema
pub fn with_default_catalog_and_schema(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this API. 👍

I wonder if we need an API for getting default_catalog and default_schema?

Comment threadrust/datafusion/src/execution/context.rs Outdated
@@ -1922,6 +2035,114 @@ mod tests {
Ok(())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are excellent tests . 👍

&mut ctx,
"SELECT cat, SUM(i) AS total FROM (
SELECT i, 'a' AS cat FROM catalog_a.schema_a.table_a
UNION ALL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DandandanUNION is already being used!

for table_ref in &[
"nonexistentschema.aggregate_test_100",
"nonexistentcatalog.public.aggregate_test_100",
"way.too.many.namespaces.as.ident.prefixes.aggregate_test_100",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
@alamb

Copy link
Copy Markdown
Contributor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

@returnString

Copy link
Copy Markdown
ContributorAuthor

@returnString do you plan anything else for this PR? I think it is ready to merge but I wanted to check to see if you think there is anything else left to do?

I was looking to see if I could improve the test setup any further, but on reflection I'm actually pretty happy with the state of things; I don't think we're missing any use cases in the coverage (at least, ones I can conceive of right now). So from my side, happy with things as they are :)

@alambalamb closed this in 14441dbMar 23, 2021
@alamb

Copy link
Copy Markdown
Contributor

Thanks again @returnString ! This is a great feature

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@returnString@Dandandan@andygrove@codecov-io@alamb