Repository: ibis-project/ibis

Issue:
regression(mssql): investigate bringing back `any`/`all` and cumulative versions
### What happened?

These are now failing on `the-epic-split`

### What version of ibis are you using?

`the-epic-split`

### What backend(s) are you using, if any?

mssql

### Relevant log output

_No response_

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct


Discussion:

Resolving patch:
diff --git a/ibis/backends/mssql/compiler.py b/ibis/backends/mssql/compiler.py
--- a/ibis/backends/mssql/compiler.py
+++ b/ibis/backends/mssql/compiler.py
@@ -63,8 +63,6 @@ class MSSQLCompiler(SQLGlotCompiler):
 
     UNSUPPORTED_OPERATIONS = frozenset(
         (
-            ops.Any,
-            ops.All,
             ops.ApproxMedian,
             ops.Arbitrary,
             ops.ArgMax,
@@ -402,6 +400,18 @@ def visit_Mean(self, op, *, arg, where):
     def visit_Not(self, op, *, arg):
         if isinstance(arg, sge.Boolean):
             return FALSE if arg == TRUE else TRUE
+        elif isinstance(arg, (sge.Window, sge.Max, sge.Min)):
+            # special case Window, Max, and Min.
+            # These are used for NOT ANY or NOT ALL and friends.
+            # We are working around MSSQL's rather unfriendly boolean handling rules
+            # and because Max or Min don't return booleans, we have to handle the equality check
+            # in a case statement instead.
+            # e.g.
+            # IFF(MAX(IFF(condition, 1, 0)) = 0, true_case, false_case)
+            # is invalid
+            # Needs to be
+            # CASE WHEN MAX(IFF(condition, 1, 0)) = 0 THEN true_case ELSE false_case END
+            return sge.Case(ifs=[self.if_(arg.eq(0), 1)], default=0)
         return self.if_(arg, 1, 0).eq(0)
 
     def visit_HashBytes(self, op, *, arg, how):
@@ -435,3 +445,15 @@ def visit_HexDigest(self, op, *, arg, how):
     def visit_StringConcat(self, op, *, arg):
         any_args_null = (a.is_(NULL) for a in arg)
         return self.if_(sg.or_(*any_args_null), NULL, self.f.concat(*arg))
+
+    def visit_Any(self, op, *, arg, where):
+        arg = self.if_(arg, 1, 0)
+        if where is not None:
+            arg = self.if_(where, arg, NULL)
+        return sge.Max(this=arg)
+
+    def visit_All(self, op, *, arg, where):
+        arg = self.if_(arg, 1, 0)
+        if where is not None:
+            arg = self.if_(where, arg, NULL)
+        return sge.Min(this=arg)


Test patch:
diff --git a/ibis/backends/tests/test_aggregation.py b/ibis/backends/tests/test_aggregation.py
--- a/ibis/backends/tests/test_aggregation.py
+++ b/ibis/backends/tests/test_aggregation.py
@@ -288,7 +288,6 @@ def mean_and_std(v):
                     raises=AttributeError,
                     reason="'IntegerColumn' object has no attribute 'any'",
                 ),
-                pytest.mark.notimpl(["mssql"], raises=com.OperationNotDefinedError),
             ],
         ),
         param(
@@ -307,7 +306,6 @@ def mean_and_std(v):
                     reason="ORA-02000: missing AS keyword",
                 ),
                 pytest.mark.notimpl(["exasol"], raises=ExaQueryError),
-                pytest.mark.notimpl(["mssql"], raises=com.OperationNotDefinedError),
             ],
         ),
         param(
@@ -326,7 +324,6 @@ def mean_and_std(v):
                     reason="ORA-02000: missing AS keyword",
                 ),
                 pytest.mark.notimpl(["exasol"], raises=ExaQueryError),
-                pytest.mark.notimpl(["mssql"], raises=com.OperationNotDefinedError),
             ],
         ),
         param(
@@ -339,7 +336,6 @@ def mean_and_std(v):
                     raises=AttributeError,
                     reason="'IntegerColumn' object has no attribute 'all'",
                 ),
-                pytest.mark.notimpl(["mssql"], raises=com.OperationNotDefinedError),
             ],
         ),
         param(
@@ -358,7 +354,6 @@ def mean_and_std(v):
                     reason="ORA-02000: missing AS keyword",
                 ),
                 pytest.mark.notimpl(["exasol"], raises=ExaQueryError),
-                pytest.mark.notimpl(["mssql"], raises=com.OperationNotDefinedError),
             ],
         ),
         param(
@@ -377,7 +372,6 @@ def mean_and_std(v):
                     reason="ORA-02000: missing AS keyword",
                 ),
                 pytest.mark.notimpl(["exasol"], raises=ExaQueryError),
-                pytest.mark.notimpl(["mssql"], raises=com.OperationNotDefinedError),
             ],
         ),
         param(
diff --git a/ibis/backends/tests/test_window.py b/ibis/backends/tests/test_window.py
--- a/ibis/backends/tests/test_window.py
+++ b/ibis/backends/tests/test_window.py
@@ -249,7 +249,6 @@ def calc_zscore(s):
                 .astype(bool)
             ),
             id="cumany",
-            marks=[pytest.mark.broken(["mssql"], raises=com.OperationNotDefinedError)],
         ),
         param(
             lambda t, win: (t.double_col == 0).notany().over(win),
@@ -262,7 +261,6 @@ def calc_zscore(s):
             id="cumnotany",
             marks=[
                 pytest.mark.broken(["oracle"], raises=OracleDatabaseError),
-                pytest.mark.broken(["mssql"], raises=com.OperationNotDefinedError),
             ],
         ),
         param(
@@ -274,7 +272,6 @@ def calc_zscore(s):
                 .astype(bool)
             ),
             id="cumall",
-            marks=[pytest.mark.broken(["mssql"], raises=com.OperationNotDefinedError)],
         ),
         param(
             lambda t, win: (t.double_col == 0).notall().over(win),
@@ -287,7 +284,6 @@ def calc_zscore(s):
             id="cumnotall",
             marks=[
                 pytest.mark.broken(["oracle"], raises=OracleDatabaseError),
-                pytest.mark.broken(["mssql"], raises=com.OperationNotDefinedError),
             ],
         ),
         param(