Migrating RelationCollector to driver APIs.
This CL introduces a follow-up TODO item which would be
to add support for LongSparseArray when room-runtime can
depend on androidx.collections in commonMain.
Bug: 299168035
Bug: 333906821
Test: DaoRelationshipKotlinCodeGenTest.kt
Change-Id: I855a47d2afd73993117e4259d68706976cec269f
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 1eb28cf..0166c7d 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
@@ -416,4 +416,57 @@
assertContentEquals(arrayOf(1, 2), resultArrayWithLong)
assertContentEquals(longArrayOf(1, 2), resultLongArray)
}
+
+ @Test
+ fun relation1to1() = runTest {
+ val sampleEntity1 = SampleEntity(1, 1)
+ val sampleEntity2 = SampleEntity2(1, 2)
+ db.dao().insert(sampleEntity1)
+ db.dao().insert(sampleEntity2)
+ assertThat(
+ db.dao().getSample1To2()
+ ).isEqualTo(
+ SampleDao.Sample1And2(sample1 = sampleEntity1, sample2 = sampleEntity2)
+ )
+ }
+
+ @Test
+ fun relation1toMany() = runTest {
+ val sampleEntity1 = SampleEntity(1, 1)
+ val sampleEntity2 = SampleEntity2(1, 2)
+ val sampleEntity2s = listOf(sampleEntity2, SampleEntity2(2, 3))
+
+ db.dao().insert(sampleEntity1)
+ db.dao().insertSampleEntity2List(sampleEntity2s)
+
+ assertThat(
+ db.dao().getSample1ToMany()
+ ).isEqualTo(
+ SampleDao.Sample1AndMany(
+ sample1 = sampleEntity1,
+ sample2s = listOf(sampleEntity2)
+ )
+ )
+ }
+
+ @Test
+ fun relationManytoMany() = runTest {
+ val sampleEntity1 = SampleEntity(1, 1)
+ val sampleEntity1s = listOf(sampleEntity1, SampleEntity(2, 2))
+
+ val sampleEntity2 = SampleEntity2(1, 1)
+ val sampleEntity2s = listOf(sampleEntity2, SampleEntity2(2, 2))
+
+ db.dao().insertSampleEntityList(sampleEntity1s)
+ db.dao().insertSampleEntity2List(sampleEntity2s)
+
+ assertThat(
+ db.dao().getSampleManyToMany()
+ ).isEqualTo(
+ SampleDao.SampleManyAndMany(
+ sample1 = sampleEntity1,
+ sample2s = listOf()
+ )
+ )
+ }
}
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 8787aed..f41e88e 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
@@ -20,12 +20,16 @@
import androidx.room.Dao
import androidx.room.Database
import androidx.room.Delete
+import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.ForeignKey
+import androidx.room.Index
import androidx.room.Insert
+import androidx.room.Junction
import androidx.room.MapColumn
import androidx.room.PrimaryKey
import androidx.room.Query
+import androidx.room.Relation
import androidx.room.RewriteQueriesToDropUnusedColumns
import androidx.room.RoomDatabase
import androidx.room.Transaction
@@ -71,6 +75,15 @@
val dataCopy: Long
)
+@Entity(
+ primaryKeys = ["sample1Key", "sample2Key"],
+ indices = [Index("sample1Key"), Index("sample2Key")]
+)
+data class Sample1Sample2XRef(
+ val sample1Key: Long,
+ val sample2Key: Long,
+)
+
@Dao
interface SampleDao {
@@ -142,6 +155,12 @@
suspend fun insertArray(entities: Array<SampleEntity>)
@Insert
+ suspend fun insertSampleEntityList(entities: List<SampleEntity>)
+
+ @Insert
+ suspend fun insertSampleEntity2List(entities: List<SampleEntity2>)
+
+ @Insert
suspend fun insert(entity: SampleEntity2)
@Insert
@@ -167,6 +186,47 @@
@Query("SELECT pk FROM SampleEntity")
suspend fun queryOfLongArray(): LongArray
+
+ @Transaction
+ @Query("SELECT * FROM SampleEntity")
+ suspend fun getSample1To2(): Sample1And2
+
+ @Transaction
+ @Query("SELECT * FROM SampleEntity")
+ suspend fun getSample1ToMany(): Sample1AndMany
+
+ @Transaction
+ @Query("SELECT * FROM SampleEntity")
+ suspend fun getSampleManyToMany(): SampleManyAndMany
+
+ data class Sample1And2(
+ @Embedded
+ val sample1: SampleEntity,
+ @Relation(parentColumn = "pk", entityColumn = "pk2")
+ val sample2: SampleEntity2
+ )
+
+ data class Sample1AndMany(
+ @Embedded
+ val sample1: SampleEntity,
+ @Relation(parentColumn = "pk", entityColumn = "pk2")
+ val sample2s: List<SampleEntity2>
+ )
+
+ data class SampleManyAndMany(
+ @Embedded
+ val sample1: SampleEntity,
+ @Relation(
+ parentColumn = "pk",
+ entityColumn = "pk2",
+ associateBy = Junction(
+ value = Sample1Sample2XRef::class,
+ parentColumn = "sample1Key",
+ entityColumn = "sample2Key"
+ )
+ )
+ val sample2s: List<SampleEntity2>
+ )
}
@Database(
@@ -174,7 +234,8 @@
SampleEntity::class,
SampleEntity2::class,
SampleEntity3::class,
- SampleEntityCopy::class],
+ SampleEntityCopy::class,
+ Sample1Sample2XRef::class],
version = 1,
exportSchema = false
)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index 99041b3..5c711a60 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -89,7 +89,7 @@
}
fun primaryKeyColumnDoesNotExist(columnName: String, allColumns: List<String>): String {
- return "$columnName referenced in the primary key does not exists in the Entity." +
+ return "$columnName referenced in the primary key does not exist in the Entity." +
" Available column names:${allColumns.joinToString(", ")}"
}
@@ -389,7 +389,7 @@
val INDEX_COLUMNS_CANNOT_BE_EMPTY = "List of columns in an index cannot be empty"
fun indexColumnDoesNotExist(columnName: String, allColumns: List<String>): String {
- return "$columnName referenced in the index does not exists in the Entity." +
+ return "$columnName referenced in the index does not exist in the Entity." +
" Available column names:${allColumns.joinToString(", ")}"
}
@@ -554,7 +554,7 @@
val FOREIGN_KEY_CANNOT_FIND_PARENT = "Cannot find parent entity class."
fun foreignKeyChildColumnDoesNotExist(columnName: String, allColumns: List<String>): String {
- return "($columnName) referenced in the foreign key does not exists in the Entity." +
+ return "($columnName) referenced in the foreign key does not exist in the Entity." +
" Available column names:${allColumns.joinToString(", ")}"
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
index e7ff05d..e245f35 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
@@ -151,9 +151,7 @@
override fun getDefaultIndexAdapter() = indexAdapter
- override fun isMigratedToDriver(): Boolean {
- return relationCollectors.isEmpty()
- }
+ override fun isMigratedToDriver(): Boolean = relationCollectors.all { it.isMigratedToDriver() }
data class PojoMapping(
val pojo: Pojo,
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
index eceddad..e005bed 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
@@ -22,8 +22,15 @@
import androidx.room.compiler.codegen.XCodeBlock.Builder.Companion.addLocalVal
import androidx.room.compiler.codegen.XTypeName
import androidx.room.compiler.processing.XNullability
-import androidx.room.ext.CollectionTypeNames
+import androidx.room.ext.CollectionTypeNames.ARRAY_MAP
+import androidx.room.ext.CollectionTypeNames.LONG_SPARSE_ARRAY
import androidx.room.ext.CommonTypeNames
+import androidx.room.ext.CommonTypeNames.ARRAY_LIST
+import androidx.room.ext.CommonTypeNames.HASH_MAP
+import androidx.room.ext.CommonTypeNames.HASH_SET
+import androidx.room.ext.KotlinCollectionMemberNames
+import androidx.room.ext.KotlinCollectionMemberNames.MUTABLE_LIST_OF
+import androidx.room.ext.KotlinCollectionMemberNames.MUTABLE_SET_OF
import androidx.room.ext.capitalize
import androidx.room.ext.stripNonJava
import androidx.room.parser.ParsedQuery
@@ -43,6 +50,7 @@
import androidx.room.verifier.DatabaseVerificationErrors
import androidx.room.writer.QueryWriter
import androidx.room.writer.RelationCollectorFunctionWriter
+import androidx.room.writer.RelationCollectorFunctionWriter.Companion.PARAM_CONNECTION_VARIABLE
import java.util.Locale
/**
@@ -72,20 +80,35 @@
val relationTypeIsCollection: Boolean,
val javaLambdaSyntaxAvailable: Boolean
) {
+ // TODO(b/319660042): Remove once migration to driver API is done.
+ fun isMigratedToDriver(): Boolean = rowAdapter.isMigratedToDriver()
+
// variable name of map containing keys to relation collections, set when writing the code
// generator in writeInitCode
- lateinit var varName: String
+ private lateinit var varName: String
fun writeInitCode(scope: CodeGenScope) {
varName = scope.getTmpVar(
"_collection${relation.field.getPath().stripNonJava().capitalize(Locale.US)}"
)
scope.builder.apply {
- addLocalVariable(
- name = varName,
- typeName = mapTypeName,
- assignExpr = XCodeBlock.ofNewInstance(language, mapTypeName)
- )
+ if (language == CodeLanguage.JAVA ||
+ mapTypeName.rawTypeName == ARRAY_MAP ||
+ mapTypeName.rawTypeName == LONG_SPARSE_ARRAY
+ ) {
+ addLocalVariable(
+ name = varName,
+ typeName = mapTypeName,
+ assignExpr = XCodeBlock.ofNewInstance(language, mapTypeName)
+ )
+ } else {
+ addLocalVal(
+ name = varName,
+ typeName = mapTypeName,
+ "%M()",
+ KotlinCollectionMemberNames.MUTABLE_MAP_OF
+ )
+ }
}
}
@@ -106,9 +129,25 @@
// for relation collection put an empty collections in the map, otherwise put nulls
if (relationTypeIsCollection) {
beginControlFlow("if (!%L.containsKey(%L))", varName, tmpVar).apply {
+ val newEmptyCollection = when (language) {
+ CodeLanguage.JAVA ->
+ XCodeBlock.ofNewInstance(language, relationTypeName)
+ CodeLanguage.KOTLIN ->
+ XCodeBlock.of(
+ language = language,
+ "%M()",
+ if (relationTypeName == CommonTypeNames.MUTABLE_SET) {
+ MUTABLE_SET_OF
+ } else {
+ MUTABLE_LIST_OF
+ }
+ )
+ }
addStatement(
"%L.put(%L, %L)",
- varName, tmpVar, XCodeBlock.ofNewInstance(language, relationTypeName)
+ varName,
+ tmpVar,
+ newEmptyCollection
)
}
endControlFlow()
@@ -152,7 +191,7 @@
// values for all keys, so this is safe. Special case for LongSParseArray
// since it does not have a getValue() from Kotlin.
val usingLongSparseArray =
- mapTypeName.rawTypeName == CollectionTypeNames.LONG_SPARSE_ARRAY
+ mapTypeName.rawTypeName == LONG_SPARSE_ARRAY
when (language) {
CodeLanguage.JAVA -> addStatement(
"%L = %L.get(%L)",
@@ -187,9 +226,23 @@
},
onKeyUnavailable = {
if (relationTypeIsCollection) {
+ val newEmptyCollection = when (language) {
+ CodeLanguage.JAVA ->
+ XCodeBlock.ofNewInstance(language, relationTypeName)
+ CodeLanguage.KOTLIN ->
+ XCodeBlock.of(
+ language = language,
+ "%M()",
+ if (relationTypeName == CommonTypeNames.MUTABLE_SET) {
+ MUTABLE_SET_OF
+ } else {
+ MUTABLE_LIST_OF
+ }
+ )
+ }
addStatement(
"%L = %L",
- tmpRelationVar, XCodeBlock.ofNewInstance(language, relationTypeName)
+ tmpRelationVar, newEmptyCollection
)
} else {
addStatement("%L = null", tmpRelationVar)
@@ -203,8 +256,14 @@
// called to write the invocation to the fetch relationship method
fun writeFetchRelationCall(scope: CodeGenScope) {
val method = scope.writer
- .getOrCreateFunction(RelationCollectorFunctionWriter(this))
- scope.builder.addStatement("%L(%L)", method.name, varName)
+ .getOrCreateFunction(RelationCollectorFunctionWriter(this, scope.useDriverApi))
+ scope.builder.apply {
+ if (scope.useDriverApi) {
+ addStatement("%L(%L, %L)", method.name, PARAM_CONNECTION_VARIABLE, varName)
+ } else {
+ addStatement("%L(%L)", method.name, varName)
+ }
+ }
}
// called to read key and call `onKeyReady` to write code once it is successfully read
@@ -339,10 +398,10 @@
val resultInfo = parsedQuery.resultInfo
val usingLongSparseArray =
- tmpMapTypeName.rawTypeName == CollectionTypeNames.LONG_SPARSE_ARRAY
+ tmpMapTypeName.rawTypeName == LONG_SPARSE_ARRAY
val queryParam = if (usingLongSparseArray) {
val longSparseArrayElement = context.processingEnv
- .requireTypeElement(CollectionTypeNames.LONG_SPARSE_ARRAY.canonicalName)
+ .requireTypeElement(LONG_SPARSE_ARRAY.canonicalName)
QueryParameter(
name = RelationCollectorFunctionWriter.PARAM_MAP_VARIABLE,
sqlName = RelationCollectorFunctionWriter.PARAM_MAP_VARIABLE,
@@ -505,13 +564,20 @@
if (fieldType.typeArguments.isNotEmpty()) {
val rawType = fieldType.rawType
val paramTypeName =
- if (context.COMMON_TYPES.LIST.rawType.isAssignableFrom(rawType)) {
- CommonTypeNames.ARRAY_LIST.parametrizedBy(relation.pojoTypeName)
- } else if (context.COMMON_TYPES.SET.rawType.isAssignableFrom(rawType)) {
- CommonTypeNames.HASH_SET.parametrizedBy(relation.pojoTypeName)
+ if (context.COMMON_TYPES.SET.rawType.isAssignableFrom(rawType)) {
+ when (context.codeLanguage) {
+ CodeLanguage.KOTLIN ->
+ CommonTypeNames.MUTABLE_SET.parametrizedBy(relation.pojoTypeName)
+ CodeLanguage.JAVA ->
+ HASH_SET.parametrizedBy(relation.pojoTypeName)
+ }
} else {
- // Default to ArrayList and see how things go...
- CommonTypeNames.ARRAY_LIST.parametrizedBy(relation.pojoTypeName)
+ when (context.codeLanguage) {
+ CodeLanguage.KOTLIN ->
+ CommonTypeNames.MUTABLE_LIST.parametrizedBy(relation.pojoTypeName)
+ CodeLanguage.JAVA ->
+ ARRAY_LIST.parametrizedBy(relation.pojoTypeName)
+ }
}
paramTypeName to true
} else {
@@ -526,24 +592,30 @@
keyTypeName: XTypeName,
valueTypeName: XTypeName,
): XTypeName {
- val canUseLongSparseArray = context.processingEnv
- .findTypeElement(CollectionTypeNames.LONG_SPARSE_ARRAY.canonicalName) != null
- val canUseArrayMap = context.processingEnv
- .findTypeElement(CollectionTypeNames.ARRAY_MAP.canonicalName) != null
+ val canUseLongSparseArray =
+ context.processingEnv
+ .findTypeElement(LONG_SPARSE_ARRAY.canonicalName) != null
+ val canUseArrayMap =
+ context.processingEnv
+ .findTypeElement(ARRAY_MAP.canonicalName) != null
return when {
canUseLongSparseArray && affinity == SQLTypeAffinity.INTEGER ->
- CollectionTypeNames.LONG_SPARSE_ARRAY.parametrizedBy(valueTypeName)
+ LONG_SPARSE_ARRAY.parametrizedBy(valueTypeName)
canUseArrayMap ->
- CollectionTypeNames.ARRAY_MAP.parametrizedBy(keyTypeName, valueTypeName)
- else ->
- CommonTypeNames.HASH_MAP.parametrizedBy(keyTypeName, valueTypeName)
+ ARRAY_MAP.parametrizedBy(keyTypeName, valueTypeName)
+ else -> when (context.codeLanguage) {
+ CodeLanguage.JAVA ->
+ HASH_MAP.parametrizedBy(keyTypeName, valueTypeName)
+ CodeLanguage.KOTLIN ->
+ CommonTypeNames.MUTABLE_MAP.parametrizedBy(keyTypeName, valueTypeName)
+ }
}
}
// Gets the type name of the relationship key.
private fun keyTypeFor(context: Context, affinity: SQLTypeAffinity): XTypeName {
val canUseLongSparseArray = context.processingEnv
- .findTypeElement(CollectionTypeNames.LONG_SPARSE_ARRAY.canonicalName) != null
+ .findTypeElement(LONG_SPARSE_ARRAY.canonicalName) != null
return when (affinity) {
SQLTypeAffinity.INTEGER ->
if (canUseLongSparseArray) {
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/RelationCollectorFunctionWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/RelationCollectorFunctionWriter.kt
index 1ecfd81..3c63ece 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/RelationCollectorFunctionWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/RelationCollectorFunctionWriter.kt
@@ -32,6 +32,8 @@
import androidx.room.ext.MapKeySetExprCode
import androidx.room.ext.RoomMemberNames
import androidx.room.ext.RoomTypeNames
+import androidx.room.ext.RoomTypeNames.RELATION_UTIL
+import androidx.room.ext.SQLiteDriverTypeNames
import androidx.room.ext.stripNonJava
import androidx.room.solver.CodeGenScope
import androidx.room.solver.query.result.PojoRowAdapter
@@ -41,13 +43,20 @@
* Writes the function that fetches the relations of a POJO and assigns them into the given map.
*/
class RelationCollectorFunctionWriter(
- private val collector: RelationCollector
+ private val collector: RelationCollector,
+ private val useDriverApi: Boolean
) : TypeWriter.SharedFunctionSpec(
- "fetchRelationship${collector.relation.entity.tableName.stripNonJava()}" +
- "As${collector.relation.pojoTypeName.toString(CodeLanguage.JAVA).stripNonJava()}"
+ baseName = if (useDriverApi) {
+ "fetchRelationship${collector.relation.entity.tableName.stripNonJava()}" +
+ "As${collector.relation.pojoTypeName.toString(CodeLanguage.JAVA).stripNonJava()}"
+ } else {
+ "fetchCompatRelationship${collector.relation.entity.tableName.stripNonJava()}" +
+ "As${collector.relation.pojoTypeName.toString(CodeLanguage.JAVA).stripNonJava()}"
+ },
) {
companion object {
const val PARAM_MAP_VARIABLE = "_map"
+ const val PARAM_CONNECTION_VARIABLE = "_connection"
const val KEY_SET_VARIABLE = "__mapKeySet"
}
@@ -63,11 +72,12 @@
"-${relation.entity.typeName.toString(CodeLanguage.JAVA)}" +
"-${relation.entityField.columnName}" +
"-${relation.pojoTypeName}" +
- "-${relation.createLoadAllSql()}"
+ "-${relation.createLoadAllSql()}" +
+ "-$useDriverApi"
}
override fun prepare(methodName: String, writer: TypeWriter, builder: XFunSpec.Builder) {
- val scope = CodeGenScope(writer)
+ val scope = CodeGenScope(writer = writer, useDriverApi = useDriverApi)
scope.builder.apply {
// Check the input map key set for emptiness, returning early as no fetching is needed.
addIsInputEmptyCheck()
@@ -75,25 +85,59 @@
// Check if the input map key set exceeds MAX_BIND_PARAMETER_CNT, if so do a recursive
// fetch.
beginControlFlow(
- "if (%L > %T.MAX_BIND_PARAMETER_CNT)",
+ "if (%L > %L)",
if (usingLongSparseArray) {
XCodeBlock.of(language, "%L.size()", PARAM_MAP_VARIABLE)
} else {
CollectionsSizeExprCode(language, PARAM_MAP_VARIABLE)
},
- RoomTypeNames.ROOM_DB
+ if (useDriverApi) {
+ "999"
+ } else {
+ XCodeBlock.of(
+ language,
+ "%T.MAX_BIND_PARAMETER_CNT",
+ RoomTypeNames.ROOM_DB
+ )
+ }
).apply {
addRecursiveFetchCall(methodName)
addStatement("return")
}.endControlFlow()
- // Create SQL query, acquire statement and bind parameters.
- val stmtVar = scope.getTmpVar("_stmt")
- val sqlQueryVar = scope.getTmpVar("_sql")
- collector.queryWriter.prepareReadAndBind(sqlQueryVar, stmtVar, scope)
+ createStmtAndReturn(scope)
+ }
+ builder.apply {
+ if (useDriverApi) {
+ addParameter(SQLiteDriverTypeNames.CONNECTION, PARAM_CONNECTION_VARIABLE)
+ }
+ addParameter(collector.mapTypeName, PARAM_MAP_VARIABLE)
+ addCode(scope.generate())
+ }
+ }
+ private fun XCodeBlock.Builder.createStmtAndReturn(
+ scope: CodeGenScope
+ ) {
+ // Create SQL query, acquire statement and bind parameters.
+ val stmtVar = scope.getTmpVar("_stmt")
+ val cursorVar = "_cursor"
+ val sqlQueryVar = scope.getTmpVar("_sql")
+
+ if (useDriverApi) {
+ val connectionVar = scope.getTmpVar(PARAM_CONNECTION_VARIABLE)
+ val listSizeVars = collector.queryWriter.prepareQuery(sqlQueryVar, scope)
+ addLocalVal(
+ stmtVar,
+ SQLiteDriverTypeNames.STATEMENT,
+ "%L.prepare(%L)",
+ connectionVar,
+ sqlQueryVar
+ )
+ collector.queryWriter.bindArgs(stmtVar, listSizeVars, scope)
+ } else {
+ collector.queryWriter.prepareReadAndBind(sqlQueryVar, stmtVar, scope)
// Perform query and get a Cursor
- val cursorVar = "_cursor"
val shouldCopyCursor = collector.rowAdapter.let {
it is PojoRowAdapter && it.relationCollectors.isNotEmpty()
}
@@ -110,86 +154,91 @@
"null"
)
)
+ }
+ addRelationCollectorCode(scope, if (useDriverApi) stmtVar else cursorVar)
+ }
- val relation = collector.relation
- beginControlFlow("try").apply {
- // Gets index of the column to be used as key
- val itemKeyIndexVar = "_itemKeyIndex"
- if (relation.junction != null) {
- // When using a junction table the relationship map is keyed on the parent
- // reference column of the junction table, the same column used in the WHERE IN
- // clause, this column is the rightmost column in the generated SELECT
- // clause.
- val junctionParentColumnIndex = relation.projection.size
- addStatement("// _junction.%L", relation.junction.parentField.columnName)
- addLocalVal(
- itemKeyIndexVar,
- XTypeName.PRIMITIVE_INT,
- "%L",
- junctionParentColumnIndex
- )
- } else {
- addLocalVal(
- itemKeyIndexVar,
- XTypeName.PRIMITIVE_INT,
- "%M(%L, %S)",
- RoomMemberNames.CURSOR_UTIL_GET_COLUMN_INDEX,
- cursorVar,
- relation.entityField.columnName
- )
- }
- // Check if index of column is not -1, indicating the column for the key is not in
- // the result, can happen if the user specified a bad projection in @Relation.
- beginControlFlow("if (%L == -1)", itemKeyIndexVar).apply {
- addStatement("return")
- }
- endControlFlow()
+ private fun XCodeBlock.Builder.addRelationCollectorCode(
+ scope: CodeGenScope,
+ cursorVar: String
+ ) {
+ val relation = collector.relation
+ beginControlFlow("try").apply {
+ // Gets index of the column to be used as key
+ val itemKeyIndexVar = "_itemKeyIndex"
+ if (relation.junction != null) {
+ // When using a junction table the relationship map is keyed on the parent
+ // reference column of the junction table, the same column used in the WHERE IN
+ // clause, this column is the rightmost column in the generated SELECT
+ // clause.
+ val junctionParentColumnIndex = relation.projection.size
+ addStatement("// _junction.%L", relation.junction.parentField.columnName)
+ addLocalVal(
+ itemKeyIndexVar,
+ XTypeName.PRIMITIVE_INT,
+ "%L",
+ junctionParentColumnIndex
+ )
+ } else {
+ addLocalVal(
+ name = itemKeyIndexVar,
+ typeName = XTypeName.PRIMITIVE_INT,
+ assignExprFormat = "%M(%L, %S)",
+ if (useDriverApi) {
+ RoomTypeNames.STATEMENT_UTIL.packageMember("getColumnIndex")
+ } else { RoomMemberNames.CURSOR_UTIL_GET_COLUMN_INDEX },
+ cursorVar,
+ relation.entityField.columnName
+ )
+ }
- // Prepare item column indices
- collector.rowAdapter.onCursorReady(cursorVarName = cursorVar, scope = scope)
+ // Check if index of column is not -1, indicating the column for the key is not in
+ // the result, can happen if the user specified a bad projection in @Relation.
+ beginControlFlow("if (%L == -1)", itemKeyIndexVar).apply {
+ addStatement("return")
+ }
+ endControlFlow()
- val tmpVarName = scope.getTmpVar("_item")
- beginControlFlow("while (%L.moveToNext())", cursorVar).apply {
- // Read key from the cursor, convert row to item and place it on map
- collector.readKey(
- cursorVarName = cursorVar,
- indexVar = itemKeyIndexVar,
- keyReader = collector.entityKeyColumnReader,
- scope = scope
- ) { keyVar ->
- if (collector.relationTypeIsCollection) {
- val relationVar = scope.getTmpVar("_tmpRelation")
- addLocalVal(
- relationVar,
- collector.relationTypeName.copy(nullable = true),
- "%L.get(%L)",
- PARAM_MAP_VARIABLE, keyVar
- )
- beginControlFlow("if (%L != null)", relationVar)
- addLocalVariable(tmpVarName, relation.pojoTypeName)
- collector.rowAdapter.convert(tmpVarName, cursorVar, scope)
- addStatement("%L.add(%L)", relationVar, tmpVarName)
- endControlFlow()
- } else {
- beginControlFlow("if (%N.containsKey(%L))", PARAM_MAP_VARIABLE, keyVar)
- addLocalVariable(tmpVarName, relation.pojoTypeName)
- collector.rowAdapter.convert(tmpVarName, cursorVar, scope)
- addStatement("%N.put(%L, %L)", PARAM_MAP_VARIABLE, keyVar, tmpVarName)
- endControlFlow()
- }
+ // Prepare item column indices
+ collector.rowAdapter.onCursorReady(cursorVarName = cursorVar, scope = scope)
+ val tmpVarName = scope.getTmpVar("_item")
+ val stepName = if (scope.useDriverApi) "step" else "moveToNext"
+ beginControlFlow("while (%L.$stepName())", cursorVar).apply {
+ // Read key from the cursor, convert row to item and place it on map
+ collector.readKey(
+ cursorVarName = cursorVar,
+ indexVar = itemKeyIndexVar,
+ keyReader = collector.entityKeyColumnReader,
+ scope = scope
+ ) { keyVar ->
+ if (collector.relationTypeIsCollection) {
+ val relationVar = scope.getTmpVar("_tmpRelation")
+ addLocalVal(
+ relationVar,
+ collector.relationTypeName.copy(nullable = true),
+ "%L.get(%L)",
+ PARAM_MAP_VARIABLE, keyVar
+ )
+ beginControlFlow("if (%L != null)", relationVar)
+ addLocalVariable(tmpVarName, relation.pojoTypeName)
+ collector.rowAdapter.convert(tmpVarName, cursorVar, scope)
+ addStatement("%L.add(%L)", relationVar, tmpVarName)
+ endControlFlow()
+ } else {
+ beginControlFlow("if (%N.containsKey(%L))", PARAM_MAP_VARIABLE, keyVar)
+ addLocalVariable(tmpVarName, relation.pojoTypeName)
+ collector.rowAdapter.convert(tmpVarName, cursorVar, scope)
+ addStatement("%N.put(%L, %L)", PARAM_MAP_VARIABLE, keyVar, tmpVarName)
+ endControlFlow()
}
}
- endControlFlow()
- }
- nextControlFlow("finally").apply {
- addStatement("%L.close()", cursorVar)
}
endControlFlow()
}
- builder.apply {
- addParameter(collector.mapTypeName, PARAM_MAP_VARIABLE)
- addCode(scope.generate())
+ nextControlFlow("finally").apply {
+ addStatement("%L.close()", cursorVar)
}
+ endControlFlow()
}
private fun XCodeBlock.Builder.addIsInputEmptyCheck() {
@@ -211,20 +260,34 @@
private fun XCodeBlock.Builder.addRecursiveFetchCall(methodName: String) {
fun getRecursiveCall(itVarName: String) =
- XCodeBlock.of(
- language,
- "%L(%L)",
- methodName, itVarName
- )
+ if (useDriverApi) {
+ XCodeBlock.of(
+ language,
+ "%L(%L, %L)",
+ methodName, PARAM_CONNECTION_VARIABLE, itVarName
+ )
+ } else {
+ XCodeBlock.of(
+ language,
+ "%L(%L)",
+ methodName, itVarName
+ )
+ }
val utilFunction =
- RoomTypeNames.RELATION_UTIL.let {
+ RELATION_UTIL.let {
when {
usingLongSparseArray ->
it.packageMember("recursiveFetchLongSparseArray")
usingArrayMap ->
it.packageMember("recursiveFetchArrayMap")
- else ->
+ language == CodeLanguage.JAVA ->
it.packageMember("recursiveFetchHashMap")
+ language == CodeLanguage.JAVA ->
+ it.packageMember("recursiveFetchHashMap")
+ else -> when (language) {
+ CodeLanguage.JAVA -> it.packageMember("recursiveFetchHashMap")
+ CodeLanguage.KOTLIN -> it.packageMember("recursiveFetchMap")
+ }
}
}
when (language) {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt
index 57c2e48..4daf31c 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt
@@ -1,21 +1,22 @@
-import android.database.Cursor
import androidx.room.RoomDatabase
-import androidx.room.RoomSQLiteQuery
-import androidx.room.RoomSQLiteQuery.Companion.acquire
import androidx.room.util.appendPlaceholders
import androidx.room.util.getColumnIndex
import androidx.room.util.getColumnIndexOrThrow
-import androidx.room.util.query
-import androidx.room.util.recursiveFetchHashMap
-import java.util.ArrayList
-import java.util.HashMap
+import androidx.room.util.performBlocking
+import androidx.room.util.recursiveFetchMap
+import androidx.sqlite.SQLiteConnection
+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
+import kotlin.collections.MutableList
+import kotlin.collections.MutableMap
import kotlin.collections.Set
+import kotlin.collections.mutableListOf
+import kotlin.collections.mutableMapOf
import kotlin.reflect.KClass
import kotlin.text.StringBuilder
@@ -31,130 +32,128 @@
public override fun getSongsWithArtist(): SongWithArtist {
val _sql: String = "SELECT * FROM Song"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfSongId: Int = getColumnIndexOrThrow(_cursor, "songId")
- val _cursorIndexOfArtistKey: Int = getColumnIndexOrThrow(_cursor, "artistKey")
- val _collectionArtist: HashMap<Long, Artist?> = HashMap<Long, Artist?>()
- while (_cursor.moveToNext()) {
- val _tmpKey: Long
- _tmpKey = _cursor.getLong(_cursorIndexOfArtistKey)
- _collectionArtist.put(_tmpKey, null)
- }
- _cursor.moveToPosition(-1)
- __fetchRelationshipArtistAsArtist(_collectionArtist)
- val _result: SongWithArtist
- if (_cursor.moveToFirst()) {
- val _tmpSong: Song
- val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
- val _tmpArtistKey: Long
- _tmpArtistKey = _cursor.getLong(_cursorIndexOfArtistKey)
- _tmpSong = Song(_tmpSongId,_tmpArtistKey)
- val _tmpArtist: Artist?
- val _tmpKey_1: Long
- _tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistKey)
- _tmpArtist = _collectionArtist.get(_tmpKey_1)
- if (_tmpArtist == null) {
- error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfSongId: Int = getColumnIndexOrThrow(_stmt, "songId")
+ val _cursorIndexOfArtistKey: Int = getColumnIndexOrThrow(_stmt, "artistKey")
+ val _collectionArtist: MutableMap<Long, Artist?> = mutableMapOf()
+ while (_stmt.step()) {
+ val _tmpKey: Long
+ _tmpKey = _stmt.getLong(_cursorIndexOfArtistKey)
+ _collectionArtist.put(_tmpKey, null)
}
- _result = SongWithArtist(_tmpSong,_tmpArtist)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
+ _stmt.reset()
+ __fetchRelationshipArtistAsArtist(_connection, _collectionArtist)
+ val _result: SongWithArtist
+ if (_stmt.step()) {
+ val _tmpSong: Song
+ val _tmpSongId: Long
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
+ val _tmpArtistKey: Long
+ _tmpArtistKey = _stmt.getLong(_cursorIndexOfArtistKey)
+ _tmpSong = Song(_tmpSongId,_tmpArtistKey)
+ val _tmpArtist: Artist?
+ val _tmpKey_1: Long
+ _tmpKey_1 = _stmt.getLong(_cursorIndexOfArtistKey)
+ _tmpArtist = _collectionArtist.get(_tmpKey_1)
+ if (_tmpArtist == null) {
+ error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
+ }
+ _result = SongWithArtist(_tmpSong,_tmpArtist)
+ } else {
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
+ }
+ _result
+ } finally {
+ _stmt.close()
}
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
public override fun getArtistAndSongs(): ArtistAndSongs {
val _sql: String = "SELECT * FROM Artist"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfArtistId: Int = getColumnIndexOrThrow(_cursor, "artistId")
- val _collectionSongs: HashMap<Long, ArrayList<Song>> = HashMap<Long, ArrayList<Song>>()
- while (_cursor.moveToNext()) {
- val _tmpKey: Long
- _tmpKey = _cursor.getLong(_cursorIndexOfArtistId)
- if (!_collectionSongs.containsKey(_tmpKey)) {
- _collectionSongs.put(_tmpKey, ArrayList<Song>())
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfArtistId: Int = getColumnIndexOrThrow(_stmt, "artistId")
+ val _collectionSongs: MutableMap<Long, MutableList<Song>> = mutableMapOf()
+ while (_stmt.step()) {
+ val _tmpKey: Long
+ _tmpKey = _stmt.getLong(_cursorIndexOfArtistId)
+ if (!_collectionSongs.containsKey(_tmpKey)) {
+ _collectionSongs.put(_tmpKey, mutableListOf())
+ }
}
+ _stmt.reset()
+ __fetchRelationshipSongAsSong(_connection, _collectionSongs)
+ val _result: ArtistAndSongs
+ if (_stmt.step()) {
+ val _tmpArtist: Artist
+ val _tmpArtistId: Long
+ _tmpArtistId = _stmt.getLong(_cursorIndexOfArtistId)
+ _tmpArtist = Artist(_tmpArtistId)
+ val _tmpSongsCollection: MutableList<Song>
+ val _tmpKey_1: Long
+ _tmpKey_1 = _stmt.getLong(_cursorIndexOfArtistId)
+ _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
+ _result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
+ } else {
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
+ }
+ _result
+ } finally {
+ _stmt.close()
}
- _cursor.moveToPosition(-1)
- __fetchRelationshipSongAsSong(_collectionSongs)
- val _result: ArtistAndSongs
- if (_cursor.moveToFirst()) {
- val _tmpArtist: Artist
- val _tmpArtistId: Long
- _tmpArtistId = _cursor.getLong(_cursorIndexOfArtistId)
- _tmpArtist = Artist(_tmpArtistId)
- val _tmpSongsCollection: ArrayList<Song>
- val _tmpKey_1: Long
- _tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistId)
- _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
- _result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
- }
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
public override fun getPlaylistAndSongs(): PlaylistAndSongs {
val _sql: String = "SELECT * FROM Playlist"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfPlaylistId: Int = getColumnIndexOrThrow(_cursor, "playlistId")
- val _collectionSongs: HashMap<Long, ArrayList<Song>> = HashMap<Long, ArrayList<Song>>()
- while (_cursor.moveToNext()) {
- val _tmpKey: Long
- _tmpKey = _cursor.getLong(_cursorIndexOfPlaylistId)
- if (!_collectionSongs.containsKey(_tmpKey)) {
- _collectionSongs.put(_tmpKey, ArrayList<Song>())
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfPlaylistId: Int = getColumnIndexOrThrow(_stmt, "playlistId")
+ val _collectionSongs: MutableMap<Long, MutableList<Song>> = mutableMapOf()
+ while (_stmt.step()) {
+ val _tmpKey: Long
+ _tmpKey = _stmt.getLong(_cursorIndexOfPlaylistId)
+ if (!_collectionSongs.containsKey(_tmpKey)) {
+ _collectionSongs.put(_tmpKey, mutableListOf())
+ }
}
+ _stmt.reset()
+ __fetchRelationshipSongAsSong_1(_connection, _collectionSongs)
+ val _result: PlaylistAndSongs
+ if (_stmt.step()) {
+ val _tmpPlaylist: Playlist
+ val _tmpPlaylistId: Long
+ _tmpPlaylistId = _stmt.getLong(_cursorIndexOfPlaylistId)
+ _tmpPlaylist = Playlist(_tmpPlaylistId)
+ val _tmpSongsCollection: MutableList<Song>
+ val _tmpKey_1: Long
+ _tmpKey_1 = _stmt.getLong(_cursorIndexOfPlaylistId)
+ _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
+ _result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
+ } else {
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
+ }
+ _result
+ } finally {
+ _stmt.close()
}
- _cursor.moveToPosition(-1)
- __fetchRelationshipSongAsSong_1(_collectionSongs)
- val _result: PlaylistAndSongs
- if (_cursor.moveToFirst()) {
- val _tmpPlaylist: Playlist
- val _tmpPlaylistId: Long
- _tmpPlaylistId = _cursor.getLong(_cursorIndexOfPlaylistId)
- _tmpPlaylist = Playlist(_tmpPlaylistId)
- val _tmpSongsCollection: ArrayList<Song>
- val _tmpKey_1: Long
- _tmpKey_1 = _cursor.getLong(_cursorIndexOfPlaylistId)
- _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
- _result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
- }
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
- private fun __fetchRelationshipArtistAsArtist(_map: HashMap<Long, Artist?>) {
+ private fun __fetchRelationshipArtistAsArtist(_connection: SQLiteConnection,
+ _map: MutableMap<Long, Artist?>) {
val __mapKeySet: Set<Long> = _map.keys
if (__mapKeySet.isEmpty()) {
return
}
- if (_map.size > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
- recursiveFetchHashMap(_map, false) {
- __fetchRelationshipArtistAsArtist(it)
+ if (_map.size > 999) {
+ recursiveFetchMap(_map, false) {
+ __fetchRelationshipArtistAsArtist(_connection, it)
}
return
}
@@ -164,44 +163,43 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (_item: Long in __mapKeySet) {
_stmt.bindLong(_argIndex, _item)
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
- val _itemKeyIndex: Int = getColumnIndex(_cursor, "artistId")
+ val _itemKeyIndex: Int = getColumnIndex(_stmt, "artistId")
if (_itemKeyIndex == -1) {
return
}
val _cursorIndexOfArtistId: Int = 0
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: Long
- _tmpKey = _cursor.getLong(_itemKeyIndex)
+ _tmpKey = _stmt.getLong(_itemKeyIndex)
if (_map.containsKey(_tmpKey)) {
val _item_1: Artist
val _tmpArtistId: Long
- _tmpArtistId = _cursor.getLong(_cursorIndexOfArtistId)
+ _tmpArtistId = _stmt.getLong(_cursorIndexOfArtistId)
_item_1 = Artist(_tmpArtistId)
_map.put(_tmpKey, _item_1)
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
- private fun __fetchRelationshipSongAsSong(_map: HashMap<Long, ArrayList<Song>>) {
+ private fun __fetchRelationshipSongAsSong(_connection: SQLiteConnection,
+ _map: MutableMap<Long, MutableList<Song>>) {
val __mapKeySet: Set<Long> = _map.keys
if (__mapKeySet.isEmpty()) {
return
}
- if (_map.size > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
- recursiveFetchHashMap(_map, true) {
- __fetchRelationshipSongAsSong(it)
+ if (_map.size > 999) {
+ recursiveFetchMap(_map, true) {
+ __fetchRelationshipSongAsSong(_connection, it)
}
return
}
@@ -211,48 +209,47 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (_item: Long in __mapKeySet) {
_stmt.bindLong(_argIndex, _item)
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
- val _itemKeyIndex: Int = getColumnIndex(_cursor, "artistKey")
+ val _itemKeyIndex: Int = getColumnIndex(_stmt, "artistKey")
if (_itemKeyIndex == -1) {
return
}
val _cursorIndexOfSongId: Int = 0
val _cursorIndexOfArtistKey: Int = 1
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: Long
- _tmpKey = _cursor.getLong(_itemKeyIndex)
- val _tmpRelation: ArrayList<Song>? = _map.get(_tmpKey)
+ _tmpKey = _stmt.getLong(_itemKeyIndex)
+ val _tmpRelation: MutableList<Song>? = _map.get(_tmpKey)
if (_tmpRelation != null) {
val _item_1: Song
val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
val _tmpArtistKey: Long
- _tmpArtistKey = _cursor.getLong(_cursorIndexOfArtistKey)
+ _tmpArtistKey = _stmt.getLong(_cursorIndexOfArtistKey)
_item_1 = Song(_tmpSongId,_tmpArtistKey)
_tmpRelation.add(_item_1)
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
- private fun __fetchRelationshipSongAsSong_1(_map: HashMap<Long, ArrayList<Song>>) {
+ private fun __fetchRelationshipSongAsSong_1(_connection: SQLiteConnection,
+ _map: MutableMap<Long, MutableList<Song>>) {
val __mapKeySet: Set<Long> = _map.keys
if (__mapKeySet.isEmpty()) {
return
}
- if (_map.size > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
- recursiveFetchHashMap(_map, true) {
- __fetchRelationshipSongAsSong_1(it)
+ if (_map.size > 999) {
+ recursiveFetchMap(_map, true) {
+ __fetchRelationshipSongAsSong_1(_connection, it)
}
return
}
@@ -262,14 +259,12 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (_item: Long in __mapKeySet) {
_stmt.bindLong(_argIndex, _item)
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
// _junction.playlistKey
val _itemKeyIndex: Int = 2
@@ -278,22 +273,22 @@
}
val _cursorIndexOfSongId: Int = 0
val _cursorIndexOfArtistKey: Int = 1
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: Long
- _tmpKey = _cursor.getLong(_itemKeyIndex)
- val _tmpRelation: ArrayList<Song>? = _map.get(_tmpKey)
+ _tmpKey = _stmt.getLong(_itemKeyIndex)
+ val _tmpRelation: MutableList<Song>? = _map.get(_tmpKey)
if (_tmpRelation != null) {
val _item_1: Song
val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
val _tmpArtistKey: Long
- _tmpArtistKey = _cursor.getLong(_cursorIndexOfArtistKey)
+ _tmpArtistKey = _stmt.getLong(_cursorIndexOfArtistKey)
_item_1 = Song(_tmpSongId,_tmpArtistKey)
_tmpRelation.add(_item_1)
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt
index 0c5dcc4..4b43e32 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt
@@ -1,21 +1,21 @@
-import android.database.Cursor
import androidx.collection.ArrayMap
import androidx.room.RoomDatabase
-import androidx.room.RoomSQLiteQuery
-import androidx.room.RoomSQLiteQuery.Companion.acquire
import androidx.room.util.appendPlaceholders
import androidx.room.util.getColumnIndex
import androidx.room.util.getColumnIndexOrThrow
-import androidx.room.util.query
+import androidx.room.util.performBlocking
import androidx.room.util.recursiveFetchArrayMap
-import java.util.ArrayList
+import androidx.sqlite.SQLiteConnection
+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
+import kotlin.collections.MutableList
import kotlin.collections.Set
+import kotlin.collections.mutableListOf
import kotlin.reflect.KClass
import kotlin.text.StringBuilder
@@ -31,130 +31,130 @@
public override fun getSongsWithArtist(): SongWithArtist {
val _sql: String = "SELECT * FROM Song"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfSongId: Int = getColumnIndexOrThrow(_cursor, "songId")
- val _cursorIndexOfArtistKey: Int = getColumnIndexOrThrow(_cursor, "artistKey")
- val _collectionArtist: ArrayMap<Long, Artist?> = ArrayMap<Long, Artist?>()
- while (_cursor.moveToNext()) {
- val _tmpKey: Long
- _tmpKey = _cursor.getLong(_cursorIndexOfArtistKey)
- _collectionArtist.put(_tmpKey, null)
- }
- _cursor.moveToPosition(-1)
- __fetchRelationshipArtistAsArtist(_collectionArtist)
- val _result: SongWithArtist
- if (_cursor.moveToFirst()) {
- val _tmpSong: Song
- val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
- val _tmpArtistKey: Long
- _tmpArtistKey = _cursor.getLong(_cursorIndexOfArtistKey)
- _tmpSong = Song(_tmpSongId,_tmpArtistKey)
- val _tmpArtist: Artist?
- val _tmpKey_1: Long
- _tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistKey)
- _tmpArtist = _collectionArtist.get(_tmpKey_1)
- if (_tmpArtist == null) {
- error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfSongId: Int = getColumnIndexOrThrow(_stmt, "songId")
+ val _cursorIndexOfArtistKey: Int = getColumnIndexOrThrow(_stmt, "artistKey")
+ val _collectionArtist: ArrayMap<Long, Artist?> = ArrayMap<Long, Artist?>()
+ while (_stmt.step()) {
+ val _tmpKey: Long
+ _tmpKey = _stmt.getLong(_cursorIndexOfArtistKey)
+ _collectionArtist.put(_tmpKey, null)
}
- _result = SongWithArtist(_tmpSong,_tmpArtist)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
+ _stmt.reset()
+ __fetchRelationshipArtistAsArtist(_connection, _collectionArtist)
+ val _result: SongWithArtist
+ if (_stmt.step()) {
+ val _tmpSong: Song
+ val _tmpSongId: Long
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
+ val _tmpArtistKey: Long
+ _tmpArtistKey = _stmt.getLong(_cursorIndexOfArtistKey)
+ _tmpSong = Song(_tmpSongId,_tmpArtistKey)
+ val _tmpArtist: Artist?
+ val _tmpKey_1: Long
+ _tmpKey_1 = _stmt.getLong(_cursorIndexOfArtistKey)
+ _tmpArtist = _collectionArtist.get(_tmpKey_1)
+ if (_tmpArtist == null) {
+ error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
+ }
+ _result = SongWithArtist(_tmpSong,_tmpArtist)
+ } else {
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
+ }
+ _result
+ } finally {
+ _stmt.close()
}
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
public override fun getArtistAndSongs(): ArtistAndSongs {
val _sql: String = "SELECT * FROM Artist"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfArtistId: Int = getColumnIndexOrThrow(_cursor, "artistId")
- val _collectionSongs: ArrayMap<Long, ArrayList<Song>> = ArrayMap<Long, ArrayList<Song>>()
- while (_cursor.moveToNext()) {
- val _tmpKey: Long
- _tmpKey = _cursor.getLong(_cursorIndexOfArtistId)
- if (!_collectionSongs.containsKey(_tmpKey)) {
- _collectionSongs.put(_tmpKey, ArrayList<Song>())
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfArtistId: Int = getColumnIndexOrThrow(_stmt, "artistId")
+ val _collectionSongs: ArrayMap<Long, MutableList<Song>> =
+ ArrayMap<Long, MutableList<Song>>()
+ while (_stmt.step()) {
+ val _tmpKey: Long
+ _tmpKey = _stmt.getLong(_cursorIndexOfArtistId)
+ if (!_collectionSongs.containsKey(_tmpKey)) {
+ _collectionSongs.put(_tmpKey, mutableListOf())
+ }
}
+ _stmt.reset()
+ __fetchRelationshipSongAsSong(_connection, _collectionSongs)
+ val _result: ArtistAndSongs
+ if (_stmt.step()) {
+ val _tmpArtist: Artist
+ val _tmpArtistId: Long
+ _tmpArtistId = _stmt.getLong(_cursorIndexOfArtistId)
+ _tmpArtist = Artist(_tmpArtistId)
+ val _tmpSongsCollection: MutableList<Song>
+ val _tmpKey_1: Long
+ _tmpKey_1 = _stmt.getLong(_cursorIndexOfArtistId)
+ _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
+ _result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
+ } else {
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
+ }
+ _result
+ } finally {
+ _stmt.close()
}
- _cursor.moveToPosition(-1)
- __fetchRelationshipSongAsSong(_collectionSongs)
- val _result: ArtistAndSongs
- if (_cursor.moveToFirst()) {
- val _tmpArtist: Artist
- val _tmpArtistId: Long
- _tmpArtistId = _cursor.getLong(_cursorIndexOfArtistId)
- _tmpArtist = Artist(_tmpArtistId)
- val _tmpSongsCollection: ArrayList<Song>
- val _tmpKey_1: Long
- _tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistId)
- _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
- _result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
- }
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
public override fun getPlaylistAndSongs(): PlaylistAndSongs {
val _sql: String = "SELECT * FROM Playlist"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfPlaylistId: Int = getColumnIndexOrThrow(_cursor, "playlistId")
- val _collectionSongs: ArrayMap<Long, ArrayList<Song>> = ArrayMap<Long, ArrayList<Song>>()
- while (_cursor.moveToNext()) {
- val _tmpKey: Long
- _tmpKey = _cursor.getLong(_cursorIndexOfPlaylistId)
- if (!_collectionSongs.containsKey(_tmpKey)) {
- _collectionSongs.put(_tmpKey, ArrayList<Song>())
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfPlaylistId: Int = getColumnIndexOrThrow(_stmt, "playlistId")
+ val _collectionSongs: ArrayMap<Long, MutableList<Song>> =
+ ArrayMap<Long, MutableList<Song>>()
+ while (_stmt.step()) {
+ val _tmpKey: Long
+ _tmpKey = _stmt.getLong(_cursorIndexOfPlaylistId)
+ if (!_collectionSongs.containsKey(_tmpKey)) {
+ _collectionSongs.put(_tmpKey, mutableListOf())
+ }
}
+ _stmt.reset()
+ __fetchRelationshipSongAsSong_1(_connection, _collectionSongs)
+ val _result: PlaylistAndSongs
+ if (_stmt.step()) {
+ val _tmpPlaylist: Playlist
+ val _tmpPlaylistId: Long
+ _tmpPlaylistId = _stmt.getLong(_cursorIndexOfPlaylistId)
+ _tmpPlaylist = Playlist(_tmpPlaylistId)
+ val _tmpSongsCollection: MutableList<Song>
+ val _tmpKey_1: Long
+ _tmpKey_1 = _stmt.getLong(_cursorIndexOfPlaylistId)
+ _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
+ _result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
+ } else {
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
+ }
+ _result
+ } finally {
+ _stmt.close()
}
- _cursor.moveToPosition(-1)
- __fetchRelationshipSongAsSong_1(_collectionSongs)
- val _result: PlaylistAndSongs
- if (_cursor.moveToFirst()) {
- val _tmpPlaylist: Playlist
- val _tmpPlaylistId: Long
- _tmpPlaylistId = _cursor.getLong(_cursorIndexOfPlaylistId)
- _tmpPlaylist = Playlist(_tmpPlaylistId)
- val _tmpSongsCollection: ArrayList<Song>
- val _tmpKey_1: Long
- _tmpKey_1 = _cursor.getLong(_cursorIndexOfPlaylistId)
- _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
- _result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
- }
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
- private fun __fetchRelationshipArtistAsArtist(_map: ArrayMap<Long, Artist?>) {
+ private fun __fetchRelationshipArtistAsArtist(_connection: SQLiteConnection,
+ _map: ArrayMap<Long, Artist?>) {
val __mapKeySet: Set<Long> = _map.keys
if (__mapKeySet.isEmpty()) {
return
}
- if (_map.size > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
+ if (_map.size > 999) {
recursiveFetchArrayMap(_map, false) {
- __fetchRelationshipArtistAsArtist(it)
+ __fetchRelationshipArtistAsArtist(_connection, it)
}
return
}
@@ -164,44 +164,43 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (_item: Long in __mapKeySet) {
_stmt.bindLong(_argIndex, _item)
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
- val _itemKeyIndex: Int = getColumnIndex(_cursor, "artistId")
+ val _itemKeyIndex: Int = getColumnIndex(_stmt, "artistId")
if (_itemKeyIndex == -1) {
return
}
val _cursorIndexOfArtistId: Int = 0
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: Long
- _tmpKey = _cursor.getLong(_itemKeyIndex)
+ _tmpKey = _stmt.getLong(_itemKeyIndex)
if (_map.containsKey(_tmpKey)) {
val _item_1: Artist
val _tmpArtistId: Long
- _tmpArtistId = _cursor.getLong(_cursorIndexOfArtistId)
+ _tmpArtistId = _stmt.getLong(_cursorIndexOfArtistId)
_item_1 = Artist(_tmpArtistId)
_map.put(_tmpKey, _item_1)
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
- private fun __fetchRelationshipSongAsSong(_map: ArrayMap<Long, ArrayList<Song>>) {
+ private fun __fetchRelationshipSongAsSong(_connection: SQLiteConnection,
+ _map: ArrayMap<Long, MutableList<Song>>) {
val __mapKeySet: Set<Long> = _map.keys
if (__mapKeySet.isEmpty()) {
return
}
- if (_map.size > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
+ if (_map.size > 999) {
recursiveFetchArrayMap(_map, true) {
- __fetchRelationshipSongAsSong(it)
+ __fetchRelationshipSongAsSong(_connection, it)
}
return
}
@@ -211,48 +210,47 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (_item: Long in __mapKeySet) {
_stmt.bindLong(_argIndex, _item)
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
- val _itemKeyIndex: Int = getColumnIndex(_cursor, "artistKey")
+ val _itemKeyIndex: Int = getColumnIndex(_stmt, "artistKey")
if (_itemKeyIndex == -1) {
return
}
val _cursorIndexOfSongId: Int = 0
val _cursorIndexOfArtistKey: Int = 1
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: Long
- _tmpKey = _cursor.getLong(_itemKeyIndex)
- val _tmpRelation: ArrayList<Song>? = _map.get(_tmpKey)
+ _tmpKey = _stmt.getLong(_itemKeyIndex)
+ val _tmpRelation: MutableList<Song>? = _map.get(_tmpKey)
if (_tmpRelation != null) {
val _item_1: Song
val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
val _tmpArtistKey: Long
- _tmpArtistKey = _cursor.getLong(_cursorIndexOfArtistKey)
+ _tmpArtistKey = _stmt.getLong(_cursorIndexOfArtistKey)
_item_1 = Song(_tmpSongId,_tmpArtistKey)
_tmpRelation.add(_item_1)
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
- private fun __fetchRelationshipSongAsSong_1(_map: ArrayMap<Long, ArrayList<Song>>) {
+ private fun __fetchRelationshipSongAsSong_1(_connection: SQLiteConnection,
+ _map: ArrayMap<Long, MutableList<Song>>) {
val __mapKeySet: Set<Long> = _map.keys
if (__mapKeySet.isEmpty()) {
return
}
- if (_map.size > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
+ if (_map.size > 999) {
recursiveFetchArrayMap(_map, true) {
- __fetchRelationshipSongAsSong_1(it)
+ __fetchRelationshipSongAsSong_1(_connection, it)
}
return
}
@@ -262,14 +260,12 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (_item: Long in __mapKeySet) {
_stmt.bindLong(_argIndex, _item)
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
// _junction.playlistKey
val _itemKeyIndex: Int = 2
@@ -278,22 +274,22 @@
}
val _cursorIndexOfSongId: Int = 0
val _cursorIndexOfArtistKey: Int = 1
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: Long
- _tmpKey = _cursor.getLong(_itemKeyIndex)
- val _tmpRelation: ArrayList<Song>? = _map.get(_tmpKey)
+ _tmpKey = _stmt.getLong(_itemKeyIndex)
+ val _tmpRelation: MutableList<Song>? = _map.get(_tmpKey)
if (_tmpRelation != null) {
val _item_1: Song
val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
val _tmpArtistKey: Long
- _tmpArtistKey = _cursor.getLong(_cursorIndexOfArtistKey)
+ _tmpArtistKey = _stmt.getLong(_cursorIndexOfArtistKey)
_item_1 = Song(_tmpSongId,_tmpArtistKey)
_tmpRelation.add(_item_1)
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt
index f6480e9c..136a991 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt
@@ -1,14 +1,12 @@
-import android.database.Cursor
import androidx.room.RoomDatabase
-import androidx.room.RoomSQLiteQuery
-import androidx.room.RoomSQLiteQuery.Companion.acquire
import androidx.room.util.appendPlaceholders
import androidx.room.util.getColumnIndex
import androidx.room.util.getColumnIndexOrThrow
-import androidx.room.util.query
-import androidx.room.util.recursiveFetchHashMap
+import androidx.room.util.performBlocking
+import androidx.room.util.recursiveFetchMap
+import androidx.sqlite.SQLiteConnection
+import androidx.sqlite.SQLiteStatement
import java.nio.ByteBuffer
-import java.util.HashMap
import javax.`annotation`.processing.Generated
import kotlin.ByteArray
import kotlin.Int
@@ -16,7 +14,9 @@
import kotlin.String
import kotlin.Suppress
import kotlin.collections.List
+import kotlin.collections.MutableMap
import kotlin.collections.Set
+import kotlin.collections.mutableMapOf
import kotlin.reflect.KClass
import kotlin.text.StringBuilder
@@ -32,54 +32,54 @@
public override fun getSongsWithArtist(): SongWithArtist {
val _sql: String = "SELECT * FROM Song"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfSongId: Int = getColumnIndexOrThrow(_cursor, "songId")
- val _cursorIndexOfArtistKey: Int = getColumnIndexOrThrow(_cursor, "artistKey")
- val _collectionArtist: HashMap<ByteBuffer, Artist?> = HashMap<ByteBuffer, Artist?>()
- while (_cursor.moveToNext()) {
- val _tmpKey: ByteBuffer
- _tmpKey = ByteBuffer.wrap(_cursor.getBlob(_cursorIndexOfArtistKey))
- _collectionArtist.put(_tmpKey, null)
- }
- _cursor.moveToPosition(-1)
- __fetchRelationshipArtistAsArtist(_collectionArtist)
- val _result: SongWithArtist
- if (_cursor.moveToFirst()) {
- val _tmpSong: Song
- val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
- val _tmpArtistKey: ByteArray
- _tmpArtistKey = _cursor.getBlob(_cursorIndexOfArtistKey)
- _tmpSong = Song(_tmpSongId,_tmpArtistKey)
- val _tmpArtist: Artist?
- val _tmpKey_1: ByteBuffer
- _tmpKey_1 = ByteBuffer.wrap(_cursor.getBlob(_cursorIndexOfArtistKey))
- _tmpArtist = _collectionArtist.get(_tmpKey_1)
- if (_tmpArtist == null) {
- error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfSongId: Int = getColumnIndexOrThrow(_stmt, "songId")
+ val _cursorIndexOfArtistKey: Int = getColumnIndexOrThrow(_stmt, "artistKey")
+ val _collectionArtist: MutableMap<ByteBuffer, Artist?> = mutableMapOf()
+ while (_stmt.step()) {
+ val _tmpKey: ByteBuffer
+ _tmpKey = ByteBuffer.wrap(_stmt.getBlob(_cursorIndexOfArtistKey))
+ _collectionArtist.put(_tmpKey, null)
}
- _result = SongWithArtist(_tmpSong,_tmpArtist)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
+ _stmt.reset()
+ __fetchRelationshipArtistAsArtist(_connection, _collectionArtist)
+ val _result: SongWithArtist
+ if (_stmt.step()) {
+ val _tmpSong: Song
+ val _tmpSongId: Long
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
+ val _tmpArtistKey: ByteArray
+ _tmpArtistKey = _stmt.getBlob(_cursorIndexOfArtistKey)
+ _tmpSong = Song(_tmpSongId,_tmpArtistKey)
+ val _tmpArtist: Artist?
+ val _tmpKey_1: ByteBuffer
+ _tmpKey_1 = ByteBuffer.wrap(_stmt.getBlob(_cursorIndexOfArtistKey))
+ _tmpArtist = _collectionArtist.get(_tmpKey_1)
+ if (_tmpArtist == null) {
+ error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
+ }
+ _result = SongWithArtist(_tmpSong,_tmpArtist)
+ } else {
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
+ }
+ _result
+ } finally {
+ _stmt.close()
}
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
- private fun __fetchRelationshipArtistAsArtist(_map: HashMap<ByteBuffer, Artist?>) {
+ private fun __fetchRelationshipArtistAsArtist(_connection: SQLiteConnection,
+ _map: MutableMap<ByteBuffer, Artist?>) {
val __mapKeySet: Set<ByteBuffer> = _map.keys
if (__mapKeySet.isEmpty()) {
return
}
- if (_map.size > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
- recursiveFetchHashMap(_map, false) {
- __fetchRelationshipArtistAsArtist(it)
+ if (_map.size > 999) {
+ recursiveFetchMap(_map, false) {
+ __fetchRelationshipArtistAsArtist(_connection, it)
}
return
}
@@ -89,33 +89,31 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (_item: ByteBuffer in __mapKeySet) {
_stmt.bindBlob(_argIndex, _item.array())
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
- val _itemKeyIndex: Int = getColumnIndex(_cursor, "artistId")
+ val _itemKeyIndex: Int = getColumnIndex(_stmt, "artistId")
if (_itemKeyIndex == -1) {
return
}
val _cursorIndexOfArtistId: Int = 0
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: ByteBuffer
- _tmpKey = ByteBuffer.wrap(_cursor.getBlob(_itemKeyIndex))
+ _tmpKey = ByteBuffer.wrap(_stmt.getBlob(_itemKeyIndex))
if (_map.containsKey(_tmpKey)) {
val _item_1: Artist
val _tmpArtistId: ByteArray
- _tmpArtistId = _cursor.getBlob(_cursorIndexOfArtistId)
+ _tmpArtistId = _stmt.getBlob(_cursorIndexOfArtistId)
_item_1 = Artist(_tmpArtistId)
_map.put(_tmpKey, _item_1)
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt
index 2c0afeb..5760d95 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt
@@ -1,20 +1,20 @@
-import android.database.Cursor
import androidx.collection.LongSparseArray
import androidx.room.RoomDatabase
-import androidx.room.RoomSQLiteQuery
-import androidx.room.RoomSQLiteQuery.Companion.acquire
import androidx.room.util.appendPlaceholders
import androidx.room.util.getColumnIndex
import androidx.room.util.getColumnIndexOrThrow
-import androidx.room.util.query
+import androidx.room.util.performBlocking
import androidx.room.util.recursiveFetchLongSparseArray
-import java.util.ArrayList
+import androidx.sqlite.SQLiteConnection
+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
+import kotlin.collections.MutableList
+import kotlin.collections.mutableListOf
import kotlin.reflect.KClass
import kotlin.text.StringBuilder
@@ -30,129 +30,129 @@
public override fun getSongsWithArtist(): SongWithArtist {
val _sql: String = "SELECT * FROM Song"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfSongId: Int = getColumnIndexOrThrow(_cursor, "songId")
- val _cursorIndexOfArtistKey: Int = getColumnIndexOrThrow(_cursor, "artistKey")
- val _collectionArtist: LongSparseArray<Artist?> = LongSparseArray<Artist?>()
- while (_cursor.moveToNext()) {
- val _tmpKey: Long
- _tmpKey = _cursor.getLong(_cursorIndexOfArtistKey)
- _collectionArtist.put(_tmpKey, null)
- }
- _cursor.moveToPosition(-1)
- __fetchRelationshipArtistAsArtist(_collectionArtist)
- val _result: SongWithArtist
- if (_cursor.moveToFirst()) {
- val _tmpSong: Song
- val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
- val _tmpArtistKey: Long
- _tmpArtistKey = _cursor.getLong(_cursorIndexOfArtistKey)
- _tmpSong = Song(_tmpSongId,_tmpArtistKey)
- val _tmpArtist: Artist?
- val _tmpKey_1: Long
- _tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistKey)
- _tmpArtist = _collectionArtist.get(_tmpKey_1)
- if (_tmpArtist == null) {
- error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfSongId: Int = getColumnIndexOrThrow(_stmt, "songId")
+ val _cursorIndexOfArtistKey: Int = getColumnIndexOrThrow(_stmt, "artistKey")
+ val _collectionArtist: LongSparseArray<Artist?> = LongSparseArray<Artist?>()
+ while (_stmt.step()) {
+ val _tmpKey: Long
+ _tmpKey = _stmt.getLong(_cursorIndexOfArtistKey)
+ _collectionArtist.put(_tmpKey, null)
}
- _result = SongWithArtist(_tmpSong,_tmpArtist)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
+ _stmt.reset()
+ __fetchRelationshipArtistAsArtist(_connection, _collectionArtist)
+ val _result: SongWithArtist
+ if (_stmt.step()) {
+ val _tmpSong: Song
+ val _tmpSongId: Long
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
+ val _tmpArtistKey: Long
+ _tmpArtistKey = _stmt.getLong(_cursorIndexOfArtistKey)
+ _tmpSong = Song(_tmpSongId,_tmpArtistKey)
+ val _tmpArtist: Artist?
+ val _tmpKey_1: Long
+ _tmpKey_1 = _stmt.getLong(_cursorIndexOfArtistKey)
+ _tmpArtist = _collectionArtist.get(_tmpKey_1)
+ if (_tmpArtist == null) {
+ error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
+ }
+ _result = SongWithArtist(_tmpSong,_tmpArtist)
+ } else {
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
+ }
+ _result
+ } finally {
+ _stmt.close()
}
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
public override fun getArtistAndSongs(): ArtistAndSongs {
val _sql: String = "SELECT * FROM Artist"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfArtistId: Int = getColumnIndexOrThrow(_cursor, "artistId")
- val _collectionSongs: LongSparseArray<ArrayList<Song>> = LongSparseArray<ArrayList<Song>>()
- while (_cursor.moveToNext()) {
- val _tmpKey: Long
- _tmpKey = _cursor.getLong(_cursorIndexOfArtistId)
- if (!_collectionSongs.containsKey(_tmpKey)) {
- _collectionSongs.put(_tmpKey, ArrayList<Song>())
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfArtistId: Int = getColumnIndexOrThrow(_stmt, "artistId")
+ val _collectionSongs: LongSparseArray<MutableList<Song>> =
+ LongSparseArray<MutableList<Song>>()
+ while (_stmt.step()) {
+ val _tmpKey: Long
+ _tmpKey = _stmt.getLong(_cursorIndexOfArtistId)
+ if (!_collectionSongs.containsKey(_tmpKey)) {
+ _collectionSongs.put(_tmpKey, mutableListOf())
+ }
}
+ _stmt.reset()
+ __fetchRelationshipSongAsSong(_connection, _collectionSongs)
+ val _result: ArtistAndSongs
+ if (_stmt.step()) {
+ val _tmpArtist: Artist
+ val _tmpArtistId: Long
+ _tmpArtistId = _stmt.getLong(_cursorIndexOfArtistId)
+ _tmpArtist = Artist(_tmpArtistId)
+ val _tmpSongsCollection: MutableList<Song>
+ val _tmpKey_1: Long
+ _tmpKey_1 = _stmt.getLong(_cursorIndexOfArtistId)
+ _tmpSongsCollection = checkNotNull(_collectionSongs.get(_tmpKey_1))
+ _result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
+ } else {
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
+ }
+ _result
+ } finally {
+ _stmt.close()
}
- _cursor.moveToPosition(-1)
- __fetchRelationshipSongAsSong(_collectionSongs)
- val _result: ArtistAndSongs
- if (_cursor.moveToFirst()) {
- val _tmpArtist: Artist
- val _tmpArtistId: Long
- _tmpArtistId = _cursor.getLong(_cursorIndexOfArtistId)
- _tmpArtist = Artist(_tmpArtistId)
- val _tmpSongsCollection: ArrayList<Song>
- val _tmpKey_1: Long
- _tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistId)
- _tmpSongsCollection = checkNotNull(_collectionSongs.get(_tmpKey_1))
- _result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
- }
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
public override fun getPlaylistAndSongs(): PlaylistAndSongs {
val _sql: String = "SELECT * FROM Playlist"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfPlaylistId: Int = getColumnIndexOrThrow(_cursor, "playlistId")
- val _collectionSongs: LongSparseArray<ArrayList<Song>> = LongSparseArray<ArrayList<Song>>()
- while (_cursor.moveToNext()) {
- val _tmpKey: Long
- _tmpKey = _cursor.getLong(_cursorIndexOfPlaylistId)
- if (!_collectionSongs.containsKey(_tmpKey)) {
- _collectionSongs.put(_tmpKey, ArrayList<Song>())
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfPlaylistId: Int = getColumnIndexOrThrow(_stmt, "playlistId")
+ val _collectionSongs: LongSparseArray<MutableList<Song>> =
+ LongSparseArray<MutableList<Song>>()
+ while (_stmt.step()) {
+ val _tmpKey: Long
+ _tmpKey = _stmt.getLong(_cursorIndexOfPlaylistId)
+ if (!_collectionSongs.containsKey(_tmpKey)) {
+ _collectionSongs.put(_tmpKey, mutableListOf())
+ }
}
+ _stmt.reset()
+ __fetchRelationshipSongAsSong_1(_connection, _collectionSongs)
+ val _result: PlaylistAndSongs
+ if (_stmt.step()) {
+ val _tmpPlaylist: Playlist
+ val _tmpPlaylistId: Long
+ _tmpPlaylistId = _stmt.getLong(_cursorIndexOfPlaylistId)
+ _tmpPlaylist = Playlist(_tmpPlaylistId)
+ val _tmpSongsCollection: MutableList<Song>
+ val _tmpKey_1: Long
+ _tmpKey_1 = _stmt.getLong(_cursorIndexOfPlaylistId)
+ _tmpSongsCollection = checkNotNull(_collectionSongs.get(_tmpKey_1))
+ _result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
+ } else {
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
+ }
+ _result
+ } finally {
+ _stmt.close()
}
- _cursor.moveToPosition(-1)
- __fetchRelationshipSongAsSong_1(_collectionSongs)
- val _result: PlaylistAndSongs
- if (_cursor.moveToFirst()) {
- val _tmpPlaylist: Playlist
- val _tmpPlaylistId: Long
- _tmpPlaylistId = _cursor.getLong(_cursorIndexOfPlaylistId)
- _tmpPlaylist = Playlist(_tmpPlaylistId)
- val _tmpSongsCollection: ArrayList<Song>
- val _tmpKey_1: Long
- _tmpKey_1 = _cursor.getLong(_cursorIndexOfPlaylistId)
- _tmpSongsCollection = checkNotNull(_collectionSongs.get(_tmpKey_1))
- _result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
- }
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
- private fun __fetchRelationshipArtistAsArtist(_map: LongSparseArray<Artist?>) {
+ private fun __fetchRelationshipArtistAsArtist(_connection: SQLiteConnection,
+ _map: LongSparseArray<Artist?>) {
if (_map.isEmpty()) {
return
}
- if (_map.size() > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
+ if (_map.size() > 999) {
recursiveFetchLongSparseArray(_map, false) {
- __fetchRelationshipArtistAsArtist(it)
+ __fetchRelationshipArtistAsArtist(_connection, it)
}
return
}
@@ -162,44 +162,43 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (i in 0 until _map.size()) {
val _item: Long = _map.keyAt(i)
_stmt.bindLong(_argIndex, _item)
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
- val _itemKeyIndex: Int = getColumnIndex(_cursor, "artistId")
+ val _itemKeyIndex: Int = getColumnIndex(_stmt, "artistId")
if (_itemKeyIndex == -1) {
return
}
val _cursorIndexOfArtistId: Int = 0
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: Long
- _tmpKey = _cursor.getLong(_itemKeyIndex)
+ _tmpKey = _stmt.getLong(_itemKeyIndex)
if (_map.containsKey(_tmpKey)) {
val _item_1: Artist
val _tmpArtistId: Long
- _tmpArtistId = _cursor.getLong(_cursorIndexOfArtistId)
+ _tmpArtistId = _stmt.getLong(_cursorIndexOfArtistId)
_item_1 = Artist(_tmpArtistId)
_map.put(_tmpKey, _item_1)
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
- private fun __fetchRelationshipSongAsSong(_map: LongSparseArray<ArrayList<Song>>) {
+ private fun __fetchRelationshipSongAsSong(_connection: SQLiteConnection,
+ _map: LongSparseArray<MutableList<Song>>) {
if (_map.isEmpty()) {
return
}
- if (_map.size() > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
+ if (_map.size() > 999) {
recursiveFetchLongSparseArray(_map, true) {
- __fetchRelationshipSongAsSong(it)
+ __fetchRelationshipSongAsSong(_connection, it)
}
return
}
@@ -209,48 +208,47 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (i in 0 until _map.size()) {
val _item: Long = _map.keyAt(i)
_stmt.bindLong(_argIndex, _item)
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
- val _itemKeyIndex: Int = getColumnIndex(_cursor, "artistKey")
+ val _itemKeyIndex: Int = getColumnIndex(_stmt, "artistKey")
if (_itemKeyIndex == -1) {
return
}
val _cursorIndexOfSongId: Int = 0
val _cursorIndexOfArtistKey: Int = 1
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: Long
- _tmpKey = _cursor.getLong(_itemKeyIndex)
- val _tmpRelation: ArrayList<Song>? = _map.get(_tmpKey)
+ _tmpKey = _stmt.getLong(_itemKeyIndex)
+ val _tmpRelation: MutableList<Song>? = _map.get(_tmpKey)
if (_tmpRelation != null) {
val _item_1: Song
val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
val _tmpArtistKey: Long
- _tmpArtistKey = _cursor.getLong(_cursorIndexOfArtistKey)
+ _tmpArtistKey = _stmt.getLong(_cursorIndexOfArtistKey)
_item_1 = Song(_tmpSongId,_tmpArtistKey)
_tmpRelation.add(_item_1)
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
- private fun __fetchRelationshipSongAsSong_1(_map: LongSparseArray<ArrayList<Song>>) {
+ private fun __fetchRelationshipSongAsSong_1(_connection: SQLiteConnection,
+ _map: LongSparseArray<MutableList<Song>>) {
if (_map.isEmpty()) {
return
}
- if (_map.size() > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
+ if (_map.size() > 999) {
recursiveFetchLongSparseArray(_map, true) {
- __fetchRelationshipSongAsSong_1(it)
+ __fetchRelationshipSongAsSong_1(_connection, it)
}
return
}
@@ -260,15 +258,13 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (i in 0 until _map.size()) {
val _item: Long = _map.keyAt(i)
_stmt.bindLong(_argIndex, _item)
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
// _junction.playlistKey
val _itemKeyIndex: Int = 2
@@ -277,22 +273,22 @@
}
val _cursorIndexOfSongId: Int = 0
val _cursorIndexOfArtistKey: Int = 1
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: Long
- _tmpKey = _cursor.getLong(_itemKeyIndex)
- val _tmpRelation: ArrayList<Song>? = _map.get(_tmpKey)
+ _tmpKey = _stmt.getLong(_itemKeyIndex)
+ val _tmpRelation: MutableList<Song>? = _map.get(_tmpKey)
if (_tmpRelation != null) {
val _item_1: Song
val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
val _tmpArtistKey: Long
- _tmpArtistKey = _cursor.getLong(_cursorIndexOfArtistKey)
+ _tmpArtistKey = _stmt.getLong(_cursorIndexOfArtistKey)
_item_1 = Song(_tmpSongId,_tmpArtistKey)
_tmpRelation.add(_item_1)
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt
index 37123cf2..15d43af 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt
@@ -1,21 +1,22 @@
-import android.database.Cursor
import androidx.room.RoomDatabase
-import androidx.room.RoomSQLiteQuery
-import androidx.room.RoomSQLiteQuery.Companion.acquire
import androidx.room.util.appendPlaceholders
import androidx.room.util.getColumnIndex
import androidx.room.util.getColumnIndexOrThrow
-import androidx.room.util.query
-import androidx.room.util.recursiveFetchHashMap
-import java.util.ArrayList
-import java.util.HashMap
+import androidx.room.util.performBlocking
+import androidx.room.util.recursiveFetchMap
+import androidx.sqlite.SQLiteConnection
+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
+import kotlin.collections.MutableList
+import kotlin.collections.MutableMap
import kotlin.collections.Set
+import kotlin.collections.mutableListOf
+import kotlin.collections.mutableMapOf
import kotlin.reflect.KClass
import kotlin.text.StringBuilder
@@ -31,145 +32,143 @@
public override fun getSongsWithArtist(): SongWithArtist {
val _sql: String = "SELECT * FROM Song"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfSongId: Int = getColumnIndexOrThrow(_cursor, "songId")
- val _cursorIndexOfArtistKey: Int = getColumnIndexOrThrow(_cursor, "artistKey")
- val _collectionArtist: HashMap<Long, Artist?> = HashMap<Long, Artist?>()
- while (_cursor.moveToNext()) {
- val _tmpKey: Long?
- if (_cursor.isNull(_cursorIndexOfArtistKey)) {
- _tmpKey = null
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfSongId: Int = getColumnIndexOrThrow(_stmt, "songId")
+ val _cursorIndexOfArtistKey: Int = getColumnIndexOrThrow(_stmt, "artistKey")
+ val _collectionArtist: MutableMap<Long, Artist?> = mutableMapOf()
+ while (_stmt.step()) {
+ val _tmpKey: Long?
+ if (_stmt.isNull(_cursorIndexOfArtistKey)) {
+ _tmpKey = null
+ } else {
+ _tmpKey = _stmt.getLong(_cursorIndexOfArtistKey)
+ }
+ if (_tmpKey != null) {
+ _collectionArtist.put(_tmpKey, null)
+ }
+ }
+ _stmt.reset()
+ __fetchRelationshipArtistAsArtist(_connection, _collectionArtist)
+ val _result: SongWithArtist
+ if (_stmt.step()) {
+ val _tmpSong: Song
+ val _tmpSongId: Long
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
+ val _tmpArtistKey: Long?
+ if (_stmt.isNull(_cursorIndexOfArtistKey)) {
+ _tmpArtistKey = null
+ } else {
+ _tmpArtistKey = _stmt.getLong(_cursorIndexOfArtistKey)
+ }
+ _tmpSong = Song(_tmpSongId,_tmpArtistKey)
+ val _tmpArtist: Artist?
+ val _tmpKey_1: Long?
+ if (_stmt.isNull(_cursorIndexOfArtistKey)) {
+ _tmpKey_1 = null
+ } else {
+ _tmpKey_1 = _stmt.getLong(_cursorIndexOfArtistKey)
+ }
+ if (_tmpKey_1 != null) {
+ _tmpArtist = _collectionArtist.get(_tmpKey_1)
+ } else {
+ _tmpArtist = null
+ }
+ _result = SongWithArtist(_tmpSong,_tmpArtist)
} else {
- _tmpKey = _cursor.getLong(_cursorIndexOfArtistKey)
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
}
- if (_tmpKey != null) {
- _collectionArtist.put(_tmpKey, null)
- }
+ _result
+ } finally {
+ _stmt.close()
}
- _cursor.moveToPosition(-1)
- __fetchRelationshipArtistAsArtist(_collectionArtist)
- val _result: SongWithArtist
- if (_cursor.moveToFirst()) {
- val _tmpSong: Song
- val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
- val _tmpArtistKey: Long?
- if (_cursor.isNull(_cursorIndexOfArtistKey)) {
- _tmpArtistKey = null
- } else {
- _tmpArtistKey = _cursor.getLong(_cursorIndexOfArtistKey)
- }
- _tmpSong = Song(_tmpSongId,_tmpArtistKey)
- val _tmpArtist: Artist?
- val _tmpKey_1: Long?
- if (_cursor.isNull(_cursorIndexOfArtistKey)) {
- _tmpKey_1 = null
- } else {
- _tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistKey)
- }
- if (_tmpKey_1 != null) {
- _tmpArtist = _collectionArtist.get(_tmpKey_1)
- } else {
- _tmpArtist = null
- }
- _result = SongWithArtist(_tmpSong,_tmpArtist)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
- }
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
public override fun getArtistAndSongs(): ArtistAndSongs {
val _sql: String = "SELECT * FROM Artist"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfArtistId: Int = getColumnIndexOrThrow(_cursor, "artistId")
- val _collectionSongs: HashMap<Long, ArrayList<Song>> = HashMap<Long, ArrayList<Song>>()
- while (_cursor.moveToNext()) {
- val _tmpKey: Long
- _tmpKey = _cursor.getLong(_cursorIndexOfArtistId)
- if (!_collectionSongs.containsKey(_tmpKey)) {
- _collectionSongs.put(_tmpKey, ArrayList<Song>())
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfArtistId: Int = getColumnIndexOrThrow(_stmt, "artistId")
+ val _collectionSongs: MutableMap<Long, MutableList<Song>> = mutableMapOf()
+ while (_stmt.step()) {
+ val _tmpKey: Long
+ _tmpKey = _stmt.getLong(_cursorIndexOfArtistId)
+ if (!_collectionSongs.containsKey(_tmpKey)) {
+ _collectionSongs.put(_tmpKey, mutableListOf())
+ }
}
+ _stmt.reset()
+ __fetchRelationshipSongAsSong(_connection, _collectionSongs)
+ val _result: ArtistAndSongs
+ if (_stmt.step()) {
+ val _tmpArtist: Artist
+ val _tmpArtistId: Long
+ _tmpArtistId = _stmt.getLong(_cursorIndexOfArtistId)
+ _tmpArtist = Artist(_tmpArtistId)
+ val _tmpSongsCollection: MutableList<Song>
+ val _tmpKey_1: Long
+ _tmpKey_1 = _stmt.getLong(_cursorIndexOfArtistId)
+ _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
+ _result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
+ } else {
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
+ }
+ _result
+ } finally {
+ _stmt.close()
}
- _cursor.moveToPosition(-1)
- __fetchRelationshipSongAsSong(_collectionSongs)
- val _result: ArtistAndSongs
- if (_cursor.moveToFirst()) {
- val _tmpArtist: Artist
- val _tmpArtistId: Long
- _tmpArtistId = _cursor.getLong(_cursorIndexOfArtistId)
- _tmpArtist = Artist(_tmpArtistId)
- val _tmpSongsCollection: ArrayList<Song>
- val _tmpKey_1: Long
- _tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistId)
- _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
- _result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
- }
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
public override fun getPlaylistAndSongs(): PlaylistAndSongs {
val _sql: String = "SELECT * FROM Playlist"
- val _statement: RoomSQLiteQuery = acquire(_sql, 0)
- __db.assertNotSuspendingTransaction()
- val _cursor: Cursor = query(__db, _statement, true, null)
- try {
- val _cursorIndexOfPlaylistId: Int = getColumnIndexOrThrow(_cursor, "playlistId")
- val _collectionSongs: HashMap<Long, ArrayList<Song>> = HashMap<Long, ArrayList<Song>>()
- while (_cursor.moveToNext()) {
- val _tmpKey: Long
- _tmpKey = _cursor.getLong(_cursorIndexOfPlaylistId)
- if (!_collectionSongs.containsKey(_tmpKey)) {
- _collectionSongs.put(_tmpKey, ArrayList<Song>())
+ return performBlocking(__db, true, false) { _connection ->
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
+ try {
+ val _cursorIndexOfPlaylistId: Int = getColumnIndexOrThrow(_stmt, "playlistId")
+ val _collectionSongs: MutableMap<Long, MutableList<Song>> = mutableMapOf()
+ while (_stmt.step()) {
+ val _tmpKey: Long
+ _tmpKey = _stmt.getLong(_cursorIndexOfPlaylistId)
+ if (!_collectionSongs.containsKey(_tmpKey)) {
+ _collectionSongs.put(_tmpKey, mutableListOf())
+ }
}
+ _stmt.reset()
+ __fetchRelationshipSongAsSong_1(_connection, _collectionSongs)
+ val _result: PlaylistAndSongs
+ if (_stmt.step()) {
+ val _tmpPlaylist: Playlist
+ val _tmpPlaylistId: Long
+ _tmpPlaylistId = _stmt.getLong(_cursorIndexOfPlaylistId)
+ _tmpPlaylist = Playlist(_tmpPlaylistId)
+ val _tmpSongsCollection: MutableList<Song>
+ val _tmpKey_1: Long
+ _tmpKey_1 = _stmt.getLong(_cursorIndexOfPlaylistId)
+ _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
+ _result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
+ } else {
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
+ }
+ _result
+ } finally {
+ _stmt.close()
}
- _cursor.moveToPosition(-1)
- __fetchRelationshipSongAsSong_1(_collectionSongs)
- val _result: PlaylistAndSongs
- if (_cursor.moveToFirst()) {
- val _tmpPlaylist: Playlist
- val _tmpPlaylistId: Long
- _tmpPlaylistId = _cursor.getLong(_cursorIndexOfPlaylistId)
- _tmpPlaylist = Playlist(_tmpPlaylistId)
- val _tmpSongsCollection: ArrayList<Song>
- val _tmpKey_1: Long
- _tmpKey_1 = _cursor.getLong(_cursorIndexOfPlaylistId)
- _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
- _result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
- } else {
- error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
- }
- return _result
- } finally {
- _cursor.close()
- _statement.release()
}
}
- private fun __fetchRelationshipArtistAsArtist(_map: HashMap<Long, Artist?>) {
+ private fun __fetchRelationshipArtistAsArtist(_connection: SQLiteConnection,
+ _map: MutableMap<Long, Artist?>) {
val __mapKeySet: Set<Long> = _map.keys
if (__mapKeySet.isEmpty()) {
return
}
- if (_map.size > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
- recursiveFetchHashMap(_map, false) {
- __fetchRelationshipArtistAsArtist(it)
+ if (_map.size > 999) {
+ recursiveFetchMap(_map, false) {
+ __fetchRelationshipArtistAsArtist(_connection, it)
}
return
}
@@ -179,44 +178,43 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (_item: Long in __mapKeySet) {
_stmt.bindLong(_argIndex, _item)
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
- val _itemKeyIndex: Int = getColumnIndex(_cursor, "artistId")
+ val _itemKeyIndex: Int = getColumnIndex(_stmt, "artistId")
if (_itemKeyIndex == -1) {
return
}
val _cursorIndexOfArtistId: Int = 0
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: Long
- _tmpKey = _cursor.getLong(_itemKeyIndex)
+ _tmpKey = _stmt.getLong(_itemKeyIndex)
if (_map.containsKey(_tmpKey)) {
val _item_1: Artist?
val _tmpArtistId: Long
- _tmpArtistId = _cursor.getLong(_cursorIndexOfArtistId)
+ _tmpArtistId = _stmt.getLong(_cursorIndexOfArtistId)
_item_1 = Artist(_tmpArtistId)
_map.put(_tmpKey, _item_1)
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
- private fun __fetchRelationshipSongAsSong(_map: HashMap<Long, ArrayList<Song>>) {
+ private fun __fetchRelationshipSongAsSong(_connection: SQLiteConnection,
+ _map: MutableMap<Long, MutableList<Song>>) {
val __mapKeySet: Set<Long> = _map.keys
if (__mapKeySet.isEmpty()) {
return
}
- if (_map.size > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
- recursiveFetchHashMap(_map, true) {
- __fetchRelationshipSongAsSong(it)
+ if (_map.size > 999) {
+ recursiveFetchMap(_map, true) {
+ __fetchRelationshipSongAsSong(_connection, it)
}
return
}
@@ -226,39 +224,37 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (_item: Long in __mapKeySet) {
_stmt.bindLong(_argIndex, _item)
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
- val _itemKeyIndex: Int = getColumnIndex(_cursor, "artistKey")
+ val _itemKeyIndex: Int = getColumnIndex(_stmt, "artistKey")
if (_itemKeyIndex == -1) {
return
}
val _cursorIndexOfSongId: Int = 0
val _cursorIndexOfArtistKey: Int = 1
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: Long?
- if (_cursor.isNull(_itemKeyIndex)) {
+ if (_stmt.isNull(_itemKeyIndex)) {
_tmpKey = null
} else {
- _tmpKey = _cursor.getLong(_itemKeyIndex)
+ _tmpKey = _stmt.getLong(_itemKeyIndex)
}
if (_tmpKey != null) {
- val _tmpRelation: ArrayList<Song>? = _map.get(_tmpKey)
+ val _tmpRelation: MutableList<Song>? = _map.get(_tmpKey)
if (_tmpRelation != null) {
val _item_1: Song
val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
val _tmpArtistKey: Long?
- if (_cursor.isNull(_cursorIndexOfArtistKey)) {
+ if (_stmt.isNull(_cursorIndexOfArtistKey)) {
_tmpArtistKey = null
} else {
- _tmpArtistKey = _cursor.getLong(_cursorIndexOfArtistKey)
+ _tmpArtistKey = _stmt.getLong(_cursorIndexOfArtistKey)
}
_item_1 = Song(_tmpSongId,_tmpArtistKey)
_tmpRelation.add(_item_1)
@@ -266,18 +262,19 @@
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
- private fun __fetchRelationshipSongAsSong_1(_map: HashMap<Long, ArrayList<Song>>) {
+ private fun __fetchRelationshipSongAsSong_1(_connection: SQLiteConnection,
+ _map: MutableMap<Long, MutableList<Song>>) {
val __mapKeySet: Set<Long> = _map.keys
if (__mapKeySet.isEmpty()) {
return
}
- if (_map.size > RoomDatabase.MAX_BIND_PARAMETER_CNT) {
- recursiveFetchHashMap(_map, true) {
- __fetchRelationshipSongAsSong_1(it)
+ if (_map.size > 999) {
+ recursiveFetchMap(_map, true) {
+ __fetchRelationshipSongAsSong_1(_connection, it)
}
return
}
@@ -287,14 +284,12 @@
appendPlaceholders(_stringBuilder, _inputSize)
_stringBuilder.append(")")
val _sql: String = _stringBuilder.toString()
- val _argCount: Int = 0 + _inputSize
- val _stmt: RoomSQLiteQuery = acquire(_sql, _argCount)
+ val _stmt: SQLiteStatement = _connection.prepare(_sql)
var _argIndex: Int = 1
for (_item: Long in __mapKeySet) {
_stmt.bindLong(_argIndex, _item)
_argIndex++
}
- val _cursor: Cursor = query(__db, _stmt, false, null)
try {
// _junction.playlistKey
val _itemKeyIndex: Int = 2
@@ -303,26 +298,26 @@
}
val _cursorIndexOfSongId: Int = 0
val _cursorIndexOfArtistKey: Int = 1
- while (_cursor.moveToNext()) {
+ while (_stmt.step()) {
val _tmpKey: Long
- _tmpKey = _cursor.getLong(_itemKeyIndex)
- val _tmpRelation: ArrayList<Song>? = _map.get(_tmpKey)
+ _tmpKey = _stmt.getLong(_itemKeyIndex)
+ val _tmpRelation: MutableList<Song>? = _map.get(_tmpKey)
if (_tmpRelation != null) {
val _item_1: Song
val _tmpSongId: Long
- _tmpSongId = _cursor.getLong(_cursorIndexOfSongId)
+ _tmpSongId = _stmt.getLong(_cursorIndexOfSongId)
val _tmpArtistKey: Long?
- if (_cursor.isNull(_cursorIndexOfArtistKey)) {
+ if (_stmt.isNull(_cursorIndexOfArtistKey)) {
_tmpArtistKey = null
} else {
- _tmpArtistKey = _cursor.getLong(_cursorIndexOfArtistKey)
+ _tmpArtistKey = _stmt.getLong(_cursorIndexOfArtistKey)
}
_item_1 = Song(_tmpSongId,_tmpArtistKey)
_tmpRelation.add(_item_1)
}
}
} finally {
- _cursor.close()
+ _stmt.close()
}
}
diff --git a/room/room-runtime/api/restricted_current.txt b/room/room-runtime/api/restricted_current.txt
index 7039636..5634a6c 100644
--- a/room/room-runtime/api/restricted_current.txt
+++ b/room/room-runtime/api/restricted_current.txt
@@ -487,10 +487,11 @@
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static <T, C> T findAndInstantiateDatabaseImpl(Class<C> klass, optional String suffix);
}
- @RestrictTo({androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX}) public final class RelationUtil {
- method public static <K, V> void recursiveFetchArrayMap(androidx.collection.ArrayMap<K,V> map, boolean isRelationCollection, kotlin.jvm.functions.Function1<? super androidx.collection.ArrayMap<K,V>,kotlin.Unit> fetchBlock);
- method public static <K, V> void recursiveFetchHashMap(java.util.HashMap<K,V> map, boolean isRelationCollection, kotlin.jvm.functions.Function1<? super java.util.HashMap<K,V>,kotlin.Unit> fetchBlock);
- method public static <V> void recursiveFetchLongSparseArray(androidx.collection.LongSparseArray<V> map, boolean isRelationCollection, kotlin.jvm.functions.Function1<? super androidx.collection.LongSparseArray<V>,kotlin.Unit> fetchBlock);
+ public final class RelationUtil {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static <K, V> void recursiveFetchArrayMap(androidx.collection.ArrayMap<K,V> map, boolean isRelationCollection, kotlin.jvm.functions.Function1<? super androidx.collection.ArrayMap<K,V>,kotlin.Unit> fetchBlock);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static <K, V> void recursiveFetchHashMap(java.util.HashMap<K,V> map, boolean isRelationCollection, kotlin.jvm.functions.Function1<? super java.util.HashMap<K,V>,kotlin.Unit> fetchBlock);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static <V> void recursiveFetchLongSparseArray(androidx.collection.LongSparseArray<V> map, boolean isRelationCollection, kotlin.jvm.functions.Function1<? super androidx.collection.LongSparseArray<V>,kotlin.Unit> fetchBlock);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static <K, V> void recursiveFetchMap(java.util.Map<K,V> map, boolean isRelationCollection, kotlin.jvm.functions.Function1<? super java.util.Map<K,V>,kotlin.Unit> fetchBlock);
}
public final class SQLiteConnectionUtil {
@@ -499,6 +500,7 @@
}
public final class SQLiteStatementUtil {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static int getColumnIndex(androidx.sqlite.SQLiteStatement stmt, String name);
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static int getColumnIndexOrThrow(androidx.sqlite.SQLiteStatement stmt, String name);
}
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/RelationUtil.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/RelationUtil.android.kt
index cefa581..e4f7a9f 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/RelationUtil.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/RelationUtil.android.kt
@@ -14,8 +14,8 @@
* limitations under the License.
*/
+@file:JvmMultifileClass
@file:JvmName("RelationUtil")
-@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
package androidx.room.util
@@ -32,6 +32,7 @@
* @param isRelationCollection - True if [V] is a [Collection] which means it is non null.
* @param fetchBlock - A lambda for calling the generated _fetchRelationship function.
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
fun <K : Any, V> recursiveFetchHashMap(
map: HashMap<K, V>,
isRelationCollection: Boolean,
@@ -73,6 +74,7 @@
/**
* Same as [recursiveFetchHashMap] but for [LongSparseArray].
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
fun <V> recursiveFetchLongSparseArray(
map: LongSparseArray<V>,
isRelationCollection: Boolean,
@@ -112,6 +114,7 @@
/**
* Same as [recursiveFetchHashMap] but for [ArrayMap].
*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
fun <K : Any, V> recursiveFetchArrayMap(
map: ArrayMap<K, V>,
isRelationCollection: Boolean,
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/StatementUtil.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/StatementUtil.android.kt
index 6b4d5d2..587b3fd 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/StatementUtil.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/StatementUtil.android.kt
@@ -27,12 +27,12 @@
*
* The implementation also contains Android-specific patches to workaround issues on older devices.
*/
-internal actual fun SQLiteStatement.getColumnIndex(name: String): Int {
- var index = this.columnIndexOf(name)
+internal actual fun SQLiteStatement.columnIndexOf(name: String): Int {
+ var index = this.columnIndexOfCommon(name)
if (index >= 0) {
return index
}
- index = this.columnIndexOf("`$name`")
+ index = this.columnIndexOfCommon("`$name`")
return if (index >= 0) {
index
} else {
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/RelationUtil.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/RelationUtil.kt
new file mode 100644
index 0000000..3a11b73
--- /dev/null
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/RelationUtil.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2024 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.
+ */
+
+@file:JvmMultifileClass
+@file:JvmName("RelationUtil")
+
+package androidx.room.util
+
+import androidx.annotation.RestrictTo
+import kotlin.jvm.JvmMultifileClass
+import kotlin.jvm.JvmName
+
+/**
+ * Utility function used in generated code to recursively fetch relationships when the amount of
+ * keys exceed [MAX_BIND_PARAMETER_CNT].
+ *
+ * @param map - The map containing the relationship keys to fill-in.
+ * @param isRelationCollection - True if [V] is a [Collection] which means it is non null.
+ * @param fetchBlock - A lambda for calling the generated _fetchRelationship function.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+fun <K : Any, V> recursiveFetchMap(
+ map: MutableMap<K, V>,
+ isRelationCollection: Boolean,
+ fetchBlock: (MutableMap<K, V>) -> Unit
+) {
+ val tmpMap = mutableMapOf<K, V>()
+ var count = 0
+ for (key in map.keys) {
+ // Safe because `V` is a nullable type arg when isRelationCollection == false and vice versa
+ @Suppress("UNCHECKED_CAST")
+ if (isRelationCollection) {
+ tmpMap[key] = map[key] as V
+ } else {
+ tmpMap[key] = null as V
+ }
+ count++
+ if (count == MAX_BIND_PARAMETER_CNT) {
+ // recursively load that batch
+ fetchBlock(tmpMap)
+ // for non collection relation, put the loaded batch in the original map,
+ // not needed when dealing with collections since references are passed
+ if (!isRelationCollection) {
+ map.putAll(tmpMap)
+ }
+ tmpMap.clear()
+ count = 0
+ }
+ }
+ if (count > 0) {
+ // load the last batch
+ fetchBlock(tmpMap)
+ // for non collection relation, put the last batch in the original map
+ if (!isRelationCollection) {
+ map.putAll(tmpMap)
+ }
+ }
+}
+
+/**
+ * Unfortunately, we cannot read this value so we are only setting it to the SQLite default.
+ */
+internal const val MAX_BIND_PARAMETER_CNT = 999
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/SchemaInfoUtil.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/SchemaInfoUtil.kt
index d4ebdd5..2d68ae8 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/SchemaInfoUtil.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/SchemaInfoUtil.kt
@@ -69,11 +69,11 @@
): Set<TableInfo.ForeignKey> {
// this seems to return everything in order but it is not documented so better be safe
connection.prepare("PRAGMA foreign_key_list(`$tableName`)").use { stmt ->
- val idColumnIndex = stmt.getColumnIndex("id")
- val seqColumnIndex = stmt.getColumnIndex("seq")
- val tableColumnIndex = stmt.getColumnIndex("table")
- val onDeleteColumnIndex = stmt.getColumnIndex("on_delete")
- val onUpdateColumnIndex = stmt.getColumnIndex("on_update")
+ val idColumnIndex = stmt.columnIndexOf("id")
+ val seqColumnIndex = stmt.columnIndexOf("seq")
+ val tableColumnIndex = stmt.columnIndexOf("table")
+ val onDeleteColumnIndex = stmt.columnIndexOf("on_delete")
+ val onUpdateColumnIndex = stmt.columnIndexOf("on_update")
val ordered = readForeignKeyFieldMappings(stmt)
// Reset cursor as readForeignKeyFieldMappings has moved it
@@ -132,10 +132,10 @@
private fun readForeignKeyFieldMappings(
stmt: SQLiteStatement
): List<ForeignKeyWithSequence> {
- val idColumnIndex = stmt.getColumnIndex("id")
- val seqColumnIndex = stmt.getColumnIndex("seq")
- val fromColumnIndex = stmt.getColumnIndex("from")
- val toColumnIndex = stmt.getColumnIndex("to")
+ val idColumnIndex = stmt.columnIndexOf("id")
+ val seqColumnIndex = stmt.columnIndexOf("seq")
+ val fromColumnIndex = stmt.columnIndexOf("from")
+ val toColumnIndex = stmt.columnIndexOf("to")
return buildList {
while (stmt.step()) {
@@ -160,11 +160,11 @@
return emptyMap()
}
- val nameIndex = stmt.getColumnIndex("name")
- val typeIndex = stmt.getColumnIndex("type")
- val notNullIndex = stmt.getColumnIndex("notnull")
- val pkIndex = stmt.getColumnIndex("pk")
- val defaultValueIndex = stmt.getColumnIndex("dflt_value")
+ val nameIndex = stmt.columnIndexOf("name")
+ val typeIndex = stmt.columnIndexOf("type")
+ val notNullIndex = stmt.columnIndexOf("notnull")
+ val pkIndex = stmt.columnIndexOf("pk")
+ val defaultValueIndex = stmt.columnIndexOf("dflt_value")
return buildMap {
do {
@@ -195,9 +195,9 @@
*/
private fun readIndices(connection: SQLiteConnection, tableName: String): Set<TableInfo.Index>? {
connection.prepare("PRAGMA index_list(`$tableName`)").use { stmt ->
- val nameColumnIndex = stmt.getColumnIndex("name")
- val originColumnIndex = stmt.getColumnIndex("origin")
- val uniqueIndex = stmt.getColumnIndex("unique")
+ val nameColumnIndex = stmt.columnIndexOf("name")
+ val originColumnIndex = stmt.columnIndexOf("origin")
+ val uniqueIndex = stmt.columnIndexOf("unique")
if (nameColumnIndex == -1 || originColumnIndex == -1 || uniqueIndex == -1) {
// we cannot read them so better not validate any index.
return null
@@ -228,10 +228,10 @@
unique: Boolean
): TableInfo.Index? {
return connection.prepare("PRAGMA index_xinfo(`$name`)").use { stmt ->
- val seqnoColumnIndex = stmt.getColumnIndex("seqno")
- val cidColumnIndex = stmt.getColumnIndex("cid")
- val nameColumnIndex = stmt.getColumnIndex("name")
- val descColumnIndex = stmt.getColumnIndex("desc")
+ val seqnoColumnIndex = stmt.columnIndexOf("seqno")
+ val cidColumnIndex = stmt.columnIndexOf("cid")
+ val nameColumnIndex = stmt.columnIndexOf("name")
+ val descColumnIndex = stmt.columnIndexOf("desc")
if (
seqnoColumnIndex == -1 ||
cidColumnIndex == -1 ||
@@ -265,7 +265,7 @@
return buildSet {
connection.prepare("PRAGMA table_info(`$tableName`)").use { stmt ->
if (!stmt.step()) return@use
- val nameIndex = stmt.getColumnIndex("name")
+ val nameIndex = stmt.columnIndexOf("name")
do {
add(stmt.getText(nameIndex))
} while (stmt.step())
@@ -278,7 +278,7 @@
"SELECT * FROM sqlite_master WHERE `name` = '$tableName'"
).use { stmt ->
if (stmt.step()) {
- stmt.getText(stmt.getColumnIndex("sql"))
+ stmt.getText(stmt.columnIndexOf("sql"))
} else {
""
}
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/StatementUtil.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/StatementUtil.kt
index cebd289..d45b94f 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/StatementUtil.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/StatementUtil.kt
@@ -30,7 +30,7 @@
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
fun getColumnIndexOrThrow(stmt: SQLiteStatement, name: String): Int {
- val index: Int = stmt.getColumnIndex(name)
+ val index: Int = stmt.columnIndexOf(name)
if (index >= 0) {
return index
}
@@ -43,13 +43,21 @@
/**
* Returns the zero-based index for the given column name, or -1 if the column doesn't exist.
*/
-internal expect fun SQLiteStatement.getColumnIndex(name: String): Int
+internal expect fun SQLiteStatement.columnIndexOf(name: String): Int
// TODO(b/322183292): Consider optimizing by creating a String->Int map, similar to Android
-internal fun SQLiteStatement.columnIndexOf(name: String): Int {
+internal fun SQLiteStatement.columnIndexOfCommon(name: String): Int {
val columnCount = getColumnCount()
for (i in 0 until columnCount) {
if (name == getColumnName(i)) return i
}
return -1
}
+
+/**
+ * Returns the zero-based index for the given column name, or -1 if the column doesn't exist.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+fun getColumnIndex(stmt: SQLiteStatement, name: String): Int {
+ return stmt.columnIndexOf(name)
+}
diff --git a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/StatementUtil.jvmNative.kt b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/StatementUtil.jvmNative.kt
index 437fe5c..96c4bae 100644
--- a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/StatementUtil.jvmNative.kt
+++ b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/StatementUtil.jvmNative.kt
@@ -26,4 +26,4 @@
/**
* Returns the zero-based index for the given column name, or -1 if the column doesn't exist.
*/
-internal actual fun SQLiteStatement.getColumnIndex(name: String): Int = columnIndexOf(name)
+internal actual fun SQLiteStatement.columnIndexOf(name: String): Int = columnIndexOfCommon(name)