apache / apache/datafusion-sqlparser-rs

MySQL `->` / `->>` bind too loosely against arithmetic and bitwise operators

Aperta
#2,462 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub
Lingua principale
Rust
Stelle
3.5k
Fork
772
Merge medio
4g 9h
PR unite (30g)
17

Descrizione

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.

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Direzione di ricerca

Inizia leggendo la Precedence definition e la gestione della precedenza di MySqlDialect, quindi confronta PostgreSqlDialect::prec_value con le assertions esistenti in tests/sqlparser_mysql.rs:879-910. Il lavoro è completato quando le espressioni freccia di MySQL vengono raggruppate al di sopra degli operatori aritmetici e bitwise, il comportamento di PostgreSQL rimane invariato e i test a livello di albero coprono entrambi i lati dell’operatore.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
mysql, rust, sql
Ambito
compilers, databases
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Attiva
Chiarezza
Abbastanza chiara
Idoneità per principianti
48/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.