This is an automated email from the ASF dual-hosted git repository.

github-bot pushed a commit to branch 
gh-readonly-queue/main/pr-2282-1097a0d5a6a852737b55f96bd38fba3f2ece9bd0
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git

commit 7c4eac3098063d191337ecb9ac0f695ac205de67
Author: Dmitrii Blaginin <[email protected]>
AuthorDate: Tue Mar 24 04:39:25 2026 +0000

    recursive protection for `parse_subexpr`  (#2282)
---
 src/parser/mod.rs         |  1 +
 tests/sqlparser_common.rs | 28 ++++++++++++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index cefc0c6f..3a970f7a 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -1386,6 +1386,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse tokens until the precedence changes.
+    #[cfg_attr(feature = "recursive-protection", recursive::recursive)]
     pub fn parse_subexpr(&mut self, precedence: u8) -> Result<Expr, 
ParserError> {
         let _guard = self.recursion_counter.try_decrease()?;
         debug!("parsing expr");
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 6f9e4695..cff29bfe 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -15687,6 +15687,34 @@ fn overflow() {
     let statement = statements.pop().unwrap();
     assert_eq!(statement.to_string(), sql);
 }
+
+#[test]
+fn parse_deeply_nested_boolean_expr_does_not_stackoverflow() {
+    fn build_nested_expr(depth: usize) -> String {
+        if depth == 0 {
+            return "x = 1".to_string();
+        }
+        format!(
+            "({} OR {} AND ({}))",
+            build_nested_expr(0),
+            build_nested_expr(0),
+            build_nested_expr(depth - 1)
+        )
+    }
+
+    let depth = 200;
+    let where_clause = build_nested_expr(depth);
+    let sql = format!("SELECT pk FROM tab0 WHERE {where_clause}");
+
+    let mut statements = Parser::new(&GenericDialect {})
+        .try_with_sql(&sql)
+        .expect("tokenize to work")
+        .with_recursion_limit(depth * 10)
+        .parse_statements()
+        .unwrap();
+    let statement = statements.pop().unwrap();
+    assert_eq!(statement.to_string(), sql);
+}
 #[test]
 fn parse_select_without_projection() {
     let dialects = all_dialects_where(|d| d.supports_empty_projections());


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to