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;
21a7771df3696954f0e279407e8894a916a7cb26ccJeff Brownimport android.os.CancellationSignal;
22a7771df3696954f0e279407e8894a916a7cb26ccJeff Brownimport android.os.OperationCanceledException;
23e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.os.ParcelFileDescriptor;
24e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
25e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown/**
26e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Provides a single client the ability to use a database.
27e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
28e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>About database sessions</h2>
29e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p>
30e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Database access is always performed using a session.  The session
31e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * manages the lifecycle of transactions and database connections.
32e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
33e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Sessions can be used to perform both read-only and read-write operations.
34e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * There is some advantage to knowing when a session is being used for
35e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * read-only purposes because the connection pool can optimize the use
36e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * of the available connections to permit multiple read-only operations
37e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * to execute in parallel whereas read-write operations may need to be serialized.
38e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
39e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * When <em>Write Ahead Logging (WAL)</em> is enabled, the database can
40e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * execute simultaneous read-only and read-write transactions, provided that
41e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * at most one read-write transaction is performed at a time.  When WAL is not
42e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * enabled, read-only transactions can execute in parallel but read-write
43e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * transactions are mutually exclusive.
44e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p>
45e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
46e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>Ownership and concurrency guarantees</h2>
47e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p>
48e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Session objects are not thread-safe.  In fact, session objects are thread-bound.
49e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * The {@link SQLiteDatabase} uses a thread-local variable to associate a session
50e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with each thread for the use of that thread alone.  Consequently, each thread
51e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * has its own session object and therefore its own transaction state independent
52e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * of other threads.
53e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
54e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * A thread has at most one session per database.  This constraint ensures that
55e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * a thread can never use more than one database connection at a time for a
56e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * given database.  As the number of available database connections is limited,
57e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * if a single thread tried to acquire multiple connections for the same database
58e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * at the same time, it might deadlock.  Therefore we allow there to be only
59e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * one session (so, at most one connection) per thread per database.
60e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p>
61e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
62e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>Transactions</h2>
63e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p>
64e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * There are two kinds of transaction: implicit transactions and explicit
65e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * transactions.
66e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
67e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * An implicit transaction is created whenever a database operation is requested
68e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * and there is no explicit transaction currently in progress.  An implicit transaction
69e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * only lasts for the duration of the database operation in question and then it
70e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * is ended.  If the database operation was successful, then its changes are committed.
71e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
72e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * An explicit transaction is started by calling {@link #beginTransaction} and
73e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * specifying the desired transaction mode.  Once an explicit transaction has begun,
74e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * all subsequent database operations will be performed as part of that transaction.
75e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * To end an explicit transaction, first call {@link #setTransactionSuccessful} if the
76e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * transaction was successful, then call {@link #end}.  If the transaction was
77e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * marked successful, its changes will be committed, otherwise they will be rolled back.
78e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
79e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Explicit transactions can also be nested.  A nested explicit transaction is
80e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * started with {@link #beginTransaction}, marked successful with
81e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * {@link #setTransactionSuccessful}and ended with {@link #endTransaction}.
82e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * If any nested transaction is not marked successful, then the entire transaction
83e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * including all of its nested transactions will be rolled back
84e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * when the outermost transaction is ended.
85e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
86e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * To improve concurrency, an explicit transaction can be yielded by calling
87e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * {@link #yieldTransaction}.  If there is contention for use of the database,
88e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * then yielding ends the current transaction, commits its changes, releases the
89e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * database connection for use by another session for a little while, and starts a
90e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * new transaction with the same properties as the original one.
91e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Changes committed by {@link #yieldTransaction} cannot be rolled back.
92e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
93e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * When a transaction is started, the client can provide a {@link SQLiteTransactionListener}
94e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * to listen for notifications of transaction-related events.
95e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
96e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Recommended usage:
97e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <code><pre>
98e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * // First, begin the transaction.
99e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * session.beginTransaction(SQLiteSession.TRANSACTION_MODE_DEFERRED, 0);
100e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * try {
101e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *     // Then do stuff...
102e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *     session.execute("INSERT INTO ...", null, 0);
103e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
104e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *     // As the very last step before ending the transaction, mark it successful.
105e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *     session.setTransactionSuccessful();
106e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * } finally {
107e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *     // Finally, end the transaction.
108e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *     // This statement will commit the transaction if it was marked successful or
109e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *     // roll it back otherwise.
110e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *     session.endTransaction();
111e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * }
112e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </pre></code>
113e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p>
114e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
115e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>Database connections</h2>
116e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p>
117e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * A {@link SQLiteDatabase} can have multiple active sessions at the same
118e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * time.  Each session acquires and releases connections to the database
119e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * as needed to perform each requested database transaction.  If all connections
120e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * are in use, then database transactions on some sessions will block until a
121e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * connection becomes available.
122e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
123e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * The session acquires a single database connection only for the duration
124e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * of a single (implicit or explicit) database transaction, then releases it.
125e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This characteristic allows a small pool of database connections to be shared
126e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * efficiently by multiple sessions as long as they are not all trying to perform
127e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * database transactions at the same time.
128e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p>
129e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
130e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>Responsiveness</h2>
131e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p>
132e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Because there are a limited number of database connections and the session holds
133e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * a database connection for the entire duration of a database transaction,
134e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * it is important to keep transactions short.  This is especially important
135e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * for read-write transactions since they may block other transactions
136e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * from executing.  Consider calling {@link #yieldTransaction} periodically
137e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * during long-running transactions.
138e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
139e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Another important consideration is that transactions that take too long to
140e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * run may cause the application UI to become unresponsive.  Even if the transaction
141e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * is executed in a background thread, the user will get bored and
142e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * frustrated if the application shows no data for several seconds while
143e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * a transaction runs.
144e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p>
145e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Guidelines:
146e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <ul>
147e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <li>Do not perform database transactions on the UI thread.</li>
148e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <li>Keep database transactions as short as possible.</li>
149e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <li>Simple queries often run faster than complex queries.</li>
150e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <li>Measure the performance of your database transactions.</li>
151e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <li>Consider what will happen when the size of the data set grows.
152e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * A query that works well on 100 rows may struggle with 10,000.</li>
153e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </ul>
154e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
155a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * <h2>Reentrance</h2>
156a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * <p>
157a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * This class must tolerate reentrant execution of SQLite operations because
158a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * triggers may call custom SQLite functions that perform additional queries.
159a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * </p>
160a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff 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}.
2834c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
284e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
285e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws IllegalStateException if {@link #setTransactionSuccessful} has already been
286e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * called for the current transaction.
28775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws SQLiteException if an error occurs.
28875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
289e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
290e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @see #setTransactionSuccessful
291e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @see #yieldTransaction
292e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @see #endTransaction
293e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
294e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public void beginTransaction(int transactionMode,
29575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            SQLiteTransactionListener transactionListener, int connectionFlags,
2964c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
297e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throwIfTransactionMarkedSuccessful();
29875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        beginTransactionUnchecked(transactionMode, transactionListener, connectionFlags,
2994c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                cancellationSignal);
300e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
301e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
302e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void beginTransactionUnchecked(int transactionMode,
30375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            SQLiteTransactionListener transactionListener, int connectionFlags,
3044c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
3054c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        if (cancellationSignal != null) {
3064c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            cancellationSignal.throwIfCanceled();
30775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
30875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
309a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown        if (mTransactionStack == null) {
3104c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            acquireConnection(null, connectionFlags, cancellationSignal); // might throw
311a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown        }
312e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        try {
313e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // Set up the transaction such that we can back out safely
314e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // in case we fail part way.
315e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (mTransactionStack == null) {
316e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                // Execute SQL might throw a runtime exception.
317e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                switch (transactionMode) {
318e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    case TRANSACTION_MODE_IMMEDIATE:
31975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                        mConnection.execute("BEGIN IMMEDIATE;", null,
3204c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                                cancellationSignal); // might throw
321e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        break;
322e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    case TRANSACTION_MODE_EXCLUSIVE:
32375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                        mConnection.execute("BEGIN EXCLUSIVE;", null,
3244c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                                cancellationSignal); // might throw
325e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        break;
326e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    default:
3274c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                        mConnection.execute("BEGIN;", null, cancellationSignal); // might throw
328e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        break;
329e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
330e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
331e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
332e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // Listener might throw a runtime exception.
333e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (transactionListener != null) {
334e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                try {
335e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    transactionListener.onBegin(); // might throw
336e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                } catch (RuntimeException ex) {
337e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    if (mTransactionStack == null) {
3384c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                        mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
339e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    }
340e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    throw ex;
341e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
342e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
343e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
344e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // Bookkeeping can't throw, except an OOM, which is just too bad...
345e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            Transaction transaction = obtainTransaction(transactionMode, transactionListener);
346e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            transaction.mParent = mTransactionStack;
347e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            mTransactionStack = transaction;
348e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } finally {
349a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown            if (mTransactionStack == null) {
350a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown                releaseConnection(); // might throw
351a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown            }
352e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
353e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
354e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
355e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
356e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Marks the current transaction as having completed successfully.
357e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * <p>
358e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * This method can be called at most once between {@link #beginTransaction} and
359e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * {@link #endTransaction} to indicate that the changes made by the transaction should be
360e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * committed.  If this method is not called, the changes will be rolled back
361e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * when the transaction is ended.
362e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p>
363e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
364e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws IllegalStateException if there is no current transaction, or if
365e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * {@link #setTransactionSuccessful} has already been called for the current transaction.
366e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
367e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @see #beginTransaction
368e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @see #endTransaction
369e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
370e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public void setTransactionSuccessful() {
371e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throwIfNoTransaction();
372e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throwIfTransactionMarkedSuccessful();
373e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
374e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        mTransactionStack.mMarkedSuccessful = true;
375e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
376e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
377e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
378e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Ends the current transaction and commits or rolls back changes.
379e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * <p>
380e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * If this is the outermost transaction (not nested within any other
381e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * transaction), then the changes are committed if {@link #setTransactionSuccessful}
382e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * was called or rolled back otherwise.
383e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p><p>
384e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * This method must be called exactly once for each call to {@link #beginTransaction}.
385e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p>
386e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
3874c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
38875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
389e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws IllegalStateException if there is no current transaction.
39075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws SQLiteException if an error occurs.
39175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
392e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
393e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @see #beginTransaction
394e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @see #setTransactionSuccessful
395e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @see #yieldTransaction
396e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
3974c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    public void endTransaction(CancellationSignal cancellationSignal) {
398e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throwIfNoTransaction();
399e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        assert mConnection != null;
400e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
401d19ff5f95dc9ea684edb5097ce97e7bf78c2e628Jeff Brown        endTransactionUnchecked(cancellationSignal, false);
402e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
403e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
404d19ff5f95dc9ea684edb5097ce97e7bf78c2e628Jeff Brown    private void endTransactionUnchecked(CancellationSignal cancellationSignal, boolean yielding) {
4054c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        if (cancellationSignal != null) {
4064c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            cancellationSignal.throwIfCanceled();
40775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
40875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
409e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        final Transaction top = mTransactionStack;
410d19ff5f95dc9ea684edb5097ce97e7bf78c2e628Jeff Brown        boolean successful = (top.mMarkedSuccessful || yielding) && !top.mChildFailed;
411e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
412e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        RuntimeException listenerException = null;
413e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        final SQLiteTransactionListener listener = top.mListener;
414e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (listener != null) {
415e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            try {
416e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                if (successful) {
417e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    listener.onCommit(); // might throw
418e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                } else {
419e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    listener.onRollback(); // might throw
420e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
421e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } catch (RuntimeException ex) {
422e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                listenerException = ex;
423e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                successful = false;
424e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
425e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
426e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
427e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        mTransactionStack = top.mParent;
428e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        recycleTransaction(top);
429e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
430e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (mTransactionStack != null) {
431e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (!successful) {
432e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                mTransactionStack.mChildFailed = true;
433e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
434e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } else {
435e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            try {
436e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                if (successful) {
4374c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                    mConnection.execute("COMMIT;", null, cancellationSignal); // might throw
438e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                } else {
4394c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                    mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
440e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
441e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } finally {
442a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown                releaseConnection(); // might throw
443e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
444e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
445e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
446e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (listenerException != null) {
447e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw listenerException;
448e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
449e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
450e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
451e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
452e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Temporarily ends a transaction to let other threads have use of
453e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * the database.  Begins a new transaction after a specified delay.
454e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * <p>
455e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * If there are other threads waiting to acquire connections,
456e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * then the current transaction is committed and the database
457e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * connection is released.  After a short delay, a new transaction
458e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * is started.
459e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p><p>
460e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * The transaction is assumed to be successful so far.  Do not call
461e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * {@link #setTransactionSuccessful()} before calling this method.
462e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * This method will fail if the transaction has already been marked
463e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * successful.
464e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p><p>
465e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * The changes that were committed by a yield cannot be rolled back later.
466e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p><p>
467e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Before this method was called, there must already have been
468e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * a transaction in progress.  When this method returns, there will
469e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * still be a transaction in progress, either the same one as before
470e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * or a new one if the transaction was actually yielded.
471e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p><p>
472e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * This method should not be called when there is a nested transaction
473e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * in progress because it is not possible to yield a nested transaction.
474e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * If <code>throwIfNested</code> is true, then attempting to yield
475e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * a nested transaction will throw {@link IllegalStateException}, otherwise
476e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * the method will return <code>false</code> in that case.
477e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p><p>
478e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * If there is no nested transaction in progress but a previous nested
479e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * transaction failed, then the transaction is not yielded (because it
480e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * must be rolled back) and this method returns <code>false</code>.
481e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p>
482e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
483e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param sleepAfterYieldDelayMillis A delay time to wait after yielding
484e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * the database connection to allow other threads some time to run.
485e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * If the value is less than or equal to zero, there will be no additional
486e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * delay beyond the time it will take to begin a new transaction.
487e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param throwIfUnsafe If true, then instead of returning false when no
488e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * transaction is in progress, a nested transaction is in progress, or when
489e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * the transaction has already been marked successful, throws {@link IllegalStateException}.
4904c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
491e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @return True if the transaction was actually yielded.
492e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
493e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws IllegalStateException if <code>throwIfNested</code> is true and
494e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * there is no current transaction, there is a nested transaction in progress or
495e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * if {@link #setTransactionSuccessful} has already been called for the current transaction.
49675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws SQLiteException if an error occurs.
49775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
498e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
499e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @see #beginTransaction
500e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @see #endTransaction
501e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
50275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public boolean yieldTransaction(long sleepAfterYieldDelayMillis, boolean throwIfUnsafe,
5034c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
504e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (throwIfUnsafe) {
505e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throwIfNoTransaction();
506e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throwIfTransactionMarkedSuccessful();
507e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throwIfNestedTransaction();
508e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } else {
509e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (mTransactionStack == null || mTransactionStack.mMarkedSuccessful
510e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    || mTransactionStack.mParent != null) {
511e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                return false;
512e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
513e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
514e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        assert mConnection != null;
515e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
516e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (mTransactionStack.mChildFailed) {
517e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return false;
518e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
519e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
52075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        return yieldTransactionUnchecked(sleepAfterYieldDelayMillis,
5214c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                cancellationSignal); // might throw
522e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
523e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
52475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    private boolean yieldTransactionUnchecked(long sleepAfterYieldDelayMillis,
5254c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
5264c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        if (cancellationSignal != null) {
5274c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            cancellationSignal.throwIfCanceled();
52875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
52975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
530e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (!mConnectionPool.shouldYieldConnection(mConnection, mConnectionFlags)) {
531e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return false;
532e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
533e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
534e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        final int transactionMode = mTransactionStack.mMode;
535e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        final SQLiteTransactionListener listener = mTransactionStack.mListener;
536e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        final int connectionFlags = mConnectionFlags;
537d19ff5f95dc9ea684edb5097ce97e7bf78c2e628Jeff Brown        endTransactionUnchecked(cancellationSignal, true); // might throw
538e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
539e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (sleepAfterYieldDelayMillis > 0) {
540e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            try {
541e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                Thread.sleep(sleepAfterYieldDelayMillis);
542e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } catch (InterruptedException ex) {
543e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                // we have been interrupted, that's all we need to do
544e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
545e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
546e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
54775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        beginTransactionUnchecked(transactionMode, listener, connectionFlags,
5484c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                cancellationSignal); // might throw
549e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return true;
550e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
551e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
552e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
553e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Prepares a statement for execution but does not bind its parameters or execute it.
554e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * <p>
555e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * This method can be used to check for syntax errors during compilation
556e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * prior to execution of the statement.  If the {@code outStatementInfo} argument
557e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * is not null, the provided {@link SQLiteStatementInfo} object is populated
558e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * with information about the statement.
559e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p><p>
560e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * A prepared statement makes no reference to the arguments that may eventually
561e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * be bound to it, consequently it it possible to cache certain prepared statements
562e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * such as SELECT or INSERT/UPDATE statements.  If the statement is cacheable,
563e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * then it will be stored in the cache for later and reused if possible.
564e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * </p>
565e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
566e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param sql The SQL statement to prepare.
567e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connectionFlags The connection flags to use if a connection must be
568e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
5694c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
570e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param outStatementInfo The {@link SQLiteStatementInfo} object to populate
571e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * with information about the statement, or null if none.
572e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
573e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws SQLiteException if an error occurs, such as a syntax error.
57475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
575e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
5764c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    public void prepare(String sql, int connectionFlags, CancellationSignal cancellationSignal,
57775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            SQLiteStatementInfo outStatementInfo) {
578e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (sql == null) {
579e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalArgumentException("sql must not be null.");
580e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
581e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
5824c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        if (cancellationSignal != null) {
5834c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            cancellationSignal.throwIfCanceled();
58475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
58575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
5864c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
587e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        try {
588e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            mConnection.prepare(sql, outStatementInfo); // might throw
589e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } finally {
590a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown            releaseConnection(); // might throw
591e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
592e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
593e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
594e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
595e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Executes a statement that does not return a result.
596e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
597e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param sql The SQL statement to execute.
598e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param bindArgs The arguments to bind, or null if none.
599e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connectionFlags The connection flags to use if a connection must be
600e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
6014c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
602e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
603e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws SQLiteException if an error occurs, such as a syntax error
604e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * or invalid number of bind arguments.
60575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
606e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
60775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public void execute(String sql, Object[] bindArgs, int connectionFlags,
6084c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
609e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (sql == null) {
610e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalArgumentException("sql must not be null.");
611e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
612e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
6134c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
614e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return;
615e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
616e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
6174c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
618e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        try {
6194c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            mConnection.execute(sql, bindArgs, cancellationSignal); // might throw
620e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } finally {
621a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown            releaseConnection(); // might throw
622e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
623e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
624e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
625e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
626e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Executes a statement that returns a single <code>long</code> result.
627e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
628e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param sql The SQL statement to execute.
629e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param bindArgs The arguments to bind, or null if none.
630e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connectionFlags The connection flags to use if a connection must be
631e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
6324c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
633e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @return The value of the first column in the first row of the result set
634e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * as a <code>long</code>, or zero if none.
635e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
636e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws SQLiteException if an error occurs, such as a syntax error
637e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * or invalid number of bind arguments.
63875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
639e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
64075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public long executeForLong(String sql, Object[] bindArgs, int connectionFlags,
6414c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
642e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (sql == null) {
643e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalArgumentException("sql must not be null.");
644e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
645e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
6464c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
647e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return 0;
648e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
649e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
6504c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
651e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        try {
6524c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            return mConnection.executeForLong(sql, bindArgs, cancellationSignal); // might throw
653e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } finally {
654a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown            releaseConnection(); // might throw
655e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
656e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
657e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
658e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
659e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Executes a statement that returns a single {@link String} result.
660e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
661e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param sql The SQL statement to execute.
662e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param bindArgs The arguments to bind, or null if none.
663e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connectionFlags The connection flags to use if a connection must be
664e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
6654c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
666e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @return The value of the first column in the first row of the result set
667e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * as a <code>String</code>, or null if none.
668e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
669e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws SQLiteException if an error occurs, such as a syntax error
670e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * or invalid number of bind arguments.
67175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
672e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
67375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public String executeForString(String sql, Object[] bindArgs, int connectionFlags,
6744c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
675e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (sql == null) {
676e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalArgumentException("sql must not be null.");
677e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
678e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
6794c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
680e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return null;
681e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
682e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
6834c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
684e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        try {
6854c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            return mConnection.executeForString(sql, bindArgs, cancellationSignal); // might throw
686e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } finally {
687a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown            releaseConnection(); // might throw
688e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
689e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
690e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
691e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
692e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Executes a statement that returns a single BLOB result as a
693e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * file descriptor to a shared memory region.
694e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
695e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param sql The SQL statement to execute.
696e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param bindArgs The arguments to bind, or null if none.
697e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connectionFlags The connection flags to use if a connection must be
698e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
6994c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
700e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @return The file descriptor for a shared memory region that contains
701e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * the value of the first column in the first row of the result set as a BLOB,
702e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * or null if none.
703e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
704e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws SQLiteException if an error occurs, such as a syntax error
705e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * or invalid number of bind arguments.
70675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
707e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
708e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs,
7094c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            int connectionFlags, CancellationSignal cancellationSignal) {
710e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (sql == null) {
711e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalArgumentException("sql must not be null.");
712e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
713e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
7144c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
715e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return null;
716e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
717e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
7184c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
719e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        try {
72075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            return mConnection.executeForBlobFileDescriptor(sql, bindArgs,
7214c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                    cancellationSignal); // might throw
722e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } finally {
723a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown            releaseConnection(); // might throw
724e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
725e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
726e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
727e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
728e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Executes a statement that returns a count of the number of rows
729e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * that were changed.  Use for UPDATE or DELETE SQL statements.
730e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
731e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param sql The SQL statement to execute.
732e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param bindArgs The arguments to bind, or null if none.
733e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connectionFlags The connection flags to use if a connection must be
734e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
7354c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
736e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @return The number of rows that were changed.
737e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
738e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws SQLiteException if an error occurs, such as a syntax error
739e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * or invalid number of bind arguments.
74075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
741e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
74275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public int executeForChangedRowCount(String sql, Object[] bindArgs, int connectionFlags,
7434c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
744e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (sql == null) {
745e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalArgumentException("sql must not be null.");
746e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
747e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
7484c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
749e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return 0;
750e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
751e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
7524c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
753e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        try {
75475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            return mConnection.executeForChangedRowCount(sql, bindArgs,
7554c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                    cancellationSignal); // might throw
756e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } finally {
757a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown            releaseConnection(); // might throw
758e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
759e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
760e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
761e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
762e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Executes a statement that returns the row id of the last row inserted
763e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * by the statement.  Use for INSERT SQL statements.
764e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
765e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param sql The SQL statement to execute.
766e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param bindArgs The arguments to bind, or null if none.
767e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connectionFlags The connection flags to use if a connection must be
768e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
7694c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
770e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @return The row id of the last row that was inserted, or 0 if none.
771e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
772e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws SQLiteException if an error occurs, such as a syntax error
773e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * or invalid number of bind arguments.
77475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
775e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
77675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public long executeForLastInsertedRowId(String sql, Object[] bindArgs, int connectionFlags,
7774c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
778e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (sql == null) {
779e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalArgumentException("sql must not be null.");
780e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
781e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
7824c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
783e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return 0;
784e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
785e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
7864c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
787e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        try {
78875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            return mConnection.executeForLastInsertedRowId(sql, bindArgs,
7894c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                    cancellationSignal); // might throw
790e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } finally {
791a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown            releaseConnection(); // might throw
792e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
793e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
794e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
795e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
796e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Executes a statement and populates the specified {@link CursorWindow}
797e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * with a range of results.  Returns the number of rows that were counted
798e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * during query execution.
799e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
800e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param sql The SQL statement to execute.
801e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param bindArgs The arguments to bind, or null if none.
802e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param window The cursor window to clear and fill.
803e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param startPos The start position for filling the window.
804e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param requiredPos The position of a row that MUST be in the window.
805e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * If it won't fit, then the query should discard part of what it filled
806e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * so that it does.  Must be greater than or equal to <code>startPos</code>.
807e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param countAllRows True to count all rows that the query would return
808e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * regagless of whether they fit in the window.
809e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connectionFlags The connection flags to use if a connection must be
810e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
8114c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
812e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @return The number of rows that were counted during query execution.  Might
813e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * not be all rows in the result set unless <code>countAllRows</code> is true.
814e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
815e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws SQLiteException if an error occurs, such as a syntax error
816e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * or invalid number of bind arguments.
81775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
818e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
819e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    public int executeForCursorWindow(String sql, Object[] bindArgs,
820e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
8214c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            int connectionFlags, CancellationSignal cancellationSignal) {
822e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (sql == null) {
823e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalArgumentException("sql must not be null.");
824e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
825e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (window == null) {
826e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalArgumentException("window must not be null.");
827e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
828e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
8294c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
830e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            window.clear();
831e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return 0;
832e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
833e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
8344c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
835e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        try {
836e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return mConnection.executeForCursorWindow(sql, bindArgs,
83775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                    window, startPos, requiredPos, countAllRows,
8384c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                    cancellationSignal); // might throw
839e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } finally {
840a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown            releaseConnection(); // might throw
841e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
842e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
843e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
844e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /**
845e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * Performs special reinterpretation of certain SQL statements such as "BEGIN",
846e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * "COMMIT" and "ROLLBACK" to ensure that transaction state invariants are
847e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * maintained.
848e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
849e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * This function is mainly used to support legacy apps that perform their
850e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * own transactions by executing raw SQL rather than calling {@link #beginTransaction}
851e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * and the like.
852e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
853e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param sql The SQL statement to execute.
854e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param bindArgs The arguments to bind, or null if none.
855e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @param connectionFlags The connection flags to use if a connection must be
856e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
8574c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
858e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @return True if the statement was of a special form that was handled here,
859e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * false otherwise.
860e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     *
861e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * @throws SQLiteException if an error occurs, such as a syntax error
862e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     * or invalid number of bind arguments.
86375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation was canceled.
864e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown     */
86575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags,
8664c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
8674c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        if (cancellationSignal != null) {
8684c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            cancellationSignal.throwIfCanceled();
86975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
87075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
871e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        final int type = DatabaseUtils.getSqlStatementType(sql);
872e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        switch (type) {
873e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            case DatabaseUtils.STATEMENT_BEGIN:
87475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                beginTransaction(TRANSACTION_MODE_EXCLUSIVE, null, connectionFlags,
8754c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                        cancellationSignal);
876e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                return true;
877e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
878e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            case DatabaseUtils.STATEMENT_COMMIT:
879e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                setTransactionSuccessful();
8804c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                endTransaction(cancellationSignal);
881e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                return true;
882e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
883e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            case DatabaseUtils.STATEMENT_ABORT:
8844c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                endTransaction(cancellationSignal);
885e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                return true;
886e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
887e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return false;
888e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
889e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
89075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    private void acquireConnection(String sql, int connectionFlags,
8914c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            CancellationSignal cancellationSignal) {
892a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown        if (mConnection == null) {
893a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown            assert mConnectionUseCount == 0;
89475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            mConnection = mConnectionPool.acquireConnection(sql, connectionFlags,
8954c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown                    cancellationSignal); // might throw
896e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            mConnectionFlags = connectionFlags;
897e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
898a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown        mConnectionUseCount += 1;
899e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
900e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
901a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown    private void releaseConnection() {
902a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown        assert mConnection != null;
903a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown        assert mConnectionUseCount > 0;
904a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown        if (--mConnectionUseCount == 0) {
905e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            try {
906e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                mConnectionPool.releaseConnection(mConnection); // might throw
907e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } finally {
908e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                mConnection = null;
909e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
910e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
911e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
912e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
913e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void throwIfNoTransaction() {
914e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (mTransactionStack == null) {
915e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalStateException("Cannot perform this operation because "
916e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    + "there is no current transaction.");
917e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
918e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
919e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
920e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void throwIfTransactionMarkedSuccessful() {
921e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (mTransactionStack != null && mTransactionStack.mMarkedSuccessful) {
922e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalStateException("Cannot perform this operation because "
923e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    + "the transaction has already been marked successful.  The only "
924e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    + "thing you can do now is call endTransaction().");
925e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
926e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
927e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
928e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void throwIfNestedTransaction() {
929e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (mTransactionStack == null && mTransactionStack.mParent != null) {
930e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw new IllegalStateException("Cannot perform this operation because "
931e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    + "a nested transaction is in progress.");
932e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
933e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
934e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
935e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private Transaction obtainTransaction(int mode, SQLiteTransactionListener listener) {
936e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        Transaction transaction = mTransactionPool;
937e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (transaction != null) {
938e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            mTransactionPool = transaction.mParent;
939e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            transaction.mParent = null;
940e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            transaction.mMarkedSuccessful = false;
941e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            transaction.mChildFailed = false;
942e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } else {
943e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            transaction = new Transaction();
944e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
945e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        transaction.mMode = mode;
946e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        transaction.mListener = listener;
947e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return transaction;
948e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
949e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
950e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private void recycleTransaction(Transaction transaction) {
951e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        transaction.mParent = mTransactionPool;
952e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        transaction.mListener = null;
953e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        mTransactionPool = transaction;
954e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
955e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
956e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    private static final class Transaction {
957e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public Transaction mParent;
958e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public int mMode;
959e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public SQLiteTransactionListener mListener;
960e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public boolean mMarkedSuccessful;
961e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        public boolean mChildFailed;
962e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
963e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
964