Refs #29182 -- Stopped relying on legacy alter table semantic on SQLite 3.26+.

SQLite 3.26 changed the behavior of table and column renaming operations to
repoint foreign key references even if foreign key checks are disabled.

This makes the workarounds in place to simulate this behavior unnecessary on
SQLite 3.26+. Refs #30033.
This commit is contained in:
Simon Charette 2018-12-11 03:06:24 -05:00 committed by Carlton Gibson
parent 7289874adc
commit 894cb13779
3 changed files with 9 additions and 9 deletions

View File

@ -25,7 +25,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_transactions = True supports_transactions = True
atomic_transactions = False atomic_transactions = False
can_rollback_ddl = True can_rollback_ddl = True
supports_atomic_references_rename = False supports_atomic_references_rename = Database.version_info >= (3, 26, 0)
supports_paramstyle_pyformat = False supports_paramstyle_pyformat = False
supports_sequence_reset = False supports_sequence_reset = False
can_clone_databases = True can_clone_databases = True

View File

@ -27,13 +27,11 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
'SQLite3 does not support disabling them in the middle of ' 'SQLite3 does not support disabling them in the middle of '
'a multi-statement transaction.' 'a multi-statement transaction.'
) )
self.connection.cursor().execute('PRAGMA legacy_alter_table = ON')
return super().__enter__() return super().__enter__()
def __exit__(self, exc_type, exc_value, traceback): def __exit__(self, exc_type, exc_value, traceback):
super().__exit__(exc_type, exc_value, traceback) super().__exit__(exc_type, exc_value, traceback)
self.connection.check_constraints() self.connection.check_constraints()
self.connection.cursor().execute('PRAGMA legacy_alter_table = OFF')
self.connection.enable_constraint_checking() self.connection.enable_constraint_checking()
def quote_value(self, value): def quote_value(self, value):
@ -84,11 +82,12 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
return False return False
def alter_db_table(self, model, old_db_table, new_db_table, disable_constraints=True): def alter_db_table(self, model, old_db_table, new_db_table, disable_constraints=True):
if disable_constraints and self._is_referenced_by_fk_constraint(old_db_table): if (not self.connection.features.supports_atomic_references_rename and
disable_constraints and self._is_referenced_by_fk_constraint(old_db_table)):
if self.connection.in_atomic_block: if self.connection.in_atomic_block:
raise NotSupportedError(( raise NotSupportedError((
'Renaming the %r table while in a transaction is not ' 'Renaming the %r table while in a transaction is not '
'supported on SQLite because it would break referential ' 'supported on SQLite < 3.26 because it would break referential '
'integrity. Try adding `atomic = False` to the Migration class.' 'integrity. Try adding `atomic = False` to the Migration class.'
) % old_db_table) ) % old_db_table)
self.connection.enable_constraint_checking() self.connection.enable_constraint_checking()
@ -102,11 +101,12 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
table_name = model._meta.db_table table_name = model._meta.db_table
_, old_column_name = old_field.get_attname_column() _, old_column_name = old_field.get_attname_column()
if (new_field.name != old_field_name and if (new_field.name != old_field_name and
not self.connection.features.supports_atomic_references_rename and
self._is_referenced_by_fk_constraint(table_name, old_column_name, ignore_self=True)): self._is_referenced_by_fk_constraint(table_name, old_column_name, ignore_self=True)):
if self.connection.in_atomic_block: if self.connection.in_atomic_block:
raise NotSupportedError(( raise NotSupportedError((
'Renaming the %r.%r column while in a transaction is not ' 'Renaming the %r.%r column while in a transaction is not '
'supported on SQLite because it would break referential ' 'supported on SQLite < 3.26 because it would break referential '
'integrity. Try adding `atomic = False` to the Migration class.' 'integrity. Try adding `atomic = False` to the Migration class.'
) % (model._meta.db_table, old_field_name)) ) % (model._meta.db_table, old_field_name))
with atomic(self.connection.alias): with atomic(self.connection.alias):

View File

@ -121,8 +121,8 @@ class SchemaTests(TransactionTestCase):
new_field.set_attributes_from_name('renamed') new_field.set_attributes_from_name('renamed')
msg = ( msg = (
"Renaming the 'backends_author'.'name' column while in a " "Renaming the 'backends_author'.'name' column while in a "
"transaction is not supported on SQLite because it would break " "transaction is not supported on SQLite < 3.26 because it would "
"referential integrity. Try adding `atomic = False` to the " "break referential integrity. Try adding `atomic = False` to the "
"Migration class." "Migration class."
) )
with self.assertRaisesMessage(NotSupportedError, msg): with self.assertRaisesMessage(NotSupportedError, msg):
@ -136,7 +136,7 @@ class SchemaTests(TransactionTestCase):
""" """
msg = ( msg = (
"Renaming the 'backends_author' table while in a transaction is " "Renaming the 'backends_author' table while in a transaction is "
"not supported on SQLite because it would break referential " "not supported on SQLite < 3.26 because it would break referential "
"integrity. Try adding `atomic = False` to the Migration class." "integrity. Try adding `atomic = False` to the Migration class."
) )
with self.assertRaisesMessage(NotSupportedError, msg): with self.assertRaisesMessage(NotSupportedError, msg):