Bitwise `&` and `->` group differently in the PostgreSQL and MySQL/Generic dialects
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
Research direction
Start in src/dialect/mod.rs with the default precedence table, then compare it with PostgreSqlDialect::prec_value in src/dialect/postgresql.rs:176-184 and the PostgreSQL gram.y rule cited in the issue. Add a tree-level regression test for a -> b & c, since SQL round-trip tests cannot detect the grouping, and run the full suite to verify the change.
Written by the indexing model from the issue text.
Description
& and -> have the same precedence in PostgreSQL but not in the default precedence table, so the
same expression produces two different trees depending on dialect:
| SQL | PostgreSqlDialect |
MySqlDialect / GenericDialect |
|---|---|---|
a -> b & c |
((a -> b) & c) |
(a -> (b & c)) |
a -> b | c |
((a -> b) | c) |
((a -> b) | c) |
a -> b ^ c |
(a -> (b ^ c)) |
(a -> (b ^ c)) |
a -> b + c |
(a -> (b + c)) |
(a -> (b + c)) |
& is the only row that disagrees.
Cause
The default table in src/dialect/mod.rs has:
Precedence::Ampersand => 23,
Precedence::Caret => 22,
Precedence::Pipe => 21,
Precedence::Colon => 21,
Precedence::PgOther => 21,
PostgreSqlDialect::prec_value instead maps Ampersand, Pipe, Colon and PgOther all to
PG_OTHER_PREC (src/dialect/postgresql.rs:176-184), which matches gram.y, where & is just a
generic Op and shares one left-associative level with ->:
%left Op OPERATOR RIGHT_ARROW '|'
So Pipe already agrees with PgOther in the default table (both 21), and Caret is legitimately
above it, but Ampersand at 23 is left as the sole outlier.
Candidate fix
- Precedence::Ampersand => 23,
+ Precedence::Ampersand => 21,
The full suite passes unchanged with that applied, so no existing test pins the current grouping —
which is also why this went unnoticed. Display for Expr::BinaryOp emits no parentheses, so a
mis-grouped tree round-trips to the original SQL and verified_expr / verified_stmt cannot catch
it; a test would have to assert on the tree.
Open question, possibly a separate issue
For MySQL the fix above is necessary but not sufficient. MySQL's -> / ->> take a quoted JSON path
on the right-hand side, so there is nothing for MySQL to resolve — col->'$.a' + 1 can only mean
(col->'$.a') + 1. sqlparser parses that right operand as a full expression at PgOther, giving
col -> ('$.a' + 1), so -> under-binds in MySQL against +, *, ^ and friends, not just &.
Making that correct probably means a MySQL-specific precedence for the arrow operators rather than
another adjustment to the shared row, so I've kept it out of scope here — happy to split it out if
a maintainer would prefer it tracked separately.
Surfaced while working on #2436. Related: #2460.
- Dominant language
- Rust
- Stars
- 3.5k
- Forks
- 774
- Avg merge
- 3d 12h
- Merged PRs (30d)
- 30
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from apache/datafusion-sqlparser-rs
-
Difficulty 2/5 1-2 days Newbie friendliness 72/100
apache/datafusion-sqlparser-rs#2495 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
apache/datafusion-sqlparser-rs#2407 ·
-
Add SQL/PGQ keywords Open
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
apache/datafusion-sqlparser-rs#2393 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
apache/datafusion-sqlparser-rs#2390 · 1 comment ·
-
Difficulty 1/5 Under an hour Newbie friendliness 72/100
apache/datafusion-sqlparser-rs#1761 ·
All issues in apache/datafusion-sqlparser-rs
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
state:needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
zed-industries/zed#64680 · 2 comments ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
RustPython/RustPython#8802 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
TheLarkInn/aipm#2390 ·