From 9d1714d45238d73be128beb3cf4ce32696db3eda Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Tue, 28 Apr 2026 16:20:18 -0400 Subject: [PATCH] Fix unique constraint crash when remapping recipients in name collision table. --- .../securesms/database/NameCollisionTables.kt | 14 ++++++-------- .../securesms/database/NameCollisionTablesTest.kt | 11 +++++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/NameCollisionTables.kt b/app/src/main/java/org/thoughtcrime/securesms/database/NameCollisionTables.kt index d6dd384c7c..9c7f3d1098 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/NameCollisionTables.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/NameCollisionTables.kt @@ -280,13 +280,11 @@ class NameCollisionTables( } override fun remapRecipient(fromId: RecipientId, toId: RecipientId) { - val count = writableDatabase - .update(NameCollisionMembershipTable.TABLE_NAME) - .values(NameCollisionMembershipTable.RECIPIENT_ID to toId.serialize()) - .where("${NameCollisionMembershipTable.RECIPIENT_ID} = ?", fromId) - .run() - - Log.d(TAG, "Remapped $fromId to $toId. count: $count") + writableDatabase.execSQL( + "UPDATE OR REPLACE ${NameCollisionMembershipTable.TABLE_NAME} SET ${NameCollisionMembershipTable.RECIPIENT_ID} = ? WHERE ${NameCollisionMembershipTable.RECIPIENT_ID} = ?", + arrayOf(toId.serialize(), fromId.serialize()) + ) + Log.d(TAG, "Remapped $fromId to $toId") } private fun handleNameCollisions( @@ -469,7 +467,7 @@ class NameCollisionTables( SELECT ${NameCollisionMembershipTable.COLLISION_ID} FROM ${NameCollisionMembershipTable.TABLE_NAME} GROUP BY ${NameCollisionMembershipTable.COLLISION_ID} - HAVING COUNT($ID) >= 2 + HAVING COUNT(*) >= 2 ) """.trimIndent() ) diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/NameCollisionTablesTest.kt b/app/src/test/java/org/thoughtcrime/securesms/database/NameCollisionTablesTest.kt index 842290dbcc..6b89cdfafd 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/NameCollisionTablesTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/NameCollisionTablesTest.kt @@ -186,6 +186,17 @@ class NameCollisionTablesTest { assertThat(collisions).hasSize(0) } + @Test + fun givenTwoUsersInTheSameNameCollision_whenIRemapOneToTheOther_thenIExpectNoConstraintViolation() { + setProfileNameAndCheckCollision(alice, ProfileName.fromParts("Bob", "Android")) + setProfileNameAndCheckCollision(bob, ProfileName.fromParts("Bob", "Android")) + + SignalDatabase.nameCollisions.remapRecipient(alice, bob) + + assertThat(SignalDatabase.nameCollisions.getCollisionsForThreadRecipientId(alice)).hasSize(0) + assertThat(SignalDatabase.nameCollisions.getCollisionsForThreadRecipientId(bob)).hasSize(0) + } + private fun setProfileNameAndCheckCollision(recipientId: RecipientId, name: ProfileName) { recipients.setProfileName(recipientId, name) SignalDatabase.nameCollisions.handleIndividualNameCollision(recipientId)