Skip to content

fix: honour datafusion.sql_parser.recursion_limit in datafusion-cli - #24914

Closed
edubraqd wants to merge 2 commits into
apache:mainfrom
edubraqd:fix/cli-parser-recursion-limit
Closed

edubraqd wants to merge 2 commits into
apache:mainfrom
edubraqd:fix/cli-parser-recursion-limit

Conversation

@edubraqd

@edubraqd edubraqd commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

exec_and_print parsed statements with DFParser::parse_sql_with_dialect, which always uses the parser's built-in recursion limit, so SET datafusion.sql_parser.recursion_limit had no effect in the CLI.

What changes are included in this PR?

Build the parser with DFParserBuilder, passing the dialect and the session's recursion_limit, the same way SessionState::sql_to_statement does.

Are these changes tested?

Yes. exec_and_print_honours_parser_recursion_limit runs a 60-level nested expression: it fails with RecursionLimitExceeded under the default limit and succeeds once the session limit is raised to 100.

Are there any user-facing changes?

datafusion.sql_parser.recursion_limit now applies to statements run through datafusion-cli.

edubraqd and others added 2 commits September 3, 2026 01:51
`exec_and_print` parsed statements with `DFParser::parse_sql_with_dialect`,
which always uses the parser's built-in recursion limit. Setting
`datafusion.sql_parser.recursion_limit` therefore had no effect in the CLI:

    > SET datafusion.sql_parser.recursion_limit = 100;
    > SELECT abs(abs(... 60 levels ...));
    SQL error: RecursionLimitExceeded (current limit: 50)

Build the parser with `DFParserBuilder` and the session's recursion limit,
the same way `SessionState::sql_to_statement` does.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
@alamb

alamb commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Closing per #24893 (comment)

@alamb alamb closed this Sep 11, 2026
Rich-T-kid pushed a commit to Rich-T-kid/datafusion that referenced this pull request Oct 28, 2026
…ating input (apache#25807)

## Which issue does this PR close?

- Closes apache#24913.

## Rationale for this change

`datafusion.sql_parser.recursion_limit` has no effect in
`datafusion-cli`. After
`SET datafusion.sql_parser.recursion_limit = 200` (or
`DATAFUSION_SQL_PARSER_RECURSION_LIMIT=200`),
a query with 60 nested `abs(...)` calls still fails with
`RecursionLimitExceeded (current limit: 51)` via `-c`, `-f` and the
interactive shell,
while the same query works through `SessionContext::sql`. Lowering the
limit is ignored too.

The CLI parses statements itself instead of going through
`SessionState::sql_to_statement`,
and only reads the dialect from the session config. There are two parse
sites:

- `exec_and_print` (`-c`, `-f`, rc files, and REPL execution)
- `CliHelper::validate_input`, the REPL's rustyline validator, which
rejects the line
  before it is executed

The earlier attempt in apache#24914 fixed only the first one, so the REPL
stayed broken.

## What changes are included in this PR?

- `exec_and_print` parses with `DFParserBuilder::with_recursion_limit`
using the session's
  limit, the same way `SessionState::sql_to_statement` does.
- `CliHelper` gets a `recursion_limit` (default taken from
`SqlParserOptions`) and a new
`set_parser_options(&SqlParserOptions)` method that sets both the
dialect and the
recursion limit. `exec_from_repl` calls it once at the top of the REPL
loop, before every
read, so changes from SQL input, `\i` files and other backslash commands
all reach the
validator. `CliHelper::new` and `set_dialect` are unchanged, so this is
additive.

Not changed:

- `is_open_quote_for_location` in `helper.rs` (tab completion for
`LOCATION '...`) still
uses the default parser. It already ignores the dialect, and a parse
failure there only
  means no filename completion.
- A single `-c` string or REPL line containing `SET ...; <query>` is
parsed as a whole
before the `SET` runs, so the new limit does not apply to the query in
that same string.
This matches how the dialect already behaves. Separate `-c` arguments,
file lines, or
  REPL entries work.

Something I noticed and did not special-case: with a limit of 1 or 2,
even a `SET`
statement fails to parse, so in the REPL you have to restart to recover
(3 and above is
fine). `SessionContext::sql` behaves the same way; the CLI just used to
ignore the setting.

## What is the testing strategy for this PR?

- Extended the existing `tests/sql/select.sql` fixture (`cli_quick_test`
case `files`,
`[email protected]`): it raises the limit and runs a 60-deep
query, then lowers it
to 5 and runs a 10-deep query. On `main` the snapshot shows the reverse
(the deep query fails at 51, the shallow one
  succeeds).
- New `helper.rs` unit test `sql_recursion_limit`, modelled on
`sql_dialect`, for the REPL
  validator.
- Manually checked a debug build with `-c`, the env var, and the
interactive shell (via
  `script` for a pty).
- Manual pty check of the REPL after `\i` (rustyline needs a terminal,
so this is not an
sqllogictest): `\i` a file that sets the limit to 100, then run a
60-deep query. Before
the follow-up commit the query was held as incomplete and never ran;
after it, the query
runs. A `SET` typed directly and the default-limit rejection behave as
before.

Commands run:

```bash
cargo test -p datafusion-cli --lib helper::tests
cargo test -p datafusion-cli --test cli_integration cli_quick_test
cargo test -p datafusion-cli
cargo fmt --all
cargo clippy -p datafusion-cli --all-targets --all-features -- -D warnings
```

## Are there any user-facing changes?

Yes: `datafusion.sql_parser.recursion_limit` is now respected by
`datafusion-cli`.
The only API change is the new public `CliHelper::set_parser_options`
method (additive).

---------

Co-authored-by: Andrew Lamb <[email protected]>
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.

datafusion-cli ignores datafusion.sql_parser.recursion_limit

2 participants