1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package androidx.room 17 18 import androidx.annotation.RestrictTo 19 import androidx.sqlite.db.SupportSQLiteStatement 20 import java.util.concurrent.atomic.AtomicBoolean 21 22 /** 23 * Represents a prepared SQLite state that can be re-used multiple times. 24 * 25 * This class is used by generated code. After it is used, `release` must be called so that it can 26 * be used by other threads. 27 * 28 * To avoid re-entry even within the same thread, this class allows only 1 time access to the shared 29 * statement until it is released. 30 * 31 * @constructor Creates an SQLite prepared statement that can be re-used across threads. If it is in 32 * use, it automatically creates a new one. 33 */ 34 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code 35 abstract class SharedSQLiteStatement(private val database: RoomDatabase) { 36 private val lock = AtomicBoolean(false) 37 <lambda>null38 private val stmt: SupportSQLiteStatement by lazy { createNewStatement() } 39 40 /** 41 * Create the query. 42 * 43 * @return The SQL query to prepare. 44 */ createQuerynull45 protected abstract fun createQuery(): String 46 47 protected open fun assertNotMainThread() { 48 database.assertNotMainThread() 49 } 50 createNewStatementnull51 private fun createNewStatement(): SupportSQLiteStatement { 52 val query = createQuery() 53 return database.compileStatement(query) 54 } 55 getStmtnull56 private fun getStmt(canUseCached: Boolean): SupportSQLiteStatement { 57 val stmt = 58 if (canUseCached) { 59 stmt 60 } else { 61 // it is in use, create a one off statement 62 createNewStatement() 63 } 64 return stmt 65 } 66 67 /** Call this to get the statement. Must call [.release] once done. */ acquirenull68 open fun acquire(): SupportSQLiteStatement { 69 assertNotMainThread() 70 return getStmt(lock.compareAndSet(false, true)) 71 } 72 73 /** 74 * Must call this when statement will not be used anymore. 75 * 76 * @param statement The statement that was returned from acquire. 77 */ releasenull78 open fun release(statement: SupportSQLiteStatement) { 79 if (statement === stmt) { 80 lock.set(false) 81 } 82 } 83 } 84