| 91 | | def alter_field(self, model, old_field, new_field, strict=False): |
| 92 | | old_field_name = old_field.name |
| 93 | | table_name = model._meta.db_table |
| 94 | | _, old_column_name = old_field.get_attname_column() |
| 95 | | if (new_field.name != old_field_name and |
| 96 | | self._is_referenced_by_fk_constraint(table_name, old_column_name, ignore_self=True)): |
| 97 | | if self.connection.in_atomic_block: |
| 98 | | raise NotSupportedError(( |
| 99 | | 'Renaming the %r.%r column while in a transaction is not ' |
| 100 | | 'supported on SQLite because it would break referential ' |
| 101 | | 'integrity. Try adding `atomic = False` to the Migration class.' |
| 102 | | ) % (model._meta.db_table, old_field_name)) |
| 103 | | with atomic(self.connection.alias): |
| 104 | | super().alter_field(model, old_field, new_field, strict=strict) |
| 105 | | # Follow SQLite's documented procedure for performing changes |
| 106 | | # that don't affect the on-disk content. |
| 107 | | # https://sqlite.org/lang_altertable.html#otheralter |
| 108 | | with self.connection.cursor() as cursor: |
| 109 | | schema_version = cursor.execute('PRAGMA schema_version').fetchone()[0] |
| 110 | | cursor.execute('PRAGMA writable_schema = 1') |
| 111 | | references_template = ' REFERENCES "%s" ("%%s") ' % table_name |
| 112 | | new_column_name = new_field.get_attname_column()[1] |
| 113 | | search = references_template % old_column_name |
| 114 | | replacement = references_template % new_column_name |
| 115 | | cursor.execute('UPDATE sqlite_master SET sql = replace(sql, %s, %s)', (search, replacement)) |
| 116 | | cursor.execute('PRAGMA schema_version = %d' % (schema_version + 1)) |
| 117 | | cursor.execute('PRAGMA writable_schema = 0') |
| 118 | | # The integrity check will raise an exception and rollback |
| 119 | | # the transaction if the sqlite_master updates corrupt the |
| 120 | | # database. |
| 121 | | cursor.execute('PRAGMA integrity_check') |
| 122 | | # Perform a VACUUM to refresh the database representation from |
| 123 | | # the sqlite_master table. |
| 124 | | with self.connection.cursor() as cursor: |
| 125 | | cursor.execute('VACUUM') |
| 126 | | else: |
| 127 | | super().alter_field(model, old_field, new_field, strict=strict) |
| 128 | | |
| | 244 | # TODO: Should be merged with the above changes |
| | 245 | # ... But that causes problems with BaseDatabaseSchemaEditor.execute |
| | 246 | # (the transaction check there) |
| | 247 | if schema_rewrite_needed: |
| | 248 | with atomic(self.connection.alias): |
| | 249 | # Follow SQLite's documented procedure for performing changes |
| | 250 | # that don't affect the on-disk content. |
| | 251 | # https://sqlite.org/lang_altertable.html#otheralter |
| | 252 | with self.connection.cursor() as cursor: |
| | 253 | # TODO: Is there any reason this doesn't go through BaseDatabaseSchemaEditor.execute |
| | 254 | # to record the queries if sqlmigrate is used? Not that the output would be nice |
| | 255 | # but it would be nearer to the truth |
| | 256 | schema_version = cursor.execute('PRAGMA schema_version').fetchone()[0] |
| | 257 | cursor.execute('PRAGMA writable_schema = 1') |
| | 258 | references_template = ' REFERENCES "%s"' |
| | 259 | search = references_template % (model._meta.db_table + "__old") |
| | 260 | replacement = references_template % model._meta.db_table |
| | 261 | cursor.execute('UPDATE sqlite_master SET sql = replace(sql, %s, %s)', (search, replacement)) |
| | 262 | cursor.execute('PRAGMA schema_version = %d' % (schema_version + 1)) |
| | 263 | cursor.execute('PRAGMA writable_schema = 0') |
| | 264 | # The integrity check will raise an exception and rollback |
| | 265 | # the transaction if the sqlite_master updates corrupt the |
| | 266 | # database. |
| | 267 | cursor.execute('PRAGMA integrity_check') |
| | 268 | |
| | 269 | # Perform a VACUUM to refresh the database representation from |
| | 270 | # the sqlite_master table. |
| | 271 | with self.connection.cursor() as cursor: |
| | 272 | cursor.execute('VACUUM') |
| | 273 | |