summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2018-06-17 08:51:02 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2018-06-17 08:54:01 +0200
commitd2ca28db54a5871d851cdd9184f4cf0d31aff946 (patch)
tree3c748d68bf15807468918b6a7c960ce7cac70738
parentd28360aa48e40af43450dcdd3843fe7b197b898c (diff)
[2.1.x] Fixed #29496 -- Fixed crash on Oracle when converting a non-unique field to primary key.
Thanks Tim Graham for the review. Backport of 6dd4edb1b4f5441c5f543e29395039839c50d10b from master
-rw-r--r--django/db/backends/base/schema.py16
-rw-r--r--django/db/backends/oracle/schema.py6
-rw-r--r--tests/schema/models.py1
-rw-r--r--tests/schema/tests.py15
4 files changed, 32 insertions, 6 deletions
diff --git a/django/db/backends/base/schema.py b/django/db/backends/base/schema.py
index cf18e7653e..a722e497c3 100644
--- a/django/db/backends/base/schema.py
+++ b/django/db/backends/base/schema.py
@@ -539,7 +539,7 @@ class BaseDatabaseSchemaEditor:
fks_dropped.add((old_field.column,))
self.execute(self._delete_constraint_sql(self.sql_delete_fk, model, fk_name))
# Has unique been removed?
- if old_field.unique and (not new_field.unique or (not old_field.primary_key and new_field.primary_key)):
+ if old_field.unique and (not new_field.unique or self._field_became_primary_key(old_field, new_field)):
# Find the unique constraint for this field
constraint_names = self._constraint_names(model, [old_field.column], unique=True, primary_key=False)
if strict and len(constraint_names) != 1:
@@ -689,9 +689,7 @@ class BaseDatabaseSchemaEditor:
if old_field.primary_key and not new_field.primary_key:
self._delete_primary_key(model, strict)
# Added a unique?
- if (not old_field.unique and new_field.unique) or (
- old_field.primary_key and not new_field.primary_key and new_field.unique
- ):
+ if self._unique_should_be_added(old_field, new_field):
self.execute(self._create_unique_sql(model, [new_field.column]))
# Added an index? Add an index if db_index switched to True or a unique
# constraint will no longer be used in lieu of an index. The following
@@ -710,7 +708,7 @@ class BaseDatabaseSchemaEditor:
if old_field.primary_key and new_field.primary_key and old_type != new_type:
rels_to_update.extend(_related_non_m2m_objects(old_field, new_field))
# Changed to become primary key?
- if not old_field.primary_key and new_field.primary_key:
+ if self._field_became_primary_key(old_field, new_field):
# Make the new one
self.execute(
self.sql_create_pk % {
@@ -966,6 +964,14 @@ class BaseDatabaseSchemaEditor:
def _field_should_be_indexed(self, model, field):
return field.db_index and not field.unique
+ def _field_became_primary_key(self, old_field, new_field):
+ return not old_field.primary_key and new_field.primary_key
+
+ def _unique_should_be_added(self, old_field, new_field):
+ return (not old_field.unique and new_field.unique) or (
+ old_field.primary_key and not new_field.primary_key and new_field.unique
+ )
+
def _rename_field_sql(self, table, old_field, new_field, new_type):
return self.sql_rename_column % {
"table": self.quote_name(table),
diff --git a/django/db/backends/oracle/schema.py b/django/db/backends/oracle/schema.py
index 39c3b7e83d..105d6a4033 100644
--- a/django/db/backends/oracle/schema.py
+++ b/django/db/backends/oracle/schema.py
@@ -144,6 +144,12 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
return False
return create_index
+ def _unique_should_be_added(self, old_field, new_field):
+ return (
+ super()._unique_should_be_added(old_field, new_field) and
+ not self._field_became_primary_key(old_field, new_field)
+ )
+
def _is_identity_column(self, table_name, column_name):
with self.connection.cursor() as cursor:
cursor.execute("""
diff --git a/tests/schema/models.py b/tests/schema/models.py
index 4512d8bc01..f6bdbd8815 100644
--- a/tests/schema/models.py
+++ b/tests/schema/models.py
@@ -12,6 +12,7 @@ class Author(models.Model):
name = models.CharField(max_length=255)
height = models.PositiveIntegerField(null=True, blank=True)
weight = models.IntegerField(null=True, blank=True)
+ uuid = models.UUIDField(null=True)
class Meta:
apps = new_apps
diff --git a/tests/schema/tests.py b/tests/schema/tests.py
index e1bf438ca3..f18b68d04d 100644
--- a/tests/schema/tests.py
+++ b/tests/schema/tests.py
@@ -12,7 +12,7 @@ from django.db.models.deletion import CASCADE, PROTECT
from django.db.models.fields import (
AutoField, BigAutoField, BigIntegerField, BinaryField, BooleanField,
CharField, DateField, DateTimeField, IntegerField, PositiveIntegerField,
- SlugField, TextField, TimeField,
+ SlugField, TextField, TimeField, UUIDField,
)
from django.db.models.fields.related import (
ForeignKey, ForeignObject, ManyToManyField, OneToOneField,
@@ -603,6 +603,19 @@ class SchemaTests(TransactionTestCase):
with connection.schema_editor() as editor:
editor.alter_field(Author, old_field, new_field, strict=True)
+ def test_alter_not_unique_field_to_primary_key(self):
+ # Create the table.
+ with connection.schema_editor() as editor:
+ editor.create_model(Author)
+ # Change UUIDField to primary key.
+ old_field = Author._meta.get_field('uuid')
+ new_field = UUIDField(primary_key=True)
+ new_field.set_attributes_from_name('uuid')
+ new_field.model = Author
+ with connection.schema_editor() as editor:
+ editor.remove_field(Author, Author._meta.get_field('id'))
+ editor.alter_field(Author, old_field, new_field, strict=True)
+
def test_alter_text_field(self):
# Regression for "BLOB/TEXT column 'info' can't have a default value")
# on MySQL.