Repository navigation
Databricks: support multipart TABLE queries - #2594
EthanVieira wants to merge 29 commits into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2594 +/- ##
=======================================
Coverage 82.54% 82.55%
=======================================
Files 42 42
Lines 35556 35558 +2
Branches 35556 35558 +2
=======================================
+ Hits 29349 29354 +5
Misses 2672 2672
+ Partials 3535 3532 -3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@EthanVieira please do add an entry to the fuzzer seed corpus with this syntax if there isn't one already |
LucaCappelletti94
left a comment
There was a problem hiding this comment.
I believe that we need to make the Table struct hold an ObjectName, as TableFactor::Table does, so a qualified name of any length keeps its parts.
@@ -300,6 +300,4 @@ impl fmt::Display for SetQuantifier {
pub struct Table {
- /// Optional table name (absent for e.g. `TABLE` command without argument).
- pub table_name: Option<Ident>,
- /// Optional schema/catalog name qualifying the table.
- pub schema_name: Option<Ident>,
+ /// Optional, possibly qualified, table name (absent for e.g. `TABLE` command without argument).
+ pub name: Option<ObjectName>,
}This of course will call for several changes both in the repo and downstream, but it seems like the cleanest solution to me. @alamb opinions?
There was a problem hiding this comment.
You should keep every name part as its own Ident instead of joining the qualifiers into one. As written, main.raw.source and `main.raw`.source both give a schema_name whose value is "main.raw", and `a b`.raw.source gives the value "`a b`.raw" with the backticks inside it, so consumers cannot recover the parts. This relies on the Table change in the global note.
| let max_parts = if self.dialect.supports_multipart_table_query_name() { | |
| usize::MAX | |
| } else { | |
| 2 | |
| }; | |
| let mut parts = vec![self.parse_identifier()?]; | |
| while parts.len() < max_parts && self.consume_token(&Token::Period) { | |
| parts.push(self.parse_identifier()?); | |
| } | |
| Ok(Table { | |
| name: Some(ObjectName::from(parts)), | |
| }) |
|
|
||
| #[test] | ||
| fn parse_databricks_multipart_table_query() { | ||
| databricks().verified_stmt("CREATE VIEW copy AS TABLE main.raw.source"); |
There was a problem hiding this comment.
You should assert the parsed parts, because verified_stmt only checks the round trip and the joined Ident passes it.
| databricks().verified_stmt("CREATE VIEW copy AS TABLE main.raw.source"); | |
| let Statement::CreateView(view) = | |
| databricks().verified_stmt("CREATE VIEW copy AS TABLE main.raw.source") | |
| else { | |
| unreachable!() | |
| }; | |
| assert_eq!( | |
| *view.query.body, | |
| SetExpr::Table(Box::new(Table { | |
| name: Some(ObjectName::from(vec![ | |
| Ident::new("main"), | |
| Ident::new("raw"), | |
| Ident::new("source"), | |
| ])), | |
| })) | |
| ); |
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…#2638) Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…e#2626) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…t-table-queries # Conflicts: # docs/fuzzing.md # fuzz/Cargo.toml # src/ast/mod.rs # src/ast/spans.rs # src/dialect/duckdb.rs # src/dialect/mod.rs # src/parser/mod.rs # tests/sqlparser_clickhouse.rs # tests/sqlparser_common.rs # tests/sqlparser_custom_dialect.rs # tests/sqlparser_databricks.rs # tests/sqlparser_duckdb.rs # tests/sqlparser_mysql.rs # tests/sqlparser_postgres.rs # tests/sqlparser_sqlite.rs
Haven't heard from @alamb, but I went ahead and did this. |
Allows Databricks TABLE queries to reference multipart names such as main.raw.source.
Reference: Names