Skip to content

PostgreSQL: bind unary plus and minus tighter than ^ - #2830

Open
compiler-segfault wants to merge 1 commit into
apache:mainfrom
compiler-segfault:pg-unary-operand-precedence
Open

compiler-segfault wants to merge 1 commit into
apache:mainfrom
compiler-segfault:pg-unary-operand-precedence

Conversation

@compiler-segfault

Copy link
Copy Markdown

SELECT -1 ^ 0 is parsed as -(1 ^ 0) by PostgreSqlDialect, so it yields -1 where PostgreSQL yields 1; SELECT +2 ^ 2 yields -4 instead of 4.

PostgreSQL 17:  SELECT -1 ^ 0;  ->  1
sqlparser:      UnaryOp { op: Minus, expr: BinaryOp { .., op: PGExp, .. } }

In gram.y UMINUS is declared above COLLATE, AT and ^, so the operand of a unary +/- may only take ., :: and []. The operand precedence is now a Dialect method that defaults to the previous MulDivModOp value, and PostgreSqlDialect returns the COLLATE level. That also makes -a AT TIME ZONE 'tz' parse as (-a) AT TIME ZONE 'tz', which is the same reading gram.y gives.

PostgreSQL precedence table

parse_unary_operand_binds_tighter_than_exponentiation is added to tests/sqlparser_postgres.rs; without the change it fails with the AST quoted above.

cargo test --all-features, cargo fmt --all and cargo clippy --all-targets --all-features -- -D warnings all pass.

Prepared with AI assistance; I reviewed the diff and ran the checks above.

Fixes #2819.

`UMINUS` is declared above `COLLATE`, `AT` and `^` in gram.y, so the operand of a
unary `+`/`-` may only take `.`, `::` and `[]`. Parse it at a dialect-provided
precedence instead of a hard-coded `MulDivModOp`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PostgreSQL: unary minus binds more loosely than ^, so -1 ^ 0 parses as -(1 ^ 0)

1 participant