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 | |