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
I investigated this issue and put together a fix for the operator precedence:
Root Cause
In standard SQL and PostgreSQL operator precedence, comparison operators (=, !=, <>, <, >, <=, >=) have higher precedence than IS, IS NOT, ISNULL, and NOTNULL.
In SQLGlot, IS was previously registered in RANGE_PARSERS under _parse_range(), which sits underneath _parse_comparison() and _parse_equality(). Consequently, in an expression like t.a = t.b IS NULL, t.b IS NULL was evaluated first as the right-hand operand of =.
Solution
Introduced _parse_is_predicate() in the parser between conjunctions (AND) and equality/comparison (_parse_equality()), and removed IS from RANGE_PARSERS.
Added test coverage in tests/test_parser.py (test_is_precedence) and PostgreSQL dialect identity tests in tests/dialects/test_postgres.py.
Verified that all dialect and parser tests pass without regressions.
PostgreSQL returns TRUE for the source and NULL for that output. SELECT FALSE = FALSE IS NULL similarly changes from FALSE to TRUE after simplification. Explicit (a = b) IS NULL and a = (b IS NULL) controls preserved their respective meanings.
I also checked the existing fix by @ansh-rohilla at d26b6cbb: those examples preserve their results there; its parent ca870e84 reproduces the failures. Across seven comparison operators, four null-predicate spellings, and explicit left/right parentheses, all 84 expression forms matched PostgreSQL over the nine TRUE/FALSE/NULL operand combinations; tested main and the fix's parent disagreed on the 28 unparenthesized forms. For the AST check I explicitly parenthesized the parsed tree, since unchanged round-trip text can mask the grouping error.
This is independent semantic validation of the existing fix, not another implementation. Python 3.12.14; PostgreSQL oracle was the WASM build, not a native server.
Activity
ansh-rohilla commentedon Oct 17, 2026
I investigated this issue and put together a fix for the operator precedence:
Root Cause
In standard SQL and PostgreSQL operator precedence, comparison operators (
=,!=,<>,<,>,<=,>=) have higher precedence thanIS,IS NOT,ISNULL, andNOTNULL.In SQLGlot,
ISwas previously registered inRANGE_PARSERSunder_parse_range(), which sits underneath_parse_comparison()and_parse_equality(). Consequently, in an expression liket.a = t.b IS NULL,t.b IS NULLwas evaluated first as the right-hand operand of=.Solution
_parse_is_predicate()in the parser between conjunctions (AND) and equality/comparison (_parse_equality()), and removedISfromRANGE_PARSERS.tests/test_parser.py(test_is_precedence) and PostgreSQL dialect identity tests intests/dialects/test_postgres.py.Branch & Commit
hafizahmedzia commentedon Oct 17, 2026
I checked an additional consequence through
simplify, using PostgreSQL 18.6 via PGlite 0.5.10 as the execution oracle. On mainb50e43e4:PostgreSQL returns TRUE for the source and NULL for that output.
SELECT FALSE = FALSE IS NULLsimilarly changes from FALSE to TRUE after simplification. Explicit(a = b) IS NULLanda = (b IS NULL)controls preserved their respective meanings.I also checked the existing fix by @ansh-rohilla at
d26b6cbb: those examples preserve their results there; its parentca870e84reproduces the failures. Across seven comparison operators, four null-predicate spellings, and explicit left/right parentheses, all 84 expression forms matched PostgreSQL over the nine TRUE/FALSE/NULL operand combinations; tested main and the fix's parent disagreed on the 28 unparenthesized forms. For the AST check I explicitly parenthesized the parsed tree, since unchanged round-trip text can mask the grouping error.This is independent semantic validation of the existing fix, not another implementation. Python 3.12.14; PostgreSQL oracle was the WASM build, not a native server.