Skip to content

Honour operator precedence in IS [NOT] DISTINCT FROM - #2459

Closed
adriangb wants to merge 1 commit into
apache:mainfrom
adriangb:fix-is-distinct-from-precedence
Closed

Honour operator precedence in IS [NOT] DISTINCT FROM#2459
adriangb wants to merge 1 commit into
apache:mainfrom
adriangb:fix-is-distinct-from-precedence

Conversation

@adriangb

Copy link
Copy Markdown

Continues #2436 by @zvonimir-dd (kept as co-author on the commit), with the review feedback there applied. Opening this since that PR has been idle — happy to close it in favour of #2436 if @zvonimir-dd picks it back up.

Two hunks:

src/parser/mod.rs — the right operand of IS [NOT] DISTINCT FROM was parsed with parse_expr(), i.e. precedence 0, so it swallowed everything following it, including AND and OR. a IS DISTINCT FROM 1 AND b = 2 parsed as a IS DISTINCT FROM (1 AND b = 2). Using the caller's precedence fixes it.

src/dialect/mod.rsPrecedence::PgOther (the "any other operator" row: ->, ->>, @>, custom operators) sat at 16, below Is (17). Without moving it, the parser hunk is a regression: a IS DISTINCT FROM b -> 'k' would regroup to (a IS DISTINCT FROM b) -> 'k' in every dialect except PostgreSQL. PostgreSQL's gram.y places %left Op OPERATOR RIGHT_ARROW '|' above IS/comparison/LIKE/BETWEEN and below +/-, and src/dialect/postgresql.rs already encodes that (PG_OTHER_PREC 70); only the default table was inverted.

Display adds no parentheses, so the wrong tree reprinted as the original text — which is why round trips never caught this, and why the tests assert on the tree.

Found via apache/datafusion#23692, where it made multi-column IS NOT DISTINCT FROM joins fail to plan. Verified end to end: with this patched into DataFusion main, those cases plan correctly and sqllogictest stays at 502/502 files.

cargo test, cargo fmt --check and cargo clippy --all-targets --all-features -- -D warnings all pass.

Out of scope: @LucaCappelletti94 noted on #2436 that MySQL/Spark DIV has the same defect (7 DIV 2 + 1). Left for a follow-up.

`parse_infix` parsed the right operand of `IS [NOT] DISTINCT FROM` with
`parse_expr` (precedence 0), so it swallowed every following operator,
including `AND` and `OR`. Use the caller's precedence instead.

`Precedence::PgOther` (`->`, `@>`, custom operators) also has to move
above `Is` in the default table, matching PostgreSQL's
`%left Op OPERATOR RIGHT_ARROW`, or the parser fix regresses
`a IS DISTINCT FROM b -> 'k'` outside PostgreSQL.

Based on apache#2436 by @zvonimir-dd, with review feedback applied.

Co-Authored-By: zvonimir.rakamaric <zvonimir.rakamaric@datadoghq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant