You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
MySQL -> / ->> bind too loosely against arithmetic and bitwise operators #2462
Split out of #2461, where this was raised as an open question.
MySQL's -> / ->> bind more tightly than every arithmetic, shift and bitwise operator: the
right-hand side is a quoted JSON path, and col->path is defined as equivalent to JSON_EXTRACT(col, path)
(docs). sqlparser gives the
arrow operators Precedence::PgOther (21), which sits below+ / - / *, so the arrow
under-binds on both sides:
SQL
sqlparser (MySqlDialect, GenericDialect)
MySQL
c -> '$.a' + 1
c -> ('$.a' + 1)
(c -> '$.a') + 1
c ->> '$.a' + 1
c ->> ('$.a' + 1)
(c ->> '$.a') + 1
c -> '$.a' * 2
c -> ('$.a' * 2)
(c -> '$.a') * 2
1 + c -> '$.a'
(1 + c) -> '$.a'
1 + (c -> '$.a')
Comparisons are already correct, since Eq (20) is below PgOther (21): c -> '$.a' = 1 → ((c -> '$.a') = 1).
As in the sibling issues, Display for Expr::BinaryOp emits no parentheses, so a mis-grouped tree
round-trips to the original SQL — verified_expr / verified_stmt cannot catch this, only a test
asserting on the tree can.
Why this is not a fix to the shared row
PgOther = 21 is correct for PostgreSQL. In gram.y the arrow shares one left-associative level
with | and generic operators, below + / -:
%left Op OPERATOR RIGHT_ARROW '|'
and PostgreSqlDialect behaves accordingly today (a -> b + c → a -> (b + c)). So the two engines
genuinely disagree about where the arrow sits, and a single shared precedence row cannot be right for
both.
Possible approaches
Add a dedicated Precedence variant for the arrow operators, defaulting to the current PgOther value so PostgreSQL and every other dialect are unchanged, and have MySqlDialect place
it above MulDivModOp. This is the narrowest option.
Give MySqlDialect its own prec_value the way PostgreSqlDialect has one. That duplicates the
whole table, and would also move @>, <@ and CustomBinaryOperator, which is probably not
intended.
I'd lean towards (1), but I don't want to presume — happy to implement whichever a maintainer
prefers.
Two open questions for whoever picks this up:
Should GenericDialect follow MySQL here? It currently produces the same grouping as MySQL, but
Generic is a permissive superset, so this seems like a judgment call rather than a clear bug.
How high should the MySQL arrow sit exactly? Since the right operand is lexically a path string in
real MySQL, anything above MulDivModOp gives correct results for valid input; placing it near DoubleColon would match the grammar most literally.
No existing test pins the current grouping — the only MySQL arrow trees asserted are single-operator
ones inside a CAST (tests/sqlparser_mysql.rs:879-910).
Reproduced on 5cad906 in both MySqlDialect and GenericDialect — all four cases in the table above group as reported.
Two things I found while confirming it, in case they change the shape of the fix. & and ^ misgroup for the same reason and are not in the table: Ampersand is 23 and Caret 22, both above PgOther at 21, so c -> '$.a' & 1 parses as c -> ('$.a' & 1). And | comes out correct today only by coincidence — Pipe shares 21 with PgOther, and left associativity happens to give MySQL's grouping — so it is worth a regression test alongside any change rather than being left alone.
I have a failing test in the style of parse_div_precedence, covering both dialects and the bitwise cases. Happy to open a PR with it — are you already on this one, given #2461?
Activity
lhadhazy commentedon Sep 28, 2026
Reproduced on
5cad906in bothMySqlDialectandGenericDialect— all four cases in the table above group as reported.Two things I found while confirming it, in case they change the shape of the fix.
&and^misgroup for the same reason and are not in the table:Ampersandis 23 andCaret22, both abovePgOtherat 21, soc -> '$.a' & 1parses asc -> ('$.a' & 1). And|comes out correct today only by coincidence —Pipeshares 21 withPgOther, and left associativity happens to give MySQL's grouping — so it is worth a regression test alongside any change rather than being left alone.I have a failing test in the style of
parse_div_precedence, covering both dialects and the bitwise cases. Happy to open a PR with it — are you already on this one, given #2461?zvonimir-dd commentedon Sep 28, 2026
Thanks! I am not on it given that there were some open questions (see the above description) that I was not totally sure about.
Bind `->` and `->>` above arithmetic in MySQL and Generic