Replaced @no_oracle skips with DatabaseFeatures.allows_group_by_lob.

This commit is contained in:
Tim Graham 2020-09-07 15:45:56 -04:00 committed by Mariusz Felisiak
parent ad11f5b8c9
commit 755dbf39fc
6 changed files with 22 additions and 23 deletions

View File

@ -4,6 +4,8 @@ from django.utils.functional import cached_property
class BaseDatabaseFeatures: class BaseDatabaseFeatures:
gis_enabled = False gis_enabled = False
# Oracle can't group by LOB (large object) data types.
allows_group_by_lob = True
allows_group_by_pk = False allows_group_by_pk = False
allows_group_by_selected_pks = False allows_group_by_selected_pks = False
empty_fetchmany_value = [] empty_fetchmany_value = []

View File

@ -4,6 +4,9 @@ from django.utils.functional import cached_property
class DatabaseFeatures(BaseDatabaseFeatures): class DatabaseFeatures(BaseDatabaseFeatures):
# Oracle crashes with "ORA-00932: inconsistent datatypes: expected - got
# BLOB" when grouping by LOBs (#24096).
allows_group_by_lob = False
interprets_empty_strings_as_nulls = True interprets_empty_strings_as_nulls = True
has_select_for_update = True has_select_for_update = True
has_select_for_update_nowait = True has_select_for_update_nowait = True

View File

@ -5,6 +5,7 @@ from operator import attrgetter, itemgetter
from uuid import UUID from uuid import UUID
from django.core.exceptions import FieldError from django.core.exceptions import FieldError
from django.db import connection
from django.db.models import ( from django.db.models import (
BinaryField, BooleanField, Case, Count, DecimalField, F, BinaryField, BooleanField, Case, Count, DecimalField, F,
GenericIPAddressField, IntegerField, Max, Min, Q, Sum, TextField, Value, GenericIPAddressField, IntegerField, Max, Min, Q, Sum, TextField, Value,
@ -56,10 +57,13 @@ class CaseExpressionTests(TestCase):
O2OCaseTestModel.objects.create(o2o=o, integer=1) O2OCaseTestModel.objects.create(o2o=o, integer=1)
FKCaseTestModel.objects.create(fk=o, integer=5) FKCaseTestModel.objects.create(fk=o, integer=5)
# GROUP BY on Oracle fails with TextField/BinaryField; see #24096. cls.group_by_fields = [
cls.non_lob_fields = [
f.name for f in CaseTestModel._meta.get_fields() f.name for f in CaseTestModel._meta.get_fields()
if not (f.is_relation and f.auto_created) and not isinstance(f, (BinaryField, TextField)) if not (f.is_relation and f.auto_created) and
(
connection.features.allows_group_by_lob or
not isinstance(f, (BinaryField, TextField))
)
] ]
def test_annotate(self): def test_annotate(self):
@ -197,7 +201,7 @@ class CaseExpressionTests(TestCase):
def test_annotate_with_aggregation_in_value(self): def test_annotate_with_aggregation_in_value(self):
self.assertQuerysetEqual( self.assertQuerysetEqual(
CaseTestModel.objects.values(*self.non_lob_fields).annotate( CaseTestModel.objects.values(*self.group_by_fields).annotate(
min=Min('fk_rel__integer'), min=Min('fk_rel__integer'),
max=Max('fk_rel__integer'), max=Max('fk_rel__integer'),
).annotate( ).annotate(
@ -212,7 +216,7 @@ class CaseExpressionTests(TestCase):
def test_annotate_with_aggregation_in_condition(self): def test_annotate_with_aggregation_in_condition(self):
self.assertQuerysetEqual( self.assertQuerysetEqual(
CaseTestModel.objects.values(*self.non_lob_fields).annotate( CaseTestModel.objects.values(*self.group_by_fields).annotate(
min=Min('fk_rel__integer'), min=Min('fk_rel__integer'),
max=Max('fk_rel__integer'), max=Max('fk_rel__integer'),
).annotate( ).annotate(
@ -227,7 +231,7 @@ class CaseExpressionTests(TestCase):
def test_annotate_with_aggregation_in_predicate(self): def test_annotate_with_aggregation_in_predicate(self):
self.assertQuerysetEqual( self.assertQuerysetEqual(
CaseTestModel.objects.values(*self.non_lob_fields).annotate( CaseTestModel.objects.values(*self.group_by_fields).annotate(
max=Max('fk_rel__integer'), max=Max('fk_rel__integer'),
).annotate( ).annotate(
test=Case( test=Case(
@ -483,7 +487,7 @@ class CaseExpressionTests(TestCase):
def test_filter_with_aggregation_in_value(self): def test_filter_with_aggregation_in_value(self):
self.assertQuerysetEqual( self.assertQuerysetEqual(
CaseTestModel.objects.values(*self.non_lob_fields).annotate( CaseTestModel.objects.values(*self.group_by_fields).annotate(
min=Min('fk_rel__integer'), min=Min('fk_rel__integer'),
max=Max('fk_rel__integer'), max=Max('fk_rel__integer'),
).filter( ).filter(
@ -498,7 +502,7 @@ class CaseExpressionTests(TestCase):
def test_filter_with_aggregation_in_condition(self): def test_filter_with_aggregation_in_condition(self):
self.assertQuerysetEqual( self.assertQuerysetEqual(
CaseTestModel.objects.values(*self.non_lob_fields).annotate( CaseTestModel.objects.values(*self.group_by_fields).annotate(
min=Min('fk_rel__integer'), min=Min('fk_rel__integer'),
max=Max('fk_rel__integer'), max=Max('fk_rel__integer'),
).filter( ).filter(
@ -513,7 +517,7 @@ class CaseExpressionTests(TestCase):
def test_filter_with_aggregation_in_predicate(self): def test_filter_with_aggregation_in_predicate(self):
self.assertQuerysetEqual( self.assertQuerysetEqual(
CaseTestModel.objects.values(*self.non_lob_fields).annotate( CaseTestModel.objects.values(*self.group_by_fields).annotate(
max=Max('fk_rel__integer'), max=Max('fk_rel__integer'),
).filter( ).filter(
integer=Case( integer=Case(

View File

@ -5,7 +5,6 @@ from django.contrib.gis.shortcuts import render_to_kmz
from django.db.models import Count, Min from django.db.models import Count, Min
from django.test import TestCase, skipUnlessDBFeature from django.test import TestCase, skipUnlessDBFeature
from ..utils import no_oracle
from .models import City, PennsylvaniaCity, State, Truth from .models import City, PennsylvaniaCity, State, Truth
@ -65,10 +64,7 @@ class GeoRegressionTests(TestCase):
# .count() should not throw TypeError in __eq__ # .count() should not throw TypeError in __eq__
self.assertEqual(cities_within_state.count(), 1) self.assertEqual(cities_within_state.count(), 1)
# TODO: fix on Oracle -- get the following error because the SQL is ordered @skipUnlessDBFeature('allows_group_by_lob')
# by a geometry object, which Oracle apparently doesn't like:
# ORA-22901: cannot compare nested table or VARRAY or LOB attributes of an object type
@no_oracle
def test_defer_or_only_with_annotate(self): def test_defer_or_only_with_annotate(self):
"Regression for #16409. Make sure defer() and only() work with annotate()" "Regression for #16409. Make sure defer() and only() work with annotate()"
self.assertIsInstance(list(City.objects.annotate(Count('point')).defer('name')), list) self.assertIsInstance(list(City.objects.annotate(Count('point')).defer('name')), list)

View File

@ -222,10 +222,7 @@ class RelatedGeoModelTest(TestCase):
self.assertIn('Aurora', names) self.assertIn('Aurora', names)
self.assertIn('Kecksburg', names) self.assertIn('Kecksburg', names)
# TODO: fix on Oracle -- get the following error because the SQL is ordered @skipUnlessDBFeature('allows_group_by_lob')
# by a geometry object, which Oracle apparently doesn't like:
# ORA-22901: cannot compare nested table or VARRAY or LOB attributes of an object type
@no_oracle
def test12a_count(self): def test12a_count(self):
"Testing `Count` aggregate on geo-fields." "Testing `Count` aggregate on geo-fields."
# The City, 'Fort Worth' uses the same location as Dallas. # The City, 'Fort Worth' uses the same location as Dallas.
@ -247,10 +244,7 @@ class RelatedGeoModelTest(TestCase):
self.assertEqual(1, len(vqs)) self.assertEqual(1, len(vqs))
self.assertEqual(3, vqs[0]['num_books']) self.assertEqual(3, vqs[0]['num_books'])
# TODO: fix on Oracle -- get the following error because the SQL is ordered @skipUnlessDBFeature('allows_group_by_lob')
# by a geometry object, which Oracle apparently doesn't like:
# ORA-22901: cannot compare nested table or VARRAY or LOB attributes of an object type
@no_oracle
def test13c_count(self): def test13c_count(self):
"Testing `Count` aggregate with `.values()`. See #15305." "Testing `Count` aggregate with `.values()`. See #15305."
qs = Location.objects.filter(id=5).annotate(num_cities=Count('city')).values('id', 'point', 'num_cities') qs = Location.objects.filter(id=5).annotate(num_cities=Count('city')).values('id', 'point', 'num_cities')

View File

@ -355,7 +355,7 @@ class TestQuerying(TestCase):
operator.itemgetter('key', 'count'), operator.itemgetter('key', 'count'),
) )
@skipIf(connection.vendor == 'oracle', "Oracle doesn't support grouping by LOBs, see #24096.") @skipUnlessDBFeature('allows_group_by_lob')
def test_ordering_grouping_by_count(self): def test_ordering_grouping_by_count(self):
qs = NullableJSONModel.objects.filter( qs = NullableJSONModel.objects.filter(
value__isnull=False, value__isnull=False,