Fix full text search migration after table name change.

main
Greyson Parrelli 2023-01-26 18:59:30 -05:00
rodzic 22a4271dfb
commit fe40e37da4
6 zmienionych plików z 87 dodań i 32 usunięć

Wyświetl plik

@ -97,7 +97,7 @@ public class FullBackupExporter extends FullBackupBase {
SignedPreKeyTable.TABLE_NAME, SignedPreKeyTable.TABLE_NAME,
OneTimePreKeyTable.TABLE_NAME, OneTimePreKeyTable.TABLE_NAME,
SessionTable.TABLE_NAME, SessionTable.TABLE_NAME,
SearchTable.MMS_FTS_TABLE_NAME, SearchTable.FTS_TABLE_NAME,
EmojiSearchTable.TABLE_NAME, EmojiSearchTable.TABLE_NAME,
SenderKeyTable.TABLE_NAME, SenderKeyTable.TABLE_NAME,
SenderKeySharedTable.TABLE_NAME, SenderKeySharedTable.TABLE_NAME,
@ -368,7 +368,7 @@ public class FullBackupExporter extends FullBackupBase {
} }
boolean isReservedTable = table.startsWith("sqlite_"); 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); boolean isEmojiFtsSecretTable = !table.equals(EmojiSearchTable.TABLE_NAME) && table.startsWith(EmojiSearchTable.TABLE_NAME);
return !isReservedTable && return !isReservedTable &&

Wyświetl plik

@ -127,7 +127,7 @@ public class FullBackupImporter extends FullBackupBase {
} }
private static void processStatement(@NonNull SQLiteDatabase db, SqlStatement statement) { 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 isForEmojiSecretTable = statement.getStatement().contains(EmojiSearchTable.TABLE_NAME + "_");
boolean isForSqliteSecretTable = statement.getStatement().toLowerCase().startsWith("create table sqlite_"); boolean isForSqliteSecretTable = statement.getStatement().toLowerCase().startsWith("create table sqlite_");

Wyświetl plik

@ -18,7 +18,7 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
companion object { companion object {
private val TAG = Log.tag(SearchTable::class.java) 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 ID = "rowid"
const val BODY = MessageTable.BODY const val BODY = MessageTable.BODY
const val THREAD_ID = MessageTable.THREAD_ID const val THREAD_ID = MessageTable.THREAD_ID
@ -31,25 +31,25 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
@Language("sql") @Language("sql")
val CREATE_TABLE = arrayOf( 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") @Language("sql")
val CREATE_TRIGGERS = arrayOf( val CREATE_TRIGGERS = arrayOf(
""" """
CREATE TRIGGER mms_ai AFTER INSERT ON ${MessageTable.TABLE_NAME} BEGIN CREATE TRIGGER message_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}); INSERT INTO $FTS_TABLE_NAME($ID, $BODY, $THREAD_ID) VALUES (new.${MessageTable.ID}, new.${MessageTable.BODY}, new.${MessageTable.THREAD_ID});
END; END;
""", """,
""" """
CREATE TRIGGER mms_ad AFTER DELETE ON ${MessageTable.TABLE_NAME} BEGIN CREATE TRIGGER message_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}); 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; END;
""", """,
""" """
CREATE TRIGGER mms_au AFTER UPDATE ON ${MessageTable.TABLE_NAME} BEGIN CREATE TRIGGER message_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 $FTS_TABLE_NAME($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}); INSERT INTO $FTS_TABLE_NAME($ID, $BODY, $THREAD_ID) VALUES (new.${MessageTable.ID}, new.${MessageTable.BODY}, new.${MessageTable.THREAD_ID});
END; END;
""" """
) )
@ -59,18 +59,18 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
SELECT SELECT
${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AS $CONVERSATION_RECIPIENT, ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AS $CONVERSATION_RECIPIENT,
${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} AS $MESSAGE_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}, ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED},
$MMS_FTS_TABLE_NAME.$THREAD_ID, $FTS_TABLE_NAME.$THREAD_ID,
$MMS_FTS_TABLE_NAME.$BODY, $FTS_TABLE_NAME.$BODY,
$MMS_FTS_TABLE_NAME.$ID AS $MESSAGE_ID, $FTS_TABLE_NAME.$ID AS $MESSAGE_ID,
1 AS $IS_MMS 1 AS $IS_MMS
FROM FROM
${MessageTable.TABLE_NAME} ${MessageTable.TABLE_NAME}
INNER JOIN $MMS_FTS_TABLE_NAME ON $MMS_FTS_TABLE_NAME.$ID = ${MessageTable.TABLE_NAME}.${MessageTable.ID} INNER JOIN $FTS_TABLE_NAME ON $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 ${ThreadTable.TABLE_NAME} ON $FTS_TABLE_NAME.$THREAD_ID = ${ThreadTable.TABLE_NAME}.${ThreadTable.ID}
WHERE 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.GROUP_V2_BIT} = 0 AND
${MessageTable.TABLE_NAME}.${MessageTable.TYPE} & ${MessageTypes.SPECIAL_TYPE_PAYMENTS_NOTIFICATION} = 0 ${MessageTable.TABLE_NAME}.${MessageTable.TYPE} & ${MessageTypes.SPECIAL_TYPE_PAYMENTS_NOTIFICATION} = 0
ORDER BY ${MessageTable.DATE_RECEIVED} DESC ORDER BY ${MessageTable.DATE_RECEIVED} DESC
@ -82,18 +82,18 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
SELECT SELECT
${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AS $CONVERSATION_RECIPIENT, ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AS $CONVERSATION_RECIPIENT,
${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} AS $MESSAGE_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}, ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED},
$MMS_FTS_TABLE_NAME.$THREAD_ID, $FTS_TABLE_NAME.$THREAD_ID,
$MMS_FTS_TABLE_NAME.$BODY, $FTS_TABLE_NAME.$BODY,
$MMS_FTS_TABLE_NAME.$ID AS $MESSAGE_ID, $FTS_TABLE_NAME.$ID AS $MESSAGE_ID,
1 AS $IS_MMS 1 AS $IS_MMS
FROM FROM
${MessageTable.TABLE_NAME} ${MessageTable.TABLE_NAME}
INNER JOIN $MMS_FTS_TABLE_NAME ON $MMS_FTS_TABLE_NAME.$ID = ${MessageTable.TABLE_NAME}.${MessageTable.ID} INNER JOIN $FTS_TABLE_NAME ON $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 ${ThreadTable.TABLE_NAME} ON $FTS_TABLE_NAME.$THREAD_ID = ${ThreadTable.TABLE_NAME}.${ThreadTable.ID}
WHERE WHERE
$MMS_FTS_TABLE_NAME MATCH ? AND $FTS_TABLE_NAME MATCH ? AND
${MessageTable.TABLE_NAME}.${MessageTable.THREAD_ID} = ? ${MessageTable.TABLE_NAME}.${MessageTable.THREAD_ID} = ?
ORDER BY ${MessageTable.DATE_RECEIVED} DESC ORDER BY ${MessageTable.DATE_RECEIVED} DESC
LIMIT 500 LIMIT 500
@ -136,7 +136,7 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
Log.i(TAG, "Reindexing ID's [$i, ${i + batchSize})") Log.i(TAG, "Reindexing ID's [$i, ${i + batchSize})")
writableDatabase.execSQL( writableDatabase.execSQL(
""" """
INSERT INTO $MMS_FTS_TABLE_NAME ($ID, $BODY) INSERT INTO $FTS_TABLE_NAME ($ID, $BODY)
SELECT SELECT
${MessageTable.ID}, ${MessageTable.ID},
${MessageTable.BODY} ${MessageTable.BODY}
@ -180,10 +180,10 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
writableDatabase.withinTransaction { db -> writableDatabase.withinTransaction { db ->
// Note the negative page size -- see sqlite docs ref'd in kdoc // 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) 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() iterativeStatement.execute()
var count = SqlUtil.getTotalChanges(db) var count = SqlUtil.getTotalChanges(db)

Wyświetl plik

@ -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.V172_GroupMembershipMigration
import org.thoughtcrime.securesms.database.helpers.migration.V173_ScheduledMessagesMigration 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.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. * 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) val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
const val DATABASE_VERSION = 174 const val DATABASE_VERSION = 175
@JvmStatic @JvmStatic
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
@ -145,6 +146,10 @@ object SignalDatabaseMigrations {
if (oldVersion < 174) { if (oldVersion < 174) {
V174_ReactionForeignKeyMigration.migrate(context, db, oldVersion, newVersion) V174_ReactionForeignKeyMigration.migrate(context, db, oldVersion, newVersion)
} }
if (oldVersion < 175) {
V175_FixFullTextSearchLink.migrate(context, db, oldVersion, newVersion)
}
} }
@JvmStatic @JvmStatic

Wyświetl plik

@ -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;
"""
)
}
}

Wyświetl plik

@ -117,9 +117,10 @@ public class ApplicationMigrations {
static final int UPDATE_SMS_JOBS = 73; static final int UPDATE_SMS_JOBS = 73;
static final int OPTIMIZE_MESSAGE_FTS_INDEX = 74; static final int OPTIMIZE_MESSAGE_FTS_INDEX = 74;
static final int REACTION_DATABASE_MIGRATION = 75; 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 * 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()); 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; return jobs;
} }