/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.arch.persistence.room; import android.arch.persistence.db.SupportSQLiteStatement; import android.support.annotation.RestrictTo; import java.util.concurrent.atomic.AtomicBoolean; /** * Represents a prepared SQLite state that can be re-used multiple times. *

* This class is used by generated code. After it is used, {@code release} must be called so that * it can be used by other threads. *

* To avoid re-entry even within the same thread, this class allows only 1 time access to the shared * statement until it is released. * * @hide */ @SuppressWarnings({"WeakerAccess", "unused"}) @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public abstract class SharedSQLiteStatement { private final AtomicBoolean mLock = new AtomicBoolean(false); private final RoomDatabase mDatabase; private volatile SupportSQLiteStatement mStmt; /** * Creates an SQLite prepared statement that can be re-used across threads. If it is in use, * it automatically creates a new one. * * @param database The database to create the statement in. */ public SharedSQLiteStatement(RoomDatabase database) { mDatabase = database; } /** * Create the query. * * @return The SQL query to prepare. */ protected abstract String createQuery(); protected void assertNotMainThread() { mDatabase.assertNotMainThread(); } private SupportSQLiteStatement createNewStatement() { String query = createQuery(); return mDatabase.compileStatement(query); } private SupportSQLiteStatement getStmt(boolean canUseCached) { final SupportSQLiteStatement stmt; if (canUseCached) { if (mStmt == null) { mStmt = createNewStatement(); } stmt = mStmt; } else { // it is in use, create a one off statement stmt = createNewStatement(); } return stmt; } /** * Call this to get the statement. Must call {@link #release(SupportSQLiteStatement)} once done. */ public SupportSQLiteStatement acquire() { assertNotMainThread(); return getStmt(mLock.compareAndSet(false, true)); } /** * Must call this when statement will not be used anymore. * * @param statement The statement that was returned from acquire. */ public void release(SupportSQLiteStatement statement) { if (statement == mStmt) { mLock.set(false); } } }