#336 hacky way to recover from SQLiteException while inserting old data

This commit is contained in:
Julian Raufelder 2021-07-23 16:42:34 +02:00
parent 05574d952c
commit a018cbd898
No known key found for this signature in database
GPG Key ID: 17EE71F6634E381D
2 changed files with 80 additions and 5 deletions

View File

@ -299,6 +299,50 @@ class UpgradeDatabaseTest {
}
}
@Test
fun recoverUpgrade6to7DueToSQLiteExceptionThrown() {
Upgrade0To1().applyTo(db, 0)
Upgrade1To2().applyTo(db, 1)
Upgrade2To3(context).applyTo(db, 2)
Upgrade3To4().applyTo(db, 3)
Upgrade4To5().applyTo(db, 4)
Upgrade5To6().applyTo(db, 5)
val licenseToken = "licenseToken"
Sql.update("UPDATE_CHECK_ENTITY")
.set("LICENSE_TOKEN", Sql.toString(licenseToken))
.set("RELEASE_NOTE", Sql.toString("releaseNote"))
.set("VERSION", Sql.toString("version"))
.set("URL_TO_APK", Sql.toString("urlApk"))
.set("URL_TO_RELEASE_NOTE", Sql.toString("urlReleaseNote"))
.executeOn(db)
Sql.alterTable("UPDATE_CHECK_ENTITY").renameTo("UPDATE_CHECK_ENTITY_OLD").executeOn(db)
Sql.createTable("UPDATE_CHECK_ENTITY") //
.id() //
.optionalText("LICENSE_TOKEN") //
.optionalText("RELEASE_NOTE") //
.optionalText("VERSION") //
.optionalText("URL_TO_APK") //
.optionalText("APK_SHA256") //
.optionalText("URL_TO_RELEASE_NOTE") //
.executeOn(db)
Upgrade6To7().tryToRecoverFromSQLiteException(db)
Sql.query("UPDATE_CHECK_ENTITY").executeOn(db).use {
it.moveToFirst()
Assert.assertThat(it.getString(it.getColumnIndex("LICENSE_TOKEN")), CoreMatchers.`is`(licenseToken))
Assert.assertThat(it.getString(it.getColumnIndex("RELEASE_NOTE")), CoreMatchers.nullValue())
Assert.assertThat(it.getString(it.getColumnIndex("VERSION")), CoreMatchers.nullValue())
Assert.assertThat(it.getString(it.getColumnIndex("URL_TO_APK")), CoreMatchers.nullValue())
Assert.assertThat(it.getString(it.getColumnIndex("APK_SHA256")), CoreMatchers.nullValue())
Assert.assertThat(it.getString(it.getColumnIndex("URL_TO_RELEASE_NOTE")), CoreMatchers.nullValue())
}
}
@Test
fun upgrade7To8() {
Upgrade0To1().applyTo(db, 0)

View File

@ -1,8 +1,10 @@
package org.cryptomator.data.db
import android.database.sqlite.SQLiteException
import org.greenrobot.greendao.database.Database
import javax.inject.Inject
import javax.inject.Singleton
import timber.log.Timber
@Singleton
internal class Upgrade6To7 @Inject constructor() : DatabaseUpgrade(6, 7) {
@ -30,12 +32,41 @@ internal class Upgrade6To7 @Inject constructor() : DatabaseUpgrade(6, 7) {
.optionalText("URL_TO_RELEASE_NOTE") //
.executeOn(db)
Sql.insertInto("UPDATE_CHECK_ENTITY") //
.select("_id", "LICENSE_TOKEN", "RELEASE_NOTE", "VERSION", "URL_TO_APK", "URL_TO_RELEASE_NOTE") //
.columns("_id", "LICENSE_TOKEN", "RELEASE_NOTE", "VERSION", "URL_TO_APK", "URL_TO_RELEASE_NOTE") //
.from("UPDATE_CHECK_ENTITY_OLD") //
.executeOn(db)
try {
Sql.insertInto("UPDATE_CHECK_ENTITY") //
.select("_id", "LICENSE_TOKEN", "RELEASE_NOTE", "VERSION", "URL_TO_APK", "URL_TO_RELEASE_NOTE") //
.columns("_id", "LICENSE_TOKEN", "RELEASE_NOTE", "VERSION", "URL_TO_APK", "URL_TO_RELEASE_NOTE") //
.from("UPDATE_CHECK_ENTITY_OLD") //
.executeOn(db)
} catch (e: SQLiteException) {
Timber.tag("Upgrade6To7").e(e, "Failed to recover data from old update check entity, insert new initial entry. More details in #336")
tryToRecoverFromSQLiteException(db)
}
Sql.dropTable("UPDATE_CHECK_ENTITY_OLD").executeOn(db)
}
fun tryToRecoverFromSQLiteException(db: Database) {
var licenseToken: String? = null
try {
Sql.query("UPDATE_CHECK_ENTITY_OLD").executeOn(db).use {
if (it.moveToNext()) {
licenseToken = it.getString(it.getColumnIndex("LICENSE_TOKEN"))
}
}
} catch (e: SQLiteException) {
Timber.tag("Upgrade6To7").e(e, "Failed to recover license token while recovery, clear license token if used.")
}
Sql.insertInto("UPDATE_CHECK_ENTITY") //
.integer("_id", 1) //
.text("LICENSE_TOKEN", licenseToken) //
.text("RELEASE_NOTE", null) //
.text("VERSION", null) //
.text("URL_TO_APK", null) //
.text("APK_SHA256", null) //
.text("URL_TO_RELEASE_NOTE", null) //
.executeOn(db)
}
}