Fixed #22738 -- made finer distinctions for when Boolean is not detected on Oracle
Thanks Claude Paroz for partial fix and Simon Charrette for review
This commit is contained in:
parent
dbdae3a755
commit
c1ae0621ba
|
@ -614,9 +614,6 @@ class BaseDatabaseFeatures(object):
|
||||||
# Can the backend introspect an BinaryField, instead of an TextField?
|
# Can the backend introspect an BinaryField, instead of an TextField?
|
||||||
can_introspect_binary_field = True
|
can_introspect_binary_field = True
|
||||||
|
|
||||||
# What is the type returned when the backend introspect a BooleanField?
|
|
||||||
introspected_boolean_field_type = 'BooleanField'
|
|
||||||
|
|
||||||
# Can the backend introspect an DecimalField, instead of an FloatField?
|
# Can the backend introspect an DecimalField, instead of an FloatField?
|
||||||
can_introspect_decimal_field = True
|
can_introspect_decimal_field = True
|
||||||
|
|
||||||
|
@ -715,6 +712,23 @@ class BaseDatabaseFeatures(object):
|
||||||
except NotImplementedError:
|
except NotImplementedError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def introspected_boolean_field_type(self, field=None, created_separately=False):
|
||||||
|
"""
|
||||||
|
What is the type returned when the backend introspects a BooleanField?
|
||||||
|
The optional arguments may be used to give further details of the field to be
|
||||||
|
introspected; in particular, they are provided by Django's test suite:
|
||||||
|
field -- the field definition
|
||||||
|
created_separately -- True if the field was added via a SchemaEditor's AddField,
|
||||||
|
False if the field was created with the model
|
||||||
|
|
||||||
|
Note that return value from this function is compared by tests against actual
|
||||||
|
introspection results; it should provide expectations, not run an introspection
|
||||||
|
itself.
|
||||||
|
"""
|
||||||
|
if self.can_introspect_null and field and field.null:
|
||||||
|
return 'NullBooleanField'
|
||||||
|
return 'BooleanField'
|
||||||
|
|
||||||
|
|
||||||
class BaseDatabaseOperations(object):
|
class BaseDatabaseOperations(object):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -178,7 +178,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
supports_regex_backreferencing = False
|
supports_regex_backreferencing = False
|
||||||
supports_date_lookup_using_string = False
|
supports_date_lookup_using_string = False
|
||||||
can_introspect_binary_field = False
|
can_introspect_binary_field = False
|
||||||
introspected_boolean_field_type = 'IntegerField'
|
|
||||||
can_introspect_small_integer_field = True
|
can_introspect_small_integer_field = True
|
||||||
supports_timezones = False
|
supports_timezones = False
|
||||||
requires_explicit_null_ordering_when_grouping = True
|
requires_explicit_null_ordering_when_grouping = True
|
||||||
|
@ -225,6 +224,9 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
cursor.execute("SELECT 1 FROM mysql.time_zone LIMIT 1")
|
cursor.execute("SELECT 1 FROM mysql.time_zone LIMIT 1")
|
||||||
return cursor.fetchone() is not None
|
return cursor.fetchone() is not None
|
||||||
|
|
||||||
|
def introspected_boolean_field_type(self, *args):
|
||||||
|
return 'IntegerField'
|
||||||
|
|
||||||
|
|
||||||
class DatabaseOperations(BaseDatabaseOperations):
|
class DatabaseOperations(BaseDatabaseOperations):
|
||||||
compiler_module = "django.db.backends.mysql.compiler"
|
compiler_module = "django.db.backends.mysql.compiler"
|
||||||
|
|
|
@ -125,19 +125,20 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
# select for update with limit can be achieved on Oracle, but not with the current backend.
|
# select for update with limit can be achieved on Oracle, but not with the current backend.
|
||||||
supports_select_for_update_with_limit = False
|
supports_select_for_update_with_limit = False
|
||||||
|
|
||||||
@cached_property
|
def introspected_boolean_field_type(self, field=None, created_separately=False):
|
||||||
def introspected_boolean_field_type(self):
|
|
||||||
"""
|
"""
|
||||||
Some versions of Oracle -- we've seen this on 11.2.0.1 and suspect
|
Some versions of Oracle -- we've seen this on 11.2.0.1 and suspect
|
||||||
it goes back -- have a weird bug where, when an integer column is
|
it goes back -- have a weird bug where, when an integer column is
|
||||||
defined with a default, its precision is later reported on introspection
|
added to an existing table with a default, its precision is later
|
||||||
as 0, regardless of the real precision. For Django introspection, this
|
reported on introspection as 0, regardless of the real precision.
|
||||||
means that such columns are reported as IntegerField even if they are
|
For Django introspection, this means that such columns are reported
|
||||||
really BigIntegerField or BooleanField.
|
as IntegerField even if they are really BigIntegerField or BooleanField.
|
||||||
|
|
||||||
The bug is solved in Oracle 11.2.0.2 and up.
|
The bug is solved in Oracle 11.2.0.2 and up.
|
||||||
"""
|
"""
|
||||||
return 'IntegerField' if self.connection.oracle_full_version < '11.2.0.2' else 'BooleanField'
|
if self.connection.oracle_full_version < '11.2.0.2' and field and field.has_default() and created_separately:
|
||||||
|
return 'IntegerField'
|
||||||
|
return super(DatabaseFeatures, self).introspected_boolean_field_type(field, created_separately)
|
||||||
|
|
||||||
|
|
||||||
class DatabaseOperations(BaseDatabaseOperations):
|
class DatabaseOperations(BaseDatabaseOperations):
|
||||||
|
|
|
@ -9,6 +9,8 @@ from django.db import connection
|
||||||
from django.test import TestCase, skipUnlessDBFeature
|
from django.test import TestCase, skipUnlessDBFeature
|
||||||
from django.utils.six import PY3, StringIO
|
from django.utils.six import PY3, StringIO
|
||||||
|
|
||||||
|
from .models import ColumnTypes
|
||||||
|
|
||||||
|
|
||||||
class InspectDBTestCase(TestCase):
|
class InspectDBTestCase(TestCase):
|
||||||
|
|
||||||
|
@ -87,19 +89,18 @@ class InspectDBTestCase(TestCase):
|
||||||
else:
|
else:
|
||||||
assertFieldType('big_int_field', "models.IntegerField()")
|
assertFieldType('big_int_field', "models.IntegerField()")
|
||||||
|
|
||||||
if connection.features.introspected_boolean_field_type == 'BooleanField':
|
bool_field = ColumnTypes._meta.get_field('bool_field')
|
||||||
assertFieldType('bool_field', "models.BooleanField()")
|
bool_field_type = connection.features.introspected_boolean_field_type(bool_field)
|
||||||
|
assertFieldType('bool_field', "models.{}()".format(bool_field_type))
|
||||||
|
null_bool_field = ColumnTypes._meta.get_field('null_bool_field')
|
||||||
|
null_bool_field_type = connection.features.introspected_boolean_field_type(null_bool_field)
|
||||||
|
if 'BooleanField' in null_bool_field_type:
|
||||||
|
assertFieldType('null_bool_field', "models.{}()".format(null_bool_field_type))
|
||||||
|
else:
|
||||||
if connection.features.can_introspect_null:
|
if connection.features.can_introspect_null:
|
||||||
assertFieldType('null_bool_field', "models.NullBooleanField()")
|
assertFieldType('null_bool_field', "models.{}(blank=True, null=True)".format(null_bool_field_type))
|
||||||
else:
|
else:
|
||||||
assertFieldType('null_bool_field', "models.BooleanField()")
|
assertFieldType('null_bool_field', "models.{}()".format(null_bool_field_type))
|
||||||
else:
|
|
||||||
field_type = connection.features.introspected_boolean_field_type
|
|
||||||
assertFieldType('bool_field', "models.{}()".format(field_type))
|
|
||||||
if connection.features.can_introspect_null:
|
|
||||||
assertFieldType('null_bool_field', "models.{}(blank=True, null=True)".format(field_type))
|
|
||||||
else:
|
|
||||||
assertFieldType('null_bool_field', "models.{}()".format(field_type))
|
|
||||||
|
|
||||||
if connection.features.can_introspect_decimal_field:
|
if connection.features.can_introspect_decimal_field:
|
||||||
assertFieldType('decimal_field', "models.DecimalField(max_digits=6, decimal_places=1)")
|
assertFieldType('decimal_field', "models.DecimalField(max_digits=6, decimal_places=1)")
|
||||||
|
|
|
@ -314,7 +314,7 @@ class SchemaTests(TransactionTestCase):
|
||||||
columns = self.column_classes(Author)
|
columns = self.column_classes(Author)
|
||||||
# BooleanField are stored as TINYINT(1) on MySQL.
|
# BooleanField are stored as TINYINT(1) on MySQL.
|
||||||
field_type = columns['awesome'][0]
|
field_type = columns['awesome'][0]
|
||||||
self.assertEqual(field_type, connection.features.introspected_boolean_field_type)
|
self.assertEqual(field_type, connection.features.introspected_boolean_field_type(new_field, created_separately=True))
|
||||||
|
|
||||||
def test_add_field_default_transform(self):
|
def test_add_field_default_transform(self):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue