Skip to content

Commit 3581453

Browse files
committed
Fix alterTable without legacy alter table
Closes #3088
1 parent 955f234 commit 3581453

File tree

3 files changed

+56
-4
lines changed

3 files changed

+56
-4
lines changed

drift/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## 2.22.1
22

33
- Fix generated SQL for `insertFromSelect` statements with upserts.
4+
- Fix `alterTable` for databases where `legacy_alter_table` is not writable.
45

56
## 2.22.0
67

drift/lib/src/runtime/query_builder/migration.dart

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ class Migrator {
158158
final foreignKeysEnabled =
159159
(await database.customSelect('PRAGMA foreign_keys').getSingle())
160160
.read<bool>('foreign_keys');
161-
final legacyAlterTable =
161+
bool? legacyAlterTable =
162162
(await database.customSelect('PRAGMA legacy_alter_table').getSingle())
163163
.read<bool>('legacy_alter_table');
164164

@@ -255,16 +255,39 @@ class Migrator {
255255
// we've just dropped the original table), we need to enable the legacy
256256
// option which skips the integrity check.
257257
// See also: https://sqlite.org/forum/forumpost/0e2390093fbb8fd6
258-
if (!legacyAlterTable) {
259-
await _issueCustomQuery('pragma legacy_alter_table = 1;');
258+
if (legacyAlterTable == false) {
259+
try {
260+
await _issueCustomQuery('pragma legacy_alter_table = 1;');
261+
} on Object {
262+
// On some databases like Turso, legacy_alter_table is not writable.
263+
legacyAlterTable = null;
264+
265+
// A workaround is to drop all views and to re-create them later.
266+
// We're not doing this by default to ensure we're not breaking
267+
// existing users (e.g. if the new table references a view somehow).
268+
final allViews = await database.customSelect(
269+
'SELECT name, sql FROM sqlite_master WHERE type = ?;',
270+
variables: [Variable<String>('view')],
271+
).get();
272+
273+
for (final row in allViews) {
274+
final sql = row.read<String>('sql');
275+
if (!createAffected.contains(sql)) {
276+
createAffected.add(sql);
277+
}
278+
279+
final name = row.read<String>('name');
280+
await database.customStatement('DROP VIEW "$name";');
281+
}
282+
}
260283
}
261284

262285
// Step 7: Rename the new table to the old name
263286
await _issueCustomQuery(
264287
'ALTER TABLE ${context.identifier(temporaryName)} '
265288
'RENAME TO ${context.identifier(tableName)}');
266289

267-
if (!legacyAlterTable) {
290+
if (legacyAlterTable == false) {
268291
await _issueCustomQuery('pragma legacy_alter_table = 0;');
269292
}
270293

drift/test/integration_tests/migrations_integration_test.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,19 @@ void main() {
534534

535535
expect(underlying.userVersion, 3);
536536
});
537+
538+
test("alterTable works for databases that can't set legacy alter table",
539+
() async {
540+
final interceptor = _NoLegacyAlterTable();
541+
final db = TodoDb(NativeDatabase.memory().interceptWith(interceptor));
542+
addTearDown(db.close);
543+
544+
final user = await db.users.insertReturning(
545+
UsersCompanion.insert(name: 'test user', profilePicture: Uint8List(0)));
546+
await Migrator(db).alterTable(TableMigration(db.users));
547+
expect(await db.users.all().get(), [user]);
548+
expect(interceptor.didPreventLegacyAlterTable, isTrue);
549+
});
537550
}
538551

539552
class _TestDatabase extends GeneratedDatabase {
@@ -548,3 +561,18 @@ class _TestDatabase extends GeneratedDatabase {
548561
@override
549562
final MigrationStrategy migration;
550563
}
564+
565+
class _NoLegacyAlterTable extends QueryInterceptor {
566+
var didPreventLegacyAlterTable = false;
567+
568+
@override
569+
Future<void> runCustom(
570+
QueryExecutor executor, String statement, List<Object?> args) {
571+
if (statement.contains('legacy_alter_table') && statement.contains('=')) {
572+
didPreventLegacyAlterTable = true;
573+
throw 'not allowed';
574+
}
575+
576+
return super.runCustom(executor, statement, args);
577+
}
578+
}

0 commit comments

Comments
 (0)