From f785bfa3d9a3f89c110d3bf30bee5d1de48d7cb9 Mon Sep 17 00:00:00 2001 From: Tim Nyborg Date: Thu, 20 May 2021 16:29:14 +0100 Subject: [PATCH 1/4] Enable support for window functions --- mssql/features.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mssql/features.py b/mssql/features.py index d1562bdd..e688012a 100644 --- a/mssql/features.py +++ b/mssql/features.py @@ -33,6 +33,7 @@ class DatabaseFeatures(BaseDatabaseFeatures): supports_index_on_text_field = False supports_json_field_contains = False supports_order_by_nulls_modifier = False + supports_over_clause = True supports_paramstyle_pyformat = False supports_primitives_in_json_field = False supports_regex_backreferencing = True From 2abea1a2bad4af1298e43e3db751a6497bb5933c Mon Sep 17 00:00:00 2001 From: Tim Nyborg Date: Thu, 20 May 2021 20:20:58 +0100 Subject: [PATCH 2/4] default null ordering for window functions --- mssql/functions.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/mssql/functions.py b/mssql/functions.py index d22eca2e..09c17ef5 100644 --- a/mssql/functions.py +++ b/mssql/functions.py @@ -4,10 +4,10 @@ import json from django import VERSION -from django.db.models import BooleanField +from django.db.models import BooleanField, Value from django.db.models.functions import Cast from django.db.models.functions.math import ATan2, Log, Ln, Mod, Round -from django.db.models.expressions import Case, Exists, OrderBy, When +from django.db.models.expressions import Case, Exists, OrderBy, When, Window from django.db.models.lookups import Lookup, In from django.db.models import lookups @@ -55,6 +55,13 @@ def sqlserver_round(self, compiler, connection, **extra_context): return self.as_sql(compiler, connection, template='%(function)s(%(expressions)s, 0)', **extra_context) +def sqlserver_window(self, compiler, connection, template=None): + # MSSQL window functions require an OVER clause with ORDER BY + if self.order_by is None: + self.order_by = Value('SELECT NULL') + return self.as_sql(compiler, connection, template) + + def sqlserver_exists(self, compiler, connection, template=None, **extra_context): # MS SQL doesn't allow EXISTS() in the SELECT list, so wrap it with a # CASE WHEN expression. Change the template since the When expression @@ -180,6 +187,7 @@ def json_HasKeyLookup(self, compiler, connection): Log.as_microsoft = sqlserver_log Mod.as_microsoft = sqlserver_mod Round.as_microsoft = sqlserver_round +Window.as_microsoft = sqlserver_window if DJANGO3: Lookup.as_microsoft = sqlserver_lookup @@ -187,3 +195,4 @@ def json_HasKeyLookup(self, compiler, connection): Exists.as_microsoft = sqlserver_exists OrderBy.as_microsoft = sqlserver_orderby + From 810336f6065e7804ae0516806975ee3a24681582 Mon Sep 17 00:00:00 2001 From: Tim Nyborg Date: Thu, 20 May 2021 21:41:10 +0100 Subject: [PATCH 3/4] mark NthValue as unsupported, and skip related tests --- mssql/functions.py | 8 +++++++- testapp/settings.py | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/mssql/functions.py b/mssql/functions.py index 09c17ef5..7c110006 100644 --- a/mssql/functions.py +++ b/mssql/functions.py @@ -4,8 +4,9 @@ import json from django import VERSION +from django.db import NotSupportedError from django.db.models import BooleanField, Value -from django.db.models.functions import Cast +from django.db.models.functions import Cast, NthValue from django.db.models.functions.math import ATan2, Log, Ln, Mod, Round from django.db.models.expressions import Case, Exists, OrderBy, When, Window from django.db.models.lookups import Lookup, In @@ -51,6 +52,10 @@ def sqlserver_mod(self, compiler, connection): ) +def sqlserver_nth_value(self, compiler, connection, **extra_content): + raise NotSupportedError('This backend does not support the NthValue function') + + def sqlserver_round(self, compiler, connection, **extra_context): return self.as_sql(compiler, connection, template='%(function)s(%(expressions)s, 0)', **extra_context) @@ -186,6 +191,7 @@ def json_HasKeyLookup(self, compiler, connection): Ln.as_microsoft = sqlserver_ln Log.as_microsoft = sqlserver_log Mod.as_microsoft = sqlserver_mod +NthValue.as_microsoft = sqlserver_nth_value Round.as_microsoft = sqlserver_round Window.as_microsoft = sqlserver_window diff --git a/testapp/settings.py b/testapp/settings.py index 626fa2c3..436a8ceb 100644 --- a/testapp/settings.py +++ b/testapp/settings.py @@ -54,6 +54,8 @@ 'expressions.tests.FTimeDeltaTests.test_duration_with_datetime_microseconds', 'expressions.tests.IterableLookupInnerExpressionsTests.test_expressions_in_lookups_join_choice', 'expressions_case.tests.CaseExpressionTests.test_annotate_with_in_clause', + 'expressions_window.tests.WindowFunctionTests.test_nth_returns_null', + 'expressions_window.tests.WindowFunctionTests.test_nthvalue', 'ordering.tests.OrderingTests.test_orders_nulls_first_on_filtered_subquery', 'queries.test_bulk_update.BulkUpdateNoteTests.test_set_field_to_null', 'get_or_create.tests.UpdateOrCreateTransactionTests.test_creation_in_transaction', From 6cce3b2a3e31842b996cd1276cf50bf6f0332edf Mon Sep 17 00:00:00 2001 From: Tim Nyborg Date: Thu, 20 May 2021 23:11:42 +0100 Subject: [PATCH 4/4] handle django 2.2 not excluding test via db feature flag --- testapp/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/testapp/settings.py b/testapp/settings.py index 436a8ceb..7af5bf96 100644 --- a/testapp/settings.py +++ b/testapp/settings.py @@ -56,6 +56,7 @@ 'expressions_case.tests.CaseExpressionTests.test_annotate_with_in_clause', 'expressions_window.tests.WindowFunctionTests.test_nth_returns_null', 'expressions_window.tests.WindowFunctionTests.test_nthvalue', + 'expressions_window.tests.WindowFunctionTests.test_range_n_preceding_and_following', 'ordering.tests.OrderingTests.test_orders_nulls_first_on_filtered_subquery', 'queries.test_bulk_update.BulkUpdateNoteTests.test_set_field_to_null', 'get_or_create.tests.UpdateOrCreateTransactionTests.test_creation_in_transaction',