Repository: ibis-project/ibis

Issue:
regression(mssql): investigate bringing back unbounded window frame window functions
### What happened?

These are failing after `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
@@ -22,6 +22,8 @@
 from ibis.backends.base.sqlglot.rewrites import (
     exclude_unsupported_window_frame_from_ops,
     exclude_unsupported_window_frame_from_row_number,
+    p,
+    replace,
     rewrite_first_to_first_value,
     rewrite_last_to_last_value,
     rewrite_sample_as_filter,
@@ -46,6 +48,16 @@
 # * Boolean expressions MUST be used in a WHERE clause, i.e., SELECT * FROM t WHERE 1 is not allowed
 
 
+@replace(
+    p.WindowFunction(
+        p.Reduction & ~p.ReductionVectorizedUDF, frame=y @ p.WindowFrame(order_by=())
+    )
+)
+def rewrite_rows_range_order_by_window(_, y, **kwargs):
+    # MSSQL requires an order by in a window frame that has either ROWS or RANGE
+    return _.copy(frame=y.copy(order_by=(_.func.arg,)))
+
+
 @public
 class MSSQLCompiler(SQLGlotCompiler):
     __slots__ = ()
@@ -58,6 +70,7 @@ class MSSQLCompiler(SQLGlotCompiler):
         rewrite_last_to_last_value,
         exclude_unsupported_window_frame_from_ops,
         exclude_unsupported_window_frame_from_row_number,
+        rewrite_rows_range_order_by_window,
         *SQLGlotCompiler.rewrites,
     )
 


Test patch:
diff --git a/ibis/backends/tests/test_numeric.py b/ibis/backends/tests/test_numeric.py
--- a/ibis/backends/tests/test_numeric.py
+++ b/ibis/backends/tests/test_numeric.py
@@ -1342,11 +1342,6 @@ def test_clip(backend, alltypes, df, ibis_func, pandas_func):
     backend.assert_series_equal(result, expected, check_names=False)
 
 
-@pytest.mark.broken(
-    ["mssql"],
-    raises=PyODBCProgrammingError,
-    reason="unbounded window frames are not supported",
-)
 @pytest.mark.notimpl(["polars"], raises=com.OperationNotDefinedError)
 @pytest.mark.broken(
     ["druid"],
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
@@ -544,17 +544,7 @@ def test_grouped_bounded_preceding_window(backend, alltypes, df, window_fn):
 @pytest.mark.parametrize(
     ("ordered"),
     [
-        param(
-            False,
-            id="unordered",
-            marks=[
-                pytest.mark.broken(
-                    ["mssql"],
-                    raises=PyODBCProgrammingError,
-                    reason="unbounded window frames are not supported",
-                ),
-            ],
-        ),
+        param(False, id="unordered"),
     ],
 )
 @pytest.mark.notimpl(["polars"], raises=com.OperationNotDefinedError)
@@ -667,13 +657,6 @@ def test_simple_ungrouped_window_with_scalar_order_by(alltypes):
             lambda df: pd.Series([df.double_col.mean()] * len(df.double_col)),
             False,
             id="unordered-mean",
-            marks=[
-                pytest.mark.broken(
-                    ["mssql"],
-                    raises=PyODBCProgrammingError,
-                    reason="unbounded window frames are not supported",
-                ),
-            ],
         ),
         param(
             lambda _, win: ibis.ntile(7).over(win),