Skip to content

Print a space between adjacent prefix unary operators - #2424

Open
shuvamk wants to merge 1 commit into
apache:mainfrom
shuvamk:nested-unary-op-space
Open

Print a space between adjacent prefix unary operators#2424
shuvamk wants to merge 1 commit into
apache:mainfrom
shuvamk:nested-unary-op-space

Conversation

@shuvamk

@shuvamk shuvamk commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Expr::UnaryOp's Display writes {op}{expr} with no separator, so a nested unary operand is printed glued to the operator:

SELECT ~ ~ 1

prints as SELECT ~~1, which no longer reparses on any dialect (Expected: an expression, found: ~~). SELECT - -1 prints as SELECT --1 the same way; that one only breaks where -- opens a line comment, so MySQL is unaffected.

On PostgreSQL it changes meaning rather than failing, because @@ is its own operator: SELECT @ @ 1 (abs of abs) prints as SELECT @@1, which reparses as UnaryOperator::DoubleAt applied to 1.

The fix extends the existing "needs a space" condition so it also fires when the operand is another Expr::UnaryOp. Non-unary operands are unchanged, so -1 and NOT a print as before.

Tests are parse_nested_unary_ops in tests/sqlparser_common.rs and parse_nested_pg_unary_ops in tests/sqlparser_postgres.rs; I checked that both fail without the source change. The AGENTS.md pre-commit checks are clean locally.

`Expr::UnaryOp`'s `Display` writes `{op}{expr}` with no separator, so when
the operand is itself a `UnaryOp` the two operator glyphs are emitted glued
together and the output no longer round-trips:

  SELECT ~ ~ 1 -> SELECT ~~1 -> "Expected: an expression, found: ~~"

`SELECT - -1` prints as `SELECT --1`, which is the same defect but only
breaks on dialects where `--` opens a line comment; MySQL requires
whitespace after `--` and reparses it unchanged.

The Postgres case is worse than a parse error, because `@@` is a distinct
operator: `SELECT @ @ 1` (abs of abs) prints as `SELECT @@1` and silently
reparses as `UnaryOperator::DoubleAt` applied to `1`.

Extend the existing "needs a space" condition so it also fires when the
operand is another `Expr::UnaryOp`. Operators already in that list and
non-unary operands are unaffected, so `-1` and `NOT a` are unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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