Skip to content

Commit

Permalink
fixes #1141
Browse files Browse the repository at this point in the history
  • Loading branch information
mtotschnig committed Feb 18, 2023
1 parent 0810ccf commit 0383515
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@ import androidx.datastore.preferences.preferencesDataStoreFile
import androidx.preference.PreferenceManager
import androidx.sqlite.db.SupportSQLiteOpenHelper
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import com.getkeepsafe.relinker.ReLinker
import com.squareup.sqlbrite3.SqlBrite
import dagger.Module
import dagger.Provides
import io.reactivex.schedulers.Schedulers
import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
import org.totschnig.myexpenses.BuildConfig
import org.totschnig.myexpenses.MyApplication
import org.totschnig.myexpenses.preference.PrefHandler
import org.totschnig.myexpenses.preference.PrefHandlerImpl
import org.totschnig.myexpenses.preference.PrefKey
import org.totschnig.myexpenses.provider.DatabaseVersionPeekHelper
import org.totschnig.myexpenses.provider.TransactionDatabase
import timber.log.Timber
Expand All @@ -34,7 +33,7 @@ interface SqlCryptProvider {
}

@Module
open class DataModule(private val frameWorkSqlite: Boolean = false) {
open class DataModule {
companion object {
val cryptProvider: SqlCryptProvider
get() = Class.forName("org.totschnig.sqlcrypt.SQLiteOpenHelperFactory")
Expand All @@ -43,6 +42,8 @@ open class DataModule(private val frameWorkSqlite: Boolean = false) {

open val databaseName = "data"

private fun frameWorkSqlite(prefHandler: PrefHandler) = prefHandler.getBoolean(PrefKey.REPAIRED_REQUERY_SCHEMA, false)

@Provides
@Named(AppComponent.DATABASE_NAME)
@Singleton
Expand Down Expand Up @@ -85,7 +86,8 @@ open class DataModule(private val frameWorkSqlite: Boolean = false) {
prefHandler: PrefHandler,
@Named(AppComponent.DATABASE_NAME) provideDatabaseName: (@JvmSuppressWildcards Boolean) -> String
): SupportSQLiteOpenHelper {
Timber.w("building SupportSQLiteOpenHelper")
val frameWorkSqlite = frameWorkSqlite(prefHandler)
Timber.w("building SupportSQLiteOpenHelper - frameWorkSqlite: $frameWorkSqlite")
val encryptDatabase = prefHandler.encryptDatabase
return when {
encryptDatabase -> cryptProvider.provideEncryptedDatabase(appContext)
Expand All @@ -95,7 +97,7 @@ open class DataModule(private val frameWorkSqlite: Boolean = false) {
SupportSQLiteOpenHelper.Configuration.builder(appContext)
.name(provideDatabaseName(encryptDatabase)).callback(
//Robolectric uses native Sqlite which as of now does not include Json extension
TransactionDatabase(!frameWorkSqlite)
TransactionDatabase(prefHandler)
).build()
).also {
it.setWriteAheadLoggingEnabled(false)
Expand All @@ -104,10 +106,10 @@ open class DataModule(private val frameWorkSqlite: Boolean = false) {

@Singleton
@Provides
open fun providePeekHelper(): DatabaseVersionPeekHelper =
open fun providePeekHelper(prefHandler: PrefHandler): DatabaseVersionPeekHelper =
DatabaseVersionPeekHelper { path ->
when {
frameWorkSqlite -> {
frameWorkSqlite(prefHandler) -> {
SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY).use {
it.version
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,9 @@ enum class PrefKey {
UI_ITEM_RENDERER_LEGACY(R.string.pref_ui_item_renderer_legacy_key),
UI_ITEM_RENDERER_CATEGORY_ICON(R.string.pref_ui_item_renderer_category_icon_key),
ENCRYPT_DATABASE("encrypt_database"),
ENCRYPT_DATABASE_INFO(R.string.pref_encrypt_database_info_key);
ENCRYPT_DATABASE_INFO(R.string.pref_encrypt_database_info_key),
REPAIRED_REQUERY_SCHEMA("repaired_requery_schema")
;

internal val resId: Int

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.db.SupportSQLiteOpenHelper
import org.totschnig.myexpenses.model.CurrencyEnum
import org.totschnig.myexpenses.model.Model
import org.totschnig.myexpenses.preference.PrefHandler
import org.totschnig.myexpenses.preference.PrefKey
import org.totschnig.myexpenses.provider.DatabaseConstants.*
import timber.log.Timber

const val DATABASE_VERSION = 133
const val DATABASE_VERSION = 134

private const val RAISE_UPDATE_SEALED_DEBT = "SELECT RAISE (FAIL, 'attempt to update sealed debt');"
private const val RAISE_INCONSISTENT_CATEGORY_HIERARCHY =
Expand Down Expand Up @@ -84,7 +85,7 @@ END
"""


abstract class BaseTransactionDatabase :
abstract class BaseTransactionDatabase(val prefHandler: PrefHandler) :
SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {

fun upgradeTo117(db: SupportSQLiteDatabase) {
Expand Down Expand Up @@ -275,7 +276,7 @@ abstract class BaseTransactionDatabase :
}

override fun onCreate(db: SupportSQLiteDatabase) {
PrefKey.FIRST_INSTALL_DB_SCHEMA_VERSION.putInt(DATABASE_VERSION)
prefHandler.putInt(PrefKey.FIRST_INSTALL_DB_SCHEMA_VERSION, DATABASE_VERSION)
}

private fun upgradeIcons(db: SupportSQLiteDatabase, map: Map<String, String>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,4 @@ with data as
exists(select 1 from data where $KEY_TAGID is not null) AS $KEY_MAPPED_TAGS
""".trimIndent()

fun tagListExpression(supportsJson: Boolean) = if (supportsJson) {
"json_group_array($TABLE_TAGS.$KEY_LABEL) filter ( where $TABLE_TAGS.$KEY_LABEL is not null ) AS $KEY_TAGLIST"
} else {
"group_concat($TABLE_TAGS.$KEY_LABEL, ', ') AS $KEY_TAGLIST"

}
const val TAG_LIST_EXPRESSION = "group_concat($TABLE_TAGS.$KEY_LABEL,'') AS $KEY_TAGLIST"
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ import androidx.core.database.getStringOrNull
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.db.SupportSQLiteQueryBuilder
import androidx.sqlite.db.SupportSQLiteStatement
import com.google.gson.Gson
import com.google.gson.JsonSyntaxException
import com.google.gson.reflect.TypeToken
import org.totschnig.myexpenses.MyApplication
import org.totschnig.myexpenses.R
import org.totschnig.myexpenses.model.PaymentMethod
Expand All @@ -37,7 +34,6 @@ import org.totschnig.myexpenses.util.Utils
import org.totschnig.myexpenses.util.crashreporting.CrashHandler
import timber.log.Timber
import java.io.File
import java.lang.reflect.Type

fun safeUpdateWithSealed(db: SupportSQLiteDatabase, runnable: Runnable) {
db.beginTransaction()
Expand Down Expand Up @@ -284,17 +280,7 @@ fun Cursor.getLongIfExistsOr0(column: String) = getColumnIndex(column).takeIf {
fun Cursor.getStringIfExists(column: String) = getColumnIndex(column).takeIf { it != -1 }?.let { getString(it) }
fun Cursor.getBoolean(column: String) = getInt(column) == 1

private val typeToken: Type = object : TypeToken<List<String>>() {}.type
private val gson = Gson()
fun Cursor.getStringListFromJson(colum: String) = getString(colum).let {
try {
gson.fromJson<List<String>>(it, typeToken)
} catch (e: JsonSyntaxException) {
// on Robolectric we run without json support, if we ever use an SQLITE version
//Without JSON extension in production, we need to change this
null
} ?: if (it.isEmpty()) emptyList() else it.split(',')
}
fun Cursor.splitQuotedStringList(colum: String) = getString(colum).split('')

fun cacheSyncState(context: Context) {
val accountManager = AccountManager.get(context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static android.database.sqlite.SQLiteDatabase.CONFLICT_NONE;
import static org.totschnig.myexpenses.provider.BaseTransactionDatabaseKt.ACCOUNT_REMAP_TRANSFER_TRIGGER_CREATE;
import static org.totschnig.myexpenses.provider.DatabaseConstants.*;
import static org.totschnig.myexpenses.provider.DbConstantsKt.TAG_LIST_EXPRESSION;
import static org.totschnig.myexpenses.util.ColorUtils.MAIN_COLORS;
import static org.totschnig.myexpenses.util.PermissionHelper.PermissionGroup.CALENDAR;

Expand Down Expand Up @@ -49,6 +50,7 @@
import org.totschnig.myexpenses.model.Plan;
import org.totschnig.myexpenses.model.PreDefinedPaymentMethod;
import org.totschnig.myexpenses.model.Template;
import org.totschnig.myexpenses.preference.PrefHandler;
import org.totschnig.myexpenses.preference.PrefKey;
import org.totschnig.myexpenses.sync.json.TransactionChange;
import org.totschnig.myexpenses.util.PictureDirHelper;
Expand All @@ -62,20 +64,6 @@

public class TransactionDatabase extends BaseTransactionDatabase {

private final boolean supportsJson;

/**
*
* @param supportsJson
* If true, it is assumed that we can rely on SQLITE's JSON extension. This parameter is used when
* creating views, so changing the value has only effect, if the database version is incremented
* and {@link #createOrRefreshViews(SupportSQLiteDatabase)} is called in
* {@link #onUpgrade(SupportSQLiteDatabase, int, int)}.
*/
public TransactionDatabase(boolean supportsJson) {
this.supportsJson = supportsJson;
}

/**
* SQL statement for expenses TABLE
* both transactions and transfers are stored in this table
Expand Down Expand Up @@ -114,6 +102,10 @@ public TransactionDatabase(boolean supportsJson) {
private static final String TRANSACTIONS_UUID_INDEX_CREATE = "CREATE UNIQUE INDEX transactions_account_uuid_index ON "
+ TABLE_TRANSACTIONS + "(" + KEY_ACCOUNTID + "," + KEY_UUID + "," + KEY_STATUS + ")";

public TransactionDatabase(@NonNull PrefHandler prefHandler) {
super(prefHandler);
}

public static String TAG_JOIN(String mainTable, String tagTable, String referenceColumn) {
return String.format(Locale.ROOT, " LEFT JOIN %1$s ON %1$s.%2$s = %3$s.%4$s LEFT JOIN %5$s ON %6$s= %5$s.%4$s",
tagTable, referenceColumn, mainTable, KEY_ROWID, TABLE_TAGS, KEY_TAGID);
Expand All @@ -137,7 +129,7 @@ private String buildViewDefinition(String tableName, boolean withTags) {
}

if (withTags) {
stringBuilder.append(", ").append(DbConstantsKt.tagListExpression(supportsJson));
stringBuilder.append(", ").append(TAG_LIST_EXPRESSION);
}

stringBuilder.append(" FROM ").append(tableName)
Expand Down Expand Up @@ -189,7 +181,7 @@ private String buildViewDefinitionExtended(String tableName) {

if (tableName.equals(TABLE_TRANSACTIONS)) {
stringBuilder.append(", ").append(TABLE_PLAN_INSTANCE_STATUS).append(".").append(KEY_TEMPLATEID);
stringBuilder.append(", ").append(DbConstantsKt.tagListExpression(supportsJson));
stringBuilder.append(", ").append(TAG_LIST_EXPRESSION);
}

stringBuilder.append(" FROM ").append(tableName).append(" LEFT JOIN ").append(TABLE_PAYEES).append(" ON ")
Expand Down Expand Up @@ -1538,10 +1530,14 @@ public void onUpgrade(@NonNull SupportSQLiteDatabase db, int oldVersion, int new
}
}
c.close();
String legacy = PrefKey.SORT_ORDER_LEGACY.getString("USAGES");
@SuppressWarnings("deprecation") String legacy = PrefKey.SORT_ORDER_LEGACY.getString("USAGES");
//noinspection deprecation
PrefKey.SORT_ORDER_TEMPLATES.putString(legacy);
//noinspection deprecation
PrefKey.SORT_ORDER_CATEGORIES.putString(legacy);
//noinspection deprecation
PrefKey.SORT_ORDER_ACCOUNTS.putString(hasAccountSortKeySet ? "CUSTOM" : legacy);
//noinspection deprecation
PrefKey.SORT_ORDER_LEGACY.remove();
}

Expand Down Expand Up @@ -2149,7 +2145,7 @@ public void onUpgrade(@NonNull SupportSQLiteDatabase db, int oldVersion, int new
repairSplitPartDates(db);
}
if (oldVersion < 112) {
String templateDefaultAction = PrefKey.TEMPLATE_CLICK_DEFAULT.getString("SAVE");
String templateDefaultAction = getPrefHandler().requireString(PrefKey.TEMPLATE_CLICK_DEFAULT,"SAVE");
if (!(templateDefaultAction.equals("SAVE") || templateDefaultAction.equals("EDIT"))) {
templateDefaultAction = "SAVE";
}
Expand Down Expand Up @@ -2246,6 +2242,10 @@ public void onUpgrade(@NonNull SupportSQLiteDatabase db, int oldVersion, int new
if (oldVersion < 133) {
upgradeTo133(db);
}
if(oldVersion < 134) {
createOrRefreshViews(db);
getPrefHandler().putBoolean(PrefKey.REPAIRED_REQUERY_SCHEMA, true);
}

TransactionProvider.resumeChangeTrigger(db);
} catch (SQLException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ class TestMyApplication : MyApplication() {
.coroutineModule(object: CoroutineModule() {
override fun provideCoroutineDispatcher() = Dispatchers.Main.immediate
})
.dataModule(DataModule(true))
.build()
}
}

0 comments on commit 0383515

Please sign in to comment.