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 22e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.database.Cursor; 23e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.database.CursorWindow; 24e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.database.DatabaseUtils; 25e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport android.database.sqlite.SQLiteDebug.DbStats; 26a7771df3696954f0e279407e8894a916a7cb26ccJeff Brownimport android.os.CancellationSignal; 27a7771df3696954f0e279407e8894a916a7cb26ccJeff Brownimport android.os.OperationCanceledException; 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(); 21496496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown setForeignKeyModeFromConfiguration(); 215d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setWalModeFromConfiguration(); 2168dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown setJournalSizeLimit(); 2178dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown setAutoCheckpointInterval(); 218e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown setLocaleFromConfiguration(); 219e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 220e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 221e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void dispose(boolean finalized) { 222e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mCloseGuard != null) { 223e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (finalized) { 224e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mCloseGuard.warnIfOpen(); 225e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 226e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mCloseGuard.close(); 227e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 228e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 229e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mConnectionPtr != 0) { 230a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("close", null, null); 231e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 232e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.evictAll(); 233e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeClose(mConnectionPtr); 234e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPtr = 0; 235e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 236a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 237e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 238e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 239e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 240e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 2415936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown private void setPageSize() { 2421d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { 2431d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final long newValue = SQLiteGlobal.getDefaultPageSize(); 2441d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown long value = executeForLong("PRAGMA page_size", null, null); 2451d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (value != newValue) { 2461d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("PRAGMA page_size=" + newValue, null, null); 2471d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 2485936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2495936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2505936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 2515936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown private void setAutoCheckpointInterval() { 2521d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { 2531d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final long newValue = SQLiteGlobal.getWALAutoCheckpoint(); 2541d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown long value = executeForLong("PRAGMA wal_autocheckpoint", null, null); 2551d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (value != newValue) { 2561d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown executeForLong("PRAGMA wal_autocheckpoint=" + newValue, null, null); 2571d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 2585936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2595936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2605936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 2615936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown private void setJournalSizeLimit() { 2621d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { 2631d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final long newValue = SQLiteGlobal.getJournalSizeLimit(); 2641d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown long value = executeForLong("PRAGMA journal_size_limit", null, null); 2651d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (value != newValue) { 2661d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown executeForLong("PRAGMA journal_size_limit=" + newValue, null, null); 2671d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 2685936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2695936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2705936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 27196496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown private void setForeignKeyModeFromConfiguration() { 27296496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown if (!mIsReadOnlyConnection) { 27396496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown final long newValue = mConfiguration.foreignKeyConstraintsEnabled ? 1 : 0; 27496496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown long value = executeForLong("PRAGMA foreign_keys", null, null); 27596496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown if (value != newValue) { 27696496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown execute("PRAGMA foreign_keys=" + newValue, null, null); 27796496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown } 27896496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown } 27996496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown } 28096496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown 281d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown private void setWalModeFromConfiguration() { 2821d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { 28347847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) { 284d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setJournalMode("WAL"); 285d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setSyncMode(SQLiteGlobal.getWALSyncMode()); 286d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } else { 287d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setJournalMode(SQLiteGlobal.getDefaultJournalMode()); 288d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setSyncMode(SQLiteGlobal.getDefaultSyncMode()); 2891d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 2908dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown } 2918dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown } 2928dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown 293d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown private void setSyncMode(String newValue) { 294d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown String value = executeForString("PRAGMA synchronous", null, null); 295d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (!canonicalizeSyncMode(value).equalsIgnoreCase( 296d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown canonicalizeSyncMode(newValue))) { 297d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown execute("PRAGMA synchronous=" + newValue, null, null); 298d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } 299d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } 300d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown 301d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown private static String canonicalizeSyncMode(String value) { 302d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (value.equals("0")) { 303d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return "OFF"; 304d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } else if (value.equals("1")) { 305d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return "NORMAL"; 306d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } else if (value.equals("2")) { 307d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return "FULL"; 308d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } 309d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return value; 310d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } 311d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown 312d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown private void setJournalMode(String newValue) { 313d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown String value = executeForString("PRAGMA journal_mode", null, null); 314d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (!value.equalsIgnoreCase(newValue)) { 315d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown try { 316d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown String result = executeForString("PRAGMA journal_mode=" + newValue, null, null); 317d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (result.equalsIgnoreCase(newValue)) { 318d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return; 3191d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 320d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // PRAGMA journal_mode silently fails and returns the original journal 321d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // mode in some cases if the journal mode could not be changed. 322d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } catch (SQLiteDatabaseLockedException ex) { 323d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // This error (SQLITE_BUSY) occurs if one connection has the database 324d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // open in WAL mode and another tries to change it to non-WAL. 3255936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 326d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // Because we always disable WAL mode when a database is first opened 327d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // (even if we intend to re-enable it), we can encounter problems if 328d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // there is another open connection to the database somewhere. 329d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // This can happen for a variety of reasons such as an application opening 330d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // the same database in multiple processes at the same time or if there is a 331d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // crashing content provider service that the ActivityManager has 332d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // removed from its registry but whose process hasn't quite died yet 333d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // by the time it is restarted in a new process. 334d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // 335d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // If we don't change the journal mode, nothing really bad happens. 336d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // In the worst case, an application that enables WAL might not actually 337d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // get it, although it can still use connection pooling. 338d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown Log.w(TAG, "Could not change the database journal mode of '" 339d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + mConfiguration.label + "' from '" + value + "' to '" + newValue 340d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + "' because the database is locked. This usually means that " 341d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + "there are other open connections to the database which prevents " 342d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + "the database from enabling or disabling write-ahead logging mode. " 343d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + "Proceeding without changing the journal mode."); 3445936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 3455936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 3465936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 347e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void setLocaleFromConfiguration() { 3481d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if ((mConfiguration.openFlags & SQLiteDatabase.NO_LOCALIZED_COLLATORS) != 0) { 3491d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown return; 3501d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 3511d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3521d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Register the localized collators. 3531d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final String newLocale = mConfiguration.locale.toString(); 3541d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown nativeRegisterLocalizedCollators(mConnectionPtr, newLocale); 3551d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3561d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // If the database is read-only, we cannot modify the android metadata table 3571d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // or existing indexes. 3581d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (mIsReadOnlyConnection) { 3591d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown return; 3601d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 3611d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3621d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown try { 3631d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Ensure the android metadata table exists. 3641d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("CREATE TABLE IF NOT EXISTS android_metadata (locale TEXT)", null, null); 3651d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3661d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Check whether the locale was actually changed. 3671d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final String oldLocale = executeForString("SELECT locale FROM android_metadata " 3681d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown + "UNION SELECT NULL ORDER BY locale DESC LIMIT 1", null, null); 3691d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (oldLocale != null && oldLocale.equals(newLocale)) { 3701d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown return; 3711d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 3721d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3731d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Go ahead and update the indexes using the new locale. 3741d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("BEGIN", null, null); 3751d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown boolean success = false; 3761d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown try { 3771d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("DELETE FROM android_metadata", null, null); 3781d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("INSERT INTO android_metadata (locale) VALUES(?)", 3791d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown new Object[] { newLocale }, null); 3801d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("REINDEX LOCALIZED", null, null); 3811d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown success = true; 3821d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } finally { 3831d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute(success ? "COMMIT" : "ROLLBACK", null, null); 3841d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 3851d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } catch (RuntimeException ex) { 3861d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown throw new SQLiteException("Failed to change locale for db '" + mConfiguration.label 3871d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown + "' to '" + newLocale + "'.", ex); 3881d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 389e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 390e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 391e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 392e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void reconfigure(SQLiteDatabaseConfiguration configuration) { 39376070d1690ef9ba2675bdc34f1405968a2123112Jeff Brown mOnlyAllowReadOnlyOperations = false; 39476070d1690ef9ba2675bdc34f1405968a2123112Jeff Brown 395e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Register custom functions. 396e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int functionCount = configuration.customFunctions.size(); 397e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < functionCount; i++) { 398e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteCustomFunction function = configuration.customFunctions.get(i); 399e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mConfiguration.customFunctions.contains(function)) { 400e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeRegisterCustomFunction(mConnectionPtr, function); 401e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 402e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 403e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 4045936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown // Remember what changed. 40596496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown boolean foreignKeyModeChanged = configuration.foreignKeyConstraintsEnabled 40696496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown != mConfiguration.foreignKeyConstraintsEnabled; 40747847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags) 40847847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0; 409e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown boolean localeChanged = !configuration.locale.equals(mConfiguration.locale); 410e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 411e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Update configuration parameters. 412e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConfiguration.updateParametersFrom(configuration); 413e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 414e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Update prepared statement cache size. 415e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.resize(configuration.maxSqlCacheSize); 416e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 41796496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown // Update foreign key mode. 41896496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown if (foreignKeyModeChanged) { 41996496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown setForeignKeyModeFromConfiguration(); 42096496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown } 42196496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown 422d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // Update WAL. 423d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (walModeChanged) { 424d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setWalModeFromConfiguration(); 4255936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 4265936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 427e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Update locale. 428e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (localeChanged) { 429e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown setLocaleFromConfiguration(); 430e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 431e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 432e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 433e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 434e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // When set to true, executing write operations will throw SQLiteException. 435e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Preparing statements that might write is ok, just don't execute them. 436e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void setOnlyAllowReadOnlyOperations(boolean readOnly) { 437e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mOnlyAllowReadOnlyOperations = readOnly; 438e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 439e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 440e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 441e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Returns true if the prepared statement cache contains the specified SQL. 442e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown boolean isPreparedStatementInCache(String sql) { 443e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mPreparedStatementCache.get(sql) != null; 444e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 445e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 446e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 447e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Gets the unique id of this connection. 448e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The connection id. 449e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 450e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int getConnectionId() { 451e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mConnectionId; 452e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 453e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 454e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 455e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Returns true if this is the primary database connection. 456e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return True if this is the primary database connection. 457e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 458e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean isPrimaryConnection() { 459e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mIsPrimaryConnection; 460e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 461e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 462e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 463e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Prepares a statement for execution but does not bind its parameters or execute it. 464e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 465e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This method can be used to check for syntax errors during compilation 466e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * prior to execution of the statement. If the {@code outStatementInfo} argument 467e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * is not null, the provided {@link SQLiteStatementInfo} object is populated 468e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with information about the statement. 469e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 470e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * A prepared statement makes no reference to the arguments that may eventually 471e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * be bound to it, consequently it it possible to cache certain prepared statements 472e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * such as SELECT or INSERT/UPDATE statements. If the statement is cacheable, 473e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * then it will be stored in the cache for later. 474e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 475e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * To take advantage of this behavior as an optimization, the connection pool 476e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * provides a method to acquire a connection that already has a given SQL statement 477e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * in its prepared statement cache so that it is ready for execution. 478e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 479e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 480e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to prepare. 481e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param outStatementInfo The {@link SQLiteStatementInfo} object to populate 482e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with information about the statement, or null if none. 483e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 484e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error. 485e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 486e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void prepare(String sql, SQLiteStatementInfo outStatementInfo) { 487e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 488e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 489e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 490e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 491a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("prepare", sql, null); 492e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 493a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 494e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 495e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (outStatementInfo != null) { 496e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.numParameters = statement.mNumParameters; 497e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.readOnly = statement.mReadOnly; 498e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 499e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int columnCount = nativeGetColumnCount( 500e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPtr, statement.mStatementPtr); 501e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (columnCount == 0) { 502e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.columnNames = EMPTY_STRING_ARRAY; 503e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 504e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.columnNames = new String[columnCount]; 505e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < columnCount; i++) { 506e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.columnNames[i] = nativeGetColumnName( 507e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPtr, statement.mStatementPtr, i); 508e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 509e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 510e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 511e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 512e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 513e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 514e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 515a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 516e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 517e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 518a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 519e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 520e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 521e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 522e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 523e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that does not return a result. 524e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 525e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 526e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 5274c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 528e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 529e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 530e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 53175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 532e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 53375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public void execute(String sql, Object[] bindArgs, 5344c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 535e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 536e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 537e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 538e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 539a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("execute", sql, bindArgs); 540e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 541a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 542e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 543e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 544e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 545e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 5464c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 54775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 54875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown nativeExecute(mConnectionPtr, statement.mStatementPtr); 54975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 5504c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 55175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 552e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 553e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 554e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 555e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 556a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 557e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 558e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 559a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 560e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 561e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 562e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 563e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 564e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a single <code>long</code> result. 565e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 566e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 567e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 5684c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 569e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The value of the first column in the first row of the result set 570e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * as a <code>long</code>, or zero if none. 571e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 572e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 573e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 57475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 575e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 57675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public long executeForLong(String sql, Object[] bindArgs, 5774c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 578e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 579e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 580e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 581e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 582a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForLong", sql, bindArgs); 583e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 584a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 585e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 586e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 587e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 588e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 5894c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 59075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 59175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return nativeExecuteForLong(mConnectionPtr, statement.mStatementPtr); 59275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 5934c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 59475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 595e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 596e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 597e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 598e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 599a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 600e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 601e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 602a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 603e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 604e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 605e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 606e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 607e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a single {@link String} result. 608e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 609e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 610e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 6114c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 612e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The value of the first column in the first row of the result set 613e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * as a <code>String</code>, or null if none. 614e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 615e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 616e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 61775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 618e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 61975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public String executeForString(String sql, Object[] bindArgs, 6204c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 621e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 622e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 623e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 624e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 625a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForString", sql, bindArgs); 626e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 627a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 628e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 629e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 630e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 631e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 6324c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 63375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 63475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return nativeExecuteForString(mConnectionPtr, statement.mStatementPtr); 63575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 6364c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 63775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 638e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 639e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 640e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 641e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 642a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 643e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 644e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 645a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 646e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 647e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 648e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 649e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 650e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a single BLOB result as a 651e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * file descriptor to a shared memory region. 652e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 653e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 654e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 6554c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 656e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The file descriptor for a shared memory region that contains 657e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * the value of the first column in the first row of the result set as a BLOB, 658e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or null if none. 659e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 660e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 661e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 66275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 663e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 66475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs, 6654c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 666e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 667e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 668e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 669e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 670a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForBlobFileDescriptor", 671a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown sql, bindArgs); 672e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 673a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 674e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 675e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 676e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 677e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 6784c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 67975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 68075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown int fd = nativeExecuteForBlobFileDescriptor( 68175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown mConnectionPtr, statement.mStatementPtr); 68275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return fd >= 0 ? ParcelFileDescriptor.adoptFd(fd) : null; 68375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 6844c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 68575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 686e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 687e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 688e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 689e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 690a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 691e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 692e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 693a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 694e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 695e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 696e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 697e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 698e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a count of the number of rows 699e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * that were changed. Use for UPDATE or DELETE SQL statements. 700e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 701e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 702e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 7034c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 704e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The number of rows that were changed. 705e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 706e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 707e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 70875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 709e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 71075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public int executeForChangedRowCount(String sql, Object[] bindArgs, 7114c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 712e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 713e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 714e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 715e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 71672eebb6b6d4b16bcba415236dd182a3ba9a72951Makoto Onuki int changedRows = 0; 717a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForChangedRowCount", 718a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown sql, bindArgs); 719e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 720a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 721e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 722e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 723e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 724e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 7254c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 72675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 72772eebb6b6d4b16bcba415236dd182a3ba9a72951Makoto Onuki changedRows = nativeExecuteForChangedRowCount( 72875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown mConnectionPtr, statement.mStatementPtr); 72972eebb6b6d4b16bcba415236dd182a3ba9a72951Makoto Onuki return changedRows; 73075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 7314c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 73275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 733e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 734e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 735e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 736e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 737a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 738e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 739e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 74072eebb6b6d4b16bcba415236dd182a3ba9a72951Makoto Onuki if (mRecentOperations.endOperationDeferLog(cookie)) { 74172eebb6b6d4b16bcba415236dd182a3ba9a72951Makoto Onuki mRecentOperations.logOperation(cookie, "changedRows=" + changedRows); 74272eebb6b6d4b16bcba415236dd182a3ba9a72951Makoto Onuki } 743e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 744e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 745e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 746e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 747e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns the row id of the last row inserted 748e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * by the statement. Use for INSERT SQL statements. 749e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 750e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 751e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 7524c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 753e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The row id of the last row that was inserted, or 0 if none. 754e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 755e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 756e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 75775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 758e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 75975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public long executeForLastInsertedRowId(String sql, Object[] bindArgs, 7604c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 761e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 762e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 763e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 764e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 765a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForLastInsertedRowId", 766a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown sql, bindArgs); 767e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 768a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 769e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 770e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 771e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 772e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 7734c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 77475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 77575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return nativeExecuteForLastInsertedRowId( 77675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown mConnectionPtr, statement.mStatementPtr); 77775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 7784c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 77975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 780e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 781e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 782e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 783e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 784a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 785e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 786e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 787a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 788e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 789e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 790e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 791e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 792e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement and populates the specified {@link CursorWindow} 793e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with a range of results. Returns the number of rows that were counted 794e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * during query execution. 795e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 796e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 797e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 798e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param window The cursor window to clear and fill. 799e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param startPos The start position for filling the window. 800e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param requiredPos The position of a row that MUST be in the window. 801e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * If it won't fit, then the query should discard part of what it filled 802e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * so that it does. Must be greater than or equal to <code>startPos</code>. 803e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param countAllRows True to count all rows that the query would return 804e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * regagless of whether they fit in the window. 8054c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 806e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The number of rows that were counted during query execution. Might 807e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * not be all rows in the result set unless <code>countAllRows</code> is true. 808e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 809e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 810e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 81175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 812e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 813e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int executeForCursorWindow(String sql, Object[] bindArgs, 81475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown CursorWindow window, int startPos, int requiredPos, boolean countAllRows, 8154c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 816e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 817e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 818e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 819e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (window == null) { 820e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("window must not be null."); 821e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 822e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 82303bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown window.acquireReference(); 824e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 82503bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown int actualPos = -1; 82603bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown int countedRows = -1; 82703bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown int filledRows = -1; 82803bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForCursorWindow", 82903bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown sql, bindArgs); 830e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 83103bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 83275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 83303bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown throwIfStatementForbidden(statement); 83403bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown bindArguments(statement, bindArgs); 83503bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown applyBlockGuardPolicy(statement); 83603bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown attachCancellationSignal(cancellationSignal); 83703bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown try { 83803bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown final long result = nativeExecuteForCursorWindow( 83903bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown mConnectionPtr, statement.mStatementPtr, window.mWindowPtr, 84003bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown startPos, requiredPos, countAllRows); 84103bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown actualPos = (int)(result >> 32); 84203bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown countedRows = (int)result; 84303bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown filledRows = window.getNumRows(); 84403bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown window.setStartPosition(actualPos); 84503bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown return countedRows; 84603bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown } finally { 84703bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown detachCancellationSignal(cancellationSignal); 84803bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown } 84975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 85003bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown releasePreparedStatement(statement); 85175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 85203bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown } catch (RuntimeException ex) { 85303bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown mRecentOperations.failOperation(cookie, ex); 85403bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown throw ex; 855e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 85603bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown if (mRecentOperations.endOperationDeferLog(cookie)) { 85703bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown mRecentOperations.logOperation(cookie, "window='" + window 85803bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown + "', startPos=" + startPos 85903bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown + ", actualPos=" + actualPos 86003bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown + ", filledRows=" + filledRows 86103bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown + ", countedRows=" + countedRows); 86203bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown } 863e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 864e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 86503bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown window.releaseReference(); 866e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 867e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 868e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 869e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private PreparedStatement acquirePreparedStatement(String sql) { 870e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown PreparedStatement statement = mPreparedStatementCache.get(sql); 871a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown boolean skipCache = false; 872e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement != null) { 873a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (!statement.mInUse) { 874a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return statement; 875a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 876a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // The statement is already in the cache but is in use (this statement appears 877a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // to be not only re-entrant but recursive!). So prepare a new copy of the 878a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // statement but do not cache it. 879a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown skipCache = true; 880e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 881e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 882e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int statementPtr = nativePrepareStatement(mConnectionPtr, sql); 883e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 884e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int numParameters = nativeGetParameterCount(mConnectionPtr, statementPtr); 885e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int type = DatabaseUtils.getSqlStatementType(sql); 886e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final boolean readOnly = nativeIsReadOnly(mConnectionPtr, statementPtr); 887e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement = obtainPreparedStatement(sql, statementPtr, numParameters, type, readOnly); 888a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (!skipCache && isCacheable(type)) { 889e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.put(sql, statement); 890e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mInCache = true; 891e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 892e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 893e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Finalize the statement if an exception occurred and we did not add 894e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // it to the cache. If it is already in the cache, then leave it there. 895e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement == null || !statement.mInCache) { 896e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeFinalizeStatement(mConnectionPtr, statementPtr); 897e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 898e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 899e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 900a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown statement.mInUse = true; 901e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return statement; 902e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 903e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 904e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void releasePreparedStatement(PreparedStatement statement) { 905a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown statement.mInUse = false; 906e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement.mInCache) { 907e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 908e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeResetStatementAndClearBindings(mConnectionPtr, statement.mStatementPtr); 909e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 910a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // The statement could not be reset due to an error. Remove it from the cache. 911a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // When remove() is called, the cache will invoke its entryRemoved() callback, 912a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // which will in turn call finalizePreparedStatement() to finalize and 913a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // recycle the statement. 9142a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown if (DEBUG) { 9152a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown Log.d(TAG, "Could not reset prepared statement due to an exception. " 916e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + "Removing it from the cache. SQL: " 917e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + trimSqlForDisplay(statement.mSql), ex); 918e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 9192a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown 920e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.remove(statement.mSql); 921e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 922e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 923a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown finalizePreparedStatement(statement); 924e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 925e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 926e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 927a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private void finalizePreparedStatement(PreparedStatement statement) { 928a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown nativeFinalizeStatement(mConnectionPtr, statement.mStatementPtr); 929a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown recyclePreparedStatement(statement); 930a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 931a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 9324c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown private void attachCancellationSignal(CancellationSignal cancellationSignal) { 9334c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown if (cancellationSignal != null) { 9344c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown cancellationSignal.throwIfCanceled(); 93575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9364c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown mCancellationSignalAttachCount += 1; 9374c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown if (mCancellationSignalAttachCount == 1) { 9384c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // Reset cancellation flag before executing the statement. 93975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown nativeResetCancel(mConnectionPtr, true /*cancelable*/); 94075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 94175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // After this point, onCancel() may be called concurrently. 9424c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown cancellationSignal.setOnCancelListener(this); 94375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 94475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 94575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 94675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9474c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown private void detachCancellationSignal(CancellationSignal cancellationSignal) { 9484c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown if (cancellationSignal != null) { 9494c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown assert mCancellationSignalAttachCount > 0; 95075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9514c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown mCancellationSignalAttachCount -= 1; 9524c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown if (mCancellationSignalAttachCount == 0) { 95375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // After this point, onCancel() cannot be called concurrently. 9544c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown cancellationSignal.setOnCancelListener(null); 95575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9564c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // Reset cancellation flag after executing the statement. 95775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown nativeResetCancel(mConnectionPtr, false /*cancelable*/); 95875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 95975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 96075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 96175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9624c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // CancellationSignal.OnCancelListener callback. 96375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // This method may be called on a different thread than the executing statement. 9644c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // However, it will only be called between calls to attachCancellationSignal and 9654c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // detachCancellationSignal, while a statement is executing. We can safely assume 96675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // that the SQLite connection is still alive. 96775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown @Override 96875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public void onCancel() { 96975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown nativeCancel(mConnectionPtr); 97075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 97175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 972e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void bindArguments(PreparedStatement statement, Object[] bindArgs) { 973e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int count = bindArgs != null ? bindArgs.length : 0; 974e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (count != statement.mNumParameters) { 975e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new SQLiteBindOrColumnIndexOutOfRangeException( 976e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown "Expected " + statement.mNumParameters + " bind arguments but " 977e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + bindArgs.length + " were provided."); 978e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 979e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (count == 0) { 980e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return; 981e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 982e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 983e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int statementPtr = statement.mStatementPtr; 984e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < count; i++) { 985e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Object arg = bindArgs[i]; 986e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown switch (DatabaseUtils.getTypeOfObject(arg)) { 987e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_NULL: 988e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindNull(mConnectionPtr, statementPtr, i + 1); 989e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 990e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_INTEGER: 991e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindLong(mConnectionPtr, statementPtr, i + 1, 992e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown ((Number)arg).longValue()); 993e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 994e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_FLOAT: 995e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindDouble(mConnectionPtr, statementPtr, i + 1, 996e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown ((Number)arg).doubleValue()); 997e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 998e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_BLOB: 999e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindBlob(mConnectionPtr, statementPtr, i + 1, (byte[])arg); 1000e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 1001e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_STRING: 1002e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown default: 1003e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (arg instanceof Boolean) { 1004e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Provide compatibility with legacy applications which may pass 1005e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Boolean values in bind args. 1006e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindLong(mConnectionPtr, statementPtr, i + 1, 1007e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown ((Boolean)arg).booleanValue() ? 1 : 0); 1008e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1009e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindString(mConnectionPtr, statementPtr, i + 1, arg.toString()); 1010e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1011e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 1012e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1013e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1014e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1015e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1016e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void throwIfStatementForbidden(PreparedStatement statement) { 1017e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mOnlyAllowReadOnlyOperations && !statement.mReadOnly) { 1018e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new SQLiteException("Cannot execute this statement because it " 1019e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + "might modify the database but the connection is read-only."); 1020e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1021e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1022e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1023e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static boolean isCacheable(int statementType) { 1024e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statementType == DatabaseUtils.STATEMENT_UPDATE 1025e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown || statementType == DatabaseUtils.STATEMENT_SELECT) { 1026e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return true; 1027e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1028e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return false; 1029e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1030e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1031e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void applyBlockGuardPolicy(PreparedStatement statement) { 1032e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mConfiguration.isInMemoryDb()) { 1033e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement.mReadOnly) { 1034e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown BlockGuard.getThreadPolicy().onReadFromDisk(); 1035e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1036e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown BlockGuard.getThreadPolicy().onWriteToDisk(); 1037e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1038e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1039e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1040e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1041e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1042e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Dumps debugging information about this connection. 1043e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1044e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param printer The printer to receive the dump, not null. 1045a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * @param verbose True to dump more verbose information. 1046e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1047a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public void dump(Printer printer, boolean verbose) { 1048a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown dumpUnsafe(printer, verbose); 1049e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1050e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1051e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1052e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Dumps debugging information about this connection, in the case where the 1053e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * caller might not actually own the connection. 1054e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1055e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This function is written so that it may be called by a thread that does not 1056e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * own the connection. We need to be very careful because the connection state is 1057e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * not synchronized. 1058e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1059e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * At worst, the method may return stale or slightly wrong data, however 1060e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * it should not crash. This is ok as it is only used for diagnostic purposes. 1061e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1062e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param printer The printer to receive the dump, not null. 1063a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * @param verbose True to dump more verbose information. 1064e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1065a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown void dumpUnsafe(Printer printer, boolean verbose) { 1066e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println("Connection #" + mConnectionId + ":"); 1067a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (verbose) { 1068a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown printer.println(" connectionPtr: 0x" + Integer.toHexString(mConnectionPtr)); 1069a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1070e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" isPrimaryConnection: " + mIsPrimaryConnection); 1071e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" onlyAllowReadOnlyOperations: " + mOnlyAllowReadOnlyOperations); 1072e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1073e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mRecentOperations.dump(printer); 1074a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 1075a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (verbose) { 1076a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mPreparedStatementCache.dump(printer); 1077a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1078e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1079e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1080e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1081e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Describes the currently executing operation, in the case where the 1082e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * caller might not actually own the connection. 1083e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1084e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This function is written so that it may be called by a thread that does not 1085e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * own the connection. We need to be very careful because the connection state is 1086e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * not synchronized. 1087e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1088e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * At worst, the method may return stale or slightly wrong data, however 1089e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * it should not crash. This is ok as it is only used for diagnostic purposes. 1090e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1091e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return A description of the current operation including how long it has been running, 1092e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or null if none. 1093e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1094e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String describeCurrentOperationUnsafe() { 1095e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mRecentOperations.describeCurrentOperation(); 1096e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1097e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1098e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1099e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Collects statistics about database connection memory usage. 1100e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1101e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param dbStatsList The list to populate. 1102e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1103e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void collectDbStats(ArrayList<DbStats> dbStatsList) { 1104e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Get information about the main database. 1105e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int lookaside = nativeGetDbLookaside(mConnectionPtr); 1106e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown long pageCount = 0; 1107e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown long pageSize = 0; 1108e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 110975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown pageCount = executeForLong("PRAGMA page_count;", null, null); 111075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown pageSize = executeForLong("PRAGMA page_size;", null, null); 1111e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 1112e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Ignore. 1113e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1114e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dbStatsList.add(getMainDbStatsUnsafe(lookaside, pageCount, pageSize)); 1115e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1116e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Get information about attached databases. 1117e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // We ignore the first row in the database list because it corresponds to 1118e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // the main database which we have already described. 1119e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown CursorWindow window = new CursorWindow("collectDbStats"); 1120e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 112175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown executeForCursorWindow("PRAGMA database_list;", null, window, 0, 0, false, null); 1122e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 1; i < window.getNumRows(); i++) { 1123e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String name = window.getString(i, 1); 1124e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String path = window.getString(i, 2); 1125e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown pageCount = 0; 1126e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown pageSize = 0; 1127e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 112875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown pageCount = executeForLong("PRAGMA " + name + ".page_count;", null, null); 112975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown pageSize = executeForLong("PRAGMA " + name + ".page_size;", null, null); 1130e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 1131e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Ignore. 1132e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1133e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String label = " (attached) " + name; 1134e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!path.isEmpty()) { 1135e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown label += ": " + path; 1136e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1137e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dbStatsList.add(new DbStats(label, pageCount, pageSize, 0, 0, 0, 0)); 1138e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1139e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 1140e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Ignore. 1141e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 1142e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown window.close(); 1143e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1144e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1145e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1146e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1147e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Collects statistics about database connection memory usage, in the case where the 1148e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * caller might not actually own the connection. 1149e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1150e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The statistics object, never null. 1151e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1152e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void collectDbStatsUnsafe(ArrayList<DbStats> dbStatsList) { 1153e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dbStatsList.add(getMainDbStatsUnsafe(0, 0, 0)); 1154e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1155e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1156e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private DbStats getMainDbStatsUnsafe(int lookaside, long pageCount, long pageSize) { 1157e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The prepared statement cache is thread-safe so we can access its statistics 1158e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // even if we do not own the database connection. 1159e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String label = mConfiguration.path; 1160e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mIsPrimaryConnection) { 1161e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown label += " (" + mConnectionId + ")"; 1162e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1163e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return new DbStats(label, pageCount, pageSize, lookaside, 1164e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.hitCount(), 1165e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.missCount(), 1166e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.size()); 1167e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1168e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1169e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown @Override 1170e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String toString() { 1171e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return "SQLiteConnection: " + mConfiguration.path + " (" + mConnectionId + ")"; 1172e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1173e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1174e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private PreparedStatement obtainPreparedStatement(String sql, int statementPtr, 1175e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int numParameters, int type, boolean readOnly) { 1176e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown PreparedStatement statement = mPreparedStatementPool; 1177e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement != null) { 1178e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementPool = statement.mPoolNext; 1179e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mPoolNext = null; 1180e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mInCache = false; 1181e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1182e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement = new PreparedStatement(); 1183e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1184e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mSql = sql; 1185e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mStatementPtr = statementPtr; 1186e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mNumParameters = numParameters; 1187e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mType = type; 1188e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mReadOnly = readOnly; 1189e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return statement; 1190e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1191e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1192e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void recyclePreparedStatement(PreparedStatement statement) { 1193e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mSql = null; 1194e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mPoolNext = mPreparedStatementPool; 1195e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementPool = statement; 1196e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1197e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1198e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static String trimSqlForDisplay(String sql) { 1199e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return TRIM_SQL_PATTERN.matcher(sql).replaceAll(" "); 1200e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1201e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1202e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1203e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Holder type for a prepared statement. 1204e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1205e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Although this object holds a pointer to a native statement object, it 1206e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * does not have a finalizer. This is deliberate. The {@link SQLiteConnection} 1207e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * owns the statement object and will take care of freeing it when needed. 1208e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * In particular, closing the connection requires a guarantee of deterministic 1209e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * resource disposal because all native statement objects must be freed before 1210e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * the native database object can be closed. So no finalizers here. 1211e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1212e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final class PreparedStatement { 1213e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Next item in pool. 1214e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public PreparedStatement mPoolNext; 1215e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1216e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The SQL from which the statement was prepared. 1217e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String mSql; 1218e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1219e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The native sqlite3_stmt object pointer. 1220e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Lifetime is managed explicitly by the connection. 1221e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int mStatementPtr; 1222e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1223e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The number of parameters that the prepared statement has. 1224e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int mNumParameters; 1225e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1226e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The statement type. 1227e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int mType; 1228e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1229e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // True if the statement is read-only. 1230e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean mReadOnly; 1231e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1232e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // True if the statement is in the cache. 1233e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean mInCache; 1234a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 1235a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // True if the statement is in use (currently executing). 1236a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // We need this flag because due to the use of custom functions in triggers, it's 1237a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // possible for SQLite calls to be re-entrant. Consequently we need to prevent 1238a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // in use statements from being finalized until they are no longer in use. 1239a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public boolean mInUse; 1240e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1241e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1242e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final class PreparedStatementCache 1243e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown extends LruCache<String, PreparedStatement> { 1244e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public PreparedStatementCache(int size) { 1245e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown super(size); 1246e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1247e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1248e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown @Override 1249e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown protected void entryRemoved(boolean evicted, String key, 1250e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown PreparedStatement oldValue, PreparedStatement newValue) { 1251e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown oldValue.mInCache = false; 1252a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (!oldValue.mInUse) { 1253a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown finalizePreparedStatement(oldValue); 1254a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1255e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1256e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1257e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void dump(Printer printer) { 1258e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" Prepared statement cache:"); 1259e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Map<String, PreparedStatement> cache = snapshot(); 1260e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!cache.isEmpty()) { 1261e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int i = 0; 1262e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (Map.Entry<String, PreparedStatement> entry : cache.entrySet()) { 1263e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown PreparedStatement statement = entry.getValue(); 1264e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement.mInCache) { // might be false due to a race with entryRemoved 1265e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String sql = entry.getKey(); 1266e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" " + i + ": statementPtr=0x" 1267e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + Integer.toHexString(statement.mStatementPtr) 1268e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + ", numParameters=" + statement.mNumParameters 1269e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + ", type=" + statement.mType 1270e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + ", readOnly=" + statement.mReadOnly 1271e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + ", sql=\"" + trimSqlForDisplay(sql) + "\""); 1272e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1273e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown i += 1; 1274e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1275e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1276e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" <none>"); 1277e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1278e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1279e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1280e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1281e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final class OperationLog { 12822a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown private static final int MAX_RECENT_OPERATIONS = 20; 1283a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private static final int COOKIE_GENERATION_SHIFT = 8; 1284a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private static final int COOKIE_INDEX_MASK = 0xff; 1285e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1286e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final Operation[] mOperations = new Operation[MAX_RECENT_OPERATIONS]; 1287e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private int mIndex; 1288a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private int mGeneration; 1289e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1290a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public int beginOperation(String kind, String sql, Object[] bindArgs) { 1291e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1292e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int index = (mIndex + 1) % MAX_RECENT_OPERATIONS; 1293e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Operation operation = mOperations[index]; 1294e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation == null) { 1295e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation = new Operation(); 1296e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mOperations[index] = operation; 1297e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1298e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mFinished = false; 1299e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mException = null; 1300e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation.mBindArgs != null) { 1301e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs.clear(); 1302e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1303e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1304e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mStartTime = System.currentTimeMillis(); 1305e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mKind = kind; 1306e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mSql = sql; 1307e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (bindArgs != null) { 1308e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation.mBindArgs == null) { 1309e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs = new ArrayList<Object>(); 1310e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1311e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs.clear(); 1312e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1313e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < bindArgs.length; i++) { 1314e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Object arg = bindArgs[i]; 1315e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (arg != null && arg instanceof byte[]) { 1316e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Don't hold onto the real byte array longer than necessary. 1317e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs.add(EMPTY_BYTE_ARRAY); 1318e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1319e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs.add(arg); 1320e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1321e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1322e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1323a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mCookie = newOperationCookieLocked(index); 1324e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mIndex = index; 1325a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return operation.mCookie; 1326e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1327e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1328e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1329a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public void failOperation(int cookie, Exception ex) { 1330e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1331a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final Operation operation = getOperationLocked(cookie); 1332a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (operation != null) { 1333a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mException = ex; 1334a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1335e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1336e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1337e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1338a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public void endOperation(int cookie) { 1339e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1340a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (endOperationDeferLogLocked(cookie)) { 1341a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown logOperationLocked(cookie, null); 1342a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1343e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1344e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1345e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1346a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public boolean endOperationDeferLog(int cookie) { 1347a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown synchronized (mOperations) { 1348a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return endOperationDeferLogLocked(cookie); 1349a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1350e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1351e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1352a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public void logOperation(int cookie, String detail) { 1353e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1354a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown logOperationLocked(cookie, detail); 1355e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1356e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1357e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1358a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private boolean endOperationDeferLogLocked(int cookie) { 1359a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final Operation operation = getOperationLocked(cookie); 1360a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (operation != null) { 1361a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mEndTime = System.currentTimeMillis(); 1362a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mFinished = true; 1363a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return SQLiteDebug.DEBUG_LOG_SLOW_QUERIES && SQLiteDebug.shouldLogSlowQuery( 1364a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mEndTime - operation.mStartTime); 1365e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1366a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return false; 1367e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1368e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1369a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private void logOperationLocked(int cookie, String detail) { 1370a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final Operation operation = getOperationLocked(cookie); 1371e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown StringBuilder msg = new StringBuilder(); 1372e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.describe(msg); 1373e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (detail != null) { 1374e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", ").append(detail); 1375e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1376e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Log.d(TAG, msg.toString()); 1377e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1378e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1379a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private int newOperationCookieLocked(int index) { 1380a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int generation = mGeneration++; 1381a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return generation << COOKIE_GENERATION_SHIFT | index; 1382a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1383a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 1384a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private Operation getOperationLocked(int cookie) { 1385a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int index = cookie & COOKIE_INDEX_MASK; 1386a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final Operation operation = mOperations[index]; 1387a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return operation.mCookie == cookie ? operation : null; 1388a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1389a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 1390e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String describeCurrentOperation() { 1391e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1392e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Operation operation = mOperations[mIndex]; 1393e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation != null && !operation.mFinished) { 1394e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown StringBuilder msg = new StringBuilder(); 1395e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.describe(msg); 1396e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return msg.toString(); 1397e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1398e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return null; 1399e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1400e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1401e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1402e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void dump(Printer printer) { 1403e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1404e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" Most recently executed operations:"); 1405e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index = mIndex; 1406e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Operation operation = mOperations[index]; 1407e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation != null) { 1408e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int n = 0; 1409e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown do { 1410e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown StringBuilder msg = new StringBuilder(); 1411e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(" ").append(n).append(": ["); 1412e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(operation.getFormattedStartTime()); 1413e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("] "); 1414e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.describe(msg); 1415e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(msg.toString()); 1416e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1417e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (index > 0) { 1418e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown index -= 1; 1419e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1420e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown index = MAX_RECENT_OPERATIONS - 1; 1421e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1422e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown n += 1; 1423e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation = mOperations[index]; 1424e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } while (operation != null && n < MAX_RECENT_OPERATIONS); 1425e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1426e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" <none>"); 1427e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1428e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1429e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1430e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1431e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1432e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final class Operation { 1433e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final SimpleDateFormat sDateFormat = 1434e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 1435e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1436e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public long mStartTime; 1437e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public long mEndTime; 1438e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String mKind; 1439e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String mSql; 1440e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public ArrayList<Object> mBindArgs; 1441e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean mFinished; 1442e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public Exception mException; 1443a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public int mCookie; 1444e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1445e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void describe(StringBuilder msg) { 1446e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(mKind); 1447e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mFinished) { 1448e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(" took ").append(mEndTime - mStartTime).append("ms"); 1449e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1450e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(" started ").append(System.currentTimeMillis() - mStartTime) 1451e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown .append("ms ago"); 1452e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1453e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(" - ").append(getStatus()); 1454e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mSql != null) { 1455e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", sql=\"").append(trimSqlForDisplay(mSql)).append("\""); 1456e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1457e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mBindArgs != null && mBindArgs.size() != 0) { 1458e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", bindArgs=["); 1459e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int count = mBindArgs.size(); 1460e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < count; i++) { 1461e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Object arg = mBindArgs.get(i); 1462e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (i != 0) { 1463e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", "); 1464e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1465e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (arg == null) { 1466e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("null"); 1467e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else if (arg instanceof byte[]) { 1468e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("<byte[]>"); 1469e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else if (arg instanceof String) { 1470e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("\"").append((String)arg).append("\""); 1471e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1472e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(arg); 1473e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1474e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1475e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("]"); 1476e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1477e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mException != null) { 1478e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", exception=\"").append(mException.getMessage()).append("\""); 1479e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1480e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1481e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1482e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private String getStatus() { 1483e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mFinished) { 1484e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return "running"; 1485e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1486e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mException != null ? "failed" : "succeeded"; 1487e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1488e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1489e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private String getFormattedStartTime() { 1490e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return sDateFormat.format(new Date(mStartTime)); 1491e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1492e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1493e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown} 1494