Enable legacy alter table in alterTable

This commit is contained in:
Simon Binder 2022-12-21 18:09:05 +01:00
parent 7be97d139e
commit 1d8fa16e2c
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
4 changed files with 31 additions and 16 deletions

View File

@ -8,6 +8,8 @@
generate a mapping to the new `DriftAny` type. generate a mapping to the new `DriftAny` type.
- Fix `UNIQUE` keys declared in drift files being written twice. - Fix `UNIQUE` keys declared in drift files being written twice.
- Fix `customConstraints` not appearing in dumped database schema files. - Fix `customConstraints` not appearing in dumped database schema files.
- Work-around an issue causing complex migrations via `Migrator.alterTable` not to
work if a view referenced the altered table.
## 2.3.0-dev ## 2.3.0-dev

View File

@ -146,6 +146,9 @@ class Migrator {
final foreignKeysEnabled = final foreignKeysEnabled =
(await _db.customSelect('PRAGMA foreign_keys').getSingle()) (await _db.customSelect('PRAGMA foreign_keys').getSingle())
.read<bool>('foreign_keys'); .read<bool>('foreign_keys');
final legacyAlterTable =
(await _db.customSelect('PRAGMA legacy_alter_table').getSingle())
.read<bool>('legacy_alter_table');
if (foreignKeysEnabled) { if (foreignKeysEnabled) {
await _db.customStatement('PRAGMA foreign_keys = OFF;'); await _db.customStatement('PRAGMA foreign_keys = OFF;');
@ -235,11 +238,24 @@ class Migrator {
// Step 6: Drop the old table // Step 6: Drop the old table
await _issueCustomQuery('DROP TABLE ${context.identifier(tableName)}'); await _issueCustomQuery('DROP TABLE ${context.identifier(tableName)}');
// This step is not mentioned in the documentation, but: If we use `ALTER`
// on an inconsistent schema (and it is inconsistent right now because
// we've just dropped the original table), we need to enable the legacy
// option which skips the integrity check.
// See also: https://sqlite.org/forum/forumpost/0e2390093fbb8fd6
if (!legacyAlterTable) {
await _issueCustomQuery('pragma legacy_alter_table = 1;');
}
// Step 7: Rename the new table to the old name // Step 7: Rename the new table to the old name
await _issueCustomQuery( await _issueCustomQuery(
'ALTER TABLE ${context.identifier(temporaryName)} ' 'ALTER TABLE ${context.identifier(temporaryName)} '
'RENAME TO ${context.identifier(tableName)}'); 'RENAME TO ${context.identifier(tableName)}');
if (!legacyAlterTable) {
await _issueCustomQuery('pragma legacy_alter_table = 0;');
}
// Step 8: Re-create associated indexes, triggers and views // Step 8: Re-create associated indexes, triggers and views
for (final stmt in createAffected) { for (final stmt in createAffected) {
await _issueCustomQuery(stmt); await _issueCustomQuery(stmt);

View File

@ -15,7 +15,8 @@ void main() {
test('change column types', () async { test('change column types', () async {
// Create todos table with category as text (it's an int? in Dart). // Create todos table with category as text (it's an int? in Dart).
final executor = NativeDatabase.memory(setup: (db) { final executor = NativeDatabase.memory(setup: (db) {
db.execute(''' db
..execute('''
CREATE TABLE todos ( CREATE TABLE todos (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL, title TEXT NOT NULL,
@ -25,14 +26,12 @@ void main() {
status TEXT NULL, status TEXT NULL,
UNIQUE(title, category) UNIQUE(title, category)
); );
'''); ''')
..execute('CREATE INDEX my_index ON todos (content);')
db.execute('CREATE INDEX my_index ON todos (content);'); ..execute('INSERT INTO todos (title, content, target_date, category) '
"VALUES ('title', 'content', 0, '12')")
db.execute('INSERT INTO todos (title, content, target_date, category) ' ..execute('CREATE VIEW todo_categories AS SELECT category FROM todos;')
"VALUES ('title', 'content', 0, '12')"); ..execute('PRAGMA foreign_keys = ON');
db.execute('PRAGMA foreign_keys = ON');
}); });
final db = TodoDb(executor); final db = TodoDb(executor);
@ -63,6 +62,11 @@ void main() {
final foreignKeysResult = final foreignKeysResult =
await db.customSelect('PRAGMA foreign_keys').getSingle(); await db.customSelect('PRAGMA foreign_keys').getSingle();
expect(foreignKeysResult.read<bool>('foreign_keys'), isTrue); expect(foreignKeysResult.read<bool>('foreign_keys'), isTrue);
// Similarly, the legacy_alter_table behavior should be disabled.
final legacyAlterTable =
await db.customSelect('PRAGMA legacy_alter_table').getSingle();
expect(legacyAlterTable.read<bool>('legacy_alter_table'), isFalse);
}); });
test('rename columns', () async { test('rename columns', () async {

View File

@ -63,18 +63,11 @@ class Database extends _$Database {
break; break;
case 8: case 8:
// Added a unique key to the users table // Added a unique key to the users table
// TODO: Figure out why dropping the view is necessary (https://sqlite.org/forum/forumpost/de614349cb)
await m.drop(groupCount);
await m.alterTable(TableMigration(v8.Users(this))); await m.alterTable(TableMigration(v8.Users(this)));
await m.recreateAllViews();
break; break;
case 9: case 9:
// Added a check to the users table // Added a check to the users table
await m.drop(groupCount);
await m.alterTable(TableMigration(users)); await m.alterTable(TableMigration(users));
await m.recreateAllViews();
break; break;
} }
} }