I have a room database in my Android app. A recent change has resulted in crashes:
Fatal Exception: android.database.sqlite.SQLiteException: cannot start a transaction within a transaction (code 1 SQLITE_ERROR[1])
at android.database.sqlite.SQLiteConnection.nativeExecute(SQLiteConnection.java)
at android.database.sqlite.SQLiteConnection.execute(SQLiteConnection.java:1033)
at android.database.sqlite.SQLiteSession.beginTransactionUnchecked(SQLiteSession.java:321)
at android.database.sqlite.SQLiteSession.beginTransaction(SQLiteSession.java:300)
at android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:970)
at android.database.sqlite.SQLiteDatabase.beginTransactionNonExclusive(SQLiteDatabase.java:904)
at androidx.sqlite.db.framework.FrameworkSQLiteDatabase.beginTransactionNonExclusive(FrameworkSQLiteDatabase.kt:59)
at androidx.room.RoomDatabase.internalBeginTransaction(RoomDatabase.kt:527)
at androidx.room.RoomDatabase.beginTransaction(RoomDatabase.kt:511)
at myapp.data.dao.DocumentDao_Impl$updatePosition$2.call(DocumentDao_Impl.java:1576)
at myapp.data.dao.DocumentDao_Impl$updatePosition$2.call(DocumentDao_Impl.java:1566)
at androidx.room.CoroutinesRoom$Companion$execute$2.invokeSuspend(CoroutinesRoom.kt:64)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
at androidx.room.TransactionExecutor.execute$lambda$1$lambda$0(TransactionExecutor.java:36)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at java.lang.Thread.run(Thread.java:1012)
The dao for the call is:
@Query("update document set bookmarkLocation=:position, bookmarkLength=:length where documentId=:documentId")
abstract suspend fun updatePosition(
documentId: String,
position: Int,
length: Int
)
Its not using a transaction. There's nothing above it that starts a transaction. There's nothing tricky about the entity. I don't get it, I've used Room extensively. Why is this simple update causing an issue? This is happening in production. I've don't see it in testing. In production it's causing crashes for about 1% of my users.
After making some changes to some of my tests, the tests started reproducing the issue. It was actually, a different call than I originally thought.
adding @Transaction to the doa entry solved the issue:
so it now looks like:
@Query("UPDATE cursor_position SET cursorPosition = :cursorPosition, cursorLength = :cursorLength WHERE documentId = :documentId")
@Transaction
abstract suspend fun updateCursorPosition(
documentId: String,
cursorPosition: Int,
cursorLength: Int
): Int