diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index 3e2e1b72c5..0bc6165a0c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -99,6 +99,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V238_AddGroupSendEn import org.thoughtcrime.securesms.database.helpers.migration.V239_MessageFullTextSearchEmojiSupport import org.thoughtcrime.securesms.database.helpers.migration.V240_MessageFullTextSearchSecureDelete import org.thoughtcrime.securesms.database.helpers.migration.V241_ExpireTimerVersion +import org.thoughtcrime.securesms.database.helpers.migration.V242_MessageFullTextSearchEmojiSupportV2 /** * Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness. @@ -200,10 +201,11 @@ object SignalDatabaseMigrations { 238 to V238_AddGroupSendEndorsementsColumns, 239 to V239_MessageFullTextSearchEmojiSupport, 240 to V240_MessageFullTextSearchSecureDelete, - 241 to V241_ExpireTimerVersion + 241 to V241_ExpireTimerVersion, + 242 to V242_MessageFullTextSearchEmojiSupportV2 ) - const val DATABASE_VERSION = 241 + const val DATABASE_VERSION = 242 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V242_MessageFullTextSearchEmojiSupportV2.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V242_MessageFullTextSearchEmojiSupportV2.kt new file mode 100644 index 0000000000..eb5e7d892c --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V242_MessageFullTextSearchEmojiSupportV2.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase + +/** + * Recreates the message FTS stuff, but with a tokenizer property that lets us search for emoji. + * This is paired with an ApplicationMigration to rebuild the message index in the background. + * + * This is the second attempt (see [V239_MessageFullTextSearchEmojiSupport]). The first attempt saw weird vtable issues. + */ +@Suppress("ClassName") +object V242_MessageFullTextSearchEmojiSupportV2 : SignalDatabaseMigration { + + private const val FTS_TABLE_NAME = "message_fts" + + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + // Due to issues we've had in the past, the delete sequence here is very particular. It mimics the "safe drop" process in the SQLite source code + // that prevents weird vtable constructor issues when dropping potentially-corrupt tables. https://sqlite.org/src/info/4db9258a78?ln=1549-1592 + db.execSQL("DELETE FROM ${FTS_TABLE_NAME}_data") + db.execSQL("DELETE FROM ${FTS_TABLE_NAME}_config") + db.execSQL("INSERT INTO ${FTS_TABLE_NAME}_data VALUES(10, X'0000000000')") + db.execSQL("INSERT INTO ${FTS_TABLE_NAME}_config VALUES('version', 4)") + db.execSQL("DROP TABLE $FTS_TABLE_NAME") + + db.execSQL("DROP TRIGGER IF EXISTS message_ai") + db.execSQL("DROP TRIGGER IF EXISTS message_ad") + db.execSQL("DROP TRIGGER IF EXISTS message_au") + + db.execSQL("""CREATE VIRTUAL TABLE message_fts USING fts5(body, thread_id UNINDEXED, content=message, content_rowid=_id, tokenize = "unicode61 categories 'L* N* Co Sc So'")""") + db.execSQL("INSERT INTO $FTS_TABLE_NAME ($FTS_TABLE_NAME, rank) VALUES('secure-delete', 1)") + + db.execSQL( + """ + CREATE TRIGGER message_ai AFTER INSERT ON message BEGIN + INSERT INTO message_fts(rowid, body, thread_id) VALUES (new._id, new.body, new.thread_id); + END; + """ + ) + db.execSQL( + """ + CREATE TRIGGER message_ad AFTER DELETE ON message BEGIN + INSERT INTO message_fts(message_fts, rowid, body, thread_id) VALUES('delete', old._id, old.body, old.thread_id); + END; + """ + ) + db.execSQL( + """ + CREATE TRIGGER message_au AFTER UPDATE ON message BEGIN + INSERT INTO message_fts(message_fts, rowid, body, thread_id) VALUES('delete', old._id, old.body, old.thread_id); + INSERT INTO message_fts(rowid, body, thread_id) VALUES (new._id, new.body, new.thread_id); + END; + """ + ) + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java index b092f88c50..0d55e699f5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java @@ -152,9 +152,10 @@ public class ApplicationMigrations { static final int DELETE_SYNC_CAPABILITY = 107; static final int REBUILD_MESSAGE_FTS_INDEX_5 = 108; static final int EXPIRE_TIMER_CAPABILITY = 109; + static final int REBUILD_MESSAGE_FTS_INDEX_6 = 110; } - public static final int CURRENT_VERSION = 109; + public static final int CURRENT_VERSION = 110; /** * This *must* be called after the {@link JobManager} has been instantiated, but *before* the call @@ -693,6 +694,10 @@ public class ApplicationMigrations { jobs.put(Version.EXPIRE_TIMER_CAPABILITY, new AttributesMigrationJob()); } + if (lastSeenVersion < Version.REBUILD_MESSAGE_FTS_INDEX_6) { + jobs.put(Version.REBUILD_MESSAGE_FTS_INDEX_6, new RebuildMessageSearchIndexMigrationJob()); + } + return jobs; }