mirror of https://github.com/django/django.git
Fixed #31183 -- Added a feature flag for "<db> only supports UNBOUNDED together with PRECEDING and FOLLOWING".
This commit is contained in:
parent
2a2ea4ee18
commit
227d0c7365
|
@ -246,6 +246,7 @@ class BaseDatabaseFeatures:
|
||||||
# Does the backend support window expressions (expression OVER (...))?
|
# Does the backend support window expressions (expression OVER (...))?
|
||||||
supports_over_clause = False
|
supports_over_clause = False
|
||||||
supports_frame_range_fixed_distance = False
|
supports_frame_range_fixed_distance = False
|
||||||
|
only_supports_unbounded_with_preceding_and_following = False
|
||||||
|
|
||||||
# Does the backend support CAST with precision?
|
# Does the backend support CAST with precision?
|
||||||
supports_cast_with_precision = True
|
supports_cast_with_precision = True
|
||||||
|
|
|
@ -658,7 +658,16 @@ class BaseDatabaseOperations:
|
||||||
return self.window_frame_start(start), self.window_frame_end(end)
|
return self.window_frame_start(start), self.window_frame_end(end)
|
||||||
|
|
||||||
def window_frame_range_start_end(self, start=None, end=None):
|
def window_frame_range_start_end(self, start=None, end=None):
|
||||||
return self.window_frame_rows_start_end(start, end)
|
start_, end_ = self.window_frame_rows_start_end(start, end)
|
||||||
|
if (
|
||||||
|
self.connection.features.only_supports_unbounded_with_preceding_and_following and
|
||||||
|
((start and start < 0) or (end and end > 0))
|
||||||
|
):
|
||||||
|
raise NotSupportedError(
|
||||||
|
'%s only supports UNBOUNDED together with PRECEDING and '
|
||||||
|
'FOLLOWING.' % self.connection.display_name
|
||||||
|
)
|
||||||
|
return start_, end_
|
||||||
|
|
||||||
def explain_query_prefix(self, format=None, **options):
|
def explain_query_prefix(self, format=None, **options):
|
||||||
if not self.connection.features.supports_explaining_query_execution:
|
if not self.connection.features.supports_explaining_query_execution:
|
||||||
|
|
|
@ -52,6 +52,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
$$ LANGUAGE plpgsql;"""
|
$$ LANGUAGE plpgsql;"""
|
||||||
requires_casted_case_in_updates = True
|
requires_casted_case_in_updates = True
|
||||||
supports_over_clause = True
|
supports_over_clause = True
|
||||||
|
only_supports_unbounded_with_preceding_and_following = True
|
||||||
supports_aggregate_filter_clause = True
|
supports_aggregate_filter_clause = True
|
||||||
supported_explain_formats = {'JSON', 'TEXT', 'XML', 'YAML'}
|
supported_explain_formats = {'JSON', 'TEXT', 'XML', 'YAML'}
|
||||||
validates_explain_options = False # A query will error on invalid options.
|
validates_explain_options = False # A query will error on invalid options.
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from psycopg2.extras import Inet
|
from psycopg2.extras import Inet
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import NotSupportedError
|
|
||||||
from django.db.backends.base.operations import BaseDatabaseOperations
|
from django.db.backends.base.operations import BaseDatabaseOperations
|
||||||
|
|
||||||
|
|
||||||
|
@ -275,15 +274,6 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
return "(interval '1 day' * (%s - %s))" % (lhs_sql, rhs_sql), params
|
return "(interval '1 day' * (%s - %s))" % (lhs_sql, rhs_sql), params
|
||||||
return super().subtract_temporals(internal_type, lhs, rhs)
|
return super().subtract_temporals(internal_type, lhs, rhs)
|
||||||
|
|
||||||
def window_frame_range_start_end(self, start=None, end=None):
|
|
||||||
start_, end_ = super().window_frame_range_start_end(start, end)
|
|
||||||
if (start and start < 0) or (end and end > 0):
|
|
||||||
raise NotSupportedError(
|
|
||||||
'PostgreSQL only supports UNBOUNDED together with PRECEDING '
|
|
||||||
'and FOLLOWING.'
|
|
||||||
)
|
|
||||||
return start_, end_
|
|
||||||
|
|
||||||
def explain_query_prefix(self, format=None, **options):
|
def explain_query_prefix(self, format=None, **options):
|
||||||
prefix = super().explain_query_prefix(format)
|
prefix = super().explain_query_prefix(format)
|
||||||
extra = {}
|
extra = {}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import datetime
|
import datetime
|
||||||
from unittest import mock, skipIf, skipUnless
|
from unittest import mock, skipIf
|
||||||
|
|
||||||
from django.core.exceptions import FieldError
|
from django.core.exceptions import FieldError
|
||||||
from django.db import NotSupportedError, connection
|
from django.db import NotSupportedError, connection
|
||||||
|
@ -750,9 +750,9 @@ class WindowFunctionTests(TestCase):
|
||||||
frame=RowRange(end='a'),
|
frame=RowRange(end='a'),
|
||||||
)))
|
)))
|
||||||
|
|
||||||
@skipUnless(connection.vendor == 'postgresql', 'Frame construction not allowed on PostgreSQL')
|
@skipUnlessDBFeature('only_supports_unbounded_with_preceding_and_following')
|
||||||
def test_postgresql_illegal_range_frame_start(self):
|
def test_unsupported_range_frame_start(self):
|
||||||
msg = 'PostgreSQL only supports UNBOUNDED together with PRECEDING and FOLLOWING.'
|
msg = '%s only supports UNBOUNDED together with PRECEDING and FOLLOWING.' % connection.display_name
|
||||||
with self.assertRaisesMessage(NotSupportedError, msg):
|
with self.assertRaisesMessage(NotSupportedError, msg):
|
||||||
list(Employee.objects.annotate(test=Window(
|
list(Employee.objects.annotate(test=Window(
|
||||||
expression=Sum('salary'),
|
expression=Sum('salary'),
|
||||||
|
@ -760,9 +760,9 @@ class WindowFunctionTests(TestCase):
|
||||||
frame=ValueRange(start=-1),
|
frame=ValueRange(start=-1),
|
||||||
)))
|
)))
|
||||||
|
|
||||||
@skipUnless(connection.vendor == 'postgresql', 'Frame construction not allowed on PostgreSQL')
|
@skipUnlessDBFeature('only_supports_unbounded_with_preceding_and_following')
|
||||||
def test_postgresql_illegal_range_frame_end(self):
|
def test_unsupported_range_frame_end(self):
|
||||||
msg = 'PostgreSQL only supports UNBOUNDED together with PRECEDING and FOLLOWING.'
|
msg = '%s only supports UNBOUNDED together with PRECEDING and FOLLOWING.' % connection.display_name
|
||||||
with self.assertRaisesMessage(NotSupportedError, msg):
|
with self.assertRaisesMessage(NotSupportedError, msg):
|
||||||
list(Employee.objects.annotate(test=Window(
|
list(Employee.objects.annotate(test=Window(
|
||||||
expression=Sum('salary'),
|
expression=Sum('salary'),
|
||||||
|
|
Loading…
Reference in New Issue