diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ChatFolderTables.kt b/app/src/main/java/org/thoughtcrime/securesms/database/ChatFolderTables.kt index 20e40bc823..af83f53a72 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ChatFolderTables.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ChatFolderTables.kt @@ -336,7 +336,7 @@ class ChatFolderTables(context: Context?, databaseHelper: SignalDatabase?) : Dat ChatFolderTable.DELETED_TIMESTAMP_MS to chatFolder.deletedTimestampMs ) .where("${ChatFolderTable.ID} = ?", chatFolder.id) - .run(SQLiteDatabase.CONFLICT_IGNORE) + .run() db .delete(ChatFolderMembershipTable.TABLE_NAME) @@ -394,7 +394,7 @@ class ChatFolderTables(context: Context?, databaseHelper: SignalDatabase?) : Dat db.update(ChatFolderTable.TABLE_NAME) .values(ChatFolderTable.POSITION to folder.position) .where("${ChatFolderTable.ID} = ?", folder.id) - .run(SQLiteDatabase.CONFLICT_IGNORE) + .run() } AppDependencies.databaseObserver.notifyChatFolderObservers() } @@ -533,7 +533,7 @@ class ChatFolderTables(context: Context?, databaseHelper: SignalDatabase?) : Dat ChatFolderTable.STORAGE_SERVICE_PROTO to storageServiceProto ) .where("${ChatFolderTable.FOLDER_TYPE} = ?", ChatFolderRecord.FolderType.ALL.value) - .run(SQLiteDatabase.CONFLICT_IGNORE) + .run() } } else { createFolder(remoteChatFolderRecordToLocal(record)) @@ -636,7 +636,7 @@ class ChatFolderTables(context: Context?, databaseHelper: SignalDatabase?) : Dat db.update(ChatFolderTable.TABLE_NAME) .values(ChatFolderTable.POSITION to index) .where("${ChatFolderTable.ID} = ?", id) - .run(SQLiteDatabase.CONFLICT_IGNORE) + .run() } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DistributionListTables.kt b/app/src/main/java/org/thoughtcrime/securesms/database/DistributionListTables.kt index 4f8cdd79b0..0707def510 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/DistributionListTables.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/DistributionListTables.kt @@ -7,6 +7,7 @@ import androidx.core.content.contentValuesOf import org.signal.core.util.Base64 import org.signal.core.util.CursorUtil import org.signal.core.util.SqlUtil +import org.signal.core.util.SqlUtil.buildArgs import org.signal.core.util.delete import org.signal.core.util.logging.Log import org.signal.core.util.readToList @@ -526,13 +527,32 @@ class DistributionListTables constructor(context: Context?, databaseHelper: Sign } override fun remapRecipient(fromId: RecipientId, toId: RecipientId) { - val count = writableDatabase - .update(MembershipTable.TABLE_NAME) - .values(MembershipTable.RECIPIENT_ID to toId.serialize()) - .where("${MembershipTable.RECIPIENT_ID} = ?", fromId) - .run(SQLiteDatabase.CONFLICT_REPLACE) + // Remap all recipients that would not result in conflicts + writableDatabase.execSQL( + """ + UPDATE ${MembershipTable.TABLE_NAME} AS parent + SET ${MembershipTable.RECIPIENT_ID} = ? + WHERE + ${MembershipTable.RECIPIENT_ID} = ? + AND NOT EXISTS ( + SELECT 1 + FROM ${MembershipTable.TABLE_NAME} child + WHERE + child.${MembershipTable.RECIPIENT_ID} = ? + AND parent.${MembershipTable.LIST_ID} = child.${MembershipTable.LIST_ID} + AND parent.${MembershipTable.PRIVACY_MODE} = child.${MembershipTable.PRIVACY_MODE} + ) + """, + buildArgs(toId, fromId, toId) + ) - Log.d(TAG, "Remapped $fromId to $toId. count: $count") + // Delete the remaining fromId's (the only remaining ones should be those in lists where the toId is already present) + writableDatabase + .delete(MembershipTable.TABLE_NAME) + .where("${MembershipTable.RECIPIENT_ID} = ?", fromId) + .run() + + Log.d(TAG, "Remapped $fromId to $toId.") } fun deleteList(distributionListId: DistributionListId, deletionTimestamp: Long = System.currentTimeMillis()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt index 0b4771c57c..853c7bec24 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt @@ -1129,10 +1129,14 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da writableDatabase.withinTransaction { for ((originalE164, updatedE164) in mapping) { - writableDatabase.update(TABLE_NAME) - .values(E164 to updatedE164) - .where("$E164 = ?", originalE164) - .run(SQLiteDatabase.CONFLICT_IGNORE) + try { + writableDatabase.update(TABLE_NAME) + .values(E164 to updatedE164) + .where("$E164 = ?", originalE164) + .run() + } catch (_: SQLiteConstraintException) { + Log.w(TAG, "Unable to update e164 due to constraint, ignoring") + } } } } diff --git a/core-util/src/main/java/org/signal/core/util/SQLiteDatabaseExtensions.kt b/core-util/src/main/java/org/signal/core/util/SQLiteDatabaseExtensions.kt index 9b76e5899e..f30692de7b 100644 --- a/core-util/src/main/java/org/signal/core/util/SQLiteDatabaseExtensions.kt +++ b/core-util/src/main/java/org/signal/core/util/SQLiteDatabaseExtensions.kt @@ -464,7 +464,7 @@ class UpdateBuilderPart3( private val whereArgs: Array ) { @JvmOverloads - fun run(conflictStrategy: Int = SQLiteDatabase.CONFLICT_NONE): Int { + fun run(): Int { val query = StringBuilder("UPDATE $tableName SET ") val contentValuesKeys = values.keySet() @@ -477,16 +477,6 @@ class UpdateBuilderPart3( query.append(" WHERE ").append(where) - val conflictString = when (conflictStrategy) { - SQLiteDatabase.CONFLICT_IGNORE -> " ON CONFLICT IGNORE" - SQLiteDatabase.CONFLICT_ABORT -> " ON CONFLICT ABORT" - SQLiteDatabase.CONFLICT_FAIL -> " ON CONFLICT FAIL" - SQLiteDatabase.CONFLICT_ROLLBACK -> " ON CONFLICT ROLLBACK" - SQLiteDatabase.CONFLICT_REPLACE -> " ON CONFLICT REPLACE" - else -> "" - } - query.append(conflictString) - val statement = db.compileStatement(query.toString()) var bindIndex = 1 for (key in contentValuesKeys) {