Skip to content

fix(sql): only force a LIMIT onto query expressions - #43097

Merged
nytai merged 2 commits into
apache:masterfrom
nytai:limit-only-query-expressions
Aug 13, 2026
Merged

fix(sql): only force a LIMIT onto query expressions#43097
nytai merged 2 commits into
apache:masterfrom
nytai:limit-only-query-expressions

Conversation

@nytai

@nytai nytai commented Aug 12, 2026

Copy link
Copy Markdown
Member

SUMMARY

apply_limit() in superset/sql_lab.py skips only mutating statements, so every read-only non-query statement — SHOW, DESCRIBE, SET, USE, GRANT, and anything sqlglot falls back to parsing as an opaque Command — reaches SQLStatement.set_limit_value(), which has nowhere valid to put a limit.

#36939 fixed the loudest case by special-casing exp.Show inside the FORCE_LIMIT branch: on MySQL/StarRocks a forced limit renders a SHOW with two LIMIT keywords and the engine rejects it outright.

starrocks error: Getting syntax error at line 1, column 36. Detail message:
Unexpected input 'LIMIT', the most similar input is {<EOF>, ';'}.

Two gaps remained:

  • WRAP_SQL was never guarded, so it rewrites any non-query statement as SELECT * FROM (SHOW DATABASES) LIMIT 1001, discarding the statement quietly instead of failing.
  • A single node-type special-case stops holding the moment another statement type's generator learns to render a limit arg.

So this guards on the node category at the top of the method instead: query expressions (SELECT, UNION, subqueries) get a limit, everything else is returned untouched, for every limit method.

is_select() would have been too narrow — UNION parses as exp.Union and a parenthesized query as exp.Subquery, neither of which is an exp.Select, and both must keep being limited. I verified exp.Query covers exactly Select/Union/Subquery and excludes Show/Describe/Use/Set/Grant/Command/Values on both sqlglot 30.16.0.

Found via querying starrocks, where show databases from default_catalog; failed for every user. The same bug breaks SHOW DATABASES and SHOW CREATE FUNCTION which are common operation for listing resources and udfs.

TESTING INSTRUCTIONS

pytest tests/unit_tests/sql/parse_tests.py -k set_limit_value

Reverting just the parse.py hunk turns 13 of these red, all WRAP_SQL — including the new DESCRIBE/USE/SET/GRANT cases, which #36939's guard does not cover.

Manually, against a StarRocks or MySQL connection in SQL Lab with a row limit set, run SHOW DATABASES;. Before: syntax error on the injected LIMIT. After: the statement runs.

Full local run: pytest tests/unit_tests --ignore=tests/unit_tests/mcp_service9143 passed, 0 failed. mcp_service is excluded only because it downloads tiktoken encodings at import and my environment has no egress; it is untouched by this change.

ADDITIONAL INFORMATION

`apply_limit()` skips only *mutating* statements, so every read-only
non-query statement -- `SHOW`, `DESCRIBE`, `SET`, `USE`, `GRANT`, and
anything sqlglot falls back to parsing as an opaque `Command` -- reaches
`SQLStatement.set_limit_value()`, which has nowhere valid to put a limit.

`FORCE_LIMIT` branch, where MySQL/StarRocks reject the doubled `LIMIT`
keyword sqlglot renders ("Getting syntax error ... Unexpected input
'LIMIT'"). Two gaps remained:

- `WRAP_SQL` was left unguarded, so it rewrote any non-query statement
  as `SELECT * FROM (SHOW DATABASES)`, discarding it quietly instead of
  failing.
- A single node-type special-case stops holding as soon as another
  statement type's generator learns to render a `limit` arg.

Guard on the node category at the top of the method instead: query
expressions (`SELECT`, `UNION`, subqueries) get a limit, everything else
is returned untouched, for every limit method.

`is_select()` would have been too narrow here -- `UNION` parses as
`exp.Union` and a parenthesized query as `exp.Subquery`, neither of which
is an `exp.Select`, and both must keep being limited.
@dosubot dosubot Bot added the sqllab Namespace | Anything related to the SQL Lab label Aug 12, 2026
@bito-code-review

bito-code-review Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #9aecaa

Actionable Suggestions - 0
Additional Suggestions - 1
  • tests/unit_tests/sql/parse_tests.py - 1
    • Missing WRAP_SQL in non-select test · Line 2638-2644
      `test_set_limit_value_limits_non_select_query_expressions` only tests `FORCE_LIMIT` on non-SELECT query expressions (`UNION`, subquery), but the two tests directly above it both parametrize over `FORCE_LIMIT` and `WRAP_SQL`. `WRAP_SQL` also adds a `LIMIT` to these expressions, so covering it here maintains consistency and ensures both paths are exercised.
Review Details
  • Files reviewed - 2 · Commit Range: 4e7a738..4e7a738
    • superset/sql/parse.py
    • tests/unit_tests/sql/parse_tests.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@villebro villebro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for fixing and the tests are easy to follow. Minor nit: The PR description refers to #36939 as a fix, but it's actually an issue.

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.63%. Comparing base (762fdcc) to head (2fda0f3).
⚠️ Report is 5 commits behind head on master.

Files with missing lines Patch % Lines
superset/sql/parse.py 0.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #43097      +/-   ##
==========================================
- Coverage   66.64%   66.63%   -0.02%     
==========================================
  Files        2866     2866              
  Lines      162896   162852      -44     
  Branches    37525    37504      -21     
==========================================
- Hits       108568   108512      -56     
- Misses      52203    52214      +11     
- Partials     2125     2126       +1     
Flag Coverage Δ
hive 38.17% <0.00%> (ø)
mysql 57.91% <0.00%> (ø)
postgres 57.94% <0.00%> (-0.01%) ⬇️
presto 40.12% <0.00%> (ø)
python 59.33% <0.00%> (-0.01%) ⬇️
sqlite 57.58% <0.00%> (ø)
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@nytai

nytai commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

thanks @villebro, description updated to mention the PR instead of the issue.

@nytai
nytai merged commit b8ca729 into apache:master Aug 13, 2026
69 checks passed
@bito-code-review

Copy link
Copy Markdown
Contributor

Bito Automatic Review Skipped – PR Already Merged

Bito scheduled an automatic review for this pull request, but the review was skipped because this PR was merged before the review could be run.
No action is needed if you didn't intend to review it. To get a review, you can type /review in a comment and save it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L sqllab Namespace | Anything related to the SQL Lab

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants