You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by lu...@apache.org on 2026/10/18 08:46:07 UTC
(datafusion-sqlparser-rs) branch upstream/in-subquery-error-diagnostics updated (0aef4eaa9 -> 7d98f0ee7)
This is an automated email from the ASF dual-hosted git repository.
LucaCappelletti94 pushed a change to branch upstream/in-subquery-error-diagnostics
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
discard 0aef4eaa9 Report the furthest IN subquery error when the list fails
add e790703ab Parser: fix exponential parse time on nested POSITION calls (#2619)
add dacdbc99c ClickHouse: Support GLOBAL IN / GLOBAL NOT IN (#2598)
add 5d1eaf352 Assert exact errors in negative tests (1/4): PostgreSQL tests (#2628)
add 5d653a257 ci: raise the merge queue status check timeout to 360 minutes (#2638)
add 7cac9e17a MySQL: Add support for `ZEROFILL` on numeric data types (#2636)
add fef1e355f Postgres: support OVERRIDING { SYSTEM | USER } VALUE in INSERT (#2626)
add 92e88502a ClickHouse: Support ON CLUSTER and SETTINGS in DELETE and UPDATE (#2617)
add a6f518bf7 Bump serde_json from 1.0.151 to 1.0.154 (#2637)
add 6434b5a22 Assert exact errors in negative tests (2/4): common and parser unit tests (#2629)
add f1854e47e Assert exact errors in negative tests (3/4): dialect tests (#2630)
add a80289f9f Assert exact errors in negative tests (4/4): deny clippy::assertions_on_result_states (#2631)
add de737560d Deny `clippy::manual_assert_eq` (#2644)
add f88f68507 Parser: Fix array suffixes after a `>>` that closes two nested types (#2643)
add 942f36afc SQLite: Support comma-separated WITHOUT ROWID and STRICT table options (#2575)
add c62f01d93 PostgreSQL: Remove unreachable empty op_types branch in operator FUNCTION items (#2632)
add 8338588e9 Commit the fuzz crate's Cargo.lock (#2647)
add 7d34c89b7 Deny `clippy::should_panic_without_expect` (#2648)
add 66d90faaa SetExpr: apply recursive-protection to Display (#2623)
add dcbc923dd MySQL: Bind && with the precedence of AND (#2576)
add c98351352 Postgres: Support aliases for JOIN USING (#2492)
add 0ab37b9e2 SQLite: Support `$` inside identifiers (#2554)
add 5a975d0f4 Deny `clippy::ignore_without_reason` (#2652)
add 7b5821dd4 Deny `clippy::allow_attributes` and `allow_attributes_without_reason` (#2653)
add 1aabd12d1 Add `Dialect::supports_cte_materialization` and enable it for DuckDB (#2651)
new 7d98f0ee7 Report the furthest IN subquery error when the list fails
This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version. This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:
* -- * -- B -- O -- O -- O (0aef4eaa9)
\
N -- N -- N refs/heads/upstream/in-subquery-error-diagnostics (7d98f0ee7)
You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.
Any revisions marked "omit" are not gone; other references still
refer to them. Any revisions marked "discard" are gone forever.
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.asf.yaml | 37 +
.github/dependabot.yml | 5 +
Cargo.lock | 4 +-
Cargo.toml | 8 +
fuzz/.gitignore | 1 -
fuzz/Cargo.lock | 1139 ++++++++++++++++++++++++++++++
fuzz/fuzz_seeds/clickhouse_delete.sql | 5 +
fuzz/fuzz_seeds/clickhouse_global_in.sql | 63 ++
fuzz/fuzz_seeds/clickhouse_update.sql | 5 +
src/ast/data_type.rs | 5 +
src/ast/ddl.rs | 62 +-
src/ast/dml.rs | 56 ++
src/ast/helpers/stmt_create_table.rs | 31 +-
src/ast/mod.rs | 38 +-
src/ast/query.rs | 7 +-
src/ast/spans.rs | 71 +-
src/dialect/clickhouse.rs | 5 +
src/dialect/duckdb.rs | 4 +
src/dialect/generic.rs | 4 +
src/dialect/mod.rs | 47 +-
src/dialect/mysql.rs | 16 +-
src/dialect/postgresql.rs | 4 +
src/dialect/snowflake.rs | 6 +-
src/dialect/sqlite.rs | 2 +-
src/keywords.rs | 7 +-
src/lib.rs | 9 +-
src/parser/mod.rs | 219 +++++-
src/tokenizer.rs | 5 +-
tests/no_std_recursion.rs | 14 +-
tests/sqlparser_bigquery.rs | 39 +-
tests/sqlparser_clickhouse.rs | 320 ++++++++-
tests/sqlparser_common.rs | 670 ++++++++++++------
tests/sqlparser_custom_dialect.rs | 22 +-
tests/sqlparser_databricks.rs | 39 +-
tests/sqlparser_derive_dialect.rs | 12 +-
tests/sqlparser_duckdb.rs | 15 +-
tests/sqlparser_mssql.rs | 87 ++-
tests/sqlparser_mysql.rs | 213 ++++--
tests/sqlparser_postgres.rs | 992 +++++++++++++-------------
tests/sqlparser_redshift.rs | 10 +-
tests/sqlparser_regression.rs | 3 +-
tests/sqlparser_snowflake.rs | 172 +++--
tests/sqlparser_sqlite.rs | 136 +++-
tests/sqlparser_teradata.rs | 10 +-
44 files changed, 3588 insertions(+), 1031 deletions(-)
create mode 100644 fuzz/Cargo.lock
create mode 100644 fuzz/fuzz_seeds/clickhouse_delete.sql
create mode 100644 fuzz/fuzz_seeds/clickhouse_global_in.sql
create mode 100644 fuzz/fuzz_seeds/clickhouse_update.sql
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org
(datafusion-sqlparser-rs) 01/01: Report the furthest IN subquery error when the list fails
Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
LucaCappelletti94 pushed a commit to branch upstream/in-subquery-error-diagnostics
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit 7d98f0ee7524c5d1bbb451caef99d795181401fb
Author: LucaCappelletti94 <ca...@gmail.com>
AuthorDate: Fri Oct 2 10:57:57 2026 +0200
Report the furthest IN subquery error when the list fails
---
src/parser/mod.rs | 56 ++++++++++++++++++++++++++++++-----------------
tests/sqlparser_common.rs | 32 +++++++++++++++++++++++++++
2 files changed, 68 insertions(+), 20 deletions(-)
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 340b2d077..d0f38341a 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -361,9 +361,12 @@ pub struct Parser<'a> {
failed_position_syntax_positions: BTreeSet<(usize, ParserState)>,
/// Cached failures from the speculative subquery arm of [`Parser::parse_in`],
/// which `IN` lists nested in a leading subquery would otherwise retry at
- /// every level, taking 2^N time. Maps the arm's start to where a parsed
- /// query lacked its `)`.
- failed_in_subquery_positions: BTreeMap<usize, Option<usize>>,
+ /// every level, taking 2^N time. Maps the arm's start to the index where it
+ /// failed.
+ failed_in_subquery_positions: BTreeMap<usize, usize>,
+ /// The furthest-reaching failure of that arm, the one error a cached retry
+ /// can replay without the cache holding strings.
+ furthest_in_subquery_error: Option<(usize, ParserError)>,
}
/// Copy marker for a [`ParserError`] cached by the `parse_prefix` failure
@@ -412,6 +415,7 @@ impl<'a> Parser<'a> {
failed_derived_table_factor_positions: BTreeSet::new(),
failed_position_syntax_positions: BTreeSet::new(),
failed_in_subquery_positions: BTreeMap::new(),
+ furthest_in_subquery_error: None,
}
}
@@ -482,6 +486,7 @@ impl<'a> Parser<'a> {
self.failed_derived_table_factor_positions.clear();
self.failed_position_syntax_positions.clear();
self.failed_in_subquery_positions.clear();
+ self.furthest_in_subquery_error = None;
self
}
@@ -4500,14 +4505,17 @@ impl<'a> Parser<'a> {
// A leading query is the whole subquery only when `)` follows it,
// otherwise it is the first item of a list, as in `IN ((SELECT 1), 2)`.
let start = self.index;
- // Where a parsed query lacked its `)`. Reported if the list fails no
- // further in, since that error would sit inside the query.
- let missing_rparen = match self.failed_in_subquery_positions.get(&start) {
- Some(&cached) => cached,
+ // The arm's error is reported if the list fails at an earlier token,
+ // since the list error would then sit inside the query.
+ let query_failed_at = match self.failed_in_subquery_positions.get(&start) {
+ Some(&at) => at,
None => {
- let mut missing_rparen = None;
- if let Some(subquery) = self.maybe_parse(|p| p.parse_query())? {
- if self.consume_token(&Token::RParen) {
+ let query = self.parse_query().and_then(|subquery| {
+ self.expect_token(&Token::RParen)?;
+ Ok(subquery)
+ });
+ match query {
+ Ok(subquery) => {
return Ok(Expr::InSubquery {
expr: Box::new(expr),
subquery,
@@ -4515,12 +4523,23 @@ impl<'a> Parser<'a> {
global,
});
}
- missing_rparen = Some(self.index);
- self.index = start;
+ Err(ParserError::RecursionLimitExceeded) => {
+ return Err(ParserError::RecursionLimitExceeded);
+ }
+ Err(e) => {
+ let at = self.index;
+ self.index = start;
+ self.failed_in_subquery_positions.insert(start, at);
+ if self
+ .furthest_in_subquery_error
+ .as_ref()
+ .is_none_or(|(furthest, _)| *furthest <= at)
+ {
+ self.furthest_in_subquery_error = Some((at, e));
+ }
+ at
+ }
}
- self.failed_in_subquery_positions
- .insert(start, missing_rparen);
- missing_rparen
}
};
let list = if self.dialect.supports_in_empty_list() {
@@ -4536,11 +4555,8 @@ impl<'a> Parser<'a> {
global,
}),
Err(ParserError::RecursionLimitExceeded) => Err(ParserError::RecursionLimitExceeded),
- Err(e) => match missing_rparen {
- Some(index) if self.index <= index => {
- self.index = index;
- self.expected_ref(")", self.peek_token_ref())
- }
+ Err(e) => match &self.furthest_in_subquery_error {
+ Some((_, furthest)) if self.index < query_failed_at => Err(furthest.clone()),
_ => Err(e),
},
}
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 1959bcd34..08b184002 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -20699,3 +20699,35 @@ fn parse_cte_materialization() {
}
}
}
+
+#[test]
+fn parse_in_reports_furthest_failure() {
+ for (sql, expected) in [
+ (
+ "SELECT * FROM t WHERE x IN (SELECT y FROM u WHERE",
+ "Expected: an expression, found: EOF",
+ ),
+ (
+ "SELECT * FROM t WHERE x IN (SELECT y FROM u ORDER BY",
+ "Expected: an expression, found: EOF",
+ ),
+ (
+ "SELECT * FROM t WHERE x IN (SELECT 1 FROM u WHERE y IN (SELECT 2 FROM v",
+ "Expected: ), found: EOF",
+ ),
+ // The inner `IN` is read again for the outer list after its subquery
+ // arm was cached as failed.
+ (
+ "SELECT * FROM t WHERE x IN ((SELECT 1 FROM u WHERE y IN (SELECT 2 FROM v WHERE",
+ "Expected: an expression, found: EOF",
+ ),
+ // The list gets further than the query.
+ ("SELECT * FROM t WHERE x IN (a b", "Expected: ), found: b"),
+ ] {
+ assert_eq!(
+ ParserError::ParserError(expected.to_string()),
+ parse_sql_statements(sql).unwrap_err(),
+ "{sql}"
+ );
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org