[1.7.x] Replaced vendor checks by three feature flags.

Backport of c70a61eb from master
This commit is contained in:
Aymeric Augustin 2014-05-07 21:50:09 +02:00
parent 7f48d44c60
commit e3bc11cca9
7 changed files with 17 additions and 16 deletions

View File

@ -575,6 +575,7 @@ class BaseDatabaseFeatures(object):
can_return_id_from_insert = False can_return_id_from_insert = False
has_bulk_insert = False has_bulk_insert = False
uses_savepoints = False uses_savepoints = False
can_release_savepoints = True
can_combine_inserts_with_and_without_auto_increment_pk = False can_combine_inserts_with_and_without_auto_increment_pk = False
# If True, don't use integer foreign keys referring to, e.g., positive # If True, don't use integer foreign keys referring to, e.g., positive
@ -610,6 +611,8 @@ class BaseDatabaseFeatures(object):
supports_subqueries_in_group_by = True supports_subqueries_in_group_by = True
supports_bitwise_or = True supports_bitwise_or = True
supports_binary_field = True
# Do time/datetime fields have microsecond precision? # Do time/datetime fields have microsecond precision?
supports_microsecond_precision = True supports_microsecond_precision = True
@ -703,6 +706,9 @@ class BaseDatabaseFeatures(object):
# statements before executing them? # statements before executing them?
requires_sqlparse_for_splitting = True requires_sqlparse_for_splitting = True
# Suffix for backends that don't support "SELECT xxx;" queries.
bare_select_suffix = ''
def __init__(self, connection): def __init__(self, connection):
self.connection = connection self.connection = connection

View File

@ -172,6 +172,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
has_select_for_update_nowait = False has_select_for_update_nowait = False
supports_forward_references = False supports_forward_references = False
supports_long_model_names = False supports_long_model_names = False
# XXX MySQL DB-API drivers currently fail on binary data on Python 3.
supports_binary_field = six.PY2
supports_microsecond_precision = False supports_microsecond_precision = False
supports_regex_backreferencing = False supports_regex_backreferencing = False
supports_date_lookup_using_string = False supports_date_lookup_using_string = False

View File

@ -96,6 +96,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
needs_datetime_string_cast = False needs_datetime_string_cast = False
interprets_empty_strings_as_nulls = True interprets_empty_strings_as_nulls = True
uses_savepoints = True uses_savepoints = True
can_release_savepoints = False
has_select_for_update = True has_select_for_update = True
has_select_for_update_nowait = True has_select_for_update_nowait = True
can_return_id_from_insert = True can_return_id_from_insert = True
@ -116,6 +117,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
requires_literal_defaults = True requires_literal_defaults = True
connection_persists_old_columns = True connection_persists_old_columns = True
closed_cursor_error_class = InterfaceError closed_cursor_error_class = InterfaceError
bare_select_suffix = " FROM DUAL"
class DatabaseOperations(BaseDatabaseOperations): class DatabaseOperations(BaseDatabaseOperations):

View File

@ -3939,8 +3939,7 @@ class UserAdminTest(TestCase):
ContentType.objects.clear_cache() ContentType.objects.clear_cache()
expected_queries = 10 expected_queries = 10
# Oracle doesn't implement "RELEASE SAVPOINT", see #20387. if not connection.features.can_release_savepoints:
if connection.vendor == 'oracle':
expected_queries -= 1 expected_queries -= 1
with self.assertNumQueries(expected_queries): with self.assertNumQueries(expected_queries):
@ -3982,8 +3981,7 @@ class GroupAdminTest(TestCase):
g = Group.objects.create(name="test_group") g = Group.objects.create(name="test_group")
expected_queries = 8 expected_queries = 8
# Oracle doesn't implement "RELEASE SAVPOINT", see #20387. if not connection.features.can_release_savepoints:
if connection.vendor == 'oracle':
expected_queries -= 1 expected_queries -= 1
with self.assertNumQueries(expected_queries): with self.assertNumQueries(expected_queries):

View File

@ -131,7 +131,6 @@ class SQLiteTests(TestCase):
self.assertRaises(NotImplementedError, self.assertRaises(NotImplementedError,
models.Item.objects.all().aggregate, aggregate('last_modified')) models.Item.objects.all().aggregate, aggregate('last_modified'))
def test_convert_values_to_handle_null_value(self): def test_convert_values_to_handle_null_value(self):
convert_values = DatabaseOperations(connection).convert_values convert_values = DatabaseOperations(connection).convert_values
self.assertIsNone(convert_values(None, AutoField(primary_key=True))) self.assertIsNone(convert_values(None, AutoField(primary_key=True)))
@ -464,9 +463,7 @@ class EscapingChecks(TestCase):
EscapingChecksDebug test case, to also test CursorDebugWrapper. EscapingChecksDebug test case, to also test CursorDebugWrapper.
""" """
# For Oracle, when you want to select a value, you need to specify the bare_select_suffix = connection.features.bare_select_suffix
# special pseudo-table 'dual'; a select with no from clause is invalid.
bare_select_suffix = " FROM DUAL" if connection.vendor == 'oracle' else ""
def test_paramless_no_escaping(self): def test_paramless_no_escaping(self):
cursor = connection.cursor() cursor = connection.cursor()

View File

@ -605,6 +605,7 @@ class FileFieldTests(unittest.TestCase):
class BinaryFieldTests(test.TestCase): class BinaryFieldTests(test.TestCase):
binary_data = b'\x00\x46\xFE' binary_data = b'\x00\x46\xFE'
@test.skipUnlessDBFeature('supports_binary_field')
def test_set_and_retrieve(self): def test_set_and_retrieve(self):
data_set = (self.binary_data, six.memoryview(self.binary_data)) data_set = (self.binary_data, six.memoryview(self.binary_data))
for bdata in data_set: for bdata in data_set:
@ -619,10 +620,6 @@ class BinaryFieldTests(test.TestCase):
# Test default value # Test default value
self.assertEqual(bytes(dm.short_data), b'\x08') self.assertEqual(bytes(dm.short_data), b'\x08')
if connection.vendor == 'mysql' and six.PY3:
# Existing MySQL DB-API drivers fail on binary data.
test_set_and_retrieve = unittest.expectedFailure(test_set_and_retrieve)
def test_max_length(self): def test_max_length(self):
dm = DataModel(short_data=self.binary_data * 4) dm = DataModel(short_data=self.binary_data * 4)
self.assertRaises(ValidationError, dm.full_clean) self.assertRaises(ValidationError, dm.full_clean)

View File

@ -10,7 +10,7 @@ from __future__ import unicode_literals
import datetime import datetime
import decimal import decimal
from unittest import skip, skipUnless from unittest import skipUnless
import warnings import warnings
try: try:
@ -24,7 +24,7 @@ from django.core.serializers.base import DeserializationError
from django.core.serializers.xml_serializer import DTDForbidden from django.core.serializers.xml_serializer import DTDForbidden
from django.db import connection, models from django.db import connection, models
from django.http import HttpResponse from django.http import HttpResponse
from django.test import TestCase from django.test import skipUnlessDBFeature, TestCase
from django.utils import six from django.utils import six
from django.utils.functional import curry from django.utils.functional import curry
@ -481,8 +481,7 @@ def serializerTest(format, self):
for klass, count in instance_count.items(): for klass, count in instance_count.items():
self.assertEqual(count, klass.objects.count()) self.assertEqual(count, klass.objects.count())
if connection.vendor == 'mysql' and six.PY3: serializerTest = skipUnlessDBFeature('supports_binary_field')(serializerTest)
serializerTest = skip("Existing MySQL DB-API drivers fail on binary data.")(serializerTest)
def naturalKeySerializerTest(format, self): def naturalKeySerializerTest(format, self):