Skip to content

Bound nested SELECT parsing to MAX_PARSER_DEPTH#1

Open
nilox94 wants to merge 1 commit into
BetterStackHQ:mainfrom
nilox94:fix/subquery-parser-depth
Open

Bound nested SELECT parsing to MAX_PARSER_DEPTH#1
nilox94 wants to merge 1 commit into
BetterStackHQ:mainfrom
nilox94:fix/subquery-parser-depth

Conversation

@nilox94

@nilox94 nilox94 commented Jul 8, 2026

Copy link
Copy Markdown

Issue

MAX_PARSER_DEPTH is only checked in parse_expression_rec. Nested SELECT in FROM (...), CTEs, IN (SELECT ...), and scalar subqueries call parse_select_statement without enter_depth(). Subquery nesting has no limit. On deep input the parser stack-overflows instead of returning a parse error.

Repro

On main, with a fresh build (cargo build --bin clickhouse-analyzer):

SELECT 1 FROM (SELECT 1 FROM (SELECT 1 FROM (...)))  -- repeated 10,000 times
python3 -c "s='SELECT 1'; [s:=f'SELECT 1 FROM ({s})' for _ in range(10_000)]; print(s)" \
  | cargo run --bin clickhouse-analyzer
# thread 'main' has overflowed its stack
# fatal runtime error: stack overflow

Fix

Add parse_nested_select_statement(). It wraps enter_depth() and leave_depth() around parse_select_statement(). Use it at subquery entry points:

  • parse_subquery_table_ref (FROM (SELECT …))
  • parse_with_items (CTEs)
  • parse_in_rhs / expr_delimited (IN (SELECT …), (SELECT …))

Top-level SELECT and UNION RHS are unchanged. They are not nested inside another depth-consuming frame.

Adds bounds_deeply_nested_subqueries: 1001 nested SELECT * FROM (...) wrappers return a nesting-depth error; 999 parse cleanly.

Verify

After this PR, the same query at depth 1001 returns "Maximum expression nesting depth exceeded" without crashing.

cargo test bounds_deeply_nested_subqueries

`enter_depth()` was only checked in `parse_expression_rec`, so deeply
nested `FROM (SELECT …)` subqueries could still overflow the parser stack.

Route subquery entry points through `parse_nested_select_statement`.
Test uses `SELECT *` so the limit is exercised by subquery nesting, not
by `parse_expression_rec` on a `SELECT 1` literal.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant