diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.java b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.java index bbafbe1c2..bdac12947 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.java @@ -97,7 +97,7 @@ public class FullBackupExporter extends FullBackupBase { SignedPreKeyTable.TABLE_NAME, OneTimePreKeyTable.TABLE_NAME, SessionTable.TABLE_NAME, - SearchTable.MMS_FTS_TABLE_NAME, + SearchTable.FTS_TABLE_NAME, EmojiSearchTable.TABLE_NAME, SenderKeyTable.TABLE_NAME, SenderKeySharedTable.TABLE_NAME, @@ -368,7 +368,7 @@ public class FullBackupExporter extends FullBackupBase { } boolean isReservedTable = table.startsWith("sqlite_"); - boolean isMmsFtsSecretTable = !table.equals(SearchTable.MMS_FTS_TABLE_NAME) && table.startsWith(SearchTable.MMS_FTS_TABLE_NAME); + boolean isMmsFtsSecretTable = !table.equals(SearchTable.FTS_TABLE_NAME) && table.startsWith(SearchTable.FTS_TABLE_NAME); boolean isEmojiFtsSecretTable = !table.equals(EmojiSearchTable.TABLE_NAME) && table.startsWith(EmojiSearchTable.TABLE_NAME); return !isReservedTable && diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.java b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.java index bd96588c4..0f6e7e3ba 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.java @@ -127,7 +127,7 @@ public class FullBackupImporter extends FullBackupBase { } private static void processStatement(@NonNull SQLiteDatabase db, SqlStatement statement) { - boolean isForMmsFtsSecretTable = statement.getStatement().contains(SearchTable.MMS_FTS_TABLE_NAME + "_"); + boolean isForMmsFtsSecretTable = statement.getStatement().contains(SearchTable.FTS_TABLE_NAME + "_"); boolean isForEmojiSecretTable = statement.getStatement().contains(EmojiSearchTable.TABLE_NAME + "_"); boolean isForSqliteSecretTable = statement.getStatement().toLowerCase().startsWith("create table sqlite_"); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.kt index 21c8cb6bb..feafc8827 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.kt @@ -18,7 +18,7 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa companion object { private val TAG = Log.tag(SearchTable::class.java) - const val MMS_FTS_TABLE_NAME = "mms_fts" + const val FTS_TABLE_NAME = "message_fts" const val ID = "rowid" const val BODY = MessageTable.BODY const val THREAD_ID = MessageTable.THREAD_ID @@ -31,26 +31,26 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa @Language("sql") val CREATE_TABLE = arrayOf( - "CREATE VIRTUAL TABLE $MMS_FTS_TABLE_NAME USING fts5($BODY, $THREAD_ID UNINDEXED, content=${MessageTable.TABLE_NAME}, content_rowid=${MessageTable.ID})", + "CREATE VIRTUAL TABLE $FTS_TABLE_NAME USING fts5($BODY, $THREAD_ID UNINDEXED, content=${MessageTable.TABLE_NAME}, content_rowid=${MessageTable.ID})", ) @Language("sql") val CREATE_TRIGGERS = arrayOf( """ - CREATE TRIGGER mms_ai AFTER INSERT ON ${MessageTable.TABLE_NAME} BEGIN - INSERT INTO $MMS_FTS_TABLE_NAME($ID, $BODY, $THREAD_ID) VALUES (new.${MessageTable.ID}, new.${MessageTable.BODY}, new.${MessageTable.THREAD_ID}); + CREATE TRIGGER message_ai AFTER INSERT ON ${MessageTable.TABLE_NAME} BEGIN + INSERT INTO $FTS_TABLE_NAME($ID, $BODY, $THREAD_ID) VALUES (new.${MessageTable.ID}, new.${MessageTable.BODY}, new.${MessageTable.THREAD_ID}); END; """, """ - CREATE TRIGGER mms_ad AFTER DELETE ON ${MessageTable.TABLE_NAME} BEGIN - INSERT INTO $MMS_FTS_TABLE_NAME($MMS_FTS_TABLE_NAME, $ID, $BODY, $THREAD_ID) VALUES('delete', old.${MessageTable.ID}, old.${MessageTable.BODY}, old.${MessageTable.THREAD_ID}); + CREATE TRIGGER message_ad AFTER DELETE ON ${MessageTable.TABLE_NAME} BEGIN + INSERT INTO $FTS_TABLE_NAME($FTS_TABLE_NAME, $ID, $BODY, $THREAD_ID) VALUES('delete', old.${MessageTable.ID}, old.${MessageTable.BODY}, old.${MessageTable.THREAD_ID}); END; """, """ - CREATE TRIGGER mms_au AFTER UPDATE ON ${MessageTable.TABLE_NAME} BEGIN - INSERT INTO $MMS_FTS_TABLE_NAME($MMS_FTS_TABLE_NAME, $ID, $BODY, $THREAD_ID) VALUES('delete', old.${MessageTable.ID}, old.${MessageTable.BODY}, old.${MessageTable.THREAD_ID}); - INSERT INTO $MMS_FTS_TABLE_NAME($ID, $BODY, $THREAD_ID) VALUES (new.${MessageTable.ID}, new.${MessageTable.BODY}, new.${MessageTable.THREAD_ID}); - END; + CREATE TRIGGER message_au AFTER UPDATE ON ${MessageTable.TABLE_NAME} BEGIN + INSERT INTO $FTS_TABLE_NAME($FTS_TABLE_NAME, $ID, $BODY, $THREAD_ID) VALUES('delete', old.${MessageTable.ID}, old.${MessageTable.BODY}, old.${MessageTable.THREAD_ID}); + INSERT INTO $FTS_TABLE_NAME($ID, $BODY, $THREAD_ID) VALUES (new.${MessageTable.ID}, new.${MessageTable.BODY}, new.${MessageTable.THREAD_ID}); + END; """ ) @@ -59,18 +59,18 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa SELECT ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AS $CONVERSATION_RECIPIENT, ${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} AS $MESSAGE_RECIPIENT, - snippet($MMS_FTS_TABLE_NAME, -1, '', '', '$SNIPPET_WRAP', 7) AS $SNIPPET, + snippet($FTS_TABLE_NAME, -1, '', '', '$SNIPPET_WRAP', 7) AS $SNIPPET, ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED}, - $MMS_FTS_TABLE_NAME.$THREAD_ID, - $MMS_FTS_TABLE_NAME.$BODY, - $MMS_FTS_TABLE_NAME.$ID AS $MESSAGE_ID, + $FTS_TABLE_NAME.$THREAD_ID, + $FTS_TABLE_NAME.$BODY, + $FTS_TABLE_NAME.$ID AS $MESSAGE_ID, 1 AS $IS_MMS FROM ${MessageTable.TABLE_NAME} - INNER JOIN $MMS_FTS_TABLE_NAME ON $MMS_FTS_TABLE_NAME.$ID = ${MessageTable.TABLE_NAME}.${MessageTable.ID} - INNER JOIN ${ThreadTable.TABLE_NAME} ON $MMS_FTS_TABLE_NAME.$THREAD_ID = ${ThreadTable.TABLE_NAME}.${ThreadTable.ID} + INNER JOIN $FTS_TABLE_NAME ON $FTS_TABLE_NAME.$ID = ${MessageTable.TABLE_NAME}.${MessageTable.ID} + INNER JOIN ${ThreadTable.TABLE_NAME} ON $FTS_TABLE_NAME.$THREAD_ID = ${ThreadTable.TABLE_NAME}.${ThreadTable.ID} WHERE - $MMS_FTS_TABLE_NAME MATCH ? AND + $FTS_TABLE_NAME MATCH ? AND ${MessageTable.TABLE_NAME}.${MessageTable.TYPE} & ${MessageTypes.GROUP_V2_BIT} = 0 AND ${MessageTable.TABLE_NAME}.${MessageTable.TYPE} & ${MessageTypes.SPECIAL_TYPE_PAYMENTS_NOTIFICATION} = 0 ORDER BY ${MessageTable.DATE_RECEIVED} DESC @@ -82,18 +82,18 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa SELECT ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AS $CONVERSATION_RECIPIENT, ${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} AS $MESSAGE_RECIPIENT, - snippet($MMS_FTS_TABLE_NAME, -1, '', '', '$SNIPPET_WRAP', 7) AS $SNIPPET, + snippet($FTS_TABLE_NAME, -1, '', '', '$SNIPPET_WRAP', 7) AS $SNIPPET, ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED}, - $MMS_FTS_TABLE_NAME.$THREAD_ID, - $MMS_FTS_TABLE_NAME.$BODY, - $MMS_FTS_TABLE_NAME.$ID AS $MESSAGE_ID, + $FTS_TABLE_NAME.$THREAD_ID, + $FTS_TABLE_NAME.$BODY, + $FTS_TABLE_NAME.$ID AS $MESSAGE_ID, 1 AS $IS_MMS FROM ${MessageTable.TABLE_NAME} - INNER JOIN $MMS_FTS_TABLE_NAME ON $MMS_FTS_TABLE_NAME.$ID = ${MessageTable.TABLE_NAME}.${MessageTable.ID} - INNER JOIN ${ThreadTable.TABLE_NAME} ON $MMS_FTS_TABLE_NAME.$THREAD_ID = ${ThreadTable.TABLE_NAME}.${ThreadTable.ID} + INNER JOIN $FTS_TABLE_NAME ON $FTS_TABLE_NAME.$ID = ${MessageTable.TABLE_NAME}.${MessageTable.ID} + INNER JOIN ${ThreadTable.TABLE_NAME} ON $FTS_TABLE_NAME.$THREAD_ID = ${ThreadTable.TABLE_NAME}.${ThreadTable.ID} WHERE - $MMS_FTS_TABLE_NAME MATCH ? AND + $FTS_TABLE_NAME MATCH ? AND ${MessageTable.TABLE_NAME}.${MessageTable.THREAD_ID} = ? ORDER BY ${MessageTable.DATE_RECEIVED} DESC LIMIT 500 @@ -136,7 +136,7 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa Log.i(TAG, "Reindexing ID's [$i, ${i + batchSize})") writableDatabase.execSQL( """ - INSERT INTO $MMS_FTS_TABLE_NAME ($ID, $BODY) + INSERT INTO $FTS_TABLE_NAME ($ID, $BODY) SELECT ${MessageTable.ID}, ${MessageTable.BODY} @@ -180,10 +180,10 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa writableDatabase.withinTransaction { db -> // Note the negative page size -- see sqlite docs ref'd in kdoc - db.execSQL("INSERT INTO $MMS_FTS_TABLE_NAME ($MMS_FTS_TABLE_NAME, rank) values ('merge', -$pageSize)") + db.execSQL("INSERT INTO $FTS_TABLE_NAME ($FTS_TABLE_NAME, rank) values ('merge', -$pageSize)") var previousCount = SqlUtil.getTotalChanges(db) - val iterativeStatement = db.compileStatement("INSERT INTO $MMS_FTS_TABLE_NAME ($MMS_FTS_TABLE_NAME, rank) values ('merge', $pageSize)") + val iterativeStatement = db.compileStatement("INSERT INTO $FTS_TABLE_NAME ($FTS_TABLE_NAME, rank) values ('merge', $pageSize)") iterativeStatement.execute() var count = SqlUtil.getTotalChanges(db) 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 3ad316098..db5dc880e 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 @@ -30,6 +30,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V171_ThreadForeignK import org.thoughtcrime.securesms.database.helpers.migration.V172_GroupMembershipMigration import org.thoughtcrime.securesms.database.helpers.migration.V173_ScheduledMessagesMigration import org.thoughtcrime.securesms.database.helpers.migration.V174_ReactionForeignKeyMigration +import org.thoughtcrime.securesms.database.helpers.migration.V175_FixFullTextSearchLink /** * Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness. @@ -38,7 +39,7 @@ object SignalDatabaseMigrations { val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass) - const val DATABASE_VERSION = 174 + const val DATABASE_VERSION = 175 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { @@ -145,6 +146,10 @@ object SignalDatabaseMigrations { if (oldVersion < 174) { V174_ReactionForeignKeyMigration.migrate(context, db, oldVersion, newVersion) } + + if (oldVersion < 175) { + V175_FixFullTextSearchLink.migrate(context, db, oldVersion, newVersion) + } } @JvmStatic diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V175_FixFullTextSearchLink.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V175_FixFullTextSearchLink.kt new file mode 100644 index 000000000..1bc607f1f --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V175_FixFullTextSearchLink.kt @@ -0,0 +1,45 @@ +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase + +/** + * Turns out renaming a table will automatically update all of your indexes, foreign keys, triggers, basically everything... except full-text search tables. + * So we have to delete it and rebuild it. + */ +@Suppress("ClassName") +object V175_FixFullTextSearchLink : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("DROP TABLE mms_fts") + db.execSQL("DROP TRIGGER IF EXISTS mms_ai") + db.execSQL("DROP TRIGGER IF EXISTS mms_ad") + db.execSQL("DROP TRIGGER IF EXISTS mms_au") + + db.execSQL("CREATE VIRTUAL TABLE message_fts USING fts5(body, thread_id UNINDEXED, content=message, content_rowid=_id)") + + 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 38a1b96f5..593144449 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java @@ -117,9 +117,10 @@ public class ApplicationMigrations { static final int UPDATE_SMS_JOBS = 73; static final int OPTIMIZE_MESSAGE_FTS_INDEX = 74; static final int REACTION_DATABASE_MIGRATION = 75; + static final int REBUILD_MESSAGE_FTS_INDEX_2 = 76; } - public static final int CURRENT_VERSION = 75; + public static final int CURRENT_VERSION = 76; /** * This *must* be called after the {@link JobManager} has been instantiated, but *before* the call @@ -521,6 +522,10 @@ public class ApplicationMigrations { jobs.put(Version.REACTION_DATABASE_MIGRATION, new DatabaseMigrationJob()); } + if (lastSeenVersion < Version.REBUILD_MESSAGE_FTS_INDEX_2) { + jobs.put(Version.REBUILD_MESSAGE_FTS_INDEX_2, new RebuildMessageSearchIndexMigrationJob()); + } + return jobs; }