mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-22 20:18:36 +00:00
Get a big backupV2 import fully working.
This commit is contained in:
@@ -6,6 +6,12 @@ import android.database.sqlite.SQLiteDatabase
|
||||
import androidx.core.content.contentValuesOf
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteQueryBuilder
|
||||
import org.signal.core.util.SqlUtil.ForeignKeyViolation
|
||||
import org.signal.core.util.logging.Log
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
private val TAG = "SQLiteDatabaseExtensions"
|
||||
|
||||
/**
|
||||
* Begins a transaction on the `this` database, runs the provided [block] providing the `this` value as it's argument
|
||||
@@ -46,7 +52,11 @@ fun SupportSQLiteDatabase.getAllTables(): List<String> {
|
||||
* Returns a list of objects that represent the table definitions in the database. Basically the table name and then the SQL that was used to create it.
|
||||
*/
|
||||
fun SupportSQLiteDatabase.getAllTableDefinitions(): List<CreateStatement> {
|
||||
return this.query("SELECT name, sql FROM sqlite_schema WHERE type = 'table' AND sql NOT NULL AND name != 'sqlite_sequence'")
|
||||
return this
|
||||
.select("name", "sql")
|
||||
.from("sqlite_schema")
|
||||
.where("type = ? AND sql NOT NULL AND name != ?", "table", "sqlite_sequence")
|
||||
.run()
|
||||
.readToList { cursor ->
|
||||
CreateStatement(
|
||||
name = cursor.requireNonNullString("name"),
|
||||
@@ -61,7 +71,11 @@ fun SupportSQLiteDatabase.getAllTableDefinitions(): List<CreateStatement> {
|
||||
* Returns a list of objects that represent the index definitions in the database. Basically the index name and then the SQL that was used to create it.
|
||||
*/
|
||||
fun SupportSQLiteDatabase.getAllIndexDefinitions(): List<CreateStatement> {
|
||||
return this.query("SELECT name, sql FROM sqlite_schema WHERE type = 'index' AND sql NOT NULL")
|
||||
return this
|
||||
.select("name", "sql")
|
||||
.from("sqlite_schema")
|
||||
.where("type = ? AND sql NOT NULL", "index")
|
||||
.run()
|
||||
.readToList { cursor ->
|
||||
CreateStatement(
|
||||
name = cursor.requireNonNullString("name"),
|
||||
@@ -71,6 +85,24 @@ fun SupportSQLiteDatabase.getAllIndexDefinitions(): List<CreateStatement> {
|
||||
.sortedBy { it.name }
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the names of all triggers, sorted alphabetically.
|
||||
*/
|
||||
fun SupportSQLiteDatabase.getAllTriggerDefinitions(): List<CreateStatement> {
|
||||
return this
|
||||
.select("name", "sql")
|
||||
.from("sqlite_schema")
|
||||
.where("type = ? AND sql NOT NULL", "trigger")
|
||||
.run()
|
||||
.readToList {
|
||||
CreateStatement(
|
||||
name = it.requireNonNullString("name"),
|
||||
statement = it.requireNonNullString("sql")
|
||||
)
|
||||
}
|
||||
.sortedBy { it.name }
|
||||
}
|
||||
|
||||
fun SupportSQLiteDatabase.getForeignKeys(): List<ForeignKeyConstraint> {
|
||||
return SqlUtil.getAllTables(this)
|
||||
.map { table ->
|
||||
@@ -93,6 +125,24 @@ fun SupportSQLiteDatabase.areForeignKeyConstraintsEnabled(): Boolean {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of all foreign key violations present.
|
||||
* If a [targetTable] is specified, results will be limited to that table specifically.
|
||||
* Otherwise, the check will be performed across all tables.
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun SupportSQLiteDatabase.getForeignKeyViolations(targetTable: String? = null): List<ForeignKeyViolation> {
|
||||
return SqlUtil.getForeignKeyViolations(this, targetTable)
|
||||
}
|
||||
|
||||
/**
|
||||
* For tables that have an autoincrementing primary key, this will reset the key to start back at 1.
|
||||
* IMPORTANT: This is quite dangerous! Only do this if you're effectively resetting the entire database.
|
||||
*/
|
||||
fun SupportSQLiteDatabase.resetAutoIncrementValue(targetTable: String) {
|
||||
SqlUtil.resetAutoIncrementValue(this, targetTable)
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a full WAL checkpoint (TRUNCATE mode, where the log is for sure flushed and the log is zero'd out).
|
||||
* Will try up to [maxAttempts] times. Can technically fail if the database is too active and the checkpoint
|
||||
@@ -132,6 +182,22 @@ fun SupportSQLiteDatabase.getIndexes(): List<Index> {
|
||||
}
|
||||
}
|
||||
|
||||
fun SupportSQLiteDatabase.forceForeignKeyConstraintsEnabled(enabled: Boolean, timeout: Duration = 10.seconds) {
|
||||
val startTime = System.currentTimeMillis()
|
||||
while (true) {
|
||||
try {
|
||||
this.setForeignKeyConstraintsEnabled(enabled)
|
||||
break
|
||||
} catch (e: IllegalStateException) {
|
||||
if (System.currentTimeMillis() - startTime > timeout.inWholeMilliseconds) {
|
||||
throw IllegalStateException("Failed to force foreign keys to '$enabled' within the timeout of $timeout", e)
|
||||
}
|
||||
Log.w(TAG, "Failed to set foreign keys because we're in a transaction. Waiting 100ms then trying again.")
|
||||
ThreadUtil.sleep(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a row exists that matches the query.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user