Skip to content

Commit 4ec7eb3

Browse files
committed
Databricks SQL native parser
Add crates/sqlquack-syntax-databricks, a scanner and parser for Databricks SQL that builds the shared sqlquack-syntax tree, with parse_strict for callers that need every statement parsed in full. The parser refuses deep nesting with a parse error instead of exhausting the stack, and after each statement it applies the shared tree-depth check, which refuses a tree nested past 8,000 levels. The syntax-coverage checker links the parser as the local parser for the Databricks dialect, and the deep-nesting probe covers it, with its ARRAY<> type constructor and its pipe chain. Every Databricks construct is clean at every depth in both profiles, so the allowlist has no Databricks entries.
1 parent 97667a1 commit 4ec7eb3

58 files changed

Lines changed: 12655 additions & 3 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎Cargo.lock‎

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ members = [
2121
"crates/sqlquack-format",
2222
"crates/sqlquack-format-check",
2323
"crates/sqlquack-syntax-duckdb",
24+
"crates/sqlquack-syntax-databricks",
2425
"crates/sqlquack-python",
2526
]
2627
exclude = ["fuzz"]
@@ -78,6 +79,7 @@ sqlquack-syntax-derive = { path = "crates/sqlquack-syntax-derive" }
7879
sqlquack-syntax-postgres = { path = "crates/sqlquack-syntax-postgres" }
7980
sqlquack-syntax-bigquery = { path = "crates/sqlquack-syntax-bigquery" }
8081
sqlquack-syntax-duckdb = { path = "crates/sqlquack-syntax-duckdb" }
82+
sqlquack-syntax-databricks = { path = "crates/sqlquack-syntax-databricks" }
8183
stacker = "0.1"
8284
syn = { version = "2", features = ["full"] }
8385
tempfile = "3"

‎crates/sqlquack-syntax-coverage/Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ sha2.workspace = true
1717
sqlquack-syntax.workspace = true
1818
sqlquack-syntax-bigquery.workspace = true
1919
sqlquack-syntax-duckdb.workspace = true
20+
sqlquack-syntax-databricks.workspace = true
2021
sqlquack-syntax-postgres.workspace = true
2122
toml.workspace = true
2223

‎crates/sqlquack-syntax-coverage/src/cli/_helpers/local.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,19 @@ fn duckdb_verdict(sql: &str) -> LocalVerdict {
6969
native_verdict(sqlquack_syntax_duckdb::parse_strict(sql))
7070
}
7171

72+
/// SQLQuack's strict Databricks SQL verdict.
73+
fn databricks_verdict(sql: &str) -> LocalVerdict {
74+
native_verdict(sqlquack_syntax_databricks::parse_strict(sql))
75+
}
76+
7277
/// The verdict of each dialect's local parser, or none when the dialect has no parser yet.
7378
pub(crate) fn local_verdict(parser: LocalParser) -> Option<fn(&str) -> LocalVerdict> {
7479
match parser {
7580
LocalParser::Snowflake => Some(snowflake_verdict),
7681
LocalParser::Postgres => Some(postgres_verdict),
7782
LocalParser::BigQuery => Some(bigquery_verdict),
7883
LocalParser::DuckDb => Some(duckdb_verdict),
84+
LocalParser::Databricks => Some(databricks_verdict),
7985
LocalParser::None => None,
8086
}
8187
}

‎crates/sqlquack-syntax-coverage/src/depth/_helpers/constructs.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ fn constructed_type(parser: LocalParser, depth: usize) -> Option<String> {
2727
LocalParser::Snowflake => Some(nest("ARRAY(", "INT", ")", depth)),
2828
LocalParser::BigQuery => Some(nest("STRUCT<x ", "INT64", ">", depth)),
2929
LocalParser::DuckDb => Some(nest("STRUCT(a ", "INT", ")", depth)),
30+
LocalParser::Databricks => Some(nest("ARRAY<", "INT", ">", depth)),
3031
LocalParser::Postgres | LocalParser::None => None,
3132
}
3233
}
@@ -38,7 +39,10 @@ fn mixed_type(parser: LocalParser, depth: usize) -> Option<String> {
3839
let open: &str = match parser {
3940
LocalParser::Snowflake => "ARRAY(",
4041
LocalParser::DuckDb => "STRUCT(a ",
41-
LocalParser::Postgres | LocalParser::BigQuery | LocalParser::None => return None,
42+
LocalParser::Postgres
43+
| LocalParser::BigQuery
44+
| LocalParser::Databricks
45+
| LocalParser::None => return None,
4246
};
4347
Some(format!(
4448
"{}INT{}{run}",
@@ -258,7 +262,9 @@ pub(crate) fn constructs() -> Vec<Construct> {
258262
Construct {
259263
name: "nested_pipe_chain",
260264
text: |parser, depth| match parser {
261-
LocalParser::BigQuery => Some(nested_chain("FROM t", " |> WHERE TRUE", depth)),
265+
LocalParser::BigQuery | LocalParser::Databricks => {
266+
Some(nested_chain("FROM t", " |> WHERE TRUE", depth))
267+
}
262268
_ => None,
263269
},
264270
},

‎crates/sqlquack-syntax-coverage/src/depth/constants.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ pub const MIXED_SUFFIX_RUN: usize = 60;
1717
/// How many links each parenthesised level of a nested chain holds.
1818
pub const NESTED_CHAIN_LINKS: usize = 60;
1919
/// Every native parser this checker links, each probed in turn.
20-
pub const PROBED_PARSERS: [LocalParser; 4] = [
20+
pub const PROBED_PARSERS: [LocalParser; 5] = [
2121
LocalParser::Snowflake,
2222
LocalParser::Postgres,
2323
LocalParser::BigQuery,
2424
LocalParser::DuckDb,
25+
LocalParser::Databricks,
2526
];

‎crates/sqlquack-syntax-coverage/src/depth/tests/test_probe_construct.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ fn given_a_parser_without_a_syntax_when_listing_constructs_then_only_its_own_are
9090
construct: "nested_pipe_chain",
9191
expected_probed: true,
9292
},
93+
ConstructsTestCase {
94+
description: "Databricks chains pipe operators",
95+
parser: LocalParser::Databricks,
96+
construct: "nested_pipe_chain",
97+
expected_probed: true,
98+
},
9399
ConstructsTestCase {
94100
description: "Postgres has no pipe operator",
95101
parser: LocalParser::Postgres,

‎crates/sqlquack-syntax-coverage/src/formats/models.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,8 @@ pub enum LocalParser {
650650
#[serde(rename = "duckdb")]
651651
#[value(name = "duckdb")]
652652
DuckDb,
653+
/// `sqlquack_syntax_databricks`, through the isolated worker.
654+
Databricks,
653655
/// No parser yet: every case fails locally as `no_parser`.
654656
None,
655657
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = "sqlquack-syntax-databricks"
3+
version.workspace = true
4+
description = "SQLQuack's Databricks SQL scanner and parser into the shared sqlquack-syntax tree."
5+
edition.workspace = true
6+
license.workspace = true
7+
repository.workspace = true
8+
homepage.workspace = true
9+
publish = false
10+
rust-version.workspace = true
11+
12+
[dependencies]
13+
sqlquack-syntax.workspace = true
14+
stacker.workspace = true
15+
16+
[dev-dependencies]
17+
serde_json.workspace = true
18+
19+
[lints]
20+
workspace = true

0 commit comments

Comments
 (0)