Merge "Make room-paging KMP use SQLiteStatement." into androidx-main
diff --git a/room/integration-tests/multiplatformtestapp/build.gradle b/room/integration-tests/multiplatformtestapp/build.gradle
index 95b2df0..4ba2f01 100644
--- a/room/integration-tests/multiplatformtestapp/build.gradle
+++ b/room/integration-tests/multiplatformtestapp/build.gradle
@@ -39,8 +39,10 @@
                 implementation(libs.kotlinStdlib)
                 implementation(project(":room:room-runtime"))
                 implementation(project(":room:room-testing"))
+                implementation(project(":room:room-paging"))
                 implementation(project(":sqlite:sqlite-bundled"))
                 implementation(project(":kruth:kruth"))
+                implementation(project(":paging:paging-common"))
                 implementation(libs.kotlinTest)
                 implementation(libs.kotlinCoroutinesTest)
             }
diff --git a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseQueryTest.kt b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseQueryTest.kt
index 78e59dc..760c416 100644
--- a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseQueryTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseQueryTest.kt
@@ -18,6 +18,8 @@
 
 import androidx.kruth.assertThat
 import androidx.kruth.assertThrows
+import androidx.paging.PagingSource
+import androidx.paging.PagingSource.LoadResult
 import androidx.room.RoomRawQuery
 import androidx.room.execSQL
 import androidx.room.immediateTransaction
@@ -503,4 +505,67 @@
             .hasMessageThat()
             .contains("Only bind*() calls are allowed")
     }
+
+    @Test
+    fun simplePagingQuery() = runTest {
+        val entity1 = SampleEntity(1, 1)
+        val entity2 = SampleEntity(2, 2)
+        val sampleEntities = listOf(entity1, entity2)
+        val dao = db.dao()
+
+        dao.insertSampleEntityList(sampleEntities)
+        val pagingSource = dao.getAllIds()
+
+        val onlyLoadFirst =
+            pagingSource.load(
+                PagingSource.LoadParams.Refresh(
+                    key = null,
+                    loadSize = 1,
+                    placeholdersEnabled = true
+                )
+            ) as LoadResult.Page
+        assertThat(onlyLoadFirst.data).containsExactly(entity1)
+
+        val loadAll =
+            pagingSource.load(
+                PagingSource.LoadParams.Refresh(
+                    key = null,
+                    loadSize = 2,
+                    placeholdersEnabled = true
+                )
+            ) as LoadResult.Page
+        assertThat(loadAll.data).containsExactlyElementsIn(sampleEntities)
+    }
+
+    @Test
+    fun pagingQueryWithParams() = runTest {
+        val entity1 = SampleEntity(1, 1)
+        val entity2 = SampleEntity(2, 2)
+        val entity3 = SampleEntity(3, 3)
+        val sampleEntities = listOf(entity1, entity2, entity3)
+        val dao = db.dao()
+
+        dao.insertSampleEntityList(sampleEntities)
+        val pagingSource = dao.getAllIdsWithArgs(1)
+
+        val onlyLoadFirst =
+            pagingSource.load(
+                PagingSource.LoadParams.Refresh(
+                    key = null,
+                    loadSize = 1,
+                    placeholdersEnabled = true
+                )
+            ) as LoadResult.Page
+        assertThat(onlyLoadFirst.data).containsExactly(entity2)
+
+        val loadAll =
+            pagingSource.load(
+                PagingSource.LoadParams.Refresh(
+                    key = null,
+                    loadSize = 2,
+                    placeholdersEnabled = true
+                )
+            ) as LoadResult.Page
+        assertThat(loadAll.data).containsExactlyElementsIn(listOf(entity2, entity3))
+    }
 }
diff --git a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SampleDatabase.kt b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SampleDatabase.kt
index e511fc3..a2a3a6b 100644
--- a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SampleDatabase.kt
+++ b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SampleDatabase.kt
@@ -203,6 +203,12 @@
     @Query("SELECT * FROM StringSampleEntity1")
     suspend fun getSampleManyToMany(): SampleManyAndMany
 
+    @Query("SELECT * FROM SampleEntity")
+    fun getAllIds(): androidx.paging.PagingSource
+
+    @Query("SELECT * FROM SampleEntity WHERE pk > :gt ORDER BY pk ASC")
+    fun getAllIdsWithArgs(gt: Long): androidx.paging.PagingSource
+
     data class Sample1And2(
         @Embedded val sample1: SampleEntity,
         @Relation(parentColumn = "pk", entityColumn = "pk2") val sample2: SampleEntity2
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/ext/xpoet_ext.kt b/room/room-compiler/src/main/kotlin/androidx/room/ext/xpoet_ext.kt
index c73de92..832e27b 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/ext/xpoet_ext.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/ext/xpoet_ext.kt
@@ -337,7 +337,8 @@
         RxJava3TypeNames.COMPLETABLE,
         GuavaUtilConcurrentTypeNames.LISTENABLE_FUTURE,
         KotlinTypeNames.FLOW,
-        ReactiveStreamsTypeNames.PUBLISHER
+        ReactiveStreamsTypeNames.PUBLISHER,
+        PagingTypeNames.PAGING_SOURCE
     )
 
 fun XTypeName.defaultValue(): String {
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/binderprovider/MultiTypedPagingSourceQueryResultBinderProvider.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/binderprovider/MultiTypedPagingSourceQueryResultBinderProvider.kt
index edd1307..384b238 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/binderprovider/MultiTypedPagingSourceQueryResultBinderProvider.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/binderprovider/MultiTypedPagingSourceQueryResultBinderProvider.kt
@@ -21,6 +21,7 @@
 import androidx.room.compiler.processing.XRawType
 import androidx.room.compiler.processing.XType
 import androidx.room.ext.CommonTypeNames
+import androidx.room.ext.PagingTypeNames
 import androidx.room.parser.ParsedQuery
 import androidx.room.processor.Context
 import androidx.room.processor.ProcessorErrors
@@ -33,7 +34,7 @@
 class MultiTypedPagingSourceQueryResultBinderProvider(
     private val context: Context,
     private val roomPagingClassName: XClassName,
-    pagingSourceTypeName: XClassName,
+    private val pagingSourceTypeName: XClassName,
 ) : QueryResultBinderProvider {
 
     private val pagingSourceType: XRawType? by lazy {
@@ -60,7 +61,8 @@
         return MultiTypedPagingSourceQueryResultBinder(
             listAdapter = listAdapter,
             tableNames = tableNames,
-            className = roomPagingClassName
+            className = roomPagingClassName,
+            isBasePagingSource = pagingSourceTypeName == PagingTypeNames.PAGING_SOURCE
         )
     }
 
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt
index 41c114e..8eea718 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt
@@ -91,7 +91,7 @@
     override fun convertAndReturn(
         sqlQueryVar: String,
         dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
+        bindStatement: (CodeGenScope.(String) -> Unit)?,
         returnTypeName: XTypeName,
         inTransaction: Boolean,
         scope: CodeGenScope
@@ -128,7 +128,7 @@
                                 sqlQueryVar
                             )
                             beginControlFlow("try")
-                            bindStatement(scope, statementVar)
+                            bindStatement?.invoke(scope, statementVar)
                             val outVar = scope.getTmpVar("_result")
                             adapter?.convert(outVar, statementVar, scope)
                             addStatement("$returnPrefix%L", outVar)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt
index 2a82c10..e9ba2ce 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt
@@ -158,7 +158,7 @@
     override fun convertAndReturn(
         sqlQueryVar: String,
         dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
+        bindStatement: (CodeGenScope.(String) -> Unit)?,
         returnTypeName: XTypeName,
         inTransaction: Boolean,
         scope: CodeGenScope
@@ -194,7 +194,7 @@
                                 sqlQueryVar
                             )
                             beginControlFlow("try")
-                            bindStatement(scope, statementVar)
+                            bindStatement?.invoke(scope, statementVar)
                             val outVar = scope.getTmpVar("_result")
                             adapter?.convert(outVar, statementVar, scope)
                             addStatement("$returnPrefix%L", outVar)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/GuavaListenableFutureQueryResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/GuavaListenableFutureQueryResultBinder.kt
index 647d801..26826b7 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/GuavaListenableFutureQueryResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/GuavaListenableFutureQueryResultBinder.kt
@@ -95,7 +95,7 @@
     override fun convertAndReturn(
         sqlQueryVar: String,
         dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
+        bindStatement: (CodeGenScope.(String) -> Unit)?,
         returnTypeName: XTypeName,
         inTransaction: Boolean,
         scope: CodeGenScope
@@ -130,7 +130,7 @@
                                 sqlQueryVar
                             )
                             beginControlFlow("try")
-                            bindStatement(scope, statementVar)
+                            bindStatement?.invoke(scope, statementVar)
                             val outVar = scope.getTmpVar("_result")
                             adapter?.convert(outVar, statementVar, scope)
                             addStatement("$returnPrefix%L", outVar)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/InstantQueryResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/InstantQueryResultBinder.kt
index 5f1e385..9205913 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/InstantQueryResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/InstantQueryResultBinder.kt
@@ -85,7 +85,7 @@
     override fun convertAndReturn(
         sqlQueryVar: String,
         dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
+        bindStatement: (CodeGenScope.(String) -> Unit)?,
         returnTypeName: XTypeName,
         inTransaction: Boolean,
         scope: CodeGenScope
@@ -120,7 +120,7 @@
                                 sqlQueryVar
                             )
                             beginControlFlow("try")
-                            bindStatement(scope, statementVar)
+                            bindStatement?.invoke(scope, statementVar)
                             val outVar = scope.getTmpVar("_result")
                             adapter?.convert(outVar, statementVar, scope)
                             addStatement("$returnPrefix%L", outVar)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/LiveDataQueryResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/LiveDataQueryResultBinder.kt
index e4898ee..683be46 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/LiveDataQueryResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/LiveDataQueryResultBinder.kt
@@ -93,7 +93,7 @@
     override fun convertAndReturn(
         sqlQueryVar: String,
         dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
+        bindStatement: (CodeGenScope.(String) -> Unit)?,
         returnTypeName: XTypeName,
         inTransaction: Boolean,
         scope: CodeGenScope
@@ -139,7 +139,7 @@
                                 sqlQueryVar
                             )
                             beginControlFlow("try")
-                            bindStatement(scope, statementVar)
+                            bindStatement?.invoke(scope, statementVar)
                             val outVar = scope.getTmpVar("_result")
                             adapter?.convert(outVar, statementVar, scope)
                             addStatement("$returnPrefix%L", outVar)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MultiTypedPagingSourceQueryResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MultiTypedPagingSourceQueryResultBinder.kt
index 8b3f9a2..055401a 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MultiTypedPagingSourceQueryResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MultiTypedPagingSourceQueryResultBinder.kt
@@ -16,15 +16,21 @@
 
 package androidx.room.solver.query.result
 
+import androidx.room.compiler.codegen.CodeLanguage
 import androidx.room.compiler.codegen.VisibilityModifier
 import androidx.room.compiler.codegen.XClassName
+import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XFunSpec
 import androidx.room.compiler.codegen.XFunSpec.Builder.Companion.addStatement
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.XTypeSpec
-import androidx.room.ext.AndroidTypeNames.CURSOR
+import androidx.room.ext.AndroidTypeNames
 import androidx.room.ext.CommonTypeNames
+import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.KotlinTypeNames
+import androidx.room.ext.RoomTypeNames.RAW_QUERY
+import androidx.room.ext.SQLiteDriverTypeNames
 import androidx.room.solver.CodeGenScope
 
 /**
@@ -35,13 +41,16 @@
 class MultiTypedPagingSourceQueryResultBinder(
     private val listAdapter: ListQueryResultAdapter?,
     private val tableNames: Set,
-    className: XClassName
+    className: XClassName,
+    val isBasePagingSource: Boolean
 ) : QueryResultBinder(listAdapter) {
 
     private val itemTypeName: XTypeName =
         listAdapter?.rowAdapters?.firstOrNull()?.out?.asTypeName() ?: XTypeName.ANY_OBJECT
     private val pagingSourceTypeName: XTypeName = className.parametrizedBy(itemTypeName)
 
+    override fun isMigratedToDriver(): Boolean = isBasePagingSource
+
     override fun convertAndReturn(
         roomSQLiteQueryVar: String,
         canReleaseQuery: Boolean,
@@ -61,14 +70,134 @@
                     )
                     .apply {
                         superclass(pagingSourceTypeName)
-                        addFunction(createConvertRowsMethod(scope))
+                        addFunction(
+                            createConvertRowsMethod(
+                                scope = scope,
+                                stmtParamName = "cursor",
+                                stmtParamTypeName = AndroidTypeNames.CURSOR,
+                                rawQueryParamName = null
+                            )
+                        )
                     }
                     .build()
             addStatement("return %L", pagingSourceSpec)
         }
     }
 
-    private fun createConvertRowsMethod(scope: CodeGenScope): XFunSpec {
+    override fun convertAndReturn(
+        sqlQueryVar: String,
+        dbProperty: XPropertySpec,
+        bindStatement: (CodeGenScope.(String) -> Unit)?,
+        returnTypeName: XTypeName,
+        inTransaction: Boolean,
+        scope: CodeGenScope
+    ) {
+        check(isBasePagingSource) {
+            "This version of `convertAndReturn` should only be called when the binder is for the " +
+                "base PagingSource. "
+        }
+        val rawQueryVarName = scope.getTmpVar("_rawQuery")
+        val stmtVarName = scope.getTmpVar("_stmt")
+
+        when (scope.language) {
+            CodeLanguage.JAVA -> {
+                val assignExpr =
+                    if (bindStatement != null) {
+                        XCodeBlock.ofNewInstance(
+                            language = scope.language,
+                            typeName = RAW_QUERY,
+                            "%L, %L",
+                            sqlQueryVar,
+                            Function1TypeSpec(
+                                language = scope.language,
+                                parameterTypeName = SQLiteDriverTypeNames.STATEMENT,
+                                parameterName = stmtVarName,
+                                returnTypeName = KotlinTypeNames.UNIT
+                            ) {
+                                val functionScope = scope.fork()
+                                functionScope.builder
+                                    .apply { bindStatement.invoke(functionScope, stmtVarName) }
+                                    .build()
+                                addCode(functionScope.generate())
+                                addStatement("return %T.INSTANCE", KotlinTypeNames.UNIT)
+                            }
+                        )
+                    } else {
+                        XCodeBlock.ofNewInstance(
+                            language = scope.language,
+                            typeName = RAW_QUERY,
+                            "%L",
+                            sqlQueryVar
+                        )
+                    }
+                scope.builder.addLocalVariable(
+                    name = rawQueryVarName,
+                    typeName = RAW_QUERY,
+                    assignExpr = assignExpr
+                )
+            }
+            CodeLanguage.KOTLIN ->
+                scope.builder.apply {
+                    if (bindStatement != null) {
+                        beginControlFlow(
+                            "val %L: %T = %T(%N) { %L ->",
+                            rawQueryVarName,
+                            RAW_QUERY,
+                            RAW_QUERY,
+                            sqlQueryVar,
+                            stmtVarName
+                        )
+                        bindStatement.invoke(scope, stmtVarName)
+                        endControlFlow()
+                    } else {
+                        addLocalVariable(
+                            name = rawQueryVarName,
+                            typeName = RAW_QUERY,
+                            assignExpr =
+                                XCodeBlock.ofNewInstance(
+                                    language = scope.language,
+                                    typeName = RAW_QUERY,
+                                    argsFormat = "%N",
+                                    sqlQueryVar
+                                )
+                        )
+                    }
+                }
+        }
+
+        scope.builder.apply {
+            val tableNamesList = tableNames.joinToString(", ") { "\"$it\"" }
+            val statementParamName = "statement"
+            val pagingSourceSpec =
+                XTypeSpec.anonymousClassBuilder(
+                        language = language,
+                        argsFormat = "%L, %N, %L",
+                        rawQueryVarName,
+                        dbProperty,
+                        tableNamesList
+                    )
+                    .apply {
+                        superclass(pagingSourceTypeName)
+                        addFunction(
+                            createConvertRowsMethod(
+                                scope = scope,
+                                stmtParamName = statementParamName,
+                                stmtParamTypeName = SQLiteDriverTypeNames.STATEMENT,
+                                rawQueryParamName = rawQueryVarName
+                            )
+                        )
+                    }
+                    .build()
+            addStatement("return %L", pagingSourceSpec)
+        }
+    }
+
+    private fun createConvertRowsMethod(
+        scope: CodeGenScope,
+        stmtParamName: String,
+        stmtParamTypeName: XTypeName,
+        rawQueryParamName: String?
+    ): XFunSpec {
         return XFunSpec.builder(
                 language = scope.language,
                 name = "convertRows",
@@ -76,12 +205,24 @@
                 isOverride = true
             )
             .apply {
-                val cursorParamName = "cursor"
                 returns(CommonTypeNames.LIST.parametrizedBy(itemTypeName))
-                addParameter(typeName = CURSOR, name = cursorParamName)
+                addParameter(typeName = stmtParamTypeName, name = stmtParamName)
+                if (stmtParamTypeName == SQLiteDriverTypeNames.STATEMENT) {
+                    // The SQLiteStatement version requires a second parameter for backwards
+                    // compatibility for delegating to CursorSQLiteStatement.
+                    addParameter(typeName = XTypeName.PRIMITIVE_INT, name = "itemCount")
+                }
                 val resultVar = scope.getTmpVar("_result")
                 val rowsScope = scope.fork()
-                listAdapter?.convert(resultVar, cursorParamName, rowsScope)
+                if (stmtParamTypeName == SQLiteDriverTypeNames.STATEMENT) {
+                    checkNotNull(rawQueryParamName)
+                    addStatement(
+                        "%L.getBindingFunction().invoke(%L)",
+                        rawQueryParamName,
+                        stmtParamName,
+                    )
+                }
+                listAdapter?.convert(resultVar, stmtParamName, rowsScope)
                 addCode(rowsScope.generate())
                 addStatement("return %L", resultVar)
             }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryResultBinder.kt
index b39c993..286394d 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/QueryResultBinder.kt
@@ -51,7 +51,7 @@
     open fun convertAndReturn(
         sqlQueryVar: String,
         dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
+        bindStatement: (CodeGenScope.(String) -> Unit)?,
         returnTypeName: XTypeName,
         inTransaction: Boolean,
         scope: CodeGenScope
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/RxLambdaQueryResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/RxLambdaQueryResultBinder.kt
index 10973f37..57a43cb 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/RxLambdaQueryResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/RxLambdaQueryResultBinder.kt
@@ -171,7 +171,7 @@
     override fun convertAndReturn(
         sqlQueryVar: String,
         dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
+        bindStatement: (CodeGenScope.(String) -> Unit)?,
         returnTypeName: XTypeName,
         inTransaction: Boolean,
         scope: CodeGenScope
@@ -206,7 +206,7 @@
                                 sqlQueryVar
                             )
                             beginControlFlow("try")
-                            bindStatement(scope, statementVar)
+                            bindStatement?.invoke(scope, statementVar)
                             val outVar = scope.getTmpVar("_result")
                             adapter?.convert(outVar, statementVar, scope)
                             addStatement("$returnPrefix%L", outVar)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/RxQueryResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/RxQueryResultBinder.kt
index bc8877e..716fc2c 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/RxQueryResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/RxQueryResultBinder.kt
@@ -90,7 +90,7 @@
     override fun convertAndReturn(
         sqlQueryVar: String,
         dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
+        bindStatement: (CodeGenScope.(String) -> Unit)?,
         returnTypeName: XTypeName,
         inTransaction: Boolean,
         scope: CodeGenScope
@@ -134,7 +134,7 @@
                                 sqlQueryVar
                             )
                             beginControlFlow("try")
-                            bindStatement(scope, statementVar)
+                            bindStatement?.invoke(scope, statementVar)
                             val outVar = scope.getTmpVar("_result")
                             adapter?.convert(outVar, statementVar, scope)
                             addStatement("$returnPrefix%L", outVar)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
index 8ff5d2d..45a0481 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
@@ -685,7 +685,12 @@
         method.queryResultBinder.convertAndReturn(
             sqlQueryVar = sqlVar,
             dbProperty = dbProperty,
-            bindStatement = { stmtVar -> queryWriter.bindArgs(stmtVar, listSizeArgs, this) },
+            bindStatement =
+                if (queryWriter.parameters.isNotEmpty()) {
+                    { stmtVar -> queryWriter.bindArgs(stmtVar, listSizeArgs, this) }
+                } else {
+                    null
+                },
             returnTypeName = method.returnType.asTypeName(),
             inTransaction = method.inTransaction,
             scope = scope
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt
index a4afa61..38303f3 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt
@@ -784,6 +784,9 @@
               @Query("SELECT pk FROM MyEntity")
               abstract fun getAllIds(): androidx.paging.PagingSource
 
+              @Query("SELECT * FROM MyEntity WHERE pk > :gt ORDER BY pk ASC")
+              abstract fun getAllIdsWithArgs(gt: Long): androidx.paging.PagingSource
+
               @Query("SELECT pk FROM MyEntity")
               abstract fun getAllIdsRx2(): androidx.paging.rxjava2.RxPagingSource
 
diff --git a/room/room-compiler/src/test/test-data/common/input/LimitOffsetPagingSource.kt b/room/room-compiler/src/test/test-data/common/input/LimitOffsetPagingSource.kt
index 7b72548..a9921a2 100644
--- a/room/room-compiler/src/test/test-data/common/input/LimitOffsetPagingSource.kt
+++ b/room/room-compiler/src/test/test-data/common/input/LimitOffsetPagingSource.kt
@@ -15,14 +15,14 @@
  */
 package androidx.room.paging
 
-import android.database.Cursor
 import androidx.paging.PagingState
 import androidx.room.RoomDatabase
-import androidx.room.RoomSQLiteQuery
+import androidx.room.RoomRawQuery
+import androidx.sqlite.SQLiteStatement
 
 @Suppress("UNUSED_PARAMETER")
 abstract class LimitOffsetPagingSource(
-    private val sourceQuery: RoomSQLiteQuery,
+    private val sourceQuery: RoomRawQuery,
     private val db: RoomDatabase,
     vararg tables: String
 ) : androidx.paging.PagingSource() {
@@ -33,5 +33,5 @@
     override public suspend fun load(params: LoadParams): LoadResult {
         return LoadResult.Invalid()
     }
-    protected abstract fun convertRows(cursor: Cursor): List
+    protected abstract fun convertRows(statement: SQLiteStatement, itemCount: Int): List
 }
\ No newline at end of file
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/multiTypedPagingSourceResultBinder.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/multiTypedPagingSourceResultBinder.kt
index 386d206..eab9d14 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/multiTypedPagingSourceResultBinder.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/multiTypedPagingSourceResultBinder.kt
@@ -2,12 +2,16 @@
 import androidx.paging.ListenableFuturePagingSource
 import androidx.paging.PagingSource
 import androidx.room.RoomDatabase
+import androidx.room.RoomRawQuery
 import androidx.room.RoomSQLiteQuery
 import androidx.room.RoomSQLiteQuery.Companion.acquire
 import androidx.room.paging.LimitOffsetPagingSource
 import androidx.room.paging.guava.LimitOffsetListenableFuturePagingSource
+import androidx.room.util.getColumnIndexOrThrow
+import androidx.sqlite.SQLiteStatement
 import javax.`annotation`.processing.Generated
 import kotlin.Int
+import kotlin.Long
 import kotlin.String
 import kotlin.Suppress
 import kotlin.collections.List
@@ -31,15 +35,41 @@
 
   public override fun getAllIds(): PagingSource {
     val _sql: String = "SELECT pk FROM MyEntity"
-    val _statement: RoomSQLiteQuery = acquire(_sql, 0)
-    return object : LimitOffsetPagingSource(_statement, __db, "MyEntity") {
-      protected override fun convertRows(cursor: Cursor): List {
+    val _rawQuery: RoomRawQuery = RoomRawQuery(_sql)
+    return object : LimitOffsetPagingSource(_rawQuery, __db, "MyEntity") {
+      protected override fun convertRows(statement: SQLiteStatement, itemCount: Int):
+          List {
+        _rawQuery.getBindingFunction().invoke(statement)
         val _cursorIndexOfPk: Int = 0
         val _result: MutableList = mutableListOf()
-        while (cursor.moveToNext()) {
+        while (statement.step()) {
           val _item: MyEntity
           val _tmpPk: Int
-          _tmpPk = cursor.getInt(_cursorIndexOfPk)
+          _tmpPk = statement.getLong(_cursorIndexOfPk).toInt()
+          _item = MyEntity(_tmpPk)
+          _result.add(_item)
+        }
+        return _result
+      }
+    }
+  }
+
+  public override fun getAllIdsWithArgs(gt: Long): PagingSource {
+    val _sql: String = "SELECT * FROM MyEntity WHERE pk > ? ORDER BY pk ASC"
+    val _rawQuery: RoomRawQuery = RoomRawQuery(_sql) { _stmt ->
+      var _argIndex: Int = 1
+      _stmt.bindLong(_argIndex, gt)
+    }
+    return object : LimitOffsetPagingSource(_rawQuery, __db, "MyEntity") {
+      protected override fun convertRows(statement: SQLiteStatement, itemCount: Int):
+          List {
+        _rawQuery.getBindingFunction().invoke(statement)
+        val _cursorIndexOfPk: Int = getColumnIndexOrThrow(statement, "pk")
+        val _result: MutableList = mutableListOf()
+        while (statement.step()) {
+          val _item: MyEntity
+          val _tmpPk: Int
+          _tmpPk = statement.getLong(_cursorIndexOfPk).toInt()
           _item = MyEntity(_tmpPk)
           _result.add(_item)
         }
diff --git a/room/room-paging/build.gradle b/room/room-paging/build.gradle
index 8770d1d..c84fe70 100644
--- a/room/room-paging/build.gradle
+++ b/room/room-paging/build.gradle
@@ -17,7 +17,6 @@
 import androidx.build.PlatformIdentifier
 import androidx.build.LibraryType
 import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
-import org.jetbrains.kotlin.konan.target.Family
 
 plugins {
     id("AndroidXPlugin")