Remove unique constraint from dlist table.

This commit is contained in:
Greyson Parrelli
2023-11-20 06:20:28 -08:00
committed by Cody Henthorne
parent dd871b64ea
commit 428f963243
3 changed files with 117 additions and 5 deletions

View File

@@ -88,9 +88,9 @@ class DistributionListTables constructor(context: Context?, databaseHelper: Sign
val CREATE_TABLE = """
CREATE TABLE $TABLE_NAME (
$ID INTEGER PRIMARY KEY AUTOINCREMENT,
$NAME TEXT UNIQUE NOT NULL,
$NAME TEXT NOT NULL,
$DISTRIBUTION_ID TEXT UNIQUE NOT NULL,
$RECIPIENT_ID INTEGER UNIQUE REFERENCES ${RecipientTable.TABLE_NAME} (${RecipientTable.ID}),
$RECIPIENT_ID INTEGER UNIQUE REFERENCES ${RecipientTable.TABLE_NAME} (${RecipientTable.ID}) ON DELETE CASCADE,
$ALLOWS_REPLIES INTEGER DEFAULT 1,
$DELETION_TIMESTAMP INTEGER DEFAULT 0,
$IS_UNKNOWN INTEGER DEFAULT 0,
@@ -118,7 +118,7 @@ class DistributionListTables constructor(context: Context?, databaseHelper: Sign
CREATE TABLE $TABLE_NAME (
$ID INTEGER PRIMARY KEY AUTOINCREMENT,
$LIST_ID INTEGER NOT NULL REFERENCES ${ListTable.TABLE_NAME} (${ListTable.ID}) ON DELETE CASCADE,
$RECIPIENT_ID INTEGER NOT NULL REFERENCES ${RecipientTable.TABLE_NAME} (${RecipientTable.ID}),
$RECIPIENT_ID INTEGER NOT NULL REFERENCES ${RecipientTable.TABLE_NAME} (${RecipientTable.ID}) ON DELETE CASCADE,
$PRIVACY_MODE INTEGER DEFAULT 0
)
"""

View File

@@ -68,6 +68,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V207_AddChunkSizeCo
import org.thoughtcrime.securesms.database.helpers.migration.V209_ClearRecipientPniFromAciColumn
import org.thoughtcrime.securesms.database.helpers.migration.V210_FixPniPossibleColumns
import org.thoughtcrime.securesms.database.helpers.migration.V211_ReceiptColumnRenames
import org.thoughtcrime.securesms.database.helpers.migration.V212_RemoveDistributionListUniqueConstraint
/**
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
@@ -76,7 +77,7 @@ object SignalDatabaseMigrations {
val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
const val DATABASE_VERSION = 211
const val DATABASE_VERSION = 212
private val migrations: List<Pair<Int, SignalDatabaseMigration>> = listOf(
149 to V149_LegacyMigrations,
@@ -141,7 +142,8 @@ object SignalDatabaseMigrations {
// 208 was a bad migration that only manipulated data and did not change schema, replaced by 209
209 to V209_ClearRecipientPniFromAciColumn,
210 to V210_FixPniPossibleColumns,
211 to V211_ReceiptColumnRenames
211 to V211_ReceiptColumnRenames,
212 to V212_RemoveDistributionListUniqueConstraint
)
@JvmStatic

View File

@@ -0,0 +1,110 @@
/*
* Copyright 2023 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
import org.signal.core.util.SqlUtil
import org.signal.core.util.Stopwatch
import org.signal.core.util.logging.Log
/**
* The android app was the only one enforcing unique story names.
* It's been decided dupes are ok, so we get to do the table recreation dance.
*/
object V212_RemoveDistributionListUniqueConstraint : SignalDatabaseMigration {
private val TAG = Log.tag(V212_RemoveDistributionListUniqueConstraint::class.java)
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
val stopwatch = Stopwatch("migration")
rebuildMainTable(db)
stopwatch.split("main-table")
rebuildMembershipTable(db)
stopwatch.split("members-table")
val foreignKeyViolations: List<SqlUtil.ForeignKeyViolation> = SqlUtil.getForeignKeyViolations(db, "distribution_list") + SqlUtil.getForeignKeyViolations(db, "distribution_list_member")
if (foreignKeyViolations.isNotEmpty()) {
Log.w(TAG, "Foreign key violations!\n${foreignKeyViolations.joinToString(separator = "\n")}")
throw IllegalStateException("Foreign key violations!")
}
stopwatch.split("fk-check")
stopwatch.stop(TAG)
}
private fun rebuildMainTable(db: SQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE distribution_list_tmp (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
distribution_id TEXT UNIQUE NOT NULL,
recipient_id INTEGER UNIQUE REFERENCES recipient (_id) ON DELETE CASCADE,
allows_replies INTEGER DEFAULT 1,
deletion_timestamp INTEGER DEFAULT 0,
is_unknown INTEGER DEFAULT 0,
privacy_mode INTEGER DEFAULT 0
)
"""
)
db.execSQL(
"""
INSERT INTO distribution_list_tmp
SELECT
_id,
name,
distribution_id,
recipient_id,
allows_replies,
deletion_timestamp,
is_unknown,
privacy_mode
FROM distribution_list
"""
)
db.execSQL("DROP TABLE distribution_list")
db.execSQL("ALTER TABLE distribution_list_tmp RENAME TO distribution_list")
}
private fun rebuildMembershipTable(db: SQLiteDatabase) {
db.execSQL("DROP INDEX distribution_list_member_list_id_recipient_id_privacy_mode_index")
db.execSQL("DROP INDEX distribution_list_member_recipient_id")
db.execSQL(
"""
CREATE TABLE distribution_list_member_tmp (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
list_id INTEGER NOT NULL REFERENCES distribution_list (_id) ON DELETE CASCADE,
recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,
privacy_mode INTEGER DEFAULT 0
)
"""
)
db.execSQL(
"""
INSERT INTO distribution_list_member_tmp
SELECT
_id,
list_id,
recipient_id,
privacy_mode
FROM distribution_list_member
"""
)
db.execSQL("DROP TABLE distribution_list_member")
db.execSQL("ALTER TABLE distribution_list_member_tmp RENAME TO distribution_list_member")
db.execSQL("CREATE UNIQUE INDEX distribution_list_member_list_id_recipient_id_privacy_mode_index ON distribution_list_member (list_id, recipient_id, privacy_mode)")
db.execSQL("CREATE INDEX distribution_list_member_recipient_id ON distribution_list_member (recipient_id)")
}
}