GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix: bind bitwise operators looser than + and - by ybai08 · Pull Request #2833 · JSQLParser/JSqlParser

Conversation

@ybai08

@ybai08 ybai08 commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

Since the Pratt rewrite (5.4), &, |, #, << and >> have the same precedence as + and -. That gives 1 & 7 - 2 as (1 & 7) - 2 and 1 << n - 1 as (1 << n) - 1. PostgreSQL, MySQL and SQLite all bind + and - tighter:

Expression PostgreSQL 17 MySQL 8.4 SQLite JSqlParser master This PR
1 & 7 - 2 1 = 1 & (7 - 2) 1 1 (1 & 7) - 2 1 & (7 - 2)
1 << 2 + 1 8 = 1 << (2 + 1) 8 8 (1 << 2) + 1 1 << (2 + 1)
a + b >> 2 (a + b) >> 2 same same same unchanged

5.3 got this right: BitwiseAndOr took AdditiveExpression operands.

The change gives & | # << >> their own level (prec 4), below + - || (prec 5). With Dialect.POSTGRESQL, PostgreSQL's || and its JSON operators already use prec 4. So in that dialect, all of PostgreSQL's "other operators" now share a single level, which matches PostgreSQL. A space-separated | | concat keeps the level of +. The bitwise operators share one left-associative level, as in PostgreSQL and SQLite. MySQL separates |, & and the shifts into different levels, and this PR doesn't change how that case is handled.

One existing assertion changes. testGetSign expected 1&2||3 to parse as (1 & 2) || 3. Outside the PostgreSQL dialect, || now binds like + (since the Pratt rewrite), and & binds looser than +. So || binds tighter than & and the expression parses as 1 & (2 || 3). That is also how SQLite reads it. With Dialect.POSTGRESQL the result is still (1 & 2) || 3, as in PostgreSQL, where SELECT 1 & 2 || 'x' gives '0x'. The test now asserts both. Please tell me if you'd rather keep the old default for that mix.

Also unsure: in T-SQL, & and | sit at the + - level, so with Dialect.SQLSERVER the master behaviour was right for a & b + c. 5.3 behaved like this PR. If you'd like, I can add a Dialect.SQLSERVER branch.

Tests: three cases are added to ExpressionPrecedenceTest, covering &, |, <<, >>, # (PostgreSQL dialect) against + -, the shared bitwise level, | | concat, and a round trip. testGetSign is updated as described above.

What was run:

  • ./gradlew test --tests ExpressionPrecedenceTest without the grammar change: testBitwiseOperatorsBindLooserThanAddition and testSpaceSeparatedConcatStillBindsLikeAddition fail (expected: <BitwiseAnd> but was: <Subtraction> / <Concat>). With the change, both pass.
  • ./gradlew test with the change but before updating testGetSign: 10,747 tests, only testGetSign failed.
  • ./gradlew check (JDK 21, with a JDK 17 toolchain): BUILD SUCCESSFUL. That covers 10,748 tests with 0 failures, plus checkstyle, PMD, spotless, spotbugs and jacoco coverage verification.
  • A differential check against PostgreSQL 17. Random integer and boolean expressions using + - * / % ^ & | # << >>, comparisons, BETWEEN, IN, IS NULL, NOT, CASE and ::int were parsed with JSqlParser. Each tree was re-printed fully parenthesised, and PostgreSQL evaluated both forms. On master, a few percent of the expressions came out different. With this change, the only mismatches left involved ^, which fix: bind ^ tighter than *, / and % #2831 fixed. With both changes applied, 0 of 8,623 expressions differ.

Not run: gradle jmh. The only extra work is a getToken(2) check when the next token is |.

This is rebased on #2831, which touched the same lines. After the rebase, ExpressionPrecedenceTest was run again (without the grammar change, testGetSign, testBitwiseOperatorsBindLooserThanAddition and testSpaceSeparatedConcatStillBindsLikeAddition fail; with it, all 23 pass) along with the full ./gradlew test (10,750 tests, 0 failures).

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@ybai08
fix: bind bitwise operators looser than + and -
61ab472
Since the Pratt rewrite, &, |, #, << and >> share the precedence of +
and -, so 1 & 7 - 2 parses as (1 & 7) - 2 and 1 << n - 1 as
(1 << n) - 1. PostgreSQL, MySQL and SQLite all bind + and - tighter,
as did JSqlParser 5.3, where BitwiseAndOr was built from
AdditiveExpression operands.

Give the bitwise operators their own level below + - ||, the level
that PostgreSQL's || and JSON operators already use with
Dialect.POSTGRESQL. A space separated | | concat keeps the level of +.

1&2||3 is now 1 & (2 || 3) by default, as || binds like +, and
(1 & 2) || 3 with Dialect.POSTGRESQL, as in PostgreSQL.
@manticore-projects
manticore-projects merged commit f6ac257 into JSQLParser:master Oct 18, 2026
8 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@manticore-projects

manticore-projects commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

Thank you much!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@pbottine pbottine mentioned this pull request Oct 20, 2026
MySQL bitwise |, &, and shifts still share one parser precedence tier #2834
Closed
@princejain756 princejain756 mentioned this pull request Oct 21, 2026
Match MySQL operator precedence for XOR and bitwise operators #2838
Merged
7 tasks done
manticore-projects pushed a commit that referenced this pull request Oct 22, 2026
@princejain756
Match MySQL operator precedence for XOR and bitwise operators (#2838)
bfafeaa
XOR sat on the same level as OR, and |, &, <<, >> shared one
left-associative level, in every dialect. MySQL puts XOR between AND
and OR, and tiers the bitwise operators as <<, >> above & above |.

Gate the tiers on Dialect.MYSQL so the default dialect keeps the
shared levels established in #2833. SimpleExpression now enters the
arithmetic loop at floor 2 under MySQL so | is admitted.

Fixes #2834, fixes #2835
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@ybai08 @manticore-projects
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.