Merge "Add new room external antlr library as dependency to plugin and itg test" into androidx-main
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraValidator.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraValidator.java
index 4af8c7b..43242b4 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraValidator.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraValidator.java
@@ -22,8 +22,10 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
 import androidx.annotation.RequiresApi;
 import androidx.camera.core.CameraSelector;
+import androidx.camera.core.ExperimentalLensFacing;
 import androidx.camera.core.Logger;
 
 /**
@@ -31,11 +33,15 @@
  * b/167201193.
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+@OptIn(markerClass = ExperimentalLensFacing.class)
 public final class CameraValidator {
     private CameraValidator() {
     }
 
     private static final String TAG = "CameraValidator";
+    private static final CameraSelector EXTERNAL_LENS_FACING =
+            new CameraSelector.Builder().requireLensFacing(
+                    CameraSelector.LENS_FACING_EXTERNAL).build();
 
     /**
      * Verifies the initialized camera instance in the CameraRepository
@@ -104,6 +110,13 @@
             Logger.w(TAG, "Camera LENS_FACING_FRONT verification failed", e);
             exception = e;
         }
+        try {
+            // Verifies the EXTERNAL camera.
+            EXTERNAL_LENS_FACING.select(cameraRepository.getCameras());
+            availableCameraCount++;
+        } catch (IllegalArgumentException e) {
+            Logger.d(TAG, "No camera with LENS_FACING_EXTERNAL characteristic detected", e);
+        }
 
         if (exception != null) {
             Logger.e(TAG, "Camera LensFacing verification failed, existing cameras: "
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
index 5434623..324e4b7 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
@@ -48,6 +48,7 @@
 import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
 import org.jetbrains.kotlin.ir.visitors.acceptVoid
 import org.jetbrains.kotlin.platform.isJs
+import org.jetbrains.kotlin.platform.isWasm
 import org.jetbrains.kotlin.platform.jvm.isJvm
 import org.jetbrains.kotlin.platform.konan.isNative
 
@@ -255,7 +256,7 @@
             ).lower(moduleFragment)
         }
 
-        if (pluginContext.platform.isJs()) {
+        if (pluginContext.platform.isJs() || pluginContext.platform.isWasm()) {
             WrapJsComposableLambdaLowering(
                 pluginContext,
                 symbolRemapper,
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
index fddc4b1..3d408cf 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
@@ -98,6 +98,7 @@
 import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
 import org.jetbrains.kotlin.name.Name
 import org.jetbrains.kotlin.platform.isJs
+import org.jetbrains.kotlin.platform.isWasm
 import org.jetbrains.kotlin.platform.jvm.isJvm
 
 private class CaptureCollector {
@@ -869,24 +870,23 @@
         val function = expression.function
         val argumentCount = function.valueParameters.size
 
-        val isJs = context.platform.isJs()
-        if (argumentCount > MAX_RESTART_ARGUMENT_COUNT && isJs) {
+        if (argumentCount > MAX_RESTART_ARGUMENT_COUNT && !context.platform.isJvm()) {
             error(
                 "only $MAX_RESTART_ARGUMENT_COUNT parameters " +
-                    "in @Composable lambda are supported on JS"
+                    "in @Composable lambda are supported on" +
+                    "non-JVM targets (K/JS or K/Wasm or K/Native)"
             )
         }
 
         val useComposableLambdaN = argumentCount > MAX_RESTART_ARGUMENT_COUNT
         val useComposableFactory = collector.hasCaptures && declarationContext.composable
-        val rememberComposableN = rememberComposableLambdaNFunction ?: composableLambdaNFunction
         val rememberComposable = rememberComposableLambdaFunction ?: composableLambdaFunction
         val requiresExplicitComposerParameter = useComposableFactory &&
             rememberComposableLambdaFunction == null
         val restartFactorySymbol =
             if (useComposableFactory)
                 if (useComposableLambdaN)
-                    rememberComposableN
+                    rememberComposableLambdaNFunction ?: composableLambdaNFunction
                 else rememberComposable
             else if (useComposableLambdaN)
                 composableLambdaInstanceNFunction
@@ -952,7 +952,7 @@
     ): IrExpression {
         // Kotlin/JS doesn't have an optimization for non-capturing lambdas
         // https://youtrack.jetbrains.com/issue/KT-49923
-        val skipNonCapturingLambdas = !context.platform.isJs()
+        val skipNonCapturingLambdas = !context.platform.isJs() && !context.platform.isWasm()
 
         // If the function doesn't capture, Kotlin's default optimization is sufficient
         if (captures.isEmpty() && skipNonCapturingLambdas) {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt
index 64a3e60..9be135a 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt
@@ -88,7 +88,7 @@
     }
 
     @Deprecated(
-        "Please use the new constructor that takes optional autoCorrect parameter.",
+        "Please use the new constructor that takes optional autoCorrectEnabled parameter.",
         level = DeprecationLevel.WARNING,
         replaceWith = ReplaceWith(
             "KeyboardOptions(" +
@@ -175,7 +175,7 @@
     )
 
     @Deprecated(
-        "Please use the autoCorrectMode property.",
+        "Please use the autoCorrectEnabled property.",
         level = DeprecationLevel.WARNING
     )
     val autoCorrect: Boolean get() = autoCorrectOrDefault
@@ -253,8 +253,8 @@
     }
 
     @Deprecated(
-        "Please use the copy function that takes an autoCorrectMode parameter.",
-        level = DeprecationLevel.WARNING,
+        "Please use the copy function that takes an autoCorrectEnabled parameter.",
+        level = DeprecationLevel.HIDDEN,
         replaceWith = ReplaceWith(
             "copy(" +
                 "capitalization = capitalization, " +
diff --git a/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/CompositionLocalSamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/CompositionLocalSamples.kt
index 06e3907..915eb75 100644
--- a/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/CompositionLocalSamples.kt
+++ b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/CompositionLocalSamples.kt
@@ -65,6 +65,61 @@
 }
 
 @Sampled
+fun compositionLocalComputedAfterProvidingLocal() {
+    val LocalValue = compositionLocalOf { 10 }
+    val LocalLargerValue = compositionLocalOf { 12 }
+    val LocalComputedValue = compositionLocalWithComputedDefaultOf {
+        LocalValue.currentValue + 4
+    }
+
+    // In this example `LocalLargerValue` needs to be re-provided
+    // whenever `LocalValue` is provided to keep its value larger
+    // then `LocalValue`. However, `LocalComputedValue` does not
+    // need to be re-provided to stay larger than `LocalValue` as
+    // it is calculated based on the currently provided value for
+    // `LocalValue`. Whenever `LocalValue` is provided the value
+    // of `LocalComputedValue` is computed based on the currently
+    // provided value for `LocalValue`.
+
+    @Composable
+    fun App() {
+        // Value is 10, the default value for LocalValue
+        val value = LocalValue.current
+        // Value is 12, the default value
+        val largerValue = LocalLargerValue.current
+        // Value is computed to be 14
+        val computedValue = LocalComputedValue.current
+        CompositionLocalProvider(
+            LocalValue provides 20
+        ) {
+            // Value is 20 provided above
+            val nestedValue = LocalValue.current
+            // Value is still 12 as an updated value was not re-provided
+            val nestedLargerValue = LocalLargerValue.current
+            // Values is computed to be 24; LocalValue.current + 4
+            val nestedComputedValue = LocalComputedValue.current
+            CompositionLocalProvider(
+                LocalLargerValue provides LocalValue.current + 2
+            ) {
+                // Value is 22 provided above
+                val newLargerValue = LocalLargerValue.current
+
+                CompositionLocalProvider(
+                    LocalValue provides 50
+                ) {
+                    // Value is now 50 provided above
+                    val finalValue = LocalValue.current
+                    // Value is still 22
+                    val finalLargerValue = LocalLargerValue.current
+                    // Value is now computed to be 54
+                    val finalComputed = LocalComputedValue.current
+                }
+            }
+        }
+    }
+}
+
+@Sampled
 fun someScreenSample() {
     @Composable
     fun SomeScreen() {
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
index 4af9eb7..5cf1202 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
@@ -114,7 +114,16 @@
      * other composition locals by calling [CompositionLocalAccessorScope.currentValue], which is an
      * extension function provided by the context for a [CompositionLocal] key.
      *
+     * The lambda passed to [providesComputed] will be invoked every time the
+     * [CompositionLocal.current] is evaluated for the composition local and computes its value
+     * based on the current value of the locals referenced in the lambda at the time
+     * [CompositionLocal.current] is evaluated. This allows providing values that can be derived
+     * from other locals. For example, if accent colors can be calculated from a single base color,
+     * the accent colors can be provided as computed composition locals. Providing a new base color
+     * would automatically update all the accent colors.
+     *
      * @sample androidx.compose.runtime.samples.compositionLocalProvidedComputed
+     * @sample androidx.compose.runtime.samples.compositionLocalComputedAfterProvidingLocal
      *
      * @see CompositionLocal
      * @see CompositionLocalContext
@@ -281,7 +290,16 @@
  * when the value is not provided. For a [compositionLocalOf] the default value is returned. If no
  * default value has be computed for [CompositionLocal] the default computation is called.
  *
+ * The lambda passed to [compositionLocalWithComputedDefaultOf] will be invoked every time the
+ * [CompositionLocal.current] is evaluated for the composition local and computes its value based
+ * on the current value of the locals referenced in the lambda at the time
+ * [CompositionLocal.current] is evaluated. This allows providing values that can be derived from
+ * other locals. For example, if accent colors can be calculated from a single base color, the
+ * accent colors can be provided as computed composition locals. Providing a new base color would
+ * automatically update all the accent colors.
+ *
  * @sample androidx.compose.runtime.samples.compositionLocalComputedByDefault
+ * @sample androidx.compose.runtime.samples.compositionLocalComputedAfterProvidingLocal
  *
  * @param defaultComputation the default computation to use when this [CompositionLocal] is not
  * provided.
diff --git a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
index 3e4c0db..46de688 100644
--- a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
+++ b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
@@ -774,6 +774,65 @@
             }
         }
     }
+
+    @Suppress("LocalVariableName")
+    @Test
+    // Validate androidx.compose.runtime.samples.compositionLocalComputedAfterProvidingLocal
+    fun validateSampledExample() = compositionTest {
+        val LocalValue = compositionLocalOf { 10 }
+        val LocalLargerValue = compositionLocalOf { 12 }
+        val LocalComputedValue = compositionLocalWithComputedDefaultOf {
+            LocalValue.currentValue + 4
+        }
+
+        @Composable
+        fun App() {
+            // Value is 10, the default value for LocalValue
+            val value = LocalValue.current
+            assertEquals(10, value)
+            // Value is 12, the default value
+            val largerValue = LocalLargerValue.current
+            assertEquals(12, largerValue)
+            // Value is computed to be 14
+            val computedValue = LocalComputedValue.current
+            assertEquals(14, computedValue)
+            CompositionLocalProvider(
+                LocalValue provides 20
+            ) {
+                // Value is 20 provided above
+                val nestedValue = LocalValue.current
+                assertEquals(20, nestedValue)
+                // Value is still 12 as an updated value was not re-provided
+                val nestedLargerValue = LocalLargerValue.current
+                assertEquals(12, nestedLargerValue)
+                // Values is computed to be 24; LocalValue.current + 4
+                val nestedComputedValue = LocalComputedValue.current
+                assertEquals(24, nestedComputedValue)
+                CompositionLocalProvider(
+                    LocalLargerValue provides LocalValue.current + 2
+                ) {
+                    // Value is 22 provided above
+                    val newLargerValue = LocalLargerValue.current
+                    assertEquals(22, newLargerValue)
+                    CompositionLocalProvider(
+                        LocalValue provides 50
+                    ) {
+                        // Value is now 50 provided above
+                        val finalValue = LocalValue.current
+                        assertEquals(50, finalValue)
+                        // Value is still 22
+                        val finalLargerValue = LocalLargerValue.current
+                        assertEquals(22, finalLargerValue)
+                        // Value is now computed to be 54
+                        val finalComputed = LocalComputedValue.current
+                        assertEquals(54, finalComputed)
+                    }
+                }
+            }
+        }
+
+        compose { App() }
+    }
 }
 
 val cacheLocal = staticCompositionLocalOf { "Unset" }
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/ArtifactResolver.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/ArtifactResolver.kt
index 3d98305..89f79a8 100644
--- a/development/importMaven/src/main/kotlin/androidx/build/importMaven/ArtifactResolver.kt
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/ArtifactResolver.kt
@@ -308,15 +308,20 @@
             vararg dependencies: Dependency
         ): List<Configuration> {
             return listOf(
-                LibraryElements.JAR,
-                "aar"
-            ).map { libraryElement ->
+                LibraryElements.JAR to TargetJvmEnvironment.STANDARD_JVM,
+                LibraryElements.JAR to TargetJvmEnvironment.ANDROID,
+                "aar" to TargetJvmEnvironment.ANDROID,
+            ).map { (libraryElement, jvmEnvironment) ->
                 createConfiguration(*dependencies) {
                     attributes.apply {
                         attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, libraryElement)
                         attribute(Usage.USAGE_ATTRIBUTE, Usage.JAVA_RUNTIME)
                         attribute(Category.CATEGORY_ATTRIBUTE, Category.LIBRARY)
                         attribute(Bundling.BUNDLING_ATTRIBUTE, Bundling.EXTERNAL)
+                        attribute(
+                            TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
+                            jvmEnvironment
+                        )
                     }
                 }
             }
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 58ece42..6601baa 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -634,9 +634,14 @@
             <sha256 value="02c12c3c2ae12dd475219ff691c82a4d9ea21f44bc594a181295bf6d43dcfbb0" origin="Generated by Gradle" reason="Artifact is not signed"/>
          </artifact>
       </component>
+      <component group="com.google.guava" name="guava" version="32.1.3-jre">
+         <artifact name="guava-32.1.3-android.jar">
+            <sha256 value="20e6ac8902ddf49e7806cc70f3054c8d91accb5eefdc10f3207e80e0a336b263" reason="https://github.com/google/guava/issues/7154"/>
+         </artifact>
+      </component>
       <component group="com.google.guava" name="guava" version="32.1.3-android">
          <artifact name="guava-32.1.3-jre.jar">
-            <sha256 value="6d4e2b5a118aab62e6e5e29d185a0224eed82c85c40ac3d33cf04a270c3b3744" origin="Generated by Gradle" reason="Artifact is not signed"/>
+            <sha256 value="6d4e2b5a118aab62e6e5e29d185a0224eed82c85c40ac3d33cf04a270c3b3744" reason="https://github.com/google/guava/issues/7154"/>
          </artifact>
       </component>
       <component group="com.google.prefab" name="cli" version="2.1.0">
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt
index cc8f439..f33b5d5 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt
@@ -325,7 +325,7 @@
         val dbFile = instrumentation.targetContext.getDatabasePath("test.db")
         val driverHelper = MigrationTestHelper(
             instrumentation = instrumentation,
-            fileName = dbFile.path,
+            file = dbFile,
             driver = AndroidSQLiteDriver(),
             databaseClass = MigrationDbKotlin::class
         )
diff --git a/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt b/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt
index 52b7c70..a8c82ee 100644
--- a/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt
@@ -41,7 +41,7 @@
         instrumentation = instrumentation,
         driver = driver,
         databaseClass = AutoMigrationDatabase::class,
-        fileName = file.path
+        file = file
     )
 
     override fun getTestHelper() = migrationTestHelper
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/SingleColumnRowAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/SingleColumnRowAdapter.kt
index 28a772b..a4415ba 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/SingleColumnRowAdapter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/SingleColumnRowAdapter.kt
@@ -24,6 +24,9 @@
  * Wraps a row adapter when there is only 1 item with 1 column in the response.
  */
 class SingleColumnRowAdapter(val reader: CursorValueReader) : RowAdapter(reader.typeMirror()) {
+
+    override fun isMigratedToDriver(): Boolean = true
+
     override fun convert(outVarName: String, cursorVarName: String, scope: CodeGenScope) {
         reader.readFromCursor(outVarName, cursorVarName, "0", scope)
     }
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt
index afdf910..720724a 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt
@@ -1240,6 +1240,38 @@
     }
 
     @Test
+    fun queryResultAdapter_singleColumn() {
+        val src = Source.kotlin(
+            "MyDao.kt",
+            """
+            import androidx.room.*
+
+            @Dao
+            interface MyDao {
+              @Query("SELECT count(*) FROM MyEntity")
+              fun count(): Int
+
+              @Query("SELECT 'Tom' FROM MyEntity LIMIT 1")
+              fun text(): String
+
+              @Query("SELECT 'Tom' FROM MyEntity LIMIT 1")
+              fun nullableText(): String?
+            }
+
+            @Entity
+            data class MyEntity(
+                @PrimaryKey
+                val pk: Int,
+            )
+            """.trimIndent()
+        )
+        runTest(
+            sources = listOf(src, databaseSrc),
+            expectedFilePath = getTestGoldenPath(testName.methodName)
+        )
+    }
+
+    @Test
     fun queryResultAdapter_list() {
         val dbSource = Source.kotlin(
             "MyDatabase.kt",
@@ -2048,6 +2080,9 @@
                 @Query("SELECT * FROM MyEntity WHERE pk IN (:arg)")
                 suspend fun getSuspendList(vararg arg: String?): List<MyEntity>
 
+                @Query("SELECT count(*) FROM MyEntity")
+                suspend fun getCount(): Int
+
                 @Query("INSERT INTO MyEntity (pk) VALUES (:pk)")
                 suspend fun insertEntity(pk: Long)
 
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/ComplexDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/ComplexDao.java
index a4181dc..7c8b733 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/ComplexDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/ComplexDao.java
@@ -234,23 +234,26 @@
     @Override
     int getAge(final int id) {
         final String _sql = "SELECT ageColumn FROM user where uid = ?";
-        final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);
-        int _argIndex = 1;
-        _statement.bindLong(_argIndex, id);
-        __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
-        try {
-            final int _result;
-            if (_cursor.moveToFirst()) {
-                _result = _cursor.getInt(0);
-            } else {
-                _result = 0;
+        return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, Integer>() {
+            @Override
+            @NonNull
+            public Integer invoke(@NonNull final SQLiteConnection _connection) {
+                final SQLiteStatement _stmt = _connection.prepare(_sql);
+                try {
+                    int _argIndex = 1;
+                    _stmt.bindLong(_argIndex, id);
+                    final int _result;
+                    if (_stmt.step()) {
+                        _result = (int) (_stmt.getLong(0));
+                    } else {
+                        _result = 0;
+                    }
+                    return _result;
+                } finally {
+                    _stmt.close();
+                }
             }
-            return _result;
-        } finally {
-            _cursor.close();
-            _statement.release();
-        }
+        });
     }
 
     @Override
@@ -299,39 +302,41 @@
         StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
         _stringBuilder.append(")");
         final String _sql = _stringBuilder.toString();
-        final int _argCount = 0 + _inputSize;
-        final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, _argCount);
-        int _argIndex = 1;
-        if (ids == null) {
-            _statement.bindNull(_argIndex);
-        } else {
-            for (Integer _item : ids) {
-                if (_item == null) {
-                    _statement.bindNull(_argIndex);
-                } else {
-                    _statement.bindLong(_argIndex, _item);
+        return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, List<Integer>>() {
+            @Override
+            @NonNull
+            public List<Integer> invoke(@NonNull final SQLiteConnection _connection) {
+                final SQLiteStatement _stmt = _connection.prepare(_sql);
+                try {
+                    int _argIndex = 1;
+                    if (ids == null) {
+                        _stmt.bindNull(_argIndex);
+                    } else {
+                        for (Integer _item : ids) {
+                            if (_item == null) {
+                                _stmt.bindNull(_argIndex);
+                            } else {
+                                _stmt.bindLong(_argIndex, _item);
+                            }
+                            _argIndex++;
+                        }
+                    }
+                    final List<Integer> _result = new ArrayList<Integer>();
+                    while (_stmt.step()) {
+                        final Integer _item_1;
+                        if (_stmt.isNull(0)) {
+                            _item_1 = null;
+                        } else {
+                            _item_1 = (int) (_stmt.getLong(0));
+                        }
+                        _result.add(_item_1);
+                    }
+                    return _result;
+                } finally {
+                    _stmt.close();
                 }
-                _argIndex++;
             }
-        }
-        __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
-        try {
-            final List<Integer> _result = new ArrayList<Integer>();
-            while (_cursor.moveToNext()) {
-                final Integer _item_1;
-                if (_cursor.isNull(0)) {
-                    _item_1 = null;
-                } else {
-                    _item_1 = _cursor.getInt(0);
-                }
-                _result.add(_item_1);
-            }
-            return _result;
-        } finally {
-            _cursor.close();
-            _statement.release();
-        }
+        });
     }
 
     @Override
@@ -349,57 +354,59 @@
         StringUtil.appendPlaceholders(_stringBuilder, _inputSize_2);
         _stringBuilder.append(")");
         final String _sql = _stringBuilder.toString();
-        final int _argCount = 0 + _inputSize + _inputSize_1 + _inputSize_2;
-        final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, _argCount);
-        int _argIndex = 1;
-        if (ids1 == null) {
-            _statement.bindNull(_argIndex);
-        } else {
-            for (Integer _item : ids1) {
-                if (_item == null) {
-                    _statement.bindNull(_argIndex);
-                } else {
-                    _statement.bindLong(_argIndex, _item);
+        return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, List<Integer>>() {
+            @Override
+            @NonNull
+            public List<Integer> invoke(@NonNull final SQLiteConnection _connection) {
+                final SQLiteStatement _stmt = _connection.prepare(_sql);
+                try {
+                    int _argIndex = 1;
+                    if (ids1 == null) {
+                        _stmt.bindNull(_argIndex);
+                    } else {
+                        for (Integer _item : ids1) {
+                            if (_item == null) {
+                                _stmt.bindNull(_argIndex);
+                            } else {
+                                _stmt.bindLong(_argIndex, _item);
+                            }
+                            _argIndex++;
+                        }
+                    }
+                    _argIndex = 1 + _inputSize;
+                    if (ids2 == null) {
+                        _stmt.bindNull(_argIndex);
+                    } else {
+                        for (int _item_1 : ids2) {
+                            _stmt.bindLong(_argIndex, _item_1);
+                            _argIndex++;
+                        }
+                    }
+                    _argIndex = 1 + _inputSize + _inputSize_1;
+                    if (ids3 == null) {
+                        _stmt.bindNull(_argIndex);
+                    } else {
+                        for (int _item_2 : ids3) {
+                            _stmt.bindLong(_argIndex, _item_2);
+                            _argIndex++;
+                        }
+                    }
+                    final List<Integer> _result = new ArrayList<Integer>();
+                    while (_stmt.step()) {
+                        final Integer _item_3;
+                        if (_stmt.isNull(0)) {
+                            _item_3 = null;
+                        } else {
+                            _item_3 = (int) (_stmt.getLong(0));
+                        }
+                        _result.add(_item_3);
+                    }
+                    return _result;
+                } finally {
+                    _stmt.close();
                 }
-                _argIndex++;
             }
-        }
-        _argIndex = 1 + _inputSize;
-        if (ids2 == null) {
-            _statement.bindNull(_argIndex);
-        } else {
-            for (int _item_1 : ids2) {
-                _statement.bindLong(_argIndex, _item_1);
-                _argIndex++;
-            }
-        }
-        _argIndex = 1 + _inputSize + _inputSize_1;
-        if (ids3 == null) {
-            _statement.bindNull(_argIndex);
-        } else {
-            for (int _item_2 : ids3) {
-                _statement.bindLong(_argIndex, _item_2);
-                _argIndex++;
-            }
-        }
-        __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
-        try {
-            final List<Integer> _result = new ArrayList<Integer>();
-            while (_cursor.moveToNext()) {
-                final Integer _item_3;
-                if (_cursor.isNull(0)) {
-                    _item_3 = null;
-                } else {
-                    _item_3 = _cursor.getInt(0);
-                }
-                _result.add(_item_3);
-            }
-            return _result;
-        } finally {
-            _cursor.close();
-            _statement.release();
-        }
+        });
     }
 
     @Override
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/ComplexDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/ComplexDao.java
index 8b1399f..d8c8fde 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/ComplexDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/ComplexDao.java
@@ -198,23 +198,26 @@
     @Override
     int getAge(final int id) {
         final String _sql = "SELECT ageColumn FROM user where uid = ?";
-        final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);
-        int _argIndex = 1;
-        _statement.bindLong(_argIndex, id);
-        __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
-        try {
-            final int _result;
-            if (_cursor.moveToFirst()) {
-                _result = _cursor.getInt(0);
-            } else {
-                _result = 0;
+        return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, Integer>() {
+            @Override
+            @NonNull
+            public Integer invoke(@NonNull final SQLiteConnection _connection) {
+                final SQLiteStatement _stmt = _connection.prepare(_sql);
+                try {
+                    int _argIndex = 1;
+                    _stmt.bindLong(_argIndex, id);
+                    final int _result;
+                    if (_stmt.step()) {
+                        _result = (int) (_stmt.getLong(0));
+                    } else {
+                        _result = 0;
+                    }
+                    return _result;
+                } finally {
+                    _stmt.close();
+                }
             }
-            return _result;
-        } finally {
-            _cursor.close();
-            _statement.release();
-        }
+        });
     }
 
     @Override
@@ -263,39 +266,41 @@
         StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
         _stringBuilder.append(")");
         final String _sql = _stringBuilder.toString();
-        final int _argCount = 0 + _inputSize;
-        final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, _argCount);
-        int _argIndex = 1;
-        if (ids == null) {
-            _statement.bindNull(_argIndex);
-        } else {
-            for (Integer _item : ids) {
-                if (_item == null) {
-                    _statement.bindNull(_argIndex);
-                } else {
-                    _statement.bindLong(_argIndex, _item);
+        return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, List<Integer>>() {
+            @Override
+            @NonNull
+            public List<Integer> invoke(@NonNull final SQLiteConnection _connection) {
+                final SQLiteStatement _stmt = _connection.prepare(_sql);
+                try {
+                    int _argIndex = 1;
+                    if (ids == null) {
+                        _stmt.bindNull(_argIndex);
+                    } else {
+                        for (Integer _item : ids) {
+                            if (_item == null) {
+                                _stmt.bindNull(_argIndex);
+                            } else {
+                                _stmt.bindLong(_argIndex, _item);
+                            }
+                            _argIndex++;
+                        }
+                    }
+                    final List<Integer> _result = new ArrayList<Integer>();
+                    while (_stmt.step()) {
+                        final Integer _item_1;
+                        if (_stmt.isNull(0)) {
+                            _item_1 = null;
+                        } else {
+                            _item_1 = (int) (_stmt.getLong(0));
+                        }
+                        _result.add(_item_1);
+                    }
+                    return _result;
+                } finally {
+                    _stmt.close();
                 }
-                _argIndex++;
             }
-        }
-        __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
-        try {
-            final List<Integer> _result = new ArrayList<Integer>();
-            while (_cursor.moveToNext()) {
-                final Integer _item_1;
-                if (_cursor.isNull(0)) {
-                    _item_1 = null;
-                } else {
-                    _item_1 = _cursor.getInt(0);
-                }
-                _result.add(_item_1);
-            }
-            return _result;
-        } finally {
-            _cursor.close();
-            _statement.release();
-        }
+        });
     }
 
     @Override
@@ -313,57 +318,59 @@
         StringUtil.appendPlaceholders(_stringBuilder, _inputSize_2);
         _stringBuilder.append(")");
         final String _sql = _stringBuilder.toString();
-        final int _argCount = 0 + _inputSize + _inputSize_1 + _inputSize_2;
-        final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, _argCount);
-        int _argIndex = 1;
-        if (ids1 == null) {
-            _statement.bindNull(_argIndex);
-        } else {
-            for (Integer _item : ids1) {
-                if (_item == null) {
-                    _statement.bindNull(_argIndex);
-                } else {
-                    _statement.bindLong(_argIndex, _item);
+        return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, List<Integer>>() {
+            @Override
+            @NonNull
+            public List<Integer> invoke(@NonNull final SQLiteConnection _connection) {
+                final SQLiteStatement _stmt = _connection.prepare(_sql);
+                try {
+                    int _argIndex = 1;
+                    if (ids1 == null) {
+                        _stmt.bindNull(_argIndex);
+                    } else {
+                        for (Integer _item : ids1) {
+                            if (_item == null) {
+                                _stmt.bindNull(_argIndex);
+                            } else {
+                                _stmt.bindLong(_argIndex, _item);
+                            }
+                            _argIndex++;
+                        }
+                    }
+                    _argIndex = 1 + _inputSize;
+                    if (ids2 == null) {
+                        _stmt.bindNull(_argIndex);
+                    } else {
+                        for (int _item_1 : ids2) {
+                            _stmt.bindLong(_argIndex, _item_1);
+                            _argIndex++;
+                        }
+                    }
+                    _argIndex = 1 + _inputSize + _inputSize_1;
+                    if (ids3 == null) {
+                        _stmt.bindNull(_argIndex);
+                    } else {
+                        for (int _item_2 : ids3) {
+                            _stmt.bindLong(_argIndex, _item_2);
+                            _argIndex++;
+                        }
+                    }
+                    final List<Integer> _result = new ArrayList<Integer>();
+                    while (_stmt.step()) {
+                        final Integer _item_3;
+                        if (_stmt.isNull(0)) {
+                            _item_3 = null;
+                        } else {
+                            _item_3 = (int) (_stmt.getLong(0));
+                        }
+                        _result.add(_item_3);
+                    }
+                    return _result;
+                } finally {
+                    _stmt.close();
                 }
-                _argIndex++;
             }
-        }
-        _argIndex = 1 + _inputSize;
-        if (ids2 == null) {
-            _statement.bindNull(_argIndex);
-        } else {
-            for (int _item_1 : ids2) {
-                _statement.bindLong(_argIndex, _item_1);
-                _argIndex++;
-            }
-        }
-        _argIndex = 1 + _inputSize + _inputSize_1;
-        if (ids3 == null) {
-            _statement.bindNull(_argIndex);
-        } else {
-            for (int _item_2 : ids3) {
-                _statement.bindLong(_argIndex, _item_2);
-                _argIndex++;
-            }
-        }
-        __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
-        try {
-            final List<Integer> _result = new ArrayList<Integer>();
-            while (_cursor.moveToNext()) {
-                final Integer _item_3;
-                if (_cursor.isNull(0)) {
-                    _item_3 = null;
-                } else {
-                    _item_3 = _cursor.getInt(0);
-                }
-                _result.add(_item_3);
-            }
-            return _result;
-        } finally {
-            _cursor.close();
-            _statement.release();
-        }
+        });
     }
 
     @Override
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt
index 8987be2..c38f418 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt
@@ -142,6 +142,26 @@
     }
   }
 
+  public override suspend fun getCount(): Int {
+    val _sql: String = "SELECT count(*) FROM MyEntity"
+    return performSuspending(__db, true, false) { _connection ->
+      val _stmt: SQLiteStatement = _connection.prepare(_sql)
+      try {
+        val _result: Int
+        if (_stmt.step()) {
+          val _tmp: Int
+          _tmp = _stmt.getLong(0).toInt()
+          _result = _tmp
+        } else {
+          _result = 0
+        }
+        _result
+      } finally {
+        _stmt.close()
+      }
+    }
+  }
+
   public override suspend fun insertEntity(pk: Long) {
     val _sql: String = "INSERT INTO MyEntity (pk) VALUES (?)"
     return performSuspending(__db, false, true) { _connection ->
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_singleColumn.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_singleColumn.kt
new file mode 100644
index 0000000..d1609c4
--- /dev/null
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_singleColumn.kt
@@ -0,0 +1,86 @@
+import androidx.room.RoomDatabase
+import androidx.room.util.performBlocking
+import androidx.sqlite.SQLiteStatement
+import javax.`annotation`.processing.Generated
+import kotlin.Int
+import kotlin.String
+import kotlin.Suppress
+import kotlin.collections.List
+import kotlin.reflect.KClass
+
+@Generated(value = ["androidx.room.RoomProcessor"])
+@Suppress(names = ["UNCHECKED_CAST", "DEPRECATION", "REDUNDANT_PROJECTION", "REMOVAL"])
+public class MyDao_Impl(
+  __db: RoomDatabase,
+) : MyDao {
+  private val __db: RoomDatabase
+  init {
+    this.__db = __db
+  }
+
+  public override fun count(): Int {
+    val _sql: String = "SELECT count(*) FROM MyEntity"
+    return performBlocking(__db, true, false) { _connection ->
+      val _stmt: SQLiteStatement = _connection.prepare(_sql)
+      try {
+        val _result: Int
+        if (_stmt.step()) {
+          _result = _stmt.getLong(0).toInt()
+        } else {
+          _result = 0
+        }
+        _result
+      } finally {
+        _stmt.close()
+      }
+    }
+  }
+
+  public override fun text(): String {
+    val _sql: String = "SELECT 'Tom' FROM MyEntity LIMIT 1"
+    return performBlocking(__db, true, false) { _connection ->
+      val _stmt: SQLiteStatement = _connection.prepare(_sql)
+      try {
+        val _result: String
+        if (_stmt.step()) {
+          val _tmp: String
+          _tmp = _stmt.getText(0)
+          _result = _tmp
+        } else {
+          error("The query result was empty, but expected a single row to return a NON-NULL object of type <kotlin.String>.")
+        }
+        _result
+      } finally {
+        _stmt.close()
+      }
+    }
+  }
+
+  public override fun nullableText(): String? {
+    val _sql: String = "SELECT 'Tom' FROM MyEntity LIMIT 1"
+    return performBlocking(__db, true, false) { _connection ->
+      val _stmt: SQLiteStatement = _connection.prepare(_sql)
+      try {
+        val _result: String?
+        if (_stmt.step()) {
+          val _tmp: String?
+          if (_stmt.isNull(0)) {
+            _tmp = null
+          } else {
+            _tmp = _stmt.getText(0)
+          }
+          _result = _tmp
+        } else {
+          _result = null
+        }
+        _result
+      } finally {
+        _stmt.close()
+      }
+    }
+  }
+
+  public companion object {
+    public fun getRequiredConverters(): List<KClass<*>> = emptyList()
+  }
+}
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/driver/SupportSQLiteStatement.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/driver/SupportSQLiteStatement.android.kt
index 13f49dd..8782ee3 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/driver/SupportSQLiteStatement.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/driver/SupportSQLiteStatement.android.kt
@@ -17,7 +17,6 @@
 package androidx.room.driver
 
 import android.database.Cursor
-import android.database.DatabaseUtils
 import androidx.annotation.RestrictTo
 import androidx.sqlite.SQLiteStatement
 import androidx.sqlite.db.SupportSQLiteDatabase
@@ -43,14 +42,23 @@
 
     companion object {
         fun create(db: SupportSQLiteDatabase, sql: String): SupportSQLiteStatement {
-            return when (DatabaseUtils.getSqlStatementType(sql)) {
-                DatabaseUtils.STATEMENT_SELECT,
-                DatabaseUtils.STATEMENT_PRAGMA ->
-                    // Statements that return rows (SQLITE_ROW)
-                    SupportAndroidSQLiteStatement(db, sql)
-                else ->
-                    // Statements that don't return row (SQLITE_DONE)
-                    SupportOtherAndroidSQLiteStatement(db, sql)
+            return if (isRowStatement(sql)) {
+                // Statements that return rows (SQLITE_ROW)
+                SupportAndroidSQLiteStatement(db, sql)
+            } else {
+                // Statements that don't return row (SQLITE_DONE)
+                SupportOtherAndroidSQLiteStatement(db, sql)
+            }
+        }
+
+        private fun isRowStatement(sql: String): Boolean {
+            val prefix = sql.trim()
+            if (prefix.length < 3) {
+                return false
+            }
+            return when (prefix.substring(0, 3).uppercase()) {
+                "SEL", "PRA", "WIT" -> true
+                else -> false
             }
         }
     }
diff --git a/room/room-testing/api/current.txt b/room/room-testing/api/current.txt
index 2499cb4..92b8b5c 100644
--- a/room/room-testing/api/current.txt
+++ b/room/room-testing/api/current.txt
@@ -2,12 +2,12 @@
 package androidx.room.testing {
 
   public class MigrationTestHelper extends org.junit.rules.TestWatcher {
+    ctor public MigrationTestHelper(android.app.Instrumentation instrumentation, java.io.File file, androidx.sqlite.SQLiteDriver driver, kotlin.reflect.KClass<? extends androidx.room.RoomDatabase> databaseClass, optional kotlin.jvm.functions.Function0<? extends androidx.room.RoomDatabase> databaseFactory, optional java.util.List<? extends androidx.room.migration.AutoMigrationSpec> autoMigrationSpecs);
     ctor public MigrationTestHelper(android.app.Instrumentation instrumentation, Class<? extends androidx.room.RoomDatabase> databaseClass);
     ctor public MigrationTestHelper(android.app.Instrumentation instrumentation, Class<? extends androidx.room.RoomDatabase> databaseClass, java.util.List<? extends androidx.room.migration.AutoMigrationSpec> specs);
     ctor public MigrationTestHelper(android.app.Instrumentation instrumentation, Class<? extends androidx.room.RoomDatabase> databaseClass, java.util.List<? extends androidx.room.migration.AutoMigrationSpec> specs, optional androidx.sqlite.db.SupportSQLiteOpenHelper.Factory openFactory);
     ctor @Deprecated public MigrationTestHelper(android.app.Instrumentation instrumentation, String assetsFolder);
     ctor @Deprecated public MigrationTestHelper(android.app.Instrumentation instrumentation, String assetsFolder, optional androidx.sqlite.db.SupportSQLiteOpenHelper.Factory openFactory);
-    ctor public MigrationTestHelper(android.app.Instrumentation instrumentation, String fileName, androidx.sqlite.SQLiteDriver driver, kotlin.reflect.KClass<? extends androidx.room.RoomDatabase> databaseClass, optional kotlin.jvm.functions.Function0<? extends androidx.room.RoomDatabase> databaseFactory, optional java.util.List<? extends androidx.room.migration.AutoMigrationSpec> autoMigrationSpecs);
     method public void closeWhenFinished(androidx.room.RoomDatabase db);
     method public void closeWhenFinished(androidx.sqlite.db.SupportSQLiteDatabase db);
     method public final androidx.sqlite.SQLiteConnection createDatabase(int version);
diff --git a/room/room-testing/api/restricted_current.txt b/room/room-testing/api/restricted_current.txt
index 2499cb4..92b8b5c 100644
--- a/room/room-testing/api/restricted_current.txt
+++ b/room/room-testing/api/restricted_current.txt
@@ -2,12 +2,12 @@
 package androidx.room.testing {
 
   public class MigrationTestHelper extends org.junit.rules.TestWatcher {
+    ctor public MigrationTestHelper(android.app.Instrumentation instrumentation, java.io.File file, androidx.sqlite.SQLiteDriver driver, kotlin.reflect.KClass<? extends androidx.room.RoomDatabase> databaseClass, optional kotlin.jvm.functions.Function0<? extends androidx.room.RoomDatabase> databaseFactory, optional java.util.List<? extends androidx.room.migration.AutoMigrationSpec> autoMigrationSpecs);
     ctor public MigrationTestHelper(android.app.Instrumentation instrumentation, Class<? extends androidx.room.RoomDatabase> databaseClass);
     ctor public MigrationTestHelper(android.app.Instrumentation instrumentation, Class<? extends androidx.room.RoomDatabase> databaseClass, java.util.List<? extends androidx.room.migration.AutoMigrationSpec> specs);
     ctor public MigrationTestHelper(android.app.Instrumentation instrumentation, Class<? extends androidx.room.RoomDatabase> databaseClass, java.util.List<? extends androidx.room.migration.AutoMigrationSpec> specs, optional androidx.sqlite.db.SupportSQLiteOpenHelper.Factory openFactory);
     ctor @Deprecated public MigrationTestHelper(android.app.Instrumentation instrumentation, String assetsFolder);
     ctor @Deprecated public MigrationTestHelper(android.app.Instrumentation instrumentation, String assetsFolder, optional androidx.sqlite.db.SupportSQLiteOpenHelper.Factory openFactory);
-    ctor public MigrationTestHelper(android.app.Instrumentation instrumentation, String fileName, androidx.sqlite.SQLiteDriver driver, kotlin.reflect.KClass<? extends androidx.room.RoomDatabase> databaseClass, optional kotlin.jvm.functions.Function0<? extends androidx.room.RoomDatabase> databaseFactory, optional java.util.List<? extends androidx.room.migration.AutoMigrationSpec> autoMigrationSpecs);
     method public void closeWhenFinished(androidx.room.RoomDatabase db);
     method public void closeWhenFinished(androidx.sqlite.db.SupportSQLiteDatabase db);
     method public final androidx.sqlite.SQLiteConnection createDatabase(int version);
diff --git a/room/room-testing/src/androidMain/kotlin/androidx/room/testing/MigrationTestHelper.android.kt b/room/room-testing/src/androidMain/kotlin/androidx/room/testing/MigrationTestHelper.android.kt
index cec9729..9e4a324 100644
--- a/room/room-testing/src/androidMain/kotlin/androidx/room/testing/MigrationTestHelper.android.kt
+++ b/room/room-testing/src/androidMain/kotlin/androidx/room/testing/MigrationTestHelper.android.kt
@@ -34,6 +34,7 @@
 import androidx.sqlite.db.SupportSQLiteDatabase
 import androidx.sqlite.db.SupportSQLiteOpenHelper
 import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
+import java.io.File
 import java.io.FileNotFoundException
 import java.io.IOException
 import java.lang.ref.WeakReference
@@ -179,7 +180,7 @@
      * be used.
      *
      * @param instrumentation The instrumentation instance.
-     * @param fileName Name of the database.
+     * @param file The database file.
      * @param driver A driver that opens connection to a file database. A driver that opens connections
      * to an in-memory database would be meaningless.
      * @param databaseClass The [androidx.room.Database] annotated class.
@@ -189,9 +190,10 @@
      * @param autoMigrationSpecs The list of [androidx.room.ProvidedAutoMigrationSpec] instances
      * for [androidx.room.AutoMigration]s that require them.
      */
+    @Suppress("StreamFiles")
     constructor(
         instrumentation: Instrumentation,
-        fileName: String,
+        file: File,
         driver: SQLiteDriver,
         databaseClass: KClass<out RoomDatabase>,
         databaseFactory: () -> RoomDatabase = {
@@ -209,7 +211,7 @@
         this.delegate = SQLiteDriverMigrationTestHelper(
             instrumentation = instrumentation,
             assetsFolder = assetsFolder,
-            fileName = fileName,
+            file = file,
             driver = driver,
             databaseClass = databaseClass,
             databaseFactory = databaseFactory,
@@ -578,7 +580,7 @@
     private val driver: SQLiteDriver,
     databaseClass: KClass<out RoomDatabase>,
     databaseFactory: () -> RoomDatabase,
-    private val fileName: String,
+    private val file: File,
     private val autoMigrationSpecs: List<AutoMigrationSpec>
 ) : AndroidMigrationTestHelper(instrumentation, assetsFolder) {
 
@@ -612,5 +614,5 @@
     }
 
     private fun createConfiguration(container: RoomDatabase.MigrationContainer) =
-        createDatabaseConfiguration(container, null, driver, fileName)
+        createDatabaseConfiguration(container, null, driver, file.path)
 }
diff --git a/sqlite/integration-tests/driver-conformance-test/src/commonTest/kotlin/androidx/sqlite/driver/test/BaseConformanceTest.kt b/sqlite/integration-tests/driver-conformance-test/src/commonTest/kotlin/androidx/sqlite/driver/test/BaseConformanceTest.kt
index fe51e5b..4c8d2f2 100644
--- a/sqlite/integration-tests/driver-conformance-test/src/commonTest/kotlin/androidx/sqlite/driver/test/BaseConformanceTest.kt
+++ b/sqlite/integration-tests/driver-conformance-test/src/commonTest/kotlin/androidx/sqlite/driver/test/BaseConformanceTest.kt
@@ -288,10 +288,10 @@
     }
 
     @Test
-    fun clearBindings() = testWithConnection {
-        it.execSQL("CREATE TABLE Foo (id)")
-        it.execSQL("INSERT INTO Foo (id) VALUES (1)")
-        it.prepare("SELECT * FROM Foo WHERE id = ?").use {
+    fun clearBindings() = testWithConnection { connection ->
+        connection.execSQL("CREATE TABLE Foo (id)")
+        connection.execSQL("INSERT INTO Foo (id) VALUES (1)")
+        connection.prepare("SELECT * FROM Foo WHERE id = ?").use {
             it.bindLong(1, 1)
             assertThat(it.step()).isTrue()
             it.reset()
@@ -334,6 +334,23 @@
         assertThat(changes).isEqualTo(3)
     }
 
+    @Test
+    fun withClause() = testWithConnection { connection ->
+        var seriesSum = 0
+        connection.prepare(
+            """
+                WITH RECURSIVE
+                  cnt(x) AS (VALUES(1) UNION ALL SELECT x + 1 FROM cnt WHERE x < 10)
+                SELECT x FROM cnt;
+            """.trimIndent()
+        ).use {
+           while (it.step()) {
+               seriesSum += it.getInt(0)
+           }
+        }
+        assertThat(seriesSum).isEqualTo(55)
+    }
+
     private inline fun testWithConnection(block: (SQLiteConnection) -> Unit) {
         val driver = getDriver()
         val connection = driver.open(":memory:")
diff --git a/sqlite/sqlite-framework/src/androidMain/kotlin/androidx/sqlite/driver/AndroidSQLiteStatement.android.kt b/sqlite/sqlite-framework/src/androidMain/kotlin/androidx/sqlite/driver/AndroidSQLiteStatement.android.kt
index 1ee0693..f8ac8bc 100644
--- a/sqlite/sqlite-framework/src/androidMain/kotlin/androidx/sqlite/driver/AndroidSQLiteStatement.android.kt
+++ b/sqlite/sqlite-framework/src/androidMain/kotlin/androidx/sqlite/driver/AndroidSQLiteStatement.android.kt
@@ -17,7 +17,6 @@
 package androidx.sqlite.driver
 
 import android.database.Cursor
-import android.database.DatabaseUtils
 import android.database.sqlite.SQLiteCursor
 import android.database.sqlite.SQLiteDatabase
 import android.database.sqlite.SQLiteProgram
@@ -43,14 +42,23 @@
 
     companion object {
         fun create(db: SQLiteDatabase, sql: String): AndroidSQLiteStatement {
-            return when (DatabaseUtils.getSqlStatementType(sql)) {
-                DatabaseUtils.STATEMENT_SELECT,
-                DatabaseUtils.STATEMENT_PRAGMA ->
-                    // Statements that return rows (SQLITE_ROW)
-                    SelectAndroidSQLiteStatement(db, sql)
-                else ->
-                    // Statements that don't return row (SQLITE_DONE)
-                    OtherAndroidSQLiteStatement(db, sql)
+            return if (isRowStatement(sql)) {
+                // Statements that return rows (SQLITE_ROW)
+                SelectAndroidSQLiteStatement(db, sql)
+            } else {
+                // Statements that don't return row (SQLITE_DONE)
+                OtherAndroidSQLiteStatement(db, sql)
+            }
+        }
+
+        private fun isRowStatement(sql: String): Boolean {
+            val prefix = sql.trim()
+            if (prefix.length < 3) {
+                return false
+            }
+            return when (prefix.substring(0, 3).uppercase()) {
+                "SEL", "PRA", "WIT" -> true
+                else -> false
             }
         }
     }
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
index 9583714..4e0cd71c 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
@@ -1198,6 +1198,40 @@
         val userStyleFlavors: UserStyleFlavors
     )
 
+    internal class ChoreographerCallback(
+        val watchFaceImpl: WatchFaceImpl
+    ) : Choreographer.FrameCallback {
+        /**
+         * Whether we already have a frameCallback posted and waiting in the [Choreographer]
+         * queue. This protects us from drawing multiple times in a single frame.
+         */
+        var frameCallbackPending = false
+
+        override fun doFrame(frameTimeNs: Long) {
+            frameCallbackPending = false
+
+            /**
+             * It's possible we went ambient by the time our callback occurred in which case
+             * there's no point drawing.
+             */
+            if (watchFaceImpl.renderer.shouldAnimate()) {
+                try {
+                    if (TRACE_DRAW) {
+                        Trace.beginSection("onDraw")
+                    }
+                    if (LOG_VERBOSE) {
+                        Log.v(TAG, "drawing frame")
+                    }
+                    watchFaceImpl.onDraw()
+                } finally {
+                    if (TRACE_DRAW) {
+                        Trace.endSection()
+                    }
+                }
+            }
+        }
+    }
+
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @OptIn(WatchFaceExperimental::class)
     public inner class EngineWrapper(
@@ -1272,41 +1306,13 @@
         override val systemTimeProvider = getSystemTimeProvider()
         override val wearSdkVersion = this@WatchFaceService.wearPlatformVersion
 
-        /**
-         * Whether we already have a [frameCallback] posted and waiting in the [Choreographer]
-         * queue. This protects us from drawing multiple times in a single frame.
-         */
-        private var frameCallbackPending = false
-
         internal var editorObscuresWatchFace = false
             set(value) {
                 getWatchFaceImplOrNull()?.editorObscuresWatchFace = value
                 field = value
             }
 
-        private val frameCallback =
-            object : Choreographer.FrameCallback {
-                override fun doFrame(frameTimeNs: Long) {
-                    if (destroyed) {
-                        return
-                    }
-                    require(allowWatchfaceToAnimate) {
-                        "Choreographer doFrame called but allowWatchfaceToAnimate is false"
-                    }
-                    frameCallbackPending = false
-
-                    val watchFaceImpl: WatchFaceImpl? = getWatchFaceImplOrNull()
-
-                    /**
-                     * It's possible we went ambient by the time our callback occurred in which case
-                     * there's no point drawing.
-                     */
-                    if (watchFaceImpl?.renderer?.shouldAnimate() != false) {
-                        draw(watchFaceImpl)
-                    }
-                }
-            }
-
+        private var frameCallback: ChoreographerCallback? = null
         private val invalidateRunnable = Runnable(this::invalidate)
 
         // If non-null then changes to the style must be persisted.
@@ -1863,7 +1869,7 @@
                 quitBackgroundThreadIfCreated()
                 uiThreadHandler.removeCallbacks(invalidateRunnable)
                 if (this::choreographer.isInitialized) {
-                    choreographer.removeFrameCallback(frameCallback)
+                    frameCallback?.let { choreographer.removeFrameCallback(it) }
                 }
                 if (this::interactiveInstanceId.isInitialized) {
                     InteractiveInstanceManager.deleteInstance(interactiveInstanceId)
@@ -2446,6 +2452,9 @@
                 // executed. NB usually we won't have to wait at all.
                 initStyleAndComplicationsDone.await()
                 deferredWatchFaceImpl.complete(watchFaceImpl)
+                frameCallback = ChoreographerCallback(watchFaceImpl)
+                // Start issuing choreographer frames.
+                invalidate()
 
                 asyncWatchFaceConstructionPending = false
                 watchFaceImpl.initComplete = true
@@ -2592,18 +2601,20 @@
             if (!allowWatchfaceToAnimate) {
                 return
             }
-            if (!frameCallbackPending) {
-                if (LOG_VERBOSE) {
-                    Log.v(TAG, "invalidate: requesting draw")
-                }
-                frameCallbackPending = true
-                if (!this::choreographer.isInitialized) {
-                    choreographer = getChoreographer()
-                }
-                choreographer.postFrameCallback(frameCallback)
-            } else {
-                if (LOG_VERBOSE) {
-                    Log.v(TAG, "invalidate: draw already requested")
+            frameCallback?.let {
+                if (!it.frameCallbackPending) {
+                    if (LOG_VERBOSE) {
+                        Log.v(TAG, "invalidate: requesting draw")
+                    }
+                    it.frameCallbackPending = true
+                    if (!this::choreographer.isInitialized) {
+                        choreographer = getChoreographer()
+                    }
+                    choreographer.postFrameCallback(it)
+                } else {
+                    if (LOG_VERBOSE) {
+                        Log.v(TAG, "invalidate: draw already requested")
+                    }
                 }
             }
         }
@@ -2954,7 +2965,7 @@
                 writer.println("interactiveInstanceId=$interactiveInstanceId")
             }
 
-            writer.println("frameCallbackPending=$frameCallbackPending")
+            writer.println("frameCallbackPending=${frameCallback?.frameCallbackPending}")
             writer.println("destroyed=$destroyed")
             writer.println("surfaceDestroyed=$surfaceDestroyed")
             writer.println("lastComplications=${complicationsFlow.value}")
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java
index 10931bf..b691e7ac 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java
@@ -100,6 +100,8 @@
 
 import com.google.common.util.concurrent.ListenableFuture;
 
+import kotlinx.coroutines.Dispatchers;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -118,7 +120,6 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
-import kotlinx.coroutines.Dispatchers;
 
 @RunWith(AndroidJUnit4.class)
 public class WorkerWrapperTest extends DatabaseTest {
@@ -181,7 +182,7 @@
         FutureListener listener = createAndAddFutureListener(workerWrapper);
         assertThat(listener.mResult, is(false));
         assertThat(mWorkSpecDao.getState(work.getStringId()), is(SUCCEEDED));
-        assertBeginEndTraceSpans(work);
+        assertBeginEndTraceSpans(work.getWorkSpec());
     }
 
     @Test
@@ -194,7 +195,7 @@
                 .launch();
         WorkSpec latestWorkSpec = mWorkSpecDao.getWorkSpec(work.getStringId());
         assertThat(latestWorkSpec.runAttemptCount, is(1));
-        assertBeginEndTraceSpans(work);
+        assertBeginEndTraceSpans(work.getWorkSpec());
     }
 
     @Test
@@ -207,7 +208,7 @@
                 .launch();
         WorkSpec latestWorkSpec = mWorkSpecDao.getWorkSpec(work.getStringId());
         assertThat(latestWorkSpec.runAttemptCount, is(1));
-        assertBeginEndTraceSpans(work);
+        assertBeginEndTraceSpans(work.getWorkSpec());
     }
 
     @Test
@@ -250,7 +251,7 @@
                 .withWorker(usedWorker)
                 .build();
         workerWrapper.launch();
-        assertBeginEndTraceSpans(work);
+        assertBeginEndTraceSpans(work.getWorkSpec());
     }
 
     @Test
@@ -276,7 +277,7 @@
         FutureListener listener = createAndAddFutureListener(workerWrapper);
         assertThat(listener.mResult, is(false));
         assertThat(mWorkSpecDao.getState(work.getStringId()), is(CANCELLED));
-        assertBeginEndTraceSpans(work);
+        assertBeginEndTraceSpans(work.getWorkSpec());
     }
 
     @Test
@@ -344,7 +345,7 @@
         WorkerWrapper workerWrapper = createBuilder(work.getStringId()).build();
         FutureListener listener = createAndAddFutureListener(workerWrapper);
         assertThat(listener.mResult, is(true));
-        assertBeginEndTraceSpans(work);
+        assertBeginEndTraceSpans(work.getWorkSpec());
     }
 
     @Test
@@ -373,7 +374,7 @@
         List<Data> arguments = mWorkSpecDao.getInputsFromPrerequisites(work.getStringId());
         assertThat(arguments.size(), is(1));
         assertThat(arguments, contains(ChainedArgumentWorker.getChainedArguments()));
-        assertBeginEndTraceSpans(prerequisiteWork);
+        assertBeginEndTraceSpans(prerequisiteWork.getWorkSpec());
     }
 
     @Test
@@ -502,7 +503,7 @@
         assertThat(mWorkSpecDao.getState(work.getStringId()),
                 isOneOf(ENQUEUED, RUNNING, SUCCEEDED));
         assertThat(mWorkSpecDao.getState(cancelledWork.getStringId()), is(CANCELLED));
-        assertBeginEndTraceSpans(prerequisiteWork);
+        assertBeginEndTraceSpans(prerequisiteWork.getWorkSpec());
     }
 
     @Test
@@ -565,7 +566,7 @@
         WorkSpec workSpec = mWorkSpecDao.getWorkSpec(retryWork.getStringId());
         // The run attempt count should remain the same
         assertThat(workSpec.runAttemptCount, is(1));
-        assertBeginEndTraceSpans(retryWork);
+        assertBeginEndTraceSpans(workSpec);
     }
 
     @Test
@@ -586,7 +587,7 @@
 
         WorkSpec updatedWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
         assertThat(updatedWorkSpec.calculateNextRunTime(), greaterThan(periodStartTimeMillis));
-        assertBeginEndTraceSpans(periodicWork);
+        assertBeginEndTraceSpans(periodicWork.getWorkSpec());
     }
 
     @Test
@@ -607,7 +608,7 @@
 
         WorkSpec updatedWorkSpec = mWorkSpecDao.getWorkSpec(periodicWork.getStringId());
         assertThat(updatedWorkSpec.calculateNextRunTime(), greaterThan(periodStartTimeMillis));
-        assertBeginEndTraceSpans(periodicWork);
+        assertBeginEndTraceSpans(periodicWork.getWorkSpec());
     }
 
     @Test
@@ -628,7 +629,7 @@
         assertThat(listener.mResult, is(false));
         assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(0));
         assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
-        assertBeginEndTraceSpans(periodicWork);
+        assertBeginEndTraceSpans(periodicWork.getWorkSpec());
     }
 
     @Test
@@ -649,7 +650,7 @@
         assertThat(listener.mResult, is(false));
         assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(0));
         assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
-        assertBeginEndTraceSpans(periodicWork);
+        assertBeginEndTraceSpans(periodicWork.getWorkSpec());
     }
 
     @Test
@@ -670,7 +671,7 @@
         assertThat(listener.mResult, is(true));
         assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(1));
         assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
-        assertBeginEndTraceSpans(periodicWork);
+        assertBeginEndTraceSpans(periodicWork.getWorkSpec());
     }
 
 
@@ -693,7 +694,7 @@
         FutureListener listener = createAndAddFutureListener(workerWrapper);
         // Should get rescheduled
         assertThat(listener.mResult, is(true));
-        assertBeginEndTraceSpans(periodicWork);
+        assertBeginEndTraceSpans(periodicWork.getWorkSpec());
     }
 
     @Test
@@ -715,7 +716,7 @@
         FutureListener listener = createAndAddFutureListener(workerWrapper);
         // Should get rescheduled because flex should be respected.
         assertThat(listener.mResult, is(true));
-        assertBeginEndTraceSpans(periodicWork);
+        assertBeginEndTraceSpans(periodicWork.getWorkSpec());
     }
 
     @Test
@@ -842,7 +843,7 @@
         assertThat(afterRunWorkSpec.getNextScheduleTimeOverride(), equalTo(secondOverride));
         assertThat(afterRunWorkSpec.calculateNextRunTime(),
                 equalTo(secondOverride));
-        assertBeginEndTraceSpans(periodicWork);
+        assertBeginEndTraceSpans(periodicWork.getWorkSpec());
     }
 
     @Test
@@ -897,7 +898,7 @@
         assertThat(afterRunWorkSpec.getNextScheduleTimeOverride(), equalTo(secondOverrideMillis));
         assertThat(afterRunWorkSpec.calculateNextRunTime(),
                 equalTo(secondOverrideMillis));
-        assertBeginEndTraceSpans(periodicWork);
+        assertBeginEndTraceSpans(periodicWork.getWorkSpec());
     }
 
     @Test
@@ -945,7 +946,7 @@
         // Normal next period is scheduled.
         assertThat(afterRunWorkSpec.calculateNextRunTime(),
                 equalTo(mTestClock.currentTimeMillis + intervalDurationMillis));
-        assertBeginEndTraceSpans(periodicWork);
+        assertBeginEndTraceSpans(periodicWork.getWorkSpec());
     }
 
 
@@ -997,7 +998,7 @@
         // Backoff timing is respected
         assertThat(afterRunWorkSpec.calculateNextRunTime(),
                 equalTo(mTestClock.currentTimeMillis + backoffLinearDurationMillis));
-        assertBeginEndTraceSpans(periodicWork);
+        assertBeginEndTraceSpans(periodicWork.getWorkSpec());
     }
 
     @NonNull
@@ -1423,15 +1424,15 @@
         return listener;
     }
 
-    private void assertBeginEndTraceSpans(WorkRequest workRequest) {
+    private void assertBeginEndTraceSpans(WorkSpec workSpec) {
         ArgumentCaptor<String> traceSpan = ArgumentCaptor.forClass(String.class);
-        ArgumentCaptor<Integer> generation = ArgumentCaptor.forClass(Integer.class);
-        verify(mTracer).beginAsyncSection(traceSpan.capture(), generation.capture());
-        assertThat(workRequest.getWorkSpec().workerClassName, containsString(traceSpan.getValue()));
-        assertThat(workRequest.getWorkSpec().getGeneration(), is(generation.getValue()));
-        verify(mTracer).beginAsyncSection(traceSpan.capture(), generation.capture());
-        assertThat(workRequest.getWorkSpec().workerClassName, containsString(traceSpan.getValue()));
-        assertThat(workRequest.getWorkSpec().getGeneration(), is(generation.getValue()));
+        ArgumentCaptor<Integer> cookie = ArgumentCaptor.forClass(Integer.class);
+        verify(mTracer).beginAsyncSection(traceSpan.capture(), cookie.capture());
+        assertThat(workSpec.workerClassName, containsString(traceSpan.getValue()));
+        assertThat(workSpec.hashCode(), is(cookie.getValue()));
+        verify(mTracer).beginAsyncSection(traceSpan.capture(), cookie.capture());
+        assertThat(workSpec.workerClassName, containsString(traceSpan.getValue()));
+        assertThat(workSpec.hashCode(), is(cookie.getValue()));
     }
 
     private static class FutureListener implements Runnable {
@@ -1465,6 +1466,4 @@
             this.mThrowable = params.getThrowable();
         }
     }
-
-    ;
 }
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/WorkerWrapper.kt b/work/work-runtime/src/main/java/androidx/work/impl/WorkerWrapper.kt
index 22530dc..ba42d86 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/WorkerWrapper.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/WorkerWrapper.kt
@@ -128,7 +128,10 @@
         if (traceTag != null) {
             configuration.tracer.beginAsyncSection(
                 traceTag,
-                workGenerationalId.generation
+                // Use hashCode() instead of a generational id given we want to allow concurrent
+                // execution of Workers with the same name. Additionally `generation` is already
+                // a part of the WorkSpec's hashCode.
+                workSpec.hashCode()
             )
         }
         // Needed for nested transactions, such as when we're in a dependent work request when
@@ -256,7 +259,7 @@
             if (traceTag != null) {
                 configuration.tracer.endAsyncSection(
                     traceTag,
-                    workGenerationalId.generation
+                    workSpec.hashCode()
                 )
             }
         }