Skip to content

Commit 247e2f7

Browse files
authored
fix(comparison): wrap isnull equality check in parens (#8366)
We wrap arguments to a sge.Equals in parens if the inputs are themselves binary operations. There are other operations we will have to wrap -- for now I'm just adding isNull to the list, but I imagine this will grow, possibly on a backend-by-backend basis. I'm going to investigate the mssql and oracle failures but they are unrelated to this PR (they fail the added test with or without the parentheses)
1 parent 13d675e commit 247e2f7

File tree

3 files changed

+20
-2
lines changed

3 files changed

+20
-2
lines changed

ibis/backends/base/sqlglot/compiler.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,8 @@ class SQLGlotCompiler(abc.ABC):
321321
ops.IntervalSubtract,
322322
)
323323

324+
NEEDS_PARENS = BINARY_INFIX_OPS + (ops.IsNull,)
325+
324326
def __init__(self) -> None:
325327
self.agg = AggGen(aggfunc=self._aggregate)
326328
self.f = FuncGen()
@@ -1192,7 +1194,7 @@ def visit_Aggregate(self, op, *, parent, groups, metrics):
11921194

11931195
@classmethod
11941196
def _add_parens(cls, op, sg_expr):
1195-
if isinstance(op, cls.BINARY_INFIX_OPS):
1197+
if isinstance(op, cls.NEEDS_PARENS):
11961198
return paren(sg_expr)
11971199
return sg_expr
11981200

ibis/backends/impala/tests/snapshots/test_sql/test_is_parens/isnull/out.sql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,8 @@ SELECT
33
`t0`.`b`
44
FROM `table` AS `t0`
55
WHERE
6-
`t0`.`a` IS NULL = `t0`.`b` IS NULL
6+
(
7+
`t0`.`a` IS NULL
8+
) = (
9+
`t0`.`b` IS NULL
10+
)

ibis/backends/tests/test_generic.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,3 +1846,15 @@ def test_select_mutate_with_dict(backend):
18461846

18471847
expr = t.select({"a": ibis.literal(1.0)}).limit(1)
18481848
backend.assert_frame_equal(result, expected)
1849+
1850+
1851+
@pytest.mark.broken(["mssql", "oracle"], reason="incorrect syntax")
1852+
def test_isnull_equality(con, backend, monkeypatch):
1853+
monkeypatch.setattr(ibis.options, "default_backend", con)
1854+
t = ibis.memtable({"x": ["a", "b", None], "y": ["c", None, None], "z": [1, 2, 3]})
1855+
expr = t.mutate(out=t.x.isnull() == t.y.isnull()).order_by("z").select("out")
1856+
result = expr.to_pandas()
1857+
1858+
expected = pd.DataFrame({"out": [True, False, True]})
1859+
1860+
backend.assert_frame_equal(result, expected)

0 commit comments

Comments
 (0)