apache / apache/datafusion-sqlparser-rs
MySQL `->` / `->>` bind too loosely against arithmetic and bitwise operators
- 主要言語
- Rust
- スター
- 3.5k
- フォーク
- 772
- 平均マージ
- 4日 9時間
- マージ済み PR(30日)
- 17
説明
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](https://dev.mysql.com/doc/refman/8.4/en/json-search-functions.html)). 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
1. 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.
2. 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`).
Related: #2436, #2460, #2461.
コントリビューションガイド
このリポジトリのコントリビューションガイドは索引されていません
調査の方向性
まず Precedence definition と MySqlDialect の precedence 処理を読み、次に PostgreSqlDialect::prec_value と tests/sqlparser_mysql.rs:879-910 にある既存の assertions を比較します。MySQL の arrow expressions が算術演算子および bitwise 演算子より上位でグループ化され、PostgreSQL の動作が変更されず、tree-level tests で演算子の両側がカバーされれば、作業は完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- mysql, rust, sql
- 領域
- compilers, databases
- issue の種類
- バグ
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 活発
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 48/100