Fixed #30712 -- Allowed BLOB/TEXT defaults on MySQL 8.0.13+.

This commit is contained in:
Nasir Hussain 2019-08-17 15:49:52 +05:00 committed by Mariusz Felisiak
parent 5e2e57a5a1
commit 6b16c91157
4 changed files with 29 additions and 9 deletions

View File

@ -16,8 +16,8 @@ class MySQLGISSchemaEditor(DatabaseSchemaEditor):
self.geometry_sql = []
def skip_default(self, field):
# Geometry fields are stored as BLOB/TEXT, for which MySQL and MariaDB
# < 10.2.1 don't support defaults.
# Geometry fields are stored as BLOB/TEXT, for which MySQL < 8.0.13 and
# MariaDB < 10.2.1 don't support defaults.
if isinstance(field, GeometryField) and not self._supports_limited_data_type_defaults:
return True
return super().skip_default(field)

View File

@ -217,14 +217,15 @@ class BaseDatabaseSchemaEditor:
include_default = include_default and not self.skip_default(field)
if include_default:
default_value = self.effective_default(field)
column_default = ' DEFAULT ' + self._column_default_sql(field)
if default_value is not None:
if self.connection.features.requires_literal_defaults:
# Some databases can't take defaults as a parameter (oracle)
# If this is the case, the individual schema backend should
# implement prepare_default
sql += " DEFAULT %s" % self.prepare_default(default_value)
sql += column_default % self.prepare_default(default_value)
else:
sql += " DEFAULT %s"
sql += column_default
params += [default_value]
# Oracle treats the empty string ('') as null, so coerce the null
# option whenever '' is a possible value.
@ -263,6 +264,13 @@ class BaseDatabaseSchemaEditor:
'requires_literal_defaults must provide a prepare_default() method'
)
def _column_default_sql(self, field):
"""
Return the SQL to use in a DEFAULT clause. The resulting string should
contain a '%s' placeholder for a default value.
"""
return '%s'
@staticmethod
def _effective_default(field):
# This method allows testing its logic without a connection.
@ -826,7 +834,7 @@ class BaseDatabaseSchemaEditor:
argument) a default to new_field's column.
"""
new_default = self.effective_default(new_field)
default = '%s'
default = self._column_default_sql(new_field)
params = [new_default]
if drop:

View File

@ -131,8 +131,8 @@ class DatabaseWrapper(BaseDatabaseWrapper):
}
# For these data types:
# - MySQL and MariaDB < 10.2.1 don't accept default values and implicitly
# treat them as nullable
# - MySQL < 8.0.13 and MariaDB < 10.2.1 don't accept default values and
# implicitly treat them as nullable
# - all versions of MySQL and MariaDB don't support full width database
# indexes
_limited_data_types = (

View File

@ -54,10 +54,22 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
@property
def _supports_limited_data_type_defaults(self):
# Only MariaDB >= 10.2.1 supports defaults for BLOB and TEXT.
# MariaDB >= 10.2.1 and MySQL >= 8.0.13 supports defaults for BLOB
# and TEXT.
if self.connection.mysql_is_mariadb:
return self.connection.mysql_version >= (10, 2, 1)
return False
return self.connection.mysql_version >= (8, 0, 13)
def _column_default_sql(self, field):
if (
not self.connection.mysql_is_mariadb and
self._supports_limited_data_type_defaults and
self._is_limited_data_type(field)
):
# MySQL supports defaults for BLOB and TEXT columns only if the
# default value is written as an expression i.e. in parentheses.
return '(%s)'
return super()._column_default_sql(field)
def add_field(self, model, field):
super().add_field(model, field)