Fixed
Status Update
Comments
yb...@google.com <yb...@google.com> #2
i think it is fine, according to how RX works, we need to use the suscription thread.
we don't do it for flowable because we don't have a way to pass non-query args (e.g. scheduler) in query parameters.
we don't do it for flowable because we don't have a way to pass non-query args (e.g. scheduler) in query parameters.
da...@google.com <da...@google.com> #3
Part of the issue is that the generated code eagerly prepares the query to avoid any mutation on the params, so even if a subscription thread is used, the invocation of the DAO method in the main thread will cause the exception. A have a fix in progress that just moves the query preparing and binding to the callable used for the Rx, it does mean that if a mutable list is passed as query params and such list is mutated before the query executes then the expected query result will be wrong. However, it is somewhat reasonable to assume developers using reactive paradigms understand such implications and thus data is passed along the stream and is not kept at a higher scope where it can be mutated.
ap...@google.com <ap...@google.com> #4
Project: platform/frameworks/support
Branch: androidx-master-dev
commit 65e8fda6d3506a52e490e3b2dc8a649697e96551
Author: Daniel Santiago Rivera <danysantiago@google.com>
Date: Thu Jan 31 15:16:15 2019
Compile / prepare queries lazily for prepared query DAO methods.
This change makes it so that the sql statement is prepared / compiled
lazily for deferred INSERT, UPDATE or DELETE DAO methods with @Query.
This avoids performing IO in the main thread due to the sql statement
being eagerly prepare.
Bug: 123695593
Test: ./gradlew room:room-compiler:test \
room:integration-tests:room-testapp-kotlin:cC \
room:integration-tests:room-testapp:cC
Change-Id: If5d6755fa97d1cf521889dc5680c77c4347ba221
M room/compiler/src/main/kotlin/androidx/room/solver/prepared/binder/CallablePreparedQueryResultBinder.kt
M room/compiler/src/main/kotlin/androidx/room/solver/prepared/binder/InstantPreparedQueryResultBinder.kt
M room/compiler/src/main/kotlin/androidx/room/solver/prepared/binder/PreparedQueryResultBinder.kt
M room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
M room/compiler/src/test/data/daoWriter/output/DeletionDao.java
M room/compiler/src/test/data/daoWriter/output/UpdateDao.java
M room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/RxJava2QueryTest.kt
https://android-review.googlesource.com/891677
https://goto.google.com/android-sha1/65e8fda6d3506a52e490e3b2dc8a649697e96551
Branch: androidx-master-dev
commit 65e8fda6d3506a52e490e3b2dc8a649697e96551
Author: Daniel Santiago Rivera <danysantiago@google.com>
Date: Thu Jan 31 15:16:15 2019
Compile / prepare queries lazily for prepared query DAO methods.
This change makes it so that the sql statement is prepared / compiled
lazily for deferred INSERT, UPDATE or DELETE DAO methods with @Query.
This avoids performing IO in the main thread due to the sql statement
being eagerly prepare.
Bug: 123695593
Test: ./gradlew room:room-compiler:test \
room:integration-tests:room-testapp-kotlin:cC \
room:integration-tests:room-testapp:cC
Change-Id: If5d6755fa97d1cf521889dc5680c77c4347ba221
M room/compiler/src/main/kotlin/androidx/room/solver/prepared/binder/CallablePreparedQueryResultBinder.kt
M room/compiler/src/main/kotlin/androidx/room/solver/prepared/binder/InstantPreparedQueryResultBinder.kt
M room/compiler/src/main/kotlin/androidx/room/solver/prepared/binder/PreparedQueryResultBinder.kt
M room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
M room/compiler/src/test/data/daoWriter/output/DeletionDao.java
M room/compiler/src/test/data/daoWriter/output/UpdateDao.java
M room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/RxJava2QueryTest.kt
da...@google.com <da...@google.com> #5
A fix for this will be available in Room 2.1.0-alpha05
al...@gmail.com <al...@gmail.com> #6
Not fixed in Beta 1
The code in DAO:
@Query("DELETE FROM project WHERE id = :projectId")
abstract fun deleteById(projectId: String): Completable
generates the following in DAO impl:
@Override
public Completable deleteById(final String projectId) {
final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteById.acquire();
int _argIndex = 1;
if (projectId == null) {
_stmt.bindNull(_argIndex);
} else {
_stmt.bindString(_argIndex, projectId);
}
return Completable.fromCallable(new Callable<Void>() {
@Override
public Void call() throws Exception {
__db.beginTransaction();
try {
_stmt.executeUpdateDelete();
__db.setTransactionSuccessful();
return null;
} finally {
__db.endTransaction();
__preparedStmtOfDeleteById.release(_stmt);
}
}
});
}
In this code, __preparedStmtOfDeleteById.acquire() is executed on main thread and crashes the app.
The code in DAO:
@Query("DELETE FROM project WHERE id = :projectId")
abstract fun deleteById(projectId: String): Completable
generates the following in DAO impl:
@Override
public Completable deleteById(final String projectId) {
final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteById.acquire();
int _argIndex = 1;
if (projectId == null) {
_stmt.bindNull(_argIndex);
} else {
_stmt.bindString(_argIndex, projectId);
}
return Completable.fromCallable(new Callable<Void>() {
@Override
public Void call() throws Exception {
__db.beginTransaction();
try {
_stmt.executeUpdateDelete();
__db.setTransactionSuccessful();
return null;
} finally {
__db.endTransaction();
__preparedStmtOfDeleteById.release(_stmt);
}
}
});
}
In this code, __preparedStmtOfDeleteById.acquire() is executed on main thread and crashes the app.
al...@gmail.com <al...@gmail.com> #7
Sorry, ignore my comment above, it was my mistake.
Description
@Query("DELETE FROM book WHERE salesCnt = 0")
fun deleteUnsoldBooksSingle(): Single<Int>
will throw a main thread DB access exception if its called from the main thread since the sql compile / acquire invocation is done immediately while the actually execution of the query and data parsing is deferred.