summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2020-07-20 09:48:31 +0200
committerGitHub <noreply@github.com>2020-07-20 09:48:31 +0200
commit83f55aafdd635189c010cff403f66b54d695921a (patch)
treeba3f3244e4300bc055555f7693363f28fa885169
parent730711e8282893723f993f55d3e3b0c823cfdb9a (diff)
Fixed #17653 -- Allowed using zero as AutoFields value on MySQL if NO_AUTO_VALUE_ON_ZERO SQL mode is enabled.
-rw-r--r--django/db/backends/base/features.py2
-rw-r--r--django/db/backends/mysql/features.py9
-rw-r--r--django/db/backends/mysql/operations.py8
-rw-r--r--tests/backends/mysql/test_features.py6
-rw-r--r--tests/backends/tests.py3
-rw-r--r--tests/bulk_create/tests.py3
-rw-r--r--tests/serializers/test_data.py4
7 files changed, 27 insertions, 8 deletions
diff --git a/django/db/backends/base/features.py b/django/db/backends/base/features.py
index e156c56bda..877dd0ed88 100644
--- a/django/db/backends/base/features.py
+++ b/django/db/backends/base/features.py
@@ -100,7 +100,7 @@ class BaseDatabaseFeatures:
# The database's limit on the number of query parameters.
max_query_params = None
- # Can an object have an autoincrement primary key of 0? MySQL says No.
+ # Can an object have an autoincrement primary key of 0?
allows_auto_pk_0 = True
# Do we need to NULL a ForeignKey out, or can the constraint check be
diff --git a/django/db/backends/mysql/features.py b/django/db/backends/mysql/features.py
index d4651516fe..e55d098057 100644
--- a/django/db/backends/mysql/features.py
+++ b/django/db/backends/mysql/features.py
@@ -17,7 +17,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_index_column_ordering = False
supports_timezones = False
requires_explicit_null_ordering_when_grouping = True
- allows_auto_pk_0 = False
can_release_savepoints = True
atomic_transactions = False
can_clone_databases = True
@@ -52,6 +51,14 @@ class DatabaseFeatures(BaseDatabaseFeatures):
return self.connection.mysql_server_data['default_storage_engine']
@cached_property
+ def allows_auto_pk_0(self):
+ """
+ Autoincrement primary key can be set to 0 if it doesn't generate new
+ autoincrement values.
+ """
+ return 'NO_AUTO_VALUE_ON_ZERO' in self.connection.sql_mode
+
+ @cached_property
def update_can_self_select(self):
return self.connection.mysql_is_mariadb and self.connection.mysql_version >= (10, 3, 2)
diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py
index ffddb64e3c..05523fcdbe 100644
--- a/django/db/backends/mysql/operations.py
+++ b/django/db/backends/mysql/operations.py
@@ -227,8 +227,9 @@ class DatabaseOperations(BaseDatabaseOperations):
]
def validate_autopk_value(self, value):
- # MySQLism: zero in AUTO_INCREMENT field does not work. Refs #17653.
- if value == 0:
+ # Zero in AUTO_INCREMENT field does not work without the
+ # NO_AUTO_VALUE_ON_ZERO SQL mode.
+ if value == 0 and not self.connection.features.allows_auto_pk_0:
raise ValueError('The database backend does not accept 0 as a '
'value for AutoField.')
return value
@@ -266,6 +267,9 @@ class DatabaseOperations(BaseDatabaseOperations):
def max_name_length(self):
return 64
+ def pk_default_value(self):
+ return 'NULL'
+
def bulk_insert_sql(self, fields, placeholder_rows):
placeholder_rows_sql = (", ".join(row) for row in placeholder_rows)
values_sql = ", ".join("(%s)" % sql for sql in placeholder_rows_sql)
diff --git a/tests/backends/mysql/test_features.py b/tests/backends/mysql/test_features.py
index 1385c9b88c..5d27890a5d 100644
--- a/tests/backends/mysql/test_features.py
+++ b/tests/backends/mysql/test_features.py
@@ -32,3 +32,9 @@ class TestFeatures(TestCase):
database_features = DatabaseFeatures(_connection)
self.assertFalse(database_features.has_select_for_update_skip_locked)
self.assertFalse(database_features.has_select_for_update_nowait)
+
+ def test_allows_auto_pk_0(self):
+ with mock.MagicMock() as _connection:
+ _connection.sql_mode = {'NO_AUTO_VALUE_ON_ZERO'}
+ database_features = DatabaseFeatures(_connection)
+ self.assertIs(database_features.allows_auto_pk_0, True)
diff --git a/tests/backends/tests.py b/tests/backends/tests.py
index 08bdac3437..cf6bdbf25d 100644
--- a/tests/backends/tests.py
+++ b/tests/backends/tests.py
@@ -806,7 +806,8 @@ class ThreadTests(TransactionTestCase):
class MySQLPKZeroTests(TestCase):
"""
Zero as id for AutoField should raise exception in MySQL, because MySQL
- does not allow zero for autoincrement primary key.
+ does not allow zero for autoincrement primary key if the
+ NO_AUTO_VALUE_ON_ZERO SQL mode is not enabled.
"""
@skipIfDBFeature('allows_auto_pk_0')
def test_zero_as_autoval(self):
diff --git a/tests/bulk_create/tests.py b/tests/bulk_create/tests.py
index ff89bcb1dd..2b1d901e31 100644
--- a/tests/bulk_create/tests.py
+++ b/tests/bulk_create/tests.py
@@ -115,7 +115,8 @@ class BulkCreateTests(TestCase):
def test_zero_as_autoval(self):
"""
Zero as id for AutoField should raise exception in MySQL, because MySQL
- does not allow zero for automatic primary key.
+ does not allow zero for automatic primary key if the
+ NO_AUTO_VALUE_ON_ZERO SQL mode is not enabled.
"""
valid_country = Country(name='Germany', iso_two_letter='DE')
invalid_country = Country(id=0, name='Poland', iso_two_letter='PL')
diff --git a/tests/serializers/test_data.py b/tests/serializers/test_data.py
index 1ddba02565..323cb13e82 100644
--- a/tests/serializers/test_data.py
+++ b/tests/serializers/test_data.py
@@ -379,8 +379,8 @@ if connection.features.interprets_empty_strings_as_nulls:
data[3] is None)]
# Regression test for #8651 -- a FK to an object with PK of 0
-# This won't work on MySQL since it won't let you create an object
-# with an autoincrement primary key of 0,
+# This won't work on MySQL without the NO_AUTO_VALUE_ON_ZERO SQL mode since it
+# won't let you create an object with an autoincrement primary key of 0.
if connection.features.allows_auto_pk_0:
test_data.extend([
(data_obj, 0, Anchor, "Anchor 0"),