SQLiteSession.java revision a9be4154e8dac0de3db5ee42e878beb0639e70e6
1e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown/* 2e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Copyright (C) 2011 The Android Open Source Project 3e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 4e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 5e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * you may not use this file except in compliance with the License. 6e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * You may obtain a copy of the License at 7e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 8e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * http://www.apache.org/licenses/LICENSE-2.0 9e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 10e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Unless required by applicable law or agreed to in writing, software 11e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 12e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * See the License for the specific language governing permissions and 14e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * limitations under the License. 15e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 16e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 17e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownpackage android.database.sqlite; 18e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 19e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.database.CursorWindow; 20e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.database.DatabaseUtils; 21e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.os.ParcelFileDescriptor; 22e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 23e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown/** 24e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Provides a single client the ability to use a database. 25e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 26e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>About database sessions</h2> 27e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 28e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Database access is always performed using a session. The session 29e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * manages the lifecycle of transactions and database connections. 30e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 31e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Sessions can be used to perform both read-only and read-write operations. 32e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * There is some advantage to knowing when a session is being used for 33e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * read-only purposes because the connection pool can optimize the use 34e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * of the available connections to permit multiple read-only operations 35e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * to execute in parallel whereas read-write operations may need to be serialized. 36e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 37e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * When <em>Write Ahead Logging (WAL)</em> is enabled, the database can 38e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * execute simultaneous read-only and read-write transactions, provided that 39e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * at most one read-write transaction is performed at a time. When WAL is not 40e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * enabled, read-only transactions can execute in parallel but read-write 41e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * transactions are mutually exclusive. 42e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 43e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 44e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>Ownership and concurrency guarantees</h2> 45e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 46e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Session objects are not thread-safe. In fact, session objects are thread-bound. 47e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * The {@link SQLiteDatabase} uses a thread-local variable to associate a session 48e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with each thread for the use of that thread alone. Consequently, each thread 49e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * has its own session object and therefore its own transaction state independent 50e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * of other threads. 51e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 52e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * A thread has at most one session per database. This constraint ensures that 53e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * a thread can never use more than one database connection at a time for a 54e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * given database. As the number of available database connections is limited, 55e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * if a single thread tried to acquire multiple connections for the same database 56e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * at the same time, it might deadlock. Therefore we allow there to be only 57e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * one session (so, at most one connection) per thread per database. 58e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 59e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 60e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>Transactions</h2> 61e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 62e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * There are two kinds of transaction: implicit transactions and explicit 63e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * transactions. 64e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 65e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * An implicit transaction is created whenever a database operation is requested 66e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * and there is no explicit transaction currently in progress. An implicit transaction 67e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * only lasts for the duration of the database operation in question and then it 68e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * is ended. If the database operation was successful, then its changes are committed. 69e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 70e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * An explicit transaction is started by calling {@link #beginTransaction} and 71e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * specifying the desired transaction mode. Once an explicit transaction has begun, 72e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * all subsequent database operations will be performed as part of that transaction. 73e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * To end an explicit transaction, first call {@link #setTransactionSuccessful} if the 74e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * transaction was successful, then call {@link #end}. If the transaction was 75e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * marked successful, its changes will be committed, otherwise they will be rolled back. 76e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 77e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Explicit transactions can also be nested. A nested explicit transaction is 78e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * started with {@link #beginTransaction}, marked successful with 79e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * {@link #setTransactionSuccessful}and ended with {@link #endTransaction}. 80e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * If any nested transaction is not marked successful, then the entire transaction 81e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * including all of its nested transactions will be rolled back 82e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * when the outermost transaction is ended. 83e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 84e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * To improve concurrency, an explicit transaction can be yielded by calling 85e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * {@link #yieldTransaction}. If there is contention for use of the database, 86e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * then yielding ends the current transaction, commits its changes, releases the 87e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * database connection for use by another session for a little while, and starts a 88e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * new transaction with the same properties as the original one. 89e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Changes committed by {@link #yieldTransaction} cannot be rolled back. 90e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 91e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * When a transaction is started, the client can provide a {@link SQLiteTransactionListener} 92e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * to listen for notifications of transaction-related events. 93e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 94e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Recommended usage: 95e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <code><pre> 96e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * // First, begin the transaction. 97e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * session.beginTransaction(SQLiteSession.TRANSACTION_MODE_DEFERRED, 0); 98e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * try { 99e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * // Then do stuff... 100e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * session.execute("INSERT INTO ...", null, 0); 101e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 102e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * // As the very last step before ending the transaction, mark it successful. 103e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * session.setTransactionSuccessful(); 104e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * } finally { 105e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * // Finally, end the transaction. 106e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * // This statement will commit the transaction if it was marked successful or 107e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * // roll it back otherwise. 108e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * session.endTransaction(); 109e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * } 110e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </pre></code> 111e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 112e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 113e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>Database connections</h2> 114e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 115e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * A {@link SQLiteDatabase} can have multiple active sessions at the same 116e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * time. Each session acquires and releases connections to the database 117e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * as needed to perform each requested database transaction. If all connections 118e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * are in use, then database transactions on some sessions will block until a 119e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * connection becomes available. 120e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 121e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * The session acquires a single database connection only for the duration 122e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * of a single (implicit or explicit) database transaction, then releases it. 123e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This characteristic allows a small pool of database connections to be shared 124e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * efficiently by multiple sessions as long as they are not all trying to perform 125e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * database transactions at the same time. 126e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 127e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 128e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>Responsiveness</h2> 129e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 130e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Because there are a limited number of database connections and the session holds 131e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * a database connection for the entire duration of a database transaction, 132e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * it is important to keep transactions short. This is especially important 133e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * for read-write transactions since they may block other transactions 134e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * from executing. Consider calling {@link #yieldTransaction} periodically 135e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * during long-running transactions. 136e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 137e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Another important consideration is that transactions that take too long to 138e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * run may cause the application UI to become unresponsive. Even if the transaction 139e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * is executed in a background thread, the user will get bored and 140e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * frustrated if the application shows no data for several seconds while 141e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * a transaction runs. 142e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 143e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Guidelines: 144e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <ul> 145e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <li>Do not perform database transactions on the UI thread.</li> 146e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <li>Keep database transactions as short as possible.</li> 147e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <li>Simple queries often run faster than complex queries.</li> 148e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <li>Measure the performance of your database transactions.</li> 149e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <li>Consider what will happen when the size of the data set grows. 150e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * A query that works well on 100 rows may struggle with 10,000.</li> 151e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </ul> 152e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 153a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * <h2>Reentrance</h2> 154a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * <p> 155a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * This class must tolerate reentrant execution of SQLite operations because 156a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * triggers may call custom SQLite functions that perform additional queries. 157a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * </p> 158a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * 159e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * TODO: Support timeouts on all possibly blocking operations. 160e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 161e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @hide 162e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 163e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownpublic final class SQLiteSession { 164e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final SQLiteConnectionPool mConnectionPool; 165e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 166e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private SQLiteConnection mConnection; 167e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private int mConnectionFlags; 168a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private int mConnectionUseCount; 169e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private Transaction mTransactionPool; 170e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private Transaction mTransactionStack; 171e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 172e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 173e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Transaction mode: Deferred. 174e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 175e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * In a deferred transaction, no locks are acquired on the database 176e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * until the first operation is performed. If the first operation is 177e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * read-only, then a <code>SHARED</code> lock is acquired, otherwise 178e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * a <code>RESERVED</code> lock is acquired. 179e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 180e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * While holding a <code>SHARED</code> lock, this session is only allowed to 181e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * read but other sessions are allowed to read or write. 182e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * While holding a <code>RESERVED</code> lock, this session is allowed to read 183e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or write but other sessions are only allowed to read. 184e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 185e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Because the lock is only acquired when needed in a deferred transaction, 186e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * it is possible for another session to write to the database first before 187e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * this session has a chance to do anything. 188e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 189e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Corresponds to the SQLite <code>BEGIN DEFERRED</code> transaction mode. 190e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 191e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 192e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public static final int TRANSACTION_MODE_DEFERRED = 0; 193e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 194e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 195e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Transaction mode: Immediate. 196e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 197e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * When an immediate transaction begins, the session acquires a 198e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <code>RESERVED</code> lock. 199e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 200e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * While holding a <code>RESERVED</code> lock, this session is allowed to read 201e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or write but other sessions are only allowed to read. 202e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 203e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Corresponds to the SQLite <code>BEGIN IMMEDIATE</code> transaction mode. 204e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 205e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 206e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public static final int TRANSACTION_MODE_IMMEDIATE = 1; 207e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 208e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 209e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Transaction mode: Exclusive. 210e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 211e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * When an exclusive transaction begins, the session acquires an 212e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <code>EXCLUSIVE</code> lock. 213e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 214e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * While holding an <code>EXCLUSIVE</code> lock, this session is allowed to read 215e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or write but no other sessions are allowed to access the database. 216e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 217e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Corresponds to the SQLite <code>BEGIN EXCLUSIVE</code> transaction mode. 218e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 219e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 220e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public static final int TRANSACTION_MODE_EXCLUSIVE = 2; 221e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 222e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 223e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Creates a session bound to the specified connection pool. 224e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 225e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param connectionPool The connection pool. 226e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 227e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public SQLiteSession(SQLiteConnectionPool connectionPool) { 228e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (connectionPool == null) { 229e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("connectionPool must not be null"); 230e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 231e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 232e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPool = connectionPool; 233e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 234e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 235e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 236e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Returns true if the session has a transaction in progress. 237e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 238e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return True if the session has a transaction in progress. 239e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 240e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean hasTransaction() { 241e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mTransactionStack != null; 242e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 243e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 244e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 245e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Returns true if the session has a nested transaction in progress. 246e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 247e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return True if the session has a nested transaction in progress. 248e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 249e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean hasNestedTransaction() { 250e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mTransactionStack != null && mTransactionStack.mParent != null; 251e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 252e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 253e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 254e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Returns true if the session has an active database connection. 255e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 256e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return True if the session has an active database connection. 257e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 258e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean hasConnection() { 259e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mConnection != null; 260e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 261e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 262e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 263e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Begins a transaction. 264e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 265e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Transactions may nest. If the transaction is not in progress, 266e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * then a database connection is obtained and a new transaction is started. 267e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Otherwise, a nested transaction is started. 268e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 269e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Each call to {@link #beginTransaction} must be matched exactly by a call 270e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * to {@link #endTransaction}. To mark a transaction as successful, 271e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * call {@link #setTransactionSuccessful} before calling {@link #endTransaction}. 272e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * If the transaction is not successful, or if any of its nested 273e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * transactions were not successful, then the entire transaction will 274e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * be rolled back when the outermost transaction is ended. 275e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 276e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 277e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param transactionMode The transaction mode. One of: {@link #TRANSACTION_MODE_DEFERRED}, 278e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * {@link #TRANSACTION_MODE_IMMEDIATE}, or {@link #TRANSACTION_MODE_EXCLUSIVE}. 279e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Ignored when creating a nested transaction. 280e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param transactionListener The transaction listener, or null if none. 281e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param connectionFlags The connection flags to use if a connection must be 282e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * acquired by this operation. Refer to {@link SQLiteConnectionPool}. 283e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 284e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws IllegalStateException if {@link #setTransactionSuccessful} has already been 285e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * called for the current transaction. 286e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 287e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @see #setTransactionSuccessful 288e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @see #yieldTransaction 289e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @see #endTransaction 290e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 291e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void beginTransaction(int transactionMode, 292e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteTransactionListener transactionListener, int connectionFlags) { 293e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfTransactionMarkedSuccessful(); 294e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown beginTransactionUnchecked(transactionMode, transactionListener, connectionFlags); 295e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 296e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 297e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void beginTransactionUnchecked(int transactionMode, 298e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteTransactionListener transactionListener, int connectionFlags) { 299a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (mTransactionStack == null) { 300a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown acquireConnection(null, connectionFlags); // might throw 301a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 302e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 303e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Set up the transaction such that we can back out safely 304e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // in case we fail part way. 305e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mTransactionStack == null) { 306e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Execute SQL might throw a runtime exception. 307e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown switch (transactionMode) { 308e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case TRANSACTION_MODE_IMMEDIATE: 309e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnection.execute("BEGIN IMMEDIATE;", null); // might throw 310e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 311e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case TRANSACTION_MODE_EXCLUSIVE: 312e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnection.execute("BEGIN EXCLUSIVE;", null); // might throw 313e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 314e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown default: 315e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnection.execute("BEGIN;", null); // might throw 316e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 317e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 318e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 319e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 320e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Listener might throw a runtime exception. 321e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (transactionListener != null) { 322e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 323e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown transactionListener.onBegin(); // might throw 324e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 325e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mTransactionStack == null) { 326e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnection.execute("ROLLBACK;", null); // might throw 327e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 328e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 329e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 330e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 331e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 332e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Bookkeeping can't throw, except an OOM, which is just too bad... 333e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Transaction transaction = obtainTransaction(transactionMode, transactionListener); 334e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown transaction.mParent = mTransactionStack; 335e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mTransactionStack = transaction; 336e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 337a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (mTransactionStack == null) { 338a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown releaseConnection(); // might throw 339a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 340e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 341e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 342e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 343e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 344e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Marks the current transaction as having completed successfully. 345e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 346e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This method can be called at most once between {@link #beginTransaction} and 347e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * {@link #endTransaction} to indicate that the changes made by the transaction should be 348e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * committed. If this method is not called, the changes will be rolled back 349e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * when the transaction is ended. 350e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 351e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 352e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws IllegalStateException if there is no current transaction, or if 353e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * {@link #setTransactionSuccessful} has already been called for the current transaction. 354e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 355e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @see #beginTransaction 356e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @see #endTransaction 357e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 358e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void setTransactionSuccessful() { 359e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfNoTransaction(); 360e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfTransactionMarkedSuccessful(); 361e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 362e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mTransactionStack.mMarkedSuccessful = true; 363e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 364e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 365e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 366e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Ends the current transaction and commits or rolls back changes. 367e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 368e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * If this is the outermost transaction (not nested within any other 369e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * transaction), then the changes are committed if {@link #setTransactionSuccessful} 370e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * was called or rolled back otherwise. 371e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 372e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This method must be called exactly once for each call to {@link #beginTransaction}. 373e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 374e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 375e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws IllegalStateException if there is no current transaction. 376e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 377e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @see #beginTransaction 378e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @see #setTransactionSuccessful 379e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @see #yieldTransaction 380e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 381e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void endTransaction() { 382e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfNoTransaction(); 383e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown assert mConnection != null; 384e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 385e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown endTransactionUnchecked(); 386e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 387e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 388e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void endTransactionUnchecked() { 389e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Transaction top = mTransactionStack; 390e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown boolean successful = top.mMarkedSuccessful && !top.mChildFailed; 391e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 392e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown RuntimeException listenerException = null; 393e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final SQLiteTransactionListener listener = top.mListener; 394e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (listener != null) { 395e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 396e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (successful) { 397e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown listener.onCommit(); // might throw 398e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 399e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown listener.onRollback(); // might throw 400e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 401e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 402e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown listenerException = ex; 403e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown successful = false; 404e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 405e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 406e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 407e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mTransactionStack = top.mParent; 408e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown recycleTransaction(top); 409e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 410e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mTransactionStack != null) { 411e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!successful) { 412e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mTransactionStack.mChildFailed = true; 413e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 414e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 415e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 416e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (successful) { 417e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnection.execute("COMMIT;", null); // might throw 418e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 419e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnection.execute("ROLLBACK;", null); // might throw 420e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 421e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 422a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown releaseConnection(); // might throw 423e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 424e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 425e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 426e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (listenerException != null) { 427e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw listenerException; 428e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 429e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 430e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 431e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 432e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Temporarily ends a transaction to let other threads have use of 433e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * the database. Begins a new transaction after a specified delay. 434e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 435e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * If there are other threads waiting to acquire connections, 436e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * then the current transaction is committed and the database 437e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * connection is released. After a short delay, a new transaction 438e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * is started. 439e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 440e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * The transaction is assumed to be successful so far. Do not call 441e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * {@link #setTransactionSuccessful()} before calling this method. 442e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This method will fail if the transaction has already been marked 443e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * successful. 444e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 445e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * The changes that were committed by a yield cannot be rolled back later. 446e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 447e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Before this method was called, there must already have been 448e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * a transaction in progress. When this method returns, there will 449e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * still be a transaction in progress, either the same one as before 450e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or a new one if the transaction was actually yielded. 451e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 452e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This method should not be called when there is a nested transaction 453e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * in progress because it is not possible to yield a nested transaction. 454e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * If <code>throwIfNested</code> is true, then attempting to yield 455e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * a nested transaction will throw {@link IllegalStateException}, otherwise 456e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * the method will return <code>false</code> in that case. 457e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 458e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * If there is no nested transaction in progress but a previous nested 459e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * transaction failed, then the transaction is not yielded (because it 460e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * must be rolled back) and this method returns <code>false</code>. 461e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 462e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 463e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sleepAfterYieldDelayMillis A delay time to wait after yielding 464e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * the database connection to allow other threads some time to run. 465e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * If the value is less than or equal to zero, there will be no additional 466e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * delay beyond the time it will take to begin a new transaction. 467e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param throwIfUnsafe If true, then instead of returning false when no 468e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * transaction is in progress, a nested transaction is in progress, or when 469e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * the transaction has already been marked successful, throws {@link IllegalStateException}. 470e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return True if the transaction was actually yielded. 471e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 472e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws IllegalStateException if <code>throwIfNested</code> is true and 473e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * there is no current transaction, there is a nested transaction in progress or 474e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * if {@link #setTransactionSuccessful} has already been called for the current transaction. 475e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 476e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @see #beginTransaction 477e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @see #endTransaction 478e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 479e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean yieldTransaction(long sleepAfterYieldDelayMillis, boolean throwIfUnsafe) { 480e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (throwIfUnsafe) { 481e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfNoTransaction(); 482e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfTransactionMarkedSuccessful(); 483e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfNestedTransaction(); 484e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 485e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mTransactionStack == null || mTransactionStack.mMarkedSuccessful 486e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown || mTransactionStack.mParent != null) { 487e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return false; 488e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 489e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 490e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown assert mConnection != null; 491e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 492e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mTransactionStack.mChildFailed) { 493e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return false; 494e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 495e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 496e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return yieldTransactionUnchecked(sleepAfterYieldDelayMillis); // might throw 497e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 498e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 499e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private boolean yieldTransactionUnchecked(long sleepAfterYieldDelayMillis) { 500e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mConnectionPool.shouldYieldConnection(mConnection, mConnectionFlags)) { 501e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return false; 502e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 503e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 504e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int transactionMode = mTransactionStack.mMode; 505e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final SQLiteTransactionListener listener = mTransactionStack.mListener; 506e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int connectionFlags = mConnectionFlags; 507e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown endTransactionUnchecked(); // might throw 508e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 509e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sleepAfterYieldDelayMillis > 0) { 510e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 511e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Thread.sleep(sleepAfterYieldDelayMillis); 512e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (InterruptedException ex) { 513e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // we have been interrupted, that's all we need to do 514e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 515e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 516e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 517e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown beginTransactionUnchecked(transactionMode, listener, connectionFlags); // might throw 518e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return true; 519e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 520e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 521e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 522e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Prepares a statement for execution but does not bind its parameters or execute it. 523e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 524e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This method can be used to check for syntax errors during compilation 525e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * prior to execution of the statement. If the {@code outStatementInfo} argument 526e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * is not null, the provided {@link SQLiteStatementInfo} object is populated 527e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with information about the statement. 528e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 529e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * A prepared statement makes no reference to the arguments that may eventually 530e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * be bound to it, consequently it it possible to cache certain prepared statements 531e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * such as SELECT or INSERT/UPDATE statements. If the statement is cacheable, 532e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * then it will be stored in the cache for later and reused if possible. 533e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 534e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 535e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to prepare. 536e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param connectionFlags The connection flags to use if a connection must be 537e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * acquired by this operation. Refer to {@link SQLiteConnectionPool}. 538e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param outStatementInfo The {@link SQLiteStatementInfo} object to populate 539e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with information about the statement, or null if none. 540e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 541e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error. 542e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 543e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void prepare(String sql, int connectionFlags, SQLiteStatementInfo outStatementInfo) { 544e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 545e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 546e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 547e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 548a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown acquireConnection(sql, connectionFlags); // might throw 549e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 550e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnection.prepare(sql, outStatementInfo); // might throw 551e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 552a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown releaseConnection(); // might throw 553e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 554e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 555e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 556e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 557e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that does not return a result. 558e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 559e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 560e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 561e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param connectionFlags The connection flags to use if a connection must be 562e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * acquired by this operation. Refer to {@link SQLiteConnectionPool}. 563e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 564e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 565e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 566e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 567e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void execute(String sql, Object[] bindArgs, int connectionFlags) { 568e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 569e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 570e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 571e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 572e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (executeSpecial(sql, bindArgs, connectionFlags)) { 573e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return; 574e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 575e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 576a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown acquireConnection(sql, connectionFlags); // might throw 577e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 578e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnection.execute(sql, bindArgs); // might throw 579e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 580a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown releaseConnection(); // might throw 581e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 582e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 583e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 584e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 585e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a single <code>long</code> result. 586e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 587e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 588e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 589e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param connectionFlags The connection flags to use if a connection must be 590e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * acquired by this operation. Refer to {@link SQLiteConnectionPool}. 591e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The value of the first column in the first row of the result set 592e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * as a <code>long</code>, or zero if none. 593e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 594e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 595e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 596e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 597e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public long executeForLong(String sql, Object[] bindArgs, int connectionFlags) { 598e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 599e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 600e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 601e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 602e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (executeSpecial(sql, bindArgs, connectionFlags)) { 603e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return 0; 604e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 605e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 606a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown acquireConnection(sql, connectionFlags); // might throw 607e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 608e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mConnection.executeForLong(sql, bindArgs); // might throw 609e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 610a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown releaseConnection(); // might throw 611e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 612e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 613e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 614e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 615e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a single {@link String} result. 616e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 617e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 618e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 619e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param connectionFlags The connection flags to use if a connection must be 620e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * acquired by this operation. Refer to {@link SQLiteConnectionPool}. 621e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The value of the first column in the first row of the result set 622e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * as a <code>String</code>, or null if none. 623e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 624e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 625e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 626e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 627e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String executeForString(String sql, Object[] bindArgs, int connectionFlags) { 628e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 629e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 630e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 631e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 632e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (executeSpecial(sql, bindArgs, connectionFlags)) { 633e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return null; 634e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 635e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 636a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown acquireConnection(sql, connectionFlags); // might throw 637e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 638e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mConnection.executeForString(sql, bindArgs); // might throw 639e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 640a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown releaseConnection(); // might throw 641e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 642e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 643e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 644e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 645e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a single BLOB result as a 646e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * file descriptor to a shared memory region. 647e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 648e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 649e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 650e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param connectionFlags The connection flags to use if a connection must be 651e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * acquired by this operation. Refer to {@link SQLiteConnectionPool}. 652e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The file descriptor for a shared memory region that contains 653e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * the value of the first column in the first row of the result set as a BLOB, 654e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or null if none. 655e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 656e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 657e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 658e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 659e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs, 660e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int connectionFlags) { 661e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 662e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 663e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 664e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 665e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (executeSpecial(sql, bindArgs, connectionFlags)) { 666e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return null; 667e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 668e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 669a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown acquireConnection(sql, connectionFlags); // might throw 670e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 671e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mConnection.executeForBlobFileDescriptor(sql, bindArgs); // might throw 672e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 673a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown releaseConnection(); // might throw 674e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 675e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 676e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 677e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 678e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a count of the number of rows 679e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * that were changed. Use for UPDATE or DELETE SQL statements. 680e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 681e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 682e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 683e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param connectionFlags The connection flags to use if a connection must be 684e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * acquired by this operation. Refer to {@link SQLiteConnectionPool}. 685e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The number of rows that were changed. 686e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 687e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 688e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 689e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 690e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int executeForChangedRowCount(String sql, Object[] bindArgs, int connectionFlags) { 691e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 692e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 693e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 694e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 695e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (executeSpecial(sql, bindArgs, connectionFlags)) { 696e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return 0; 697e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 698e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 699a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown acquireConnection(sql, connectionFlags); // might throw 700e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 701e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mConnection.executeForChangedRowCount(sql, bindArgs); // might throw 702e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 703a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown releaseConnection(); // might throw 704e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 705e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 706e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 707e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 708e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns the row id of the last row inserted 709e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * by the statement. Use for INSERT SQL statements. 710e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 711e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 712e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 713e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param connectionFlags The connection flags to use if a connection must be 714e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * acquired by this operation. Refer to {@link SQLiteConnectionPool}. 715e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The row id of the last row that was inserted, or 0 if none. 716e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 717e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 718e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 719e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 720e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public long executeForLastInsertedRowId(String sql, Object[] bindArgs, int connectionFlags) { 721e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 722e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 723e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 724e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 725e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (executeSpecial(sql, bindArgs, connectionFlags)) { 726e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return 0; 727e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 728e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 729a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown acquireConnection(sql, connectionFlags); // might throw 730e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 731e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mConnection.executeForLastInsertedRowId(sql, bindArgs); // might throw 732e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 733a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown releaseConnection(); // might throw 734e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 735e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 736e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 737e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 738e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement and populates the specified {@link CursorWindow} 739e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with a range of results. Returns the number of rows that were counted 740e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * during query execution. 741e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 742e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 743e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 744e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param window The cursor window to clear and fill. 745e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param startPos The start position for filling the window. 746e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param requiredPos The position of a row that MUST be in the window. 747e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * If it won't fit, then the query should discard part of what it filled 748e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * so that it does. Must be greater than or equal to <code>startPos</code>. 749e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param countAllRows True to count all rows that the query would return 750e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * regagless of whether they fit in the window. 751e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param connectionFlags The connection flags to use if a connection must be 752e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * acquired by this operation. Refer to {@link SQLiteConnectionPool}. 753e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The number of rows that were counted during query execution. Might 754e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * not be all rows in the result set unless <code>countAllRows</code> is true. 755e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 756e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 757e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 758e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 759e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int executeForCursorWindow(String sql, Object[] bindArgs, 760e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown CursorWindow window, int startPos, int requiredPos, boolean countAllRows, 761e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int connectionFlags) { 762e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 763e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 764e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 765e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (window == null) { 766e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("window must not be null."); 767e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 768e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 769e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (executeSpecial(sql, bindArgs, connectionFlags)) { 770e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown window.clear(); 771e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return 0; 772e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 773e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 774a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown acquireConnection(sql, connectionFlags); // might throw 775e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 776e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mConnection.executeForCursorWindow(sql, bindArgs, 777e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown window, startPos, requiredPos, countAllRows); // might throw 778e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 779a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown releaseConnection(); // might throw 780e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 781e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 782e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 783e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 784e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Performs special reinterpretation of certain SQL statements such as "BEGIN", 785e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * "COMMIT" and "ROLLBACK" to ensure that transaction state invariants are 786e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * maintained. 787e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 788e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This function is mainly used to support legacy apps that perform their 789e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * own transactions by executing raw SQL rather than calling {@link #beginTransaction} 790e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * and the like. 791e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 792e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 793e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 794e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param connectionFlags The connection flags to use if a connection must be 795e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * acquired by this operation. Refer to {@link SQLiteConnectionPool}. 796e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return True if the statement was of a special form that was handled here, 797e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * false otherwise. 798e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 799e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 800e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 801e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 802e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags) { 803e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int type = DatabaseUtils.getSqlStatementType(sql); 804e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown switch (type) { 805e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case DatabaseUtils.STATEMENT_BEGIN: 806e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown beginTransaction(TRANSACTION_MODE_EXCLUSIVE, null, connectionFlags); 807e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return true; 808e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 809e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case DatabaseUtils.STATEMENT_COMMIT: 810e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown setTransactionSuccessful(); 811e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown endTransaction(); 812e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return true; 813e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 814e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case DatabaseUtils.STATEMENT_ABORT: 815e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown endTransaction(); 816e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return true; 817e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 818e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return false; 819e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 820e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 821a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private void acquireConnection(String sql, int connectionFlags) { 822a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (mConnection == null) { 823a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown assert mConnectionUseCount == 0; 824e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnection = mConnectionPool.acquireConnection(sql, connectionFlags); // might throw 825e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionFlags = connectionFlags; 826e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 827a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mConnectionUseCount += 1; 828e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 829e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 830a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private void releaseConnection() { 831a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown assert mConnection != null; 832a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown assert mConnectionUseCount > 0; 833a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (--mConnectionUseCount == 0) { 834e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 835e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPool.releaseConnection(mConnection); // might throw 836e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 837e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnection = null; 838e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 839e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 840e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 841e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 842e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void throwIfNoTransaction() { 843e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mTransactionStack == null) { 844e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalStateException("Cannot perform this operation because " 845e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + "there is no current transaction."); 846e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 847e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 848e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 849e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void throwIfTransactionMarkedSuccessful() { 850e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mTransactionStack != null && mTransactionStack.mMarkedSuccessful) { 851e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalStateException("Cannot perform this operation because " 852e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + "the transaction has already been marked successful. The only " 853e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + "thing you can do now is call endTransaction()."); 854e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 855e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 856e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 857e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void throwIfNestedTransaction() { 858e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mTransactionStack == null && mTransactionStack.mParent != null) { 859e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalStateException("Cannot perform this operation because " 860e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + "a nested transaction is in progress."); 861e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 862e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 863e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 864e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private Transaction obtainTransaction(int mode, SQLiteTransactionListener listener) { 865e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Transaction transaction = mTransactionPool; 866e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (transaction != null) { 867e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mTransactionPool = transaction.mParent; 868e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown transaction.mParent = null; 869e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown transaction.mMarkedSuccessful = false; 870e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown transaction.mChildFailed = false; 871e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 872e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown transaction = new Transaction(); 873e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 874e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown transaction.mMode = mode; 875e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown transaction.mListener = listener; 876e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return transaction; 877e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 878e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 879e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void recycleTransaction(Transaction transaction) { 880e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown transaction.mParent = mTransactionPool; 881e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown transaction.mListener = null; 882e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mTransactionPool = transaction; 883e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 884e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 885e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final class Transaction { 886e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public Transaction mParent; 887e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int mMode; 888e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public SQLiteTransactionListener mListener; 889e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean mMarkedSuccessful; 890e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean mChildFailed; 891e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 892e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown} 893