Fix "Empty query" when running with cursor past the only `;` in play.html by alexey-milovidov · Pull Request #105107 · ClickHouse/ClickHouse · GitHub
Skip to content

Fix "Empty query" when running with cursor past the only ; in play.html#105107

Merged
alexey-milovidov merged 13 commits into
masterfrom
play-fix-cursor-past-semicolon
Jun 6, 2026
Merged

Fix "Empty query" when running with cursor past the only ; in play.html#105107
alexey-milovidov merged 13 commits into
masterfrom
play-fix-cursor-past-semicolon

Conversation

@alexey-milovidov

@alexey-milovidov alexey-milovidov commented May 16, 2026

Copy link
Copy Markdown
Member

Fix a bug in the query editor of programs/server/play.html.

If the textarea contains a single query that ends with ; (with optional trailing whitespace, comments, or a newline) and the cursor is placed past that ;, pressing Run returned an empty string from getQueryUnderCursor and the server reported an "empty query" error instead of running the only query in the textarea.

getQueryUnderCursor advances current_query_start past every whitespace/comment token at the head of each query, so when the cursor was past the last ;, the start had already walked all the way to the end of the input and substring(start) was empty.

Now we additionally track the start/end of the most recently completed <text-up-to-and-including-;> while walking the tokens. After the loop, if no significant tokens follow the last ; (detected by current_query_start === current_offset), we select and return that last completed query instead of the empty tail.

Verified manually for: cursor placed right after ;; cursor on the next line; cursor after trailing whitespace; multiple queries with the cursor past every ;; no-semicolon queries (unchanged); leading whitespace (unchanged).

Changelog category (leave one):

  • Bug Fix (user-visible misbehavior in an official stable release)

Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):

Fixed a bug in the Web UI (play.html): running a query while the cursor was past the only trailing ; reported "empty query" instead of running the query.

Documentation entry for user-facing changes

  • Documentation is written (mandatory for new features)

Note

Low Risk
Low risk: isolated client-side query selection logic change in play.html, primarily affecting how the active query is chosen near trailing ; delimiters.

Overview
Fixes query selection in programs/server/play.html so Run no longer submits an empty query when the cursor is positioned after a trailing semicolon.

getQueryUnderCursor now tracks the most recent completed non-empty query, skips delimiter-only segments (e.g. ;;), and if the textarea ends with only whitespace/comments after the last ;, it selects/returns that last query instead of an empty tail.

Reviewed by Cursor Bugbot for commit 88b84f9. Bugbot is set up for automated code reviews on this repo. Configure here.

Version info

  • Merged into: 26.6.1.439

…g `;`

`getQueryUnderCursor` builds the substring to run by walking the lexer's token
stream and resetting the start position to the offset right after each `;`. If
the cursor is past the last `;`, the function would fall through to the "no
trailing semicolon" branch and return `all_queries.substring(start)`, where
`start` had already been advanced past every whitespace/comment token in the
tail — i.e. the returned string was empty and the server reported an "empty
query" error.

Track the most recently completed `<text-up-to-and-including-`;`>` while
walking the tokens. After the loop, if no significant tokens follow the last
`;` (detected by `current_query_start === current_offset`), select and return
that last completed query instead of the empty tail.

This covers the single-query case (`SELECT 1;` with the cursor placed right
after `;`, on the next line, or after trailing whitespace/comments) as well as
multi-query inputs whose cursor is past every `;`.
@clickhouse-gh

clickhouse-gh Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

@clickhouse-gh clickhouse-gh Bot added the pr-bugfix Pull request with bugfix, not backported by default label May 16, 2026
@alexey-milovidov

Copy link
Copy Markdown
Member Author

@groeneai, the Unit tests (asan_ubsan, function_prop_fuzzer) failures — FunctionsStress.stress and AllTests — are unrelated to this PR (which only modifies programs/server/play.html JavaScript). They are tracked in existing open issues #104877 and #105040 (arrayResize timeout in the function property fuzzer). Failing CI report: https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=105107&sha=cbfb99910a3a3f0a71707fcdfde931c66e7c08ea&name_0=PR&name_1=Unit%20tests%20%28asan_ubsan%2C%20function_prop_fuzzer%29

Comment thread programs/server/play.html
@groeneai

Copy link
Copy Markdown
Contributor

Confirmed @alexey-milovidov — both unrelated to this play.html JS-only change:

No action needed on this PR — safe to merge.

@alexey-milovidov

Copy link
Copy Markdown
Member Author

This was fixed by #105146. Let's update the branch.

With input like `SELECT 1;;` and the cursor placed past the final `;`,
the previous fix in this PR still selected the trailing `;` segment as
the "last completed query" and returned `;`, so the server still
reported "empty query".

Track whether the segment up to each `;` contains any content (i.e.
`current_query_start` is strictly less than the offset of the `;`
token). Only update `last_query_start` / `last_query_end` and only
return the segment in the cursor-match branch when it has content.
Delimiter-only segments are skipped entirely.

This handles `SELECT 1;;`, `SELECT 1;; ` (trailing whitespace after
double `;`), `SELECT 1; -- comment\n`, and `SELECT 1;\n\nSELECT 2;\n`
with the cursor past every `;`. Bare `;` and empty input still
correctly produce no query.

Addresses review feedback at
#105107 (comment)

@pamarcos pamarcos 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.

The code indeed fixes the issue we had. I tested it manually.

Before, with trailing whitespace

Image

Now

Image

but there are some regression cases:

  • SELECT 1; ' with cursor at end should try to run the incomplete tail and show a syntax error, not return 1.
  • SELECT 1; /* with cursor at end should show an unclosed comment/syntax error, not return 1.
  • TRUNCATE TABLE t; ' should not execute TRUNCATE TABLE t when the cursor is in the incomplete tail.

`getQueryUnderCursor` stops receiving tokens when the lexer reports an error. Without checking that tokenization reached the end of the textarea, an incomplete tail such as `SELECT 1; '` could look like whitespace-only trailing content and run the previous completed query.

Require the offset to reach the full input before falling back to the last completed query.
@pamarcos

Copy link
Copy Markdown
Member

but there are some regression cases:

  • SELECT 1; ' with cursor at end should try to run the incomplete tail and show a syntax error, not return 1.
  • SELECT 1; /* with cursor at end should show an unclosed comment/syntax error, not return 1.
  • TRUNCATE TABLE t; ' should not execute TRUNCATE TABLE t when the cursor is in the incomplete tail.

I think d59f835 should fix it

Comment thread programs/server/play.html
alexey-milovidov and others added 6 commits May 23, 2026 05:27
The `getQueryUnderCursor` logic regressed once during review (`SELECT 1;;`
and incomplete tails like `SELECT 1; '` / `SELECT 1; /*`), so lock the
contract with an automated test.

There is no JavaScript/WebAssembly runtime in CI, so the browser code in
`programs/server/play.html` cannot be run directly. Instead the test in
`src/Parsers/tests/gtest_play_get_query_under_cursor.cpp` reproduces the exact
token-walking algorithm on top of the real `DB::Lexer` — the same source the
Web UI compiles to WebAssembly. It covers the cursor-at-end cases requested in
review: `SELECT 1;`, `SELECT 1;;`, `SELECT 1; '`, `SELECT 1; /*`, plus
no-semicolon, leading whitespace, trailing comment, and multi-query selection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alexey-milovidov

Copy link
Copy Markdown
Member Author

Merged latest master and added the regression test requested in review.

  • New unit test src/Parsers/tests/gtest_play_get_query_under_cursor.cpp locks the getQueryUnderCursor contract (single trailing ;, ;;, incomplete tails ' / /*, no-semicolon, leading whitespace, trailing comment, multi-query). Since there is no JS/WASM runtime in CI, it ports the token-walking algorithm on top of the real DB::Lexer (the same src/Parsers/Lexer.cpp compiled to WebAssembly by the Web UI); cross-reference comments in both files keep them in sync. Also resolves the new_tests_check.py "No new tests" failure.
  • The previous run's Performance Comparison failures (array_reduce, logical_functions_small, prefetch_in_aggregation) are unrelated perf noise — this PR changes only programs/server/play.html and the new test, with no effect on C++ runtime — and should clear on re-run.

@clickhouse-gh

clickhouse-gh Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

LLVM Coverage Report

Metric Baseline Current Δ
Lines 84.50% 84.40% -0.10%
Functions 92.40% 92.40% +0.00%
Branches 77.10% 77.00% -0.10%

Changed lines: Changed C/C++ lines covered by tests: 50/50 (100.00%) | Lost baseline coverage: none · Uncovered code

Full report · Diff report

@alexey-milovidov alexey-milovidov added this pull request to the merge queue Jun 6, 2026
Merged via the queue into master with commit d729f75 Jun 6, 2026
166 checks passed
@alexey-milovidov alexey-milovidov deleted the play-fix-cursor-past-semicolon branch June 6, 2026 00:30
@robot-clickhouse-ci-1 robot-clickhouse-ci-1 added the pr-synced-to-cloud The PR is synced to the cloud repo label Jun 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-bugfix Pull request with bugfix, not backported by default pr-synced-to-cloud The PR is synced to the cloud repo

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants