SQLiteConnection.java revision 47847f3f4dcf2a0dbea0bc0e4f02528e21d37a88
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 dalvik.system.BlockGuard; 20e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport dalvik.system.CloseGuard; 21e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 224c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brownimport android.content.CancellationSignal; 2375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brownimport android.content.OperationCanceledException; 24e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.database.Cursor; 25e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.database.CursorWindow; 26e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.database.DatabaseUtils; 27e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.database.sqlite.SQLiteDebug.DbStats; 28e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.os.ParcelFileDescriptor; 29e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.util.Log; 30e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.util.LruCache; 31e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.util.Printer; 32e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 33e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport java.sql.Date; 34e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport java.text.SimpleDateFormat; 35e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport java.util.ArrayList; 36e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport java.util.Map; 37e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport java.util.regex.Pattern; 38e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 39e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown/** 40e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Represents a SQLite database connection. 41e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Each connection wraps an instance of a native <code>sqlite3</code> object. 42e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 43e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * When database connection pooling is enabled, there can be multiple active 44e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * connections to the same database. Otherwise there is typically only one 45e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * connection per database. 46e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 47e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * When the SQLite WAL feature is enabled, multiple readers and one writer 48e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * can concurrently access the database. Without WAL, readers and writers 49e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * are mutually exclusive. 50e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 51e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 52e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>Ownership and concurrency guarantees</h2> 53e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 54e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Connection objects are not thread-safe. They are acquired as needed to 55e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * perform a database operation and are then returned to the pool. At any 56e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * given time, a connection is either owned and used by a {@link SQLiteSession} 57e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * object or the {@link SQLiteConnectionPool}. Those classes are 58e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * responsible for serializing operations to guard against concurrent 59e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * use of a connection. 60e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 61e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * The guarantee of having a single owner allows this class to be implemented 62e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * without locks and greatly simplifies resource management. 63e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 64e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 65e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <h2>Encapsulation guarantees</h2> 66e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 67e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * The connection object object owns *all* of the SQLite related native 68e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * objects that are associated with the connection. What's more, there are 69e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * no other objects in the system that are capable of obtaining handles to 70e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * those native objects. Consequently, when the connection is closed, we do 71e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * not have to worry about what other components might have references to 72e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * its associated SQLite state -- there are none. 73e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 74e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Encapsulation is what ensures that the connection object's 75e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * lifecycle does not become a tortured mess of finalizers and reference 76e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * queues. 77e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 78e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 79a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * <h2>Reentrance</h2> 80a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * <p> 81a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * This class must tolerate reentrant execution of SQLite operations because 82a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * triggers may call custom SQLite functions that perform additional queries. 83a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * </p> 84a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * 85e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @hide 86e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 874c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brownpublic final class SQLiteConnection implements CancellationSignal.OnCancelListener { 88e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final String TAG = "SQLiteConnection"; 892a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown private static final boolean DEBUG = false; 90e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 91e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final String[] EMPTY_STRING_ARRAY = new String[0]; 92e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; 93e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 94e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final Pattern TRIM_SQL_PATTERN = Pattern.compile("[\\s]*\\n+[\\s]*"); 95e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 96e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final CloseGuard mCloseGuard = CloseGuard.get(); 97e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 98e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final SQLiteConnectionPool mPool; 99e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final SQLiteDatabaseConfiguration mConfiguration; 100e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final int mConnectionId; 101e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final boolean mIsPrimaryConnection; 1021d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown private final boolean mIsReadOnlyConnection; 103e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final PreparedStatementCache mPreparedStatementCache; 104e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private PreparedStatement mPreparedStatementPool; 105e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 106e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The recent operations log. 107e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final OperationLog mRecentOperations = new OperationLog(); 108e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 109e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The native SQLiteConnection pointer. (FOR INTERNAL USE ONLY) 110e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private int mConnectionPtr; 111e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 112e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private boolean mOnlyAllowReadOnlyOperations; 113e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1144c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // The number of times attachCancellationSignal has been called. 1151d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Because SQLite statement execution can be reentrant, we keep track of how many 1164c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // times we have attempted to attach a cancellation signal to the connection so that 11775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // we can ensure that we detach the signal at the right time. 1184c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown private int mCancellationSignalAttachCount; 11975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 120e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native int nativeOpen(String path, int openFlags, String label, 121e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown boolean enableTrace, boolean enableProfile); 122e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native void nativeClose(int connectionPtr); 123e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native void nativeRegisterCustomFunction(int connectionPtr, 124e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteCustomFunction function); 1251d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown private static native void nativeRegisterLocalizedCollators(int connectionPtr, String locale); 126e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native int nativePrepareStatement(int connectionPtr, String sql); 127e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native void nativeFinalizeStatement(int connectionPtr, int statementPtr); 128e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native int nativeGetParameterCount(int connectionPtr, int statementPtr); 129e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native boolean nativeIsReadOnly(int connectionPtr, int statementPtr); 130e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native int nativeGetColumnCount(int connectionPtr, int statementPtr); 131e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native String nativeGetColumnName(int connectionPtr, int statementPtr, 132e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index); 133e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native void nativeBindNull(int connectionPtr, int statementPtr, 134e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index); 135e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native void nativeBindLong(int connectionPtr, int statementPtr, 136e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index, long value); 137e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native void nativeBindDouble(int connectionPtr, int statementPtr, 138e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index, double value); 139e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native void nativeBindString(int connectionPtr, int statementPtr, 140e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index, String value); 141e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native void nativeBindBlob(int connectionPtr, int statementPtr, 142e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index, byte[] value); 143e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native void nativeResetStatementAndClearBindings( 144e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int connectionPtr, int statementPtr); 145e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native void nativeExecute(int connectionPtr, int statementPtr); 146e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native long nativeExecuteForLong(int connectionPtr, int statementPtr); 147e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native String nativeExecuteForString(int connectionPtr, int statementPtr); 148e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native int nativeExecuteForBlobFileDescriptor( 149e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int connectionPtr, int statementPtr); 150e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native int nativeExecuteForChangedRowCount(int connectionPtr, int statementPtr); 151e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native long nativeExecuteForLastInsertedRowId( 152e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int connectionPtr, int statementPtr); 153e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native long nativeExecuteForCursorWindow( 154e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int connectionPtr, int statementPtr, int windowPtr, 155e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int startPos, int requiredPos, boolean countAllRows); 156e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native int nativeGetDbLookaside(int connectionPtr); 15775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown private static native void nativeCancel(int connectionPtr); 15875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown private static native void nativeResetCancel(int connectionPtr, boolean cancelable); 159e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 160e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private SQLiteConnection(SQLiteConnectionPool pool, 161e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteDatabaseConfiguration configuration, 162e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int connectionId, boolean primaryConnection) { 163e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPool = pool; 164e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConfiguration = new SQLiteDatabaseConfiguration(configuration); 165e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionId = connectionId; 166e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mIsPrimaryConnection = primaryConnection; 1671d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown mIsReadOnlyConnection = (configuration.openFlags & SQLiteDatabase.OPEN_READONLY) != 0; 168e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache = new PreparedStatementCache( 169e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConfiguration.maxSqlCacheSize); 170e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mCloseGuard.open("close"); 171e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 172e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 173e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown @Override 174e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown protected void finalize() throws Throwable { 175e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 176e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mPool != null && mConnectionPtr != 0) { 177e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPool.onConnectionLeaked(); 178e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 179e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 180e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dispose(true); 181e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 182e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown super.finalize(); 183e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 184e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 185e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 186e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 187e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown static SQLiteConnection open(SQLiteConnectionPool pool, 188e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteDatabaseConfiguration configuration, 189e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int connectionId, boolean primaryConnection) { 190e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteConnection connection = new SQLiteConnection(pool, configuration, 191e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown connectionId, primaryConnection); 192e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 193e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown connection.open(); 194e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return connection; 195e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 196e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown connection.dispose(false); 197e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 198e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 199e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 200e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 201e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 202e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Closes the database closes and releases all of its associated resources. 203e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Do not call methods on the connection after it is closed. It will probably crash. 204e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void close() { 205e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dispose(false); 206e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 207e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 208e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void open() { 209e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags, 210e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConfiguration.label, 211e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME); 212e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 2135936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown setPageSize(); 214d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setWalModeFromConfiguration(); 2158dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown setJournalSizeLimit(); 2168dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown setAutoCheckpointInterval(); 217e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown setLocaleFromConfiguration(); 218e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 219e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 220e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void dispose(boolean finalized) { 221e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mCloseGuard != null) { 222e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (finalized) { 223e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mCloseGuard.warnIfOpen(); 224e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 225e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mCloseGuard.close(); 226e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 227e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 228e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mConnectionPtr != 0) { 229a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("close", null, null); 230e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 231e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.evictAll(); 232e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeClose(mConnectionPtr); 233e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPtr = 0; 234e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 235a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 236e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 237e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 238e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 239e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 2405936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown private void setPageSize() { 2411d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { 2421d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final long newValue = SQLiteGlobal.getDefaultPageSize(); 2431d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown long value = executeForLong("PRAGMA page_size", null, null); 2441d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (value != newValue) { 2451d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("PRAGMA page_size=" + newValue, null, null); 2461d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 2475936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2485936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2495936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 2505936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown private void setAutoCheckpointInterval() { 2511d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { 2521d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final long newValue = SQLiteGlobal.getWALAutoCheckpoint(); 2531d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown long value = executeForLong("PRAGMA wal_autocheckpoint", null, null); 2541d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (value != newValue) { 2551d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown executeForLong("PRAGMA wal_autocheckpoint=" + newValue, null, null); 2561d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 2575936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2585936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2595936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 2605936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown private void setJournalSizeLimit() { 2611d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { 2621d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final long newValue = SQLiteGlobal.getJournalSizeLimit(); 2631d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown long value = executeForLong("PRAGMA journal_size_limit", null, null); 2641d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (value != newValue) { 2651d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown executeForLong("PRAGMA journal_size_limit=" + newValue, null, null); 2661d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 2675936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2685936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2695936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 270d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown private void setWalModeFromConfiguration() { 2711d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { 27247847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) { 273d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setJournalMode("WAL"); 274d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setSyncMode(SQLiteGlobal.getWALSyncMode()); 275d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } else { 276d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setJournalMode(SQLiteGlobal.getDefaultJournalMode()); 277d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setSyncMode(SQLiteGlobal.getDefaultSyncMode()); 2781d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 2798dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown } 2808dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown } 2818dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown 282d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown private void setSyncMode(String newValue) { 283d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown String value = executeForString("PRAGMA synchronous", null, null); 284d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (!canonicalizeSyncMode(value).equalsIgnoreCase( 285d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown canonicalizeSyncMode(newValue))) { 286d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown execute("PRAGMA synchronous=" + newValue, null, null); 287d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } 288d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } 289d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown 290d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown private static String canonicalizeSyncMode(String value) { 291d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (value.equals("0")) { 292d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return "OFF"; 293d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } else if (value.equals("1")) { 294d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return "NORMAL"; 295d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } else if (value.equals("2")) { 296d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return "FULL"; 297d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } 298d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return value; 299d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } 300d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown 301d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown private void setJournalMode(String newValue) { 302d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown String value = executeForString("PRAGMA journal_mode", null, null); 303d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (!value.equalsIgnoreCase(newValue)) { 304d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown try { 305d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown String result = executeForString("PRAGMA journal_mode=" + newValue, null, null); 306d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (result.equalsIgnoreCase(newValue)) { 307d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return; 3081d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 309d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // PRAGMA journal_mode silently fails and returns the original journal 310d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // mode in some cases if the journal mode could not be changed. 311d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } catch (SQLiteDatabaseLockedException ex) { 312d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // This error (SQLITE_BUSY) occurs if one connection has the database 313d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // open in WAL mode and another tries to change it to non-WAL. 3145936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 315d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // Because we always disable WAL mode when a database is first opened 316d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // (even if we intend to re-enable it), we can encounter problems if 317d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // there is another open connection to the database somewhere. 318d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // This can happen for a variety of reasons such as an application opening 319d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // the same database in multiple processes at the same time or if there is a 320d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // crashing content provider service that the ActivityManager has 321d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // removed from its registry but whose process hasn't quite died yet 322d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // by the time it is restarted in a new process. 323d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // 324d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // If we don't change the journal mode, nothing really bad happens. 325d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // In the worst case, an application that enables WAL might not actually 326d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // get it, although it can still use connection pooling. 327d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown Log.w(TAG, "Could not change the database journal mode of '" 328d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + mConfiguration.label + "' from '" + value + "' to '" + newValue 329d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + "' because the database is locked. This usually means that " 330d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + "there are other open connections to the database which prevents " 331d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + "the database from enabling or disabling write-ahead logging mode. " 332d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + "Proceeding without changing the journal mode."); 3335936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 3345936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 3355936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 336e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void setLocaleFromConfiguration() { 3371d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if ((mConfiguration.openFlags & SQLiteDatabase.NO_LOCALIZED_COLLATORS) != 0) { 3381d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown return; 3391d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 3401d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3411d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Register the localized collators. 3421d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final String newLocale = mConfiguration.locale.toString(); 3431d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown nativeRegisterLocalizedCollators(mConnectionPtr, newLocale); 3441d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3451d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // If the database is read-only, we cannot modify the android metadata table 3461d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // or existing indexes. 3471d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (mIsReadOnlyConnection) { 3481d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown return; 3491d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 3501d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3511d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown try { 3521d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Ensure the android metadata table exists. 3531d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("CREATE TABLE IF NOT EXISTS android_metadata (locale TEXT)", null, null); 3541d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3551d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Check whether the locale was actually changed. 3561d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final String oldLocale = executeForString("SELECT locale FROM android_metadata " 3571d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown + "UNION SELECT NULL ORDER BY locale DESC LIMIT 1", null, null); 3581d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (oldLocale != null && oldLocale.equals(newLocale)) { 3591d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown return; 3601d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 3611d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3621d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Go ahead and update the indexes using the new locale. 3631d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("BEGIN", null, null); 3641d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown boolean success = false; 3651d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown try { 3661d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("DELETE FROM android_metadata", null, null); 3671d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("INSERT INTO android_metadata (locale) VALUES(?)", 3681d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown new Object[] { newLocale }, null); 3691d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("REINDEX LOCALIZED", null, null); 3701d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown success = true; 3711d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } finally { 3721d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute(success ? "COMMIT" : "ROLLBACK", null, null); 3731d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 3741d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } catch (RuntimeException ex) { 3751d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown throw new SQLiteException("Failed to change locale for db '" + mConfiguration.label 3761d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown + "' to '" + newLocale + "'.", ex); 3771d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 378e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 379e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 380e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 381e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void reconfigure(SQLiteDatabaseConfiguration configuration) { 382e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Register custom functions. 383e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int functionCount = configuration.customFunctions.size(); 384e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < functionCount; i++) { 385e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteCustomFunction function = configuration.customFunctions.get(i); 386e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mConfiguration.customFunctions.contains(function)) { 387e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeRegisterCustomFunction(mConnectionPtr, function); 388e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 389e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 390e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 3915936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown // Remember what changed. 39247847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags) 39347847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0; 394e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown boolean localeChanged = !configuration.locale.equals(mConfiguration.locale); 395e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 396e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Update configuration parameters. 397e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConfiguration.updateParametersFrom(configuration); 398e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 399e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Update prepared statement cache size. 400e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.resize(configuration.maxSqlCacheSize); 401e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 402d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // Update WAL. 403d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (walModeChanged) { 404d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setWalModeFromConfiguration(); 4055936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 4065936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 407e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Update locale. 408e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (localeChanged) { 409e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown setLocaleFromConfiguration(); 410e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 411e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 412e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 413e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 414e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // When set to true, executing write operations will throw SQLiteException. 415e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Preparing statements that might write is ok, just don't execute them. 416e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void setOnlyAllowReadOnlyOperations(boolean readOnly) { 417e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mOnlyAllowReadOnlyOperations = readOnly; 418e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 419e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 420e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 421e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Returns true if the prepared statement cache contains the specified SQL. 422e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown boolean isPreparedStatementInCache(String sql) { 423e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mPreparedStatementCache.get(sql) != null; 424e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 425e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 426e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 427e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Gets the unique id of this connection. 428e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The connection id. 429e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 430e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int getConnectionId() { 431e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mConnectionId; 432e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 433e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 434e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 435e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Returns true if this is the primary database connection. 436e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return True if this is the primary database connection. 437e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 438e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean isPrimaryConnection() { 439e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mIsPrimaryConnection; 440e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 441e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 442e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 443e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Prepares a statement for execution but does not bind its parameters or execute it. 444e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 445e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This method can be used to check for syntax errors during compilation 446e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * prior to execution of the statement. If the {@code outStatementInfo} argument 447e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * is not null, the provided {@link SQLiteStatementInfo} object is populated 448e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with information about the statement. 449e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 450e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * A prepared statement makes no reference to the arguments that may eventually 451e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * be bound to it, consequently it it possible to cache certain prepared statements 452e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * such as SELECT or INSERT/UPDATE statements. If the statement is cacheable, 453e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * then it will be stored in the cache for later. 454e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 455e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * To take advantage of this behavior as an optimization, the connection pool 456e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * provides a method to acquire a connection that already has a given SQL statement 457e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * in its prepared statement cache so that it is ready for execution. 458e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 459e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 460e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to prepare. 461e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param outStatementInfo The {@link SQLiteStatementInfo} object to populate 462e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with information about the statement, or null if none. 463e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 464e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error. 465e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 466e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void prepare(String sql, SQLiteStatementInfo outStatementInfo) { 467e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 468e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 469e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 470e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 471a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("prepare", sql, null); 472e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 473a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 474e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 475e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (outStatementInfo != null) { 476e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.numParameters = statement.mNumParameters; 477e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.readOnly = statement.mReadOnly; 478e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 479e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int columnCount = nativeGetColumnCount( 480e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPtr, statement.mStatementPtr); 481e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (columnCount == 0) { 482e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.columnNames = EMPTY_STRING_ARRAY; 483e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 484e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.columnNames = new String[columnCount]; 485e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < columnCount; i++) { 486e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.columnNames[i] = nativeGetColumnName( 487e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPtr, statement.mStatementPtr, i); 488e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 489e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 490e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 491e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 492e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 493e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 494e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 495a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 496e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 497e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 498a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 499e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 500e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 501e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 502e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 503e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that does not return a result. 504e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 505e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 506e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 5074c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 508e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 509e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 510e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 51175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 512e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 51375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public void execute(String sql, Object[] bindArgs, 5144c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 515e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 516e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 517e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 518e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 519a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("execute", sql, bindArgs); 520e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 521a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 522e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 523e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 524e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 525e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 5264c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 52775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 52875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown nativeExecute(mConnectionPtr, statement.mStatementPtr); 52975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 5304c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 53175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 532e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 533e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 534e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 535e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 536a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 537e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 538e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 539a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 540e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 541e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 542e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 543e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 544e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a single <code>long</code> result. 545e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 546e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 547e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 5484c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 549e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The value of the first column in the first row of the result set 550e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * as a <code>long</code>, or zero if none. 551e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 552e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 553e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 55475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 555e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 55675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public long executeForLong(String sql, Object[] bindArgs, 5574c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 558e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 559e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 560e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 561e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 562a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForLong", sql, bindArgs); 563e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 564a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 565e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 566e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 567e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 568e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 5694c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 57075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 57175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return nativeExecuteForLong(mConnectionPtr, statement.mStatementPtr); 57275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 5734c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 57475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 575e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 576e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 577e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 578e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 579a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 580e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 581e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 582a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 583e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 584e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 585e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 586e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 587e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a single {@link String} result. 588e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 589e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 590e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 5914c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 592e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The value of the first column in the first row of the result set 593e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * as a <code>String</code>, or null if none. 594e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 595e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 596e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 59775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 598e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 59975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public String executeForString(String sql, Object[] bindArgs, 6004c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 601e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 602e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 603e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 604e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 605a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForString", sql, bindArgs); 606e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 607a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 608e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 609e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 610e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 611e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 6124c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 61375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 61475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return nativeExecuteForString(mConnectionPtr, statement.mStatementPtr); 61575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 6164c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 61775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 618e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 619e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 620e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 621e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 622a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 623e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 624e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 625a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 626e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 627e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 628e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 629e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 630e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a single BLOB result as a 631e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * file descriptor to a shared memory region. 632e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 633e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 634e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 6354c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 636e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The file descriptor for a shared memory region that contains 637e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * the value of the first column in the first row of the result set as a BLOB, 638e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or null if none. 639e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 640e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 641e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 64275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 643e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 64475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs, 6454c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 646e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 647e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 648e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 649e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 650a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForBlobFileDescriptor", 651a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown sql, bindArgs); 652e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 653a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 654e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 655e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 656e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 657e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 6584c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 65975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 66075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown int fd = nativeExecuteForBlobFileDescriptor( 66175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown mConnectionPtr, statement.mStatementPtr); 66275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return fd >= 0 ? ParcelFileDescriptor.adoptFd(fd) : null; 66375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 6644c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 66575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 666e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 667e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 668e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 669e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 670a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 671e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 672e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 673a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 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. 6834c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 684e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The number of rows that were changed. 685e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 686e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 687e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 68875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 689e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 69075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public int executeForChangedRowCount(String sql, Object[] bindArgs, 6914c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 692e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 693e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 694e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 695e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 696a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForChangedRowCount", 697a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown sql, bindArgs); 698e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 699a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 700e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 701e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 702e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 703e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 7044c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 70575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 70675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return nativeExecuteForChangedRowCount( 70775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown mConnectionPtr, statement.mStatementPtr); 70875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 7094c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 71075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 711e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 712e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 713e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 714e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 715a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 716e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 717e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 718a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 719e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 720e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 721e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 722e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 723e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns the row id of the last row inserted 724e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * by the statement. Use for INSERT SQL statements. 725e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 726e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 727e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 7284c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 729e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The row id of the last row that was inserted, or 0 if none. 730e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 731e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 732e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 73375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 734e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 73575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public long executeForLastInsertedRowId(String sql, Object[] bindArgs, 7364c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 737e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 738e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 739e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 740e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 741a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForLastInsertedRowId", 742a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown sql, bindArgs); 743e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 744a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 745e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 746e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 747e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 748e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 7494c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 75075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 75175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return nativeExecuteForLastInsertedRowId( 75275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown mConnectionPtr, statement.mStatementPtr); 75375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 7544c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 75575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 756e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 757e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 758e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 759e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 760a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 761e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 762e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 763a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 764e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 765e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 766e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 767e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 768e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement and populates the specified {@link CursorWindow} 769e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with a range of results. Returns the number of rows that were counted 770e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * during query execution. 771e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 772e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 773e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 774e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param window The cursor window to clear and fill. 775e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param startPos The start position for filling the window. 776e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param requiredPos The position of a row that MUST be in the window. 777e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * If it won't fit, then the query should discard part of what it filled 778e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * so that it does. Must be greater than or equal to <code>startPos</code>. 779e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param countAllRows True to count all rows that the query would return 780e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * regagless of whether they fit in the window. 7814c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 782e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The number of rows that were counted during query execution. Might 783e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * not be all rows in the result set unless <code>countAllRows</code> is true. 784e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 785e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 786e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 78775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 788e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 789e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int executeForCursorWindow(String sql, Object[] bindArgs, 79075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown CursorWindow window, int startPos, int requiredPos, boolean countAllRows, 7914c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 792e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 793e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 794e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 795e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (window == null) { 796e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("window must not be null."); 797e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 798e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 79903bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown window.acquireReference(); 800e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 80103bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown int actualPos = -1; 80203bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown int countedRows = -1; 80303bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown int filledRows = -1; 80403bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForCursorWindow", 80503bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown sql, bindArgs); 806e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 80703bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 80875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 80903bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown throwIfStatementForbidden(statement); 81003bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown bindArguments(statement, bindArgs); 81103bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown applyBlockGuardPolicy(statement); 81203bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown attachCancellationSignal(cancellationSignal); 81303bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown try { 81403bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown final long result = nativeExecuteForCursorWindow( 81503bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown mConnectionPtr, statement.mStatementPtr, window.mWindowPtr, 81603bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown startPos, requiredPos, countAllRows); 81703bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown actualPos = (int)(result >> 32); 81803bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown countedRows = (int)result; 81903bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown filledRows = window.getNumRows(); 82003bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown window.setStartPosition(actualPos); 82103bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown return countedRows; 82203bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown } finally { 82303bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown detachCancellationSignal(cancellationSignal); 82403bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown } 82575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 82603bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown releasePreparedStatement(statement); 82775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 82803bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown } catch (RuntimeException ex) { 82903bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown mRecentOperations.failOperation(cookie, ex); 83003bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown throw ex; 831e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 83203bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown if (mRecentOperations.endOperationDeferLog(cookie)) { 83303bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown mRecentOperations.logOperation(cookie, "window='" + window 83403bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown + "', startPos=" + startPos 83503bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown + ", actualPos=" + actualPos 83603bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown + ", filledRows=" + filledRows 83703bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown + ", countedRows=" + countedRows); 83803bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown } 839e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 840e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 84103bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown window.releaseReference(); 842e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 843e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 844e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 845e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private PreparedStatement acquirePreparedStatement(String sql) { 846e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown PreparedStatement statement = mPreparedStatementCache.get(sql); 847a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown boolean skipCache = false; 848e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement != null) { 849a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (!statement.mInUse) { 850a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return statement; 851a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 852a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // The statement is already in the cache but is in use (this statement appears 853a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // to be not only re-entrant but recursive!). So prepare a new copy of the 854a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // statement but do not cache it. 855a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown skipCache = true; 856e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 857e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 858e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int statementPtr = nativePrepareStatement(mConnectionPtr, sql); 859e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 860e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int numParameters = nativeGetParameterCount(mConnectionPtr, statementPtr); 861e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int type = DatabaseUtils.getSqlStatementType(sql); 862e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final boolean readOnly = nativeIsReadOnly(mConnectionPtr, statementPtr); 863e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement = obtainPreparedStatement(sql, statementPtr, numParameters, type, readOnly); 864a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (!skipCache && isCacheable(type)) { 865e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.put(sql, statement); 866e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mInCache = true; 867e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 868e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 869e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Finalize the statement if an exception occurred and we did not add 870e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // it to the cache. If it is already in the cache, then leave it there. 871e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement == null || !statement.mInCache) { 872e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeFinalizeStatement(mConnectionPtr, statementPtr); 873e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 874e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 875e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 876a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown statement.mInUse = true; 877e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return statement; 878e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 879e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 880e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void releasePreparedStatement(PreparedStatement statement) { 881a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown statement.mInUse = false; 882e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement.mInCache) { 883e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 884e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeResetStatementAndClearBindings(mConnectionPtr, statement.mStatementPtr); 885e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 886a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // The statement could not be reset due to an error. Remove it from the cache. 887a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // When remove() is called, the cache will invoke its entryRemoved() callback, 888a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // which will in turn call finalizePreparedStatement() to finalize and 889a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // recycle the statement. 8902a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown if (DEBUG) { 8912a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown Log.d(TAG, "Could not reset prepared statement due to an exception. " 892e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + "Removing it from the cache. SQL: " 893e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + trimSqlForDisplay(statement.mSql), ex); 894e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 8952a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown 896e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.remove(statement.mSql); 897e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 898e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 899a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown finalizePreparedStatement(statement); 900e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 901e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 902e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 903a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private void finalizePreparedStatement(PreparedStatement statement) { 904a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown nativeFinalizeStatement(mConnectionPtr, statement.mStatementPtr); 905a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown recyclePreparedStatement(statement); 906a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 907a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 9084c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown private void attachCancellationSignal(CancellationSignal cancellationSignal) { 9094c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown if (cancellationSignal != null) { 9104c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown cancellationSignal.throwIfCanceled(); 91175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9124c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown mCancellationSignalAttachCount += 1; 9134c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown if (mCancellationSignalAttachCount == 1) { 9144c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // Reset cancellation flag before executing the statement. 91575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown nativeResetCancel(mConnectionPtr, true /*cancelable*/); 91675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 91775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // After this point, onCancel() may be called concurrently. 9184c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown cancellationSignal.setOnCancelListener(this); 91975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 92075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 92175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 92275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9234c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown private void detachCancellationSignal(CancellationSignal cancellationSignal) { 9244c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown if (cancellationSignal != null) { 9254c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown assert mCancellationSignalAttachCount > 0; 92675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9274c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown mCancellationSignalAttachCount -= 1; 9284c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown if (mCancellationSignalAttachCount == 0) { 92975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // After this point, onCancel() cannot be called concurrently. 9304c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown cancellationSignal.setOnCancelListener(null); 93175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9324c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // Reset cancellation flag after executing the statement. 93375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown nativeResetCancel(mConnectionPtr, false /*cancelable*/); 93475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 93575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 93675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 93775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9384c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // CancellationSignal.OnCancelListener callback. 93975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // This method may be called on a different thread than the executing statement. 9404c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // However, it will only be called between calls to attachCancellationSignal and 9414c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // detachCancellationSignal, while a statement is executing. We can safely assume 94275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // that the SQLite connection is still alive. 94375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown @Override 94475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public void onCancel() { 94575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown nativeCancel(mConnectionPtr); 94675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 94775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 948e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void bindArguments(PreparedStatement statement, Object[] bindArgs) { 949e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int count = bindArgs != null ? bindArgs.length : 0; 950e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (count != statement.mNumParameters) { 951e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new SQLiteBindOrColumnIndexOutOfRangeException( 952e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown "Expected " + statement.mNumParameters + " bind arguments but " 953e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + bindArgs.length + " were provided."); 954e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 955e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (count == 0) { 956e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return; 957e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 958e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 959e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int statementPtr = statement.mStatementPtr; 960e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < count; i++) { 961e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Object arg = bindArgs[i]; 962e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown switch (DatabaseUtils.getTypeOfObject(arg)) { 963e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_NULL: 964e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindNull(mConnectionPtr, statementPtr, i + 1); 965e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 966e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_INTEGER: 967e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindLong(mConnectionPtr, statementPtr, i + 1, 968e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown ((Number)arg).longValue()); 969e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 970e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_FLOAT: 971e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindDouble(mConnectionPtr, statementPtr, i + 1, 972e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown ((Number)arg).doubleValue()); 973e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 974e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_BLOB: 975e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindBlob(mConnectionPtr, statementPtr, i + 1, (byte[])arg); 976e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 977e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_STRING: 978e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown default: 979e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (arg instanceof Boolean) { 980e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Provide compatibility with legacy applications which may pass 981e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Boolean values in bind args. 982e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindLong(mConnectionPtr, statementPtr, i + 1, 983e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown ((Boolean)arg).booleanValue() ? 1 : 0); 984e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 985e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindString(mConnectionPtr, statementPtr, i + 1, arg.toString()); 986e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 987e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 988e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 989e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 990e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 991e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 992e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void throwIfStatementForbidden(PreparedStatement statement) { 993e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mOnlyAllowReadOnlyOperations && !statement.mReadOnly) { 994e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new SQLiteException("Cannot execute this statement because it " 995e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + "might modify the database but the connection is read-only."); 996e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 997e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 998e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 999e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static boolean isCacheable(int statementType) { 1000e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statementType == DatabaseUtils.STATEMENT_UPDATE 1001e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown || statementType == DatabaseUtils.STATEMENT_SELECT) { 1002e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return true; 1003e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1004e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return false; 1005e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1006e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1007e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void applyBlockGuardPolicy(PreparedStatement statement) { 1008e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mConfiguration.isInMemoryDb()) { 1009e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement.mReadOnly) { 1010e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown BlockGuard.getThreadPolicy().onReadFromDisk(); 1011e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1012e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown BlockGuard.getThreadPolicy().onWriteToDisk(); 1013e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1014e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1015e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1016e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1017e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1018e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Dumps debugging information about this connection. 1019e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1020e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param printer The printer to receive the dump, not null. 1021a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * @param verbose True to dump more verbose information. 1022e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1023a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public void dump(Printer printer, boolean verbose) { 1024a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown dumpUnsafe(printer, verbose); 1025e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1026e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1027e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1028e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Dumps debugging information about this connection, in the case where the 1029e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * caller might not actually own the connection. 1030e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1031e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This function is written so that it may be called by a thread that does not 1032e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * own the connection. We need to be very careful because the connection state is 1033e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * not synchronized. 1034e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1035e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * At worst, the method may return stale or slightly wrong data, however 1036e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * it should not crash. This is ok as it is only used for diagnostic purposes. 1037e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1038e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param printer The printer to receive the dump, not null. 1039a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * @param verbose True to dump more verbose information. 1040e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1041a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown void dumpUnsafe(Printer printer, boolean verbose) { 1042e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println("Connection #" + mConnectionId + ":"); 1043a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (verbose) { 1044a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown printer.println(" connectionPtr: 0x" + Integer.toHexString(mConnectionPtr)); 1045a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1046e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" isPrimaryConnection: " + mIsPrimaryConnection); 1047e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" onlyAllowReadOnlyOperations: " + mOnlyAllowReadOnlyOperations); 1048e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1049e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mRecentOperations.dump(printer); 1050a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 1051a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (verbose) { 1052a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mPreparedStatementCache.dump(printer); 1053a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1054e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1055e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1056e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1057e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Describes the currently executing operation, in the case where the 1058e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * caller might not actually own the connection. 1059e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1060e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This function is written so that it may be called by a thread that does not 1061e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * own the connection. We need to be very careful because the connection state is 1062e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * not synchronized. 1063e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1064e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * At worst, the method may return stale or slightly wrong data, however 1065e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * it should not crash. This is ok as it is only used for diagnostic purposes. 1066e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1067e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return A description of the current operation including how long it has been running, 1068e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or null if none. 1069e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1070e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String describeCurrentOperationUnsafe() { 1071e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mRecentOperations.describeCurrentOperation(); 1072e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1073e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1074e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1075e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Collects statistics about database connection memory usage. 1076e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1077e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param dbStatsList The list to populate. 1078e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1079e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void collectDbStats(ArrayList<DbStats> dbStatsList) { 1080e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Get information about the main database. 1081e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int lookaside = nativeGetDbLookaside(mConnectionPtr); 1082e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown long pageCount = 0; 1083e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown long pageSize = 0; 1084e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 108575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown pageCount = executeForLong("PRAGMA page_count;", null, null); 108675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown pageSize = executeForLong("PRAGMA page_size;", null, null); 1087e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 1088e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Ignore. 1089e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1090e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dbStatsList.add(getMainDbStatsUnsafe(lookaside, pageCount, pageSize)); 1091e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1092e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Get information about attached databases. 1093e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // We ignore the first row in the database list because it corresponds to 1094e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // the main database which we have already described. 1095e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown CursorWindow window = new CursorWindow("collectDbStats"); 1096e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 109775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown executeForCursorWindow("PRAGMA database_list;", null, window, 0, 0, false, null); 1098e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 1; i < window.getNumRows(); i++) { 1099e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String name = window.getString(i, 1); 1100e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String path = window.getString(i, 2); 1101e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown pageCount = 0; 1102e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown pageSize = 0; 1103e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 110475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown pageCount = executeForLong("PRAGMA " + name + ".page_count;", null, null); 110575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown pageSize = executeForLong("PRAGMA " + name + ".page_size;", null, null); 1106e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 1107e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Ignore. 1108e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1109e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String label = " (attached) " + name; 1110e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!path.isEmpty()) { 1111e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown label += ": " + path; 1112e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1113e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dbStatsList.add(new DbStats(label, pageCount, pageSize, 0, 0, 0, 0)); 1114e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1115e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 1116e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Ignore. 1117e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 1118e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown window.close(); 1119e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1120e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1121e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1122e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1123e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Collects statistics about database connection memory usage, in the case where the 1124e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * caller might not actually own the connection. 1125e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1126e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The statistics object, never null. 1127e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1128e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void collectDbStatsUnsafe(ArrayList<DbStats> dbStatsList) { 1129e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dbStatsList.add(getMainDbStatsUnsafe(0, 0, 0)); 1130e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1131e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1132e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private DbStats getMainDbStatsUnsafe(int lookaside, long pageCount, long pageSize) { 1133e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The prepared statement cache is thread-safe so we can access its statistics 1134e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // even if we do not own the database connection. 1135e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String label = mConfiguration.path; 1136e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mIsPrimaryConnection) { 1137e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown label += " (" + mConnectionId + ")"; 1138e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1139e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return new DbStats(label, pageCount, pageSize, lookaside, 1140e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.hitCount(), 1141e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.missCount(), 1142e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.size()); 1143e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1144e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1145e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown @Override 1146e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String toString() { 1147e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return "SQLiteConnection: " + mConfiguration.path + " (" + mConnectionId + ")"; 1148e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1149e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1150e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private PreparedStatement obtainPreparedStatement(String sql, int statementPtr, 1151e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int numParameters, int type, boolean readOnly) { 1152e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown PreparedStatement statement = mPreparedStatementPool; 1153e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement != null) { 1154e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementPool = statement.mPoolNext; 1155e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mPoolNext = null; 1156e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mInCache = false; 1157e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1158e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement = new PreparedStatement(); 1159e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1160e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mSql = sql; 1161e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mStatementPtr = statementPtr; 1162e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mNumParameters = numParameters; 1163e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mType = type; 1164e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mReadOnly = readOnly; 1165e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return statement; 1166e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1167e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1168e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void recyclePreparedStatement(PreparedStatement statement) { 1169e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mSql = null; 1170e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mPoolNext = mPreparedStatementPool; 1171e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementPool = statement; 1172e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1173e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1174e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static String trimSqlForDisplay(String sql) { 1175e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return TRIM_SQL_PATTERN.matcher(sql).replaceAll(" "); 1176e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1177e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1178e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1179e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Holder type for a prepared statement. 1180e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1181e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Although this object holds a pointer to a native statement object, it 1182e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * does not have a finalizer. This is deliberate. The {@link SQLiteConnection} 1183e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * owns the statement object and will take care of freeing it when needed. 1184e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * In particular, closing the connection requires a guarantee of deterministic 1185e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * resource disposal because all native statement objects must be freed before 1186e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * the native database object can be closed. So no finalizers here. 1187e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1188e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final class PreparedStatement { 1189e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Next item in pool. 1190e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public PreparedStatement mPoolNext; 1191e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1192e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The SQL from which the statement was prepared. 1193e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String mSql; 1194e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1195e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The native sqlite3_stmt object pointer. 1196e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Lifetime is managed explicitly by the connection. 1197e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int mStatementPtr; 1198e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1199e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The number of parameters that the prepared statement has. 1200e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int mNumParameters; 1201e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1202e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The statement type. 1203e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int mType; 1204e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1205e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // True if the statement is read-only. 1206e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean mReadOnly; 1207e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1208e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // True if the statement is in the cache. 1209e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean mInCache; 1210a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 1211a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // True if the statement is in use (currently executing). 1212a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // We need this flag because due to the use of custom functions in triggers, it's 1213a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // possible for SQLite calls to be re-entrant. Consequently we need to prevent 1214a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // in use statements from being finalized until they are no longer in use. 1215a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public boolean mInUse; 1216e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1217e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1218e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final class PreparedStatementCache 1219e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown extends LruCache<String, PreparedStatement> { 1220e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public PreparedStatementCache(int size) { 1221e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown super(size); 1222e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1223e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1224e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown @Override 1225e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown protected void entryRemoved(boolean evicted, String key, 1226e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown PreparedStatement oldValue, PreparedStatement newValue) { 1227e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown oldValue.mInCache = false; 1228a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (!oldValue.mInUse) { 1229a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown finalizePreparedStatement(oldValue); 1230a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1231e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1232e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1233e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void dump(Printer printer) { 1234e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" Prepared statement cache:"); 1235e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Map<String, PreparedStatement> cache = snapshot(); 1236e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!cache.isEmpty()) { 1237e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int i = 0; 1238e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (Map.Entry<String, PreparedStatement> entry : cache.entrySet()) { 1239e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown PreparedStatement statement = entry.getValue(); 1240e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement.mInCache) { // might be false due to a race with entryRemoved 1241e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String sql = entry.getKey(); 1242e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" " + i + ": statementPtr=0x" 1243e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + Integer.toHexString(statement.mStatementPtr) 1244e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + ", numParameters=" + statement.mNumParameters 1245e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + ", type=" + statement.mType 1246e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + ", readOnly=" + statement.mReadOnly 1247e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + ", sql=\"" + trimSqlForDisplay(sql) + "\""); 1248e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1249e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown i += 1; 1250e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1251e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1252e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" <none>"); 1253e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1254e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1255e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1256e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1257e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final class OperationLog { 12582a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown private static final int MAX_RECENT_OPERATIONS = 20; 1259a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private static final int COOKIE_GENERATION_SHIFT = 8; 1260a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private static final int COOKIE_INDEX_MASK = 0xff; 1261e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1262e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final Operation[] mOperations = new Operation[MAX_RECENT_OPERATIONS]; 1263e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private int mIndex; 1264a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private int mGeneration; 1265e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1266a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public int beginOperation(String kind, String sql, Object[] bindArgs) { 1267e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1268e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int index = (mIndex + 1) % MAX_RECENT_OPERATIONS; 1269e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Operation operation = mOperations[index]; 1270e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation == null) { 1271e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation = new Operation(); 1272e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mOperations[index] = operation; 1273e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1274e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mFinished = false; 1275e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mException = null; 1276e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation.mBindArgs != null) { 1277e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs.clear(); 1278e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1279e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1280e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mStartTime = System.currentTimeMillis(); 1281e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mKind = kind; 1282e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mSql = sql; 1283e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (bindArgs != null) { 1284e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation.mBindArgs == null) { 1285e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs = new ArrayList<Object>(); 1286e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1287e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs.clear(); 1288e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1289e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < bindArgs.length; i++) { 1290e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Object arg = bindArgs[i]; 1291e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (arg != null && arg instanceof byte[]) { 1292e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Don't hold onto the real byte array longer than necessary. 1293e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs.add(EMPTY_BYTE_ARRAY); 1294e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1295e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs.add(arg); 1296e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1297e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1298e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1299a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mCookie = newOperationCookieLocked(index); 1300e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mIndex = index; 1301a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return operation.mCookie; 1302e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1303e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1304e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1305a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public void failOperation(int cookie, Exception ex) { 1306e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1307a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final Operation operation = getOperationLocked(cookie); 1308a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (operation != null) { 1309a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mException = ex; 1310a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1311e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1312e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1313e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1314a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public void endOperation(int cookie) { 1315e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1316a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (endOperationDeferLogLocked(cookie)) { 1317a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown logOperationLocked(cookie, null); 1318a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1319e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1320e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1321e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1322a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public boolean endOperationDeferLog(int cookie) { 1323a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown synchronized (mOperations) { 1324a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return endOperationDeferLogLocked(cookie); 1325a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1326e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1327e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1328a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public void logOperation(int cookie, String detail) { 1329e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1330a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown logOperationLocked(cookie, detail); 1331e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1332e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1333e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1334a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private boolean endOperationDeferLogLocked(int cookie) { 1335a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final Operation operation = getOperationLocked(cookie); 1336a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (operation != null) { 1337a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mEndTime = System.currentTimeMillis(); 1338a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mFinished = true; 1339a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return SQLiteDebug.DEBUG_LOG_SLOW_QUERIES && SQLiteDebug.shouldLogSlowQuery( 1340a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mEndTime - operation.mStartTime); 1341e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1342a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return false; 1343e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1344e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1345a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private void logOperationLocked(int cookie, String detail) { 1346a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final Operation operation = getOperationLocked(cookie); 1347e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown StringBuilder msg = new StringBuilder(); 1348e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.describe(msg); 1349e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (detail != null) { 1350e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", ").append(detail); 1351e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1352e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Log.d(TAG, msg.toString()); 1353e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1354e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1355a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private int newOperationCookieLocked(int index) { 1356a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int generation = mGeneration++; 1357a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return generation << COOKIE_GENERATION_SHIFT | index; 1358a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1359a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 1360a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private Operation getOperationLocked(int cookie) { 1361a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int index = cookie & COOKIE_INDEX_MASK; 1362a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final Operation operation = mOperations[index]; 1363a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return operation.mCookie == cookie ? operation : null; 1364a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1365a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 1366e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String describeCurrentOperation() { 1367e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1368e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Operation operation = mOperations[mIndex]; 1369e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation != null && !operation.mFinished) { 1370e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown StringBuilder msg = new StringBuilder(); 1371e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.describe(msg); 1372e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return msg.toString(); 1373e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1374e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return null; 1375e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1376e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1377e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1378e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void dump(Printer printer) { 1379e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1380e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" Most recently executed operations:"); 1381e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index = mIndex; 1382e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Operation operation = mOperations[index]; 1383e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation != null) { 1384e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int n = 0; 1385e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown do { 1386e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown StringBuilder msg = new StringBuilder(); 1387e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(" ").append(n).append(": ["); 1388e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(operation.getFormattedStartTime()); 1389e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("] "); 1390e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.describe(msg); 1391e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(msg.toString()); 1392e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1393e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (index > 0) { 1394e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown index -= 1; 1395e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1396e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown index = MAX_RECENT_OPERATIONS - 1; 1397e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1398e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown n += 1; 1399e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation = mOperations[index]; 1400e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } while (operation != null && n < MAX_RECENT_OPERATIONS); 1401e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1402e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" <none>"); 1403e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1404e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1405e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1406e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1407e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1408e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final class Operation { 1409e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final SimpleDateFormat sDateFormat = 1410e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 1411e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1412e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public long mStartTime; 1413e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public long mEndTime; 1414e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String mKind; 1415e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String mSql; 1416e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public ArrayList<Object> mBindArgs; 1417e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean mFinished; 1418e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public Exception mException; 1419a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public int mCookie; 1420e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1421e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void describe(StringBuilder msg) { 1422e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(mKind); 1423e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mFinished) { 1424e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(" took ").append(mEndTime - mStartTime).append("ms"); 1425e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1426e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(" started ").append(System.currentTimeMillis() - mStartTime) 1427e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown .append("ms ago"); 1428e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1429e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(" - ").append(getStatus()); 1430e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mSql != null) { 1431e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", sql=\"").append(trimSqlForDisplay(mSql)).append("\""); 1432e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1433e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mBindArgs != null && mBindArgs.size() != 0) { 1434e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", bindArgs=["); 1435e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int count = mBindArgs.size(); 1436e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < count; i++) { 1437e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Object arg = mBindArgs.get(i); 1438e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (i != 0) { 1439e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", "); 1440e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1441e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (arg == null) { 1442e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("null"); 1443e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else if (arg instanceof byte[]) { 1444e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("<byte[]>"); 1445e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else if (arg instanceof String) { 1446e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("\"").append((String)arg).append("\""); 1447e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1448e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(arg); 1449e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1450e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1451e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("]"); 1452e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1453e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mException != null) { 1454e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", exception=\"").append(mException.getMessage()).append("\""); 1455e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1456e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1457e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1458e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private String getStatus() { 1459e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mFinished) { 1460e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return "running"; 1461e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1462e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mException != null ? "failed" : "succeeded"; 1463e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1464e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1465e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private String getFormattedStartTime() { 1466e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return sDateFormat.format(new Date(mStartTime)); 1467e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1468e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1469e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown} 1470