Bitwise `&` and `->` group differently in the PostgreSQL and MySQL/Generic dialects

Aperta Adatta ai principianti
#2,461 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
78/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
mysql, postgresql, rust

Direzione di ricerca

Inizia in src/dialect/mod.rs con la tabella di precedenza predefinita, quindi confrontala con PostgreSqlDialect::prec_value in src/dialect/postgresql.rs:176-184 e con la regola PostgreSQL di gram.y citata nell'issue. Aggiungi un test di regressione a livello di albero per a -> b & c, poiché i test di round-trip SQL non possono rilevare il raggruppamento, ed esegui l'intera suite per verificare la modifica.

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

Descrizione

& 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.

Lingua principale
Rust
Stelle
3.5k
Fork
774
Merge medio
3g 4h
PR unite (30g)
19

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di apache/datafusion-sqlparser-rs

Tutte le issue di apache/datafusion-sqlparser-rs

Issue simili

Altre issue su Rust

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.