Commit dbdae3a7 authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #22738 -- Abstracted boolean field type introspection

Thanks maxi for the report, Shai Berger for his help with the patch
and Tim Graham for the review.
parent 45840927
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -614,8 +614,8 @@ class BaseDatabaseFeatures(object):
    # Can the backend introspect an BinaryField, instead of an TextField?
    can_introspect_binary_field = True

    # Can the backend introspect an BooleanField, instead of an IntegerField?
    can_introspect_boolean_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_introspect_decimal_field = True
+1 −1
Original line number Diff line number Diff line
@@ -178,7 +178,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
    supports_regex_backreferencing = False
    supports_date_lookup_using_string = False
    can_introspect_binary_field = False
    can_introspect_boolean_field = False
    introspected_boolean_field_type = 'IntegerField'
    can_introspect_small_integer_field = True
    supports_timezones = False
    requires_explicit_null_ordering_when_grouping = True
+14 −14
Original line number Diff line number Diff line
@@ -125,6 +125,20 @@ class DatabaseFeatures(BaseDatabaseFeatures):
    # select for update with limit can be achieved on Oracle, but not with the current backend.
    supports_select_for_update_with_limit = False

    @cached_property
    def introspected_boolean_field_type(self):
        """
        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
        defined with a default, its precision is later reported on introspection
        as 0, regardless of the real precision. For Django introspection, this
        means that such columns are reported as IntegerField even if they are
        really BigIntegerField or BooleanField.

        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'


class DatabaseOperations(BaseDatabaseOperations):
    compiler_module = "django.db.backends.oracle.compiler"
@@ -735,20 +749,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
        except ValueError:
            return None

    @cached_property
    def version_has_default_introspection_bug(self):
        """
        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
        defined with a default, its precision is later reported on introspection
        as 0, regardless of the real precision. For Django introspection, this
        means that such columns are reported as IntegerField even if they are
        really BigIntegerField or BooleanField.

        The bug is solved in Oracle 11.2.0.2 and up.
        """
        return self.oracle_full_version < '11.2.0.2'


class OracleParam(object):
    """
+5 −4
Original line number Diff line number Diff line
@@ -87,18 +87,19 @@ class InspectDBTestCase(TestCase):
        else:
            assertFieldType('big_int_field', "models.IntegerField()")

        if connection.features.can_introspect_boolean_field:
        if connection.features.introspected_boolean_field_type == 'BooleanField':
            assertFieldType('bool_field', "models.BooleanField()")
            if connection.features.can_introspect_null:
                assertFieldType('null_bool_field', "models.NullBooleanField()")
            else:
                assertFieldType('null_bool_field', "models.BooleanField()")
        else:
            assertFieldType('bool_field', "models.IntegerField()")
            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.IntegerField(blank=True, null=True)")
                assertFieldType('null_bool_field', "models.{}(blank=True, null=True)".format(field_type))
            else:
                assertFieldType('null_bool_field', "models.IntegerField()")
                assertFieldType('null_bool_field', "models.{}()".format(field_type))

        if connection.features.can_introspect_decimal_field:
            assertFieldType('decimal_field', "models.DecimalField(max_digits=6, decimal_places=1)")
+2 −9
Original line number Diff line number Diff line
@@ -313,15 +313,8 @@ class SchemaTests(TransactionTestCase):
        # Ensure the field is right afterwards
        columns = self.column_classes(Author)
        # BooleanField are stored as TINYINT(1) on MySQL.
        field_type, field_info = columns['awesome']
        if connection.vendor == 'mysql':
            self.assertEqual(field_type, 'IntegerField')
            self.assertEqual(field_info.precision, 1)
        elif connection.vendor == 'oracle' and connection.version_has_default_introspection_bug:
            self.assertEqual(field_type, 'IntegerField')
            self.assertEqual(field_info.precision, 0)
        else:
            self.assertEqual(field_type, 'BooleanField')
        field_type = columns['awesome'][0]
        self.assertEqual(field_type, connection.features.introspected_boolean_field_type)

    def test_add_field_default_transform(self):
        """