Follow-up CL resolving b/174478034. Adding functionality for handling bind arguments provided for queries.
Test: Tests have been added QueryLoggerTest.kt
Bug: 174478034
Change-Id: Ida02dcdaff6ef22011c3f67adeb9c949fb37fff7
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/QueryInterceptorTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/QueryInterceptorTest.kt
index 4db8a26..a23ce6b 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/QueryInterceptorTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/QueryInterceptorTest.kt
@@ -26,6 +26,7 @@
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.Update
+import androidx.sqlite.db.SimpleSQLiteQuery
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -104,7 +105,7 @@
assertQueryLogged(
"INSERT OR ABORT INTO `queryInterceptorTestDatabase` (`id`,`description`) " +
"VALUES (?,?)",
- emptyList()
+ listOf("Insert", "Inserted a placeholder query")
)
assertTransactionQueries()
}
@@ -112,8 +113,10 @@
@Test
fun testDelete() {
mDatabase.queryInterceptorDao().delete("Insert")
-
- assertQueryLogged("DELETE FROM queryInterceptorTestDatabase WHERE id=?", emptyList())
+ assertQueryLogged(
+ "DELETE FROM queryInterceptorTestDatabase WHERE id=?",
+ listOf("Insert")
+ )
assertTransactionQueries()
}
@@ -130,7 +133,7 @@
"UPDATE OR ABORT `queryInterceptorTestDatabase` SET `id` " +
"= ?,`description` = ? " +
"WHERE `id` = ?",
- emptyList()
+ listOf("Insert", "Updated the placeholder query", "Insert")
)
assertTransactionQueries()
}
@@ -147,17 +150,47 @@
assertQueryLogged("DELETE FROM queryInterceptorTestDatabase WHERE id=?", emptyList())
}
+ @Test
+ fun testLoggingSupportSQLiteQuery() {
+ mDatabase.openHelper.writableDatabase.query(
+ SimpleSQLiteQuery(
+ "INSERT OR ABORT INTO `queryInterceptorTestDatabase` (`id`,`description`) " +
+ "VALUES (?,?)",
+ arrayOf<Any>("3", "Description")
+ )
+ )
+ assertQueryLogged(
+ "INSERT OR ABORT INTO `queryInterceptorTestDatabase` (`id`,`description`) " +
+ "VALUES (?,?)",
+ listOf("3", "Description")
+ )
+ }
+
+ @Test
+ fun testNullBindArgument() {
+ mDatabase.openHelper.writableDatabase.query(
+ SimpleSQLiteQuery(
+ "INSERT OR ABORT INTO `queryInterceptorTestDatabase` (`id`,`description`) " +
+ "VALUES (?,?)",
+ arrayOf("ID", null)
+ )
+ )
+ assertQueryLogged(
+ "INSERT OR ABORT INTO `queryInterceptorTestDatabase` (`id`," +
+ "`description`) VALUES (?,?)",
+ listOf("ID", null)
+ )
+ }
+
private fun assertQueryLogged(
query: String,
- expectedArgs: List<Any>
+ expectedArgs: List<String?>
) {
val filteredQueries = queryAndArgs.filter {
it.first == query
}
assertThat(filteredQueries).hasSize(1)
-
- for (index in expectedArgs.indices)
- assertThat(expectedArgs).containsExactly(filteredQueries[0].second[index])
+ assertThat(expectedArgs).containsExactlyElementsIn(filteredQueries[0].second)
}
private fun assertTransactionQueries() {
diff --git a/room/runtime/src/main/java/androidx/room/QueryInterceptorDatabase.java b/room/runtime/src/main/java/androidx/room/QueryInterceptorDatabase.java
index 23dacc0..c5ef6bc 100644
--- a/room/runtime/src/main/java/androidx/room/QueryInterceptorDatabase.java
+++ b/room/runtime/src/main/java/androidx/room/QueryInterceptorDatabase.java
@@ -31,6 +31,7 @@
import androidx.sqlite.db.SupportSQLiteStatement;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -167,17 +168,20 @@
@NonNull
@Override
public Cursor query(@NonNull String query, @NonNull Object[] bindArgs) {
+ List<Object> inputArguments = new ArrayList<>();
+ inputArguments.addAll(Arrays.asList(bindArgs));
mQueryCallbackExecutor.execute(() -> mQueryCallback.onQuery(query,
- Arrays.asList(bindArgs)));
+ inputArguments));
return mDelegate.query(query, bindArgs);
}
@NonNull
@Override
public Cursor query(@NonNull SupportSQLiteQuery query) {
- // TODO: (b/174478034)
+ QueryInterceptorProgram queryInterceptorProgram = new QueryInterceptorProgram();
+ query.bindTo(queryInterceptorProgram);
mQueryCallbackExecutor.execute(() -> mQueryCallback.onQuery(query.getSql(),
- Collections.emptyList()));
+ queryInterceptorProgram.getBindArgs()));
return mDelegate.query(query);
}
@@ -185,9 +189,10 @@
@Override
public Cursor query(@NonNull SupportSQLiteQuery query,
@NonNull CancellationSignal cancellationSignal) {
- // TODO: (b/174478034)
+ QueryInterceptorProgram queryInterceptorProgram = new QueryInterceptorProgram();
+ query.bindTo(queryInterceptorProgram);
mQueryCallbackExecutor.execute(() -> mQueryCallback.onQuery(query.getSql(),
- Collections.emptyList()));
+ queryInterceptorProgram.getBindArgs()));
return mDelegate.query(query);
}
@@ -213,14 +218,16 @@
@Override
public void execSQL(@NonNull String sql) throws SQLException {
- mQueryCallbackExecutor.execute(() -> mQueryCallback.onQuery(sql, Collections.emptyList()));
+ mQueryCallbackExecutor.execute(() -> mQueryCallback.onQuery(sql, new ArrayList<>(0)));
mDelegate.execSQL(sql);
}
@Override
public void execSQL(@NonNull String sql, @NonNull Object[] bindArgs) throws SQLException {
- mQueryCallbackExecutor.execute(() -> mQueryCallback.onQuery(sql, Arrays.asList(bindArgs)));
- mDelegate.execSQL(sql, bindArgs);
+ List<Object> inputArguments = new ArrayList<>();
+ inputArguments.addAll(Arrays.asList(bindArgs));
+ mQueryCallbackExecutor.execute(() -> mQueryCallback.onQuery(sql, inputArguments));
+ mDelegate.execSQL(sql, inputArguments.toArray());
}
@Override
diff --git a/room/runtime/src/main/java/androidx/room/QueryInterceptorProgram.java b/room/runtime/src/main/java/androidx/room/QueryInterceptorProgram.java
new file mode 100644
index 0000000..2b9c554
--- /dev/null
+++ b/room/runtime/src/main/java/androidx/room/QueryInterceptorProgram.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room;
+
+import androidx.sqlite.db.SupportSQLiteProgram;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A program implementing an {@link SupportSQLiteProgram} API to record bind arguments.
+ */
+final class QueryInterceptorProgram implements SupportSQLiteProgram {
+ private List<Object> mBindArgsCache = new ArrayList<>();
+
+ @Override
+ public void bindNull(int index) {
+ saveArgsToCache(index, null);
+ }
+
+ @Override
+ public void bindLong(int index, long value) {
+ saveArgsToCache(index, value);
+ }
+
+ @Override
+ public void bindDouble(int index, double value) {
+ saveArgsToCache(index, value);
+ }
+
+ @Override
+ public void bindString(int index, String value) {
+ saveArgsToCache(index, value);
+ }
+
+ @Override
+ public void bindBlob(int index, byte[] value) {
+ saveArgsToCache(index, value);
+ }
+
+ @Override
+ public void clearBindings() {
+ mBindArgsCache.clear();
+ }
+
+ @Override
+ public void close() { }
+
+ private void saveArgsToCache(int bindIndex, Object value) {
+ // The index into bind methods are 1...n
+ int index = bindIndex - 1;
+ if (index >= mBindArgsCache.size()) {
+ for (int i = mBindArgsCache.size(); i <= index; i++) {
+ mBindArgsCache.add(null);
+ }
+ }
+ mBindArgsCache.set(index, value);
+ }
+
+ /**
+ * Returns the list of arguments associated with the query.
+ *
+ * @return argument list.
+ */
+ List<Object> getBindArgs() {
+ return mBindArgsCache;
+ }
+}
diff --git a/room/runtime/src/main/java/androidx/room/QueryInterceptorStatement.java b/room/runtime/src/main/java/androidx/room/QueryInterceptorStatement.java
index 6a08500..8825252 100644
--- a/room/runtime/src/main/java/androidx/room/QueryInterceptorStatement.java
+++ b/room/runtime/src/main/java/androidx/room/QueryInterceptorStatement.java
@@ -115,10 +115,13 @@
mDelegate.close();
}
- private void saveArgsToCache(int index, Object value) {
- // Add null entries to the list until we have the desired # of indices
- for (int i = mBindArgsCache.size(); i <= index; i++) {
- mBindArgsCache.add(null);
+ private void saveArgsToCache(int bindIndex, Object value) {
+ int index = bindIndex - 1;
+ if (index >= mBindArgsCache.size()) {
+ // Add null entries to the list until we have the desired # of indices
+ for (int i = mBindArgsCache.size(); i <= index; i++) {
+ mBindArgsCache.add(null);
+ }
}
mBindArgsCache.set(index, value);
}