Skip to content

Fix trailing SQL comments breaking multiline submit and execution - #1559

Merged
j-bennet merged 5 commits into
dbcli:mainfrom
DiegoDAF:fix/trailing-comments-semicolon
Jun 2, 2026
Merged

j-bennet merged 5 commits into
dbcli:mainfrom
DiegoDAF:fix/trailing-comments-semicolon

Conversation

@DiegoDAF

@DiegoDAF DiegoDAF commented Mar 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes two related bugs when a SQL comment follows the semicolon, e.g.:

vacuum freeze verbose tpd.file_delivery; -- 82% towards emergency, 971 MB

Bug 1 — pgbuffer._is_complete(): sql.endswith(";") returned False when a trailing comment followed the semicolon. In multiline mode, pressing Enter never submitted the query — the UI appeared frozen.

Bug 2 — pgexecute.run(): sql.rstrip(";") couldn't strip the semicolon because the string ended with the comment text, not ;. The malformed SQL (with embedded ;) was sent to PostgreSQL via psycopg's extended query protocol, which doesn't support multiple statements.

Fix

Both locations now use sqlparse.format(sql, strip_comments=True) before checking for / removing the trailing semicolon.

Files Changed

  • pgcli/pgbuffer.py — _is_complete() strips comments before endswith(";")
  • pgcli/pgexecute.py — run() strips comments before rstrip(";")
  • changelog.rst — Added bug fix entry to Upcoming
  • tests/test_trailing_comments.py — 12 new tests covering edge cases

Test plan

  • All 12 new tests pass (pytest tests/test_trailing_comments.py -v)
  • Full test suite passes (2788 passed, 128 skipped)
  • Manually verified: vacuum freeze verbose tpd.file_delivery; -- 82% towards emergency executes correctly
  • Verify multiline mode submits correctly with trailing comments

Two bugs when a comment follows the semicolon (e.g. "SELECT 1; -- note"):

1. pgbuffer._is_complete() checked sql.endswith(";") which returned False
   when a comment followed, preventing multiline mode from ever submitting

2. pgexecute.run() used rstrip(";") which couldn't find the semicolon
   past the trailing comment, sending malformed SQL to PostgreSQL

Both fixes strip comments (via sqlparse) before checking for the semicolon.

Made with ❤️ and 🤖 Claude
Comment thread tests/test_trailing_comments.py Fixed
@j-bennet

j-bennet commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

One of the integration tests is failing.

With strip_comments=True, trailing comments after \h are correctly
removed, so \h now shows full help output instead of "No help".
The original test expectations were based on a sqlparse bug where
comments were kept as arguments — the upstream TODO comments
acknowledged this was undesired behavior.
Long asserts were split unnecessarily; ruff 0.15.11 keeps them on a
single line (line-length=140).
@DiegoDAF

Copy link
Copy Markdown
Contributor Author

Merged latest main to pick up the CI fix (#1596). The integration test failure was caused by missing PG* env vars in tox.ini, not by this change. Conflicts resolved -- ready for another look, thanks!

@DiegoDAF

DiegoDAF commented Jun 1, 2026 •

Copy link
Copy Markdown
Contributor Author

Hey @j-bennet 👋 Friendly bump on this little fix for trailing SQL comments. Latest push sorted out the ruff format on the test file, so CI should be happy now (especially with #1596 back in). Whenever you get a chance, no pressure. Thanks a ton! 🙏

@j-bennet

j-bennet commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Ok, all green. Merging. Thank you!

@j-bennet
j-bennet merged commit 13f9ea4 into dbcli:main Jun 2, 2026
7 checks passed
DiegoDAF added a commit to DiegoDAF/pgcli.daf that referenced this pull request Sep 21, 2026
select 17 # 5 returned 17 instead of 20, and said nothing about it.
sqlparse follows MySQL and reads # as the start of a comment, so
sqlparse.format(strip_comments=True) dropped the rest of the line before
the statement was sent. Reported upstream as dbcli#1646; the
sqlparse side is andialbrecht/sqlparse#539.

Worth saying plainly: we introduced this. Our dbcli#1559 changed that call
from strip_comments=False to True so that rstrip(";") would work with a
comment after the semicolon. It fixed that and broke this.

The intent of dbcli#1559 only needs the TRAILING comments gone, so
strip_trailing_comments() now does exactly that, with PostgreSQL's rules
rather than sqlparse's: -- to end of line, /* */ which nest, and no
comment markers honoured inside string literals, quoted identifiers or
dollar-quoted bodies. A comment in the middle of a statement is kept, as
the server would see it. # is just an operator.

Both call sites move over: the one before execution in pgexecute, and
_is_complete() in pgbuffer, where "select 17 # 5;" would otherwise never
look finished.

15 tests.
DiegoDAF added a commit to DiegoDAF/pgcli.daf that referenced this pull request Sep 21, 2026
Fixes dbcli#1646.

  > select 17 # 5;
  +----------+
  | ?column? |
  |----------|
  | 17       |
  +----------+

The answer is 20. sqlparse follows MySQL and reads # as the start of a
comment (andialbrecht/sqlparse#539), so
sqlparse.format(strip_comments=True) dropped the rest of the line before
the statement reached the server, and the wrong answer came back without
a warning.

Only the TRAILING comments need to go there, which is what that call was
added for in dbcli#1559: rstrip(";") cannot find the semicolon when a comment
follows it. strip_trailing_comments() does that with PostgreSQL's rules
instead of sqlparse's:

  - "--" runs to the end of the line, "/* */" nest;
  - those markers mean nothing inside a string literal, a quoted
    identifier or a dollar-quoted body;
  - "#" is an operator like any other.

A comment in the middle of a statement is kept, so the server sees what
was written. Both call sites move over: the one before execution in
pgexecute, and _is_complete() in pgbuffer, where "select 17 # 5;" would
otherwise never look finished and the prompt would keep waiting.

18 tests, including nested block comments, dollar-quoted function
bodies, doubled quotes inside strings and unterminated comments.
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.

3 participants