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.text.SimpleDateFormat; 34e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownimport java.util.ArrayList; 35c00df6d52eb5f473e6e1a50fef8f17d8e712bc78Elliott Hughesimport java.util.Date; 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 final CloseGuard mCloseGuard = CloseGuard.get(); 95e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 96e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final SQLiteConnectionPool mPool; 97e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final SQLiteDatabaseConfiguration mConfiguration; 98e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final int mConnectionId; 99e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final boolean mIsPrimaryConnection; 1001d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown private final boolean mIsReadOnlyConnection; 101e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final PreparedStatementCache mPreparedStatementCache; 102e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private PreparedStatement mPreparedStatementPool; 103e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 104e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The recent operations log. 105e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final OperationLog mRecentOperations = new OperationLog(); 106e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 107e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The native SQLiteConnection pointer. (FOR INTERNAL USE ONLY) 108738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private long mConnectionPtr; 109e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 110e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private boolean mOnlyAllowReadOnlyOperations; 111e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1124c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // The number of times attachCancellationSignal has been called. 1131d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Because SQLite statement execution can be reentrant, we keep track of how many 1144c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // times we have attempted to attach a cancellation signal to the connection so that 11575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // we can ensure that we detach the signal at the right time. 1164c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown private int mCancellationSignalAttachCount; 11775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 118738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native long nativeOpen(String path, int openFlags, String label, 119e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown boolean enableTrace, boolean enableProfile); 120738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native void nativeClose(long connectionPtr); 121738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native void nativeRegisterCustomFunction(long connectionPtr, 122e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteCustomFunction function); 123738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native void nativeRegisterLocalizedCollators(long connectionPtr, String locale); 124738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native long nativePrepareStatement(long connectionPtr, String sql); 125738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native void nativeFinalizeStatement(long connectionPtr, long statementPtr); 126738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native int nativeGetParameterCount(long connectionPtr, long statementPtr); 127738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native boolean nativeIsReadOnly(long connectionPtr, long statementPtr); 128738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native int nativeGetColumnCount(long connectionPtr, long statementPtr); 129738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native String nativeGetColumnName(long connectionPtr, long statementPtr, 130e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index); 131738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native void nativeBindNull(long connectionPtr, long statementPtr, 132e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index); 133738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native void nativeBindLong(long connectionPtr, long statementPtr, 134e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index, long value); 135738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native void nativeBindDouble(long connectionPtr, long statementPtr, 136e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index, double value); 137738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native void nativeBindString(long connectionPtr, long statementPtr, 138e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index, String value); 139738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native void nativeBindBlob(long connectionPtr, long statementPtr, 140e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index, byte[] value); 141e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native void nativeResetStatementAndClearBindings( 142738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat long connectionPtr, long statementPtr); 143738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native void nativeExecute(long connectionPtr, long statementPtr); 144738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native long nativeExecuteForLong(long connectionPtr, long statementPtr); 145738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native String nativeExecuteForString(long connectionPtr, long statementPtr); 146e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native int nativeExecuteForBlobFileDescriptor( 147738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat long connectionPtr, long statementPtr); 148738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native int nativeExecuteForChangedRowCount(long connectionPtr, long statementPtr); 149e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native long nativeExecuteForLastInsertedRowId( 150738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat long connectionPtr, long statementPtr); 151e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static native long nativeExecuteForCursorWindow( 152738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat long connectionPtr, long statementPtr, long windowPtr, 153e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int startPos, int requiredPos, boolean countAllRows); 154738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native int nativeGetDbLookaside(long connectionPtr); 155738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native void nativeCancel(long connectionPtr); 156738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private static native void nativeResetCancel(long connectionPtr, boolean cancelable); 157e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 158e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private SQLiteConnection(SQLiteConnectionPool pool, 159e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteDatabaseConfiguration configuration, 160e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int connectionId, boolean primaryConnection) { 161e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPool = pool; 162e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConfiguration = new SQLiteDatabaseConfiguration(configuration); 163e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionId = connectionId; 164e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mIsPrimaryConnection = primaryConnection; 1651d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown mIsReadOnlyConnection = (configuration.openFlags & SQLiteDatabase.OPEN_READONLY) != 0; 166e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache = new PreparedStatementCache( 167e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConfiguration.maxSqlCacheSize); 168e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mCloseGuard.open("close"); 169e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 170e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 171e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown @Override 172e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown protected void finalize() throws Throwable { 173e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 174e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mPool != null && mConnectionPtr != 0) { 175e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPool.onConnectionLeaked(); 176e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 177e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 178e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dispose(true); 179e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 180e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown super.finalize(); 181e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 182e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 183e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 184e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 185e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown static SQLiteConnection open(SQLiteConnectionPool pool, 186e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteDatabaseConfiguration configuration, 187e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int connectionId, boolean primaryConnection) { 188e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteConnection connection = new SQLiteConnection(pool, configuration, 189e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown connectionId, primaryConnection); 190e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 191e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown connection.open(); 192e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return connection; 193e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 194e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown connection.dispose(false); 195e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 196e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 197e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 198e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 199e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 200e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Closes the database closes and releases all of its associated resources. 201e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Do not call methods on the connection after it is closed. It will probably crash. 202e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void close() { 203e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dispose(false); 204e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 205e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 206e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void open() { 207e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags, 208e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConfiguration.label, 209e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME); 210e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 2115936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown setPageSize(); 21296496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown setForeignKeyModeFromConfiguration(); 213d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setWalModeFromConfiguration(); 2148dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown setJournalSizeLimit(); 2158dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown setAutoCheckpointInterval(); 216e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown setLocaleFromConfiguration(); 21727a65247427d704ad98b1265bbf3a6be101a94baNiklas Brunlid 21827a65247427d704ad98b1265bbf3a6be101a94baNiklas Brunlid // Register custom functions. 21927a65247427d704ad98b1265bbf3a6be101a94baNiklas Brunlid final int functionCount = mConfiguration.customFunctions.size(); 22027a65247427d704ad98b1265bbf3a6be101a94baNiklas Brunlid for (int i = 0; i < functionCount; i++) { 22127a65247427d704ad98b1265bbf3a6be101a94baNiklas Brunlid SQLiteCustomFunction function = mConfiguration.customFunctions.get(i); 22227a65247427d704ad98b1265bbf3a6be101a94baNiklas Brunlid nativeRegisterCustomFunction(mConnectionPtr, function); 22327a65247427d704ad98b1265bbf3a6be101a94baNiklas Brunlid } 224e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 225e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 226e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void dispose(boolean finalized) { 227e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mCloseGuard != null) { 228e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (finalized) { 229e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mCloseGuard.warnIfOpen(); 230e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 231e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mCloseGuard.close(); 232e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 233e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 234e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mConnectionPtr != 0) { 235a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("close", null, null); 236e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 237e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.evictAll(); 238e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeClose(mConnectionPtr); 239e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPtr = 0; 240e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 241a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 242e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 243e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 244e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 245e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 2465936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown private void setPageSize() { 2471d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { 2481d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final long newValue = SQLiteGlobal.getDefaultPageSize(); 2491d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown long value = executeForLong("PRAGMA page_size", null, null); 2501d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (value != newValue) { 2511d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("PRAGMA page_size=" + newValue, null, null); 2521d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 2535936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2545936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2555936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 2565936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown private void setAutoCheckpointInterval() { 2571d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { 2581d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final long newValue = SQLiteGlobal.getWALAutoCheckpoint(); 2591d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown long value = executeForLong("PRAGMA wal_autocheckpoint", null, null); 2601d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (value != newValue) { 2611d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown executeForLong("PRAGMA wal_autocheckpoint=" + newValue, null, null); 2621d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 2635936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2645936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2655936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 2665936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown private void setJournalSizeLimit() { 2671d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { 2681d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final long newValue = SQLiteGlobal.getJournalSizeLimit(); 2691d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown long value = executeForLong("PRAGMA journal_size_limit", null, null); 2701d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (value != newValue) { 2711d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown executeForLong("PRAGMA journal_size_limit=" + newValue, null, null); 2721d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 2735936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2745936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 2755936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 27696496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown private void setForeignKeyModeFromConfiguration() { 27796496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown if (!mIsReadOnlyConnection) { 27896496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown final long newValue = mConfiguration.foreignKeyConstraintsEnabled ? 1 : 0; 27996496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown long value = executeForLong("PRAGMA foreign_keys", null, null); 28096496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown if (value != newValue) { 28196496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown execute("PRAGMA foreign_keys=" + newValue, null, null); 28296496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown } 28396496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown } 28496496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown } 28596496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown 286d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown private void setWalModeFromConfiguration() { 2871d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) { 28847847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) { 289d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setJournalMode("WAL"); 290d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setSyncMode(SQLiteGlobal.getWALSyncMode()); 291d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } else { 292d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setJournalMode(SQLiteGlobal.getDefaultJournalMode()); 293d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setSyncMode(SQLiteGlobal.getDefaultSyncMode()); 2941d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 2958dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown } 2968dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown } 2978dc3cc2e13b500e368f5ba1aacfaf0eddbce668cJeff Brown 298d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown private void setSyncMode(String newValue) { 299d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown String value = executeForString("PRAGMA synchronous", null, null); 300d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (!canonicalizeSyncMode(value).equalsIgnoreCase( 301d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown canonicalizeSyncMode(newValue))) { 302d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown execute("PRAGMA synchronous=" + newValue, null, null); 303d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } 304d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } 305d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown 306d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown private static String canonicalizeSyncMode(String value) { 307d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (value.equals("0")) { 308d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return "OFF"; 309d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } else if (value.equals("1")) { 310d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return "NORMAL"; 311d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } else if (value.equals("2")) { 312d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return "FULL"; 313d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } 314d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return value; 315d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } 316d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown 317d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown private void setJournalMode(String newValue) { 318d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown String value = executeForString("PRAGMA journal_mode", null, null); 319d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (!value.equalsIgnoreCase(newValue)) { 320d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown try { 321d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown String result = executeForString("PRAGMA journal_mode=" + newValue, null, null); 322d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (result.equalsIgnoreCase(newValue)) { 323d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown return; 3241d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 325d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // PRAGMA journal_mode silently fails and returns the original journal 326d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // mode in some cases if the journal mode could not be changed. 327d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown } catch (SQLiteDatabaseLockedException ex) { 328d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // This error (SQLITE_BUSY) occurs if one connection has the database 329d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // open in WAL mode and another tries to change it to non-WAL. 3305936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 331d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // Because we always disable WAL mode when a database is first opened 332d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // (even if we intend to re-enable it), we can encounter problems if 333d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // there is another open connection to the database somewhere. 334d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // This can happen for a variety of reasons such as an application opening 335d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // the same database in multiple processes at the same time or if there is a 336d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // crashing content provider service that the ActivityManager has 337d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // removed from its registry but whose process hasn't quite died yet 338d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // by the time it is restarted in a new process. 339d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // 340d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // If we don't change the journal mode, nothing really bad happens. 341d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // In the worst case, an application that enables WAL might not actually 342d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // get it, although it can still use connection pooling. 343d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown Log.w(TAG, "Could not change the database journal mode of '" 344d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + mConfiguration.label + "' from '" + value + "' to '" + newValue 345d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + "' because the database is locked. This usually means that " 346d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + "there are other open connections to the database which prevents " 347d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + "the database from enabling or disabling write-ahead logging mode. " 348d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown + "Proceeding without changing the journal mode."); 3495936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 3505936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 3515936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 352e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void setLocaleFromConfiguration() { 3531d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if ((mConfiguration.openFlags & SQLiteDatabase.NO_LOCALIZED_COLLATORS) != 0) { 3541d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown return; 3551d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 3561d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3571d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Register the localized collators. 3581d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final String newLocale = mConfiguration.locale.toString(); 3591d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown nativeRegisterLocalizedCollators(mConnectionPtr, newLocale); 3601d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3611d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // If the database is read-only, we cannot modify the android metadata table 3621d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // or existing indexes. 3631d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (mIsReadOnlyConnection) { 3641d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown return; 3651d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 3661d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3671d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown try { 3681d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Ensure the android metadata table exists. 3691d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("CREATE TABLE IF NOT EXISTS android_metadata (locale TEXT)", null, null); 3701d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3711d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Check whether the locale was actually changed. 3721d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown final String oldLocale = executeForString("SELECT locale FROM android_metadata " 3731d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown + "UNION SELECT NULL ORDER BY locale DESC LIMIT 1", null, null); 3741d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown if (oldLocale != null && oldLocale.equals(newLocale)) { 3751d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown return; 3761d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 3771d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown 3781d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown // Go ahead and update the indexes using the new locale. 3791d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("BEGIN", null, null); 3801d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown boolean success = false; 3811d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown try { 3821d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("DELETE FROM android_metadata", null, null); 3831d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("INSERT INTO android_metadata (locale) VALUES(?)", 3841d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown new Object[] { newLocale }, null); 3851d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute("REINDEX LOCALIZED", null, null); 3861d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown success = true; 3871d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } finally { 3881d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown execute(success ? "COMMIT" : "ROLLBACK", null, null); 3891d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 3901d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } catch (RuntimeException ex) { 3911d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown throw new SQLiteException("Failed to change locale for db '" + mConfiguration.label 3921d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown + "' to '" + newLocale + "'.", ex); 3931d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown } 394e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 395e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 396e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 397e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void reconfigure(SQLiteDatabaseConfiguration configuration) { 39876070d1690ef9ba2675bdc34f1405968a2123112Jeff Brown mOnlyAllowReadOnlyOperations = false; 39976070d1690ef9ba2675bdc34f1405968a2123112Jeff Brown 400e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Register custom functions. 401e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int functionCount = configuration.customFunctions.size(); 402e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < functionCount; i++) { 403e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown SQLiteCustomFunction function = configuration.customFunctions.get(i); 404e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mConfiguration.customFunctions.contains(function)) { 405e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeRegisterCustomFunction(mConnectionPtr, function); 406e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 407e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 408e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 4095936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown // Remember what changed. 41096496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown boolean foreignKeyModeChanged = configuration.foreignKeyConstraintsEnabled 41196496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown != mConfiguration.foreignKeyConstraintsEnabled; 41247847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags) 41347847f3f4dcf2a0dbea0bc0e4f02528e21d37a88Jeff Brown & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0; 414e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown boolean localeChanged = !configuration.locale.equals(mConfiguration.locale); 415e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 416e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Update configuration parameters. 417e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConfiguration.updateParametersFrom(configuration); 418e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 419e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Update prepared statement cache size. 420e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.resize(configuration.maxSqlCacheSize); 421e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 42296496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown // Update foreign key mode. 42396496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown if (foreignKeyModeChanged) { 42496496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown setForeignKeyModeFromConfiguration(); 42596496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown } 42696496adb611ced49ed1c2c778c616d1f8a5d0e6bJeff Brown 427d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown // Update WAL. 428d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown if (walModeChanged) { 429d67c8c67899481682657d41a61f3846b8d77d165Jeff Brown setWalModeFromConfiguration(); 4305936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown } 4315936ff097eff2c736af2e43fd4a8f7db0ddcfb5aJeff Brown 432e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Update locale. 433e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (localeChanged) { 434e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown setLocaleFromConfiguration(); 435e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 436e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 437e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 438e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 439e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // When set to true, executing write operations will throw SQLiteException. 440e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Preparing statements that might write is ok, just don't execute them. 441e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void setOnlyAllowReadOnlyOperations(boolean readOnly) { 442e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mOnlyAllowReadOnlyOperations = readOnly; 443e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 444e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 445e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Called by SQLiteConnectionPool only. 446e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Returns true if the prepared statement cache contains the specified SQL. 447e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown boolean isPreparedStatementInCache(String sql) { 448e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mPreparedStatementCache.get(sql) != null; 449e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 450e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 451e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 452e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Gets the unique id of this connection. 453e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The connection id. 454e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 455e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int getConnectionId() { 456e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mConnectionId; 457e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 458e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 459e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 460e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Returns true if this is the primary database connection. 461e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return True if this is the primary database connection. 462e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 463e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean isPrimaryConnection() { 464e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mIsPrimaryConnection; 465e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 466e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 467e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 468e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Prepares a statement for execution but does not bind its parameters or execute it. 469e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * <p> 470e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This method can be used to check for syntax errors during compilation 471e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * prior to execution of the statement. If the {@code outStatementInfo} argument 472e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * is not null, the provided {@link SQLiteStatementInfo} object is populated 473e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with information about the statement. 474e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 475e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * A prepared statement makes no reference to the arguments that may eventually 476e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * be bound to it, consequently it it possible to cache certain prepared statements 477e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * such as SELECT or INSERT/UPDATE statements. If the statement is cacheable, 478e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * then it will be stored in the cache for later. 479e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p><p> 480e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * To take advantage of this behavior as an optimization, the connection pool 481e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * provides a method to acquire a connection that already has a given SQL statement 482e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * in its prepared statement cache so that it is ready for execution. 483e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * </p> 484e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 485e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to prepare. 486e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param outStatementInfo The {@link SQLiteStatementInfo} object to populate 487e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with information about the statement, or null if none. 488e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 489e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error. 490e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 491e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void prepare(String sql, SQLiteStatementInfo outStatementInfo) { 492e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 493e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 494e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 495e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 496a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("prepare", sql, null); 497e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 498a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 499e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 500e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (outStatementInfo != null) { 501e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.numParameters = statement.mNumParameters; 502e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.readOnly = statement.mReadOnly; 503e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 504e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int columnCount = nativeGetColumnCount( 505e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPtr, statement.mStatementPtr); 506e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (columnCount == 0) { 507e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.columnNames = EMPTY_STRING_ARRAY; 508e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 509e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.columnNames = new String[columnCount]; 510e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < columnCount; i++) { 511e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown outStatementInfo.columnNames[i] = nativeGetColumnName( 512e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mConnectionPtr, statement.mStatementPtr, i); 513e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 514e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 515e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 516e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 517e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 518e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 519e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 520a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 521e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 522e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 523a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 524e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 525e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 526e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 527e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 528e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that does not return a result. 529e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 530e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 531e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 5324c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 533e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 534e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 535e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 53675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 537e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 53875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public void execute(String sql, Object[] bindArgs, 5394c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 540e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 541e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 542e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 543e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 544a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("execute", sql, bindArgs); 545e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 546a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 547e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 548e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 549e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 550e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 5514c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 55275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 55375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown nativeExecute(mConnectionPtr, statement.mStatementPtr); 55475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 5554c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 55675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 557e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 558e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 559e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 560e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 561a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 562e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 563e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 564a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 565e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 566e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 567e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 568e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 569e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a single <code>long</code> result. 570e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 571e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 572e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 5734c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 574e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The value of the first column in the first row of the result set 575e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * as a <code>long</code>, or zero if none. 576e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 577e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 578e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 57975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 580e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 58175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public long executeForLong(String sql, Object[] bindArgs, 5824c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 583e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 584e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 585e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 586e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 587a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForLong", sql, bindArgs); 588e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 589a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 590e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 591e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 592e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 593e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 5944c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 59575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 59675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return nativeExecuteForLong(mConnectionPtr, statement.mStatementPtr); 59775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 5984c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 59975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 600e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 601e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 602e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 603e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 604a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 605e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 606e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 607a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 608e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 609e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 610e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 611e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 612e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a single {@link String} result. 613e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 614e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 615e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 6164c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 617e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The value of the first column in the first row of the result set 618e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * as a <code>String</code>, or null if none. 619e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 620e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 621e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 62275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 623e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 62475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public String executeForString(String sql, Object[] bindArgs, 6254c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 626e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 627e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 628e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 629e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 630a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForString", sql, bindArgs); 631e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 632a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 633e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 634e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 635e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 636e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 6374c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 63875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 63975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return nativeExecuteForString(mConnectionPtr, statement.mStatementPtr); 64075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 6414c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 64275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 643e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 644e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 645e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 646e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 647a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 648e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 649e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 650a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 651e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 652e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 653e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 654e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 655e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a single BLOB result as a 656e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * file descriptor to a shared memory region. 657e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 658e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 659e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 6604c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 661e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The file descriptor for a shared memory region that contains 662e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * the value of the first column in the first row of the result set as a BLOB, 663e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or null if none. 664e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 665e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 666e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 66775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 668e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 66975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs, 6704c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 671e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 672e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 673e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 674e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 675a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForBlobFileDescriptor", 676a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown sql, bindArgs); 677e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 678a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 679e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 680e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 681e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 682e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 6834c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 68475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 68575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown int fd = nativeExecuteForBlobFileDescriptor( 68675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown mConnectionPtr, statement.mStatementPtr); 68775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return fd >= 0 ? ParcelFileDescriptor.adoptFd(fd) : null; 68875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 6894c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 69075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 691e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 692e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 693e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 694e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 695a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 696e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 697e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 698a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 699e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 700e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 701e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 702e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 703e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns a count of the number of rows 704e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * that were changed. Use for UPDATE or DELETE SQL statements. 705e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 706e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 707e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 7084c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 709e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The number of rows that were changed. 710e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 711e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 712e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 71375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 714e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 71575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public int executeForChangedRowCount(String sql, Object[] bindArgs, 7164c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 717e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 718e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 719e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 720e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 72172eebb6b6d4b16bcba415236dd182a3ba9a72951Makoto Onuki int changedRows = 0; 722a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForChangedRowCount", 723a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown sql, bindArgs); 724e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 725a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 726e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 727e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 728e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 729e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 7304c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 73175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 73272eebb6b6d4b16bcba415236dd182a3ba9a72951Makoto Onuki changedRows = nativeExecuteForChangedRowCount( 73375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown mConnectionPtr, statement.mStatementPtr); 73472eebb6b6d4b16bcba415236dd182a3ba9a72951Makoto Onuki return changedRows; 73575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 7364c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 73775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 738e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 739e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 740e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 741e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 742a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 743e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 744e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 74572eebb6b6d4b16bcba415236dd182a3ba9a72951Makoto Onuki if (mRecentOperations.endOperationDeferLog(cookie)) { 74672eebb6b6d4b16bcba415236dd182a3ba9a72951Makoto Onuki mRecentOperations.logOperation(cookie, "changedRows=" + changedRows); 74772eebb6b6d4b16bcba415236dd182a3ba9a72951Makoto Onuki } 748e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 749e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 750e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 751e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 752e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement that returns the row id of the last row inserted 753e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * by the statement. Use for INSERT SQL statements. 754e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 755e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 756e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 7574c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 758e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The row id of the last row that was inserted, or 0 if none. 759e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 760e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 761e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 76275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 763e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 76475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public long executeForLastInsertedRowId(String sql, Object[] bindArgs, 7654c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 766e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 767e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 768e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 769e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 770a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForLastInsertedRowId", 771a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown sql, bindArgs); 772e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 773a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 774e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 775e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throwIfStatementForbidden(statement); 776e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown bindArguments(statement, bindArgs); 777e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown applyBlockGuardPolicy(statement); 7784c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown attachCancellationSignal(cancellationSignal); 77975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 78075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return nativeExecuteForLastInsertedRowId( 78175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown mConnectionPtr, statement.mStatementPtr); 78275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 7834c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown detachCancellationSignal(cancellationSignal); 78475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 785e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 786e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown releasePreparedStatement(statement); 787e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 788e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 789a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.failOperation(cookie, ex); 790e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 791e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 792a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mRecentOperations.endOperation(cookie); 793e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 794e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 795e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 796e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 797e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Executes a statement and populates the specified {@link CursorWindow} 798e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * with a range of results. Returns the number of rows that were counted 799e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * during query execution. 800e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 801e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param sql The SQL statement to execute. 802e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param bindArgs The arguments to bind, or null if none. 803e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param window The cursor window to clear and fill. 804e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param startPos The start position for filling the window. 805e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param requiredPos The position of a row that MUST be in the window. 806e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * If it won't fit, then the query should discard part of what it filled 807e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * so that it does. Must be greater than or equal to <code>startPos</code>. 808e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param countAllRows True to count all rows that the query would return 809e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * regagless of whether they fit in the window. 8104c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 811e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The number of rows that were counted during query execution. Might 812e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * not be all rows in the result set unless <code>countAllRows</code> is true. 813e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 814e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @throws SQLiteException if an error occurs, such as a syntax error 815e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or invalid number of bind arguments. 81675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @throws OperationCanceledException if the operation was canceled. 817e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 818e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int executeForCursorWindow(String sql, Object[] bindArgs, 81975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown CursorWindow window, int startPos, int requiredPos, boolean countAllRows, 8204c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 821e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (sql == null) { 822e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("sql must not be null."); 823e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 824e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (window == null) { 825e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new IllegalArgumentException("window must not be null."); 826e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 827e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 82803bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown window.acquireReference(); 829e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 83003bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown int actualPos = -1; 83103bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown int countedRows = -1; 83203bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown int filledRows = -1; 83303bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown final int cookie = mRecentOperations.beginOperation("executeForCursorWindow", 83403bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown sql, bindArgs); 835e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 83603bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown final PreparedStatement statement = acquirePreparedStatement(sql); 83775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown try { 83803bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown throwIfStatementForbidden(statement); 83903bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown bindArguments(statement, bindArgs); 84003bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown applyBlockGuardPolicy(statement); 84103bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown attachCancellationSignal(cancellationSignal); 84203bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown try { 84303bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown final long result = nativeExecuteForCursorWindow( 84403bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown mConnectionPtr, statement.mStatementPtr, window.mWindowPtr, 84503bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown startPos, requiredPos, countAllRows); 84603bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown actualPos = (int)(result >> 32); 84703bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown countedRows = (int)result; 84803bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown filledRows = window.getNumRows(); 84903bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown window.setStartPosition(actualPos); 85003bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown return countedRows; 85103bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown } finally { 85203bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown detachCancellationSignal(cancellationSignal); 85303bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown } 85475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } finally { 85503bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown releasePreparedStatement(statement); 85675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 85703bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown } catch (RuntimeException ex) { 85803bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown mRecentOperations.failOperation(cookie, ex); 85903bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown throw ex; 860e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 86103bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown if (mRecentOperations.endOperationDeferLog(cookie)) { 86203bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown mRecentOperations.logOperation(cookie, "window='" + window 86303bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown + "', startPos=" + startPos 86403bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown + ", actualPos=" + actualPos 86503bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown + ", filledRows=" + filledRows 86603bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown + ", countedRows=" + countedRows); 86703bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown } 868e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 869e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 87003bd302aebbb77f4f95789a269c8a5463ac5a840Jeff Brown window.releaseReference(); 871e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 872e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 873e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 874e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private PreparedStatement acquirePreparedStatement(String sql) { 875e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown PreparedStatement statement = mPreparedStatementCache.get(sql); 876a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown boolean skipCache = false; 877e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement != null) { 878a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (!statement.mInUse) { 879a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return statement; 880a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 881a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // The statement is already in the cache but is in use (this statement appears 882a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // to be not only re-entrant but recursive!). So prepare a new copy of the 883a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // statement but do not cache it. 884a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown skipCache = true; 885e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 886e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 887738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat final long statementPtr = nativePrepareStatement(mConnectionPtr, sql); 888e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 889e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int numParameters = nativeGetParameterCount(mConnectionPtr, statementPtr); 890e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int type = DatabaseUtils.getSqlStatementType(sql); 891e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final boolean readOnly = nativeIsReadOnly(mConnectionPtr, statementPtr); 892e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement = obtainPreparedStatement(sql, statementPtr, numParameters, type, readOnly); 893a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (!skipCache && isCacheable(type)) { 894e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.put(sql, statement); 895e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mInCache = true; 896e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 897e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (RuntimeException ex) { 898e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Finalize the statement if an exception occurred and we did not add 899e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // it to the cache. If it is already in the cache, then leave it there. 900e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement == null || !statement.mInCache) { 901e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeFinalizeStatement(mConnectionPtr, statementPtr); 902e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 903e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw ex; 904e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 905a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown statement.mInUse = true; 906e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return statement; 907e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 908e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 909e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void releasePreparedStatement(PreparedStatement statement) { 910a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown statement.mInUse = false; 911e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement.mInCache) { 912e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 913e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeResetStatementAndClearBindings(mConnectionPtr, statement.mStatementPtr); 914e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 915a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // The statement could not be reset due to an error. Remove it from the cache. 916a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // When remove() is called, the cache will invoke its entryRemoved() callback, 917a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // which will in turn call finalizePreparedStatement() to finalize and 918a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // recycle the statement. 9192a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown if (DEBUG) { 9202a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown Log.d(TAG, "Could not reset prepared statement due to an exception. " 921e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + "Removing it from the cache. SQL: " 922e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + trimSqlForDisplay(statement.mSql), ex); 923e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 9242a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown 925e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.remove(statement.mSql); 926e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 927e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 928a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown finalizePreparedStatement(statement); 929e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 930e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 931e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 932a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private void finalizePreparedStatement(PreparedStatement statement) { 933a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown nativeFinalizeStatement(mConnectionPtr, statement.mStatementPtr); 934a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown recyclePreparedStatement(statement); 935a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 936a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 9374c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown private void attachCancellationSignal(CancellationSignal cancellationSignal) { 9384c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown if (cancellationSignal != null) { 9394c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown cancellationSignal.throwIfCanceled(); 94075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9414c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown mCancellationSignalAttachCount += 1; 9424c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown if (mCancellationSignalAttachCount == 1) { 9434c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // Reset cancellation flag before executing the statement. 94475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown nativeResetCancel(mConnectionPtr, true /*cancelable*/); 94575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 94675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // After this point, onCancel() may be called concurrently. 9474c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown cancellationSignal.setOnCancelListener(this); 94875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 94975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 95075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 95175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9524c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown private void detachCancellationSignal(CancellationSignal cancellationSignal) { 9534c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown if (cancellationSignal != null) { 9544c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown assert mCancellationSignalAttachCount > 0; 95575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9564c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown mCancellationSignalAttachCount -= 1; 9574c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown if (mCancellationSignalAttachCount == 0) { 95875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // After this point, onCancel() cannot be called concurrently. 9594c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown cancellationSignal.setOnCancelListener(null); 96075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9614c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // Reset cancellation flag after executing the statement. 96275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown nativeResetCancel(mConnectionPtr, false /*cancelable*/); 96375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 96475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 96575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 96675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 9674c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // CancellationSignal.OnCancelListener callback. 96875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // This method may be called on a different thread than the executing statement. 9694c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // However, it will only be called between calls to attachCancellationSignal and 9704c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown // detachCancellationSignal, while a statement is executing. We can safely assume 97175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown // that the SQLite connection is still alive. 97275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown @Override 97375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public void onCancel() { 97475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown nativeCancel(mConnectionPtr); 97575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 97675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 977e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void bindArguments(PreparedStatement statement, Object[] bindArgs) { 978e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int count = bindArgs != null ? bindArgs.length : 0; 979e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (count != statement.mNumParameters) { 980e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new SQLiteBindOrColumnIndexOutOfRangeException( 981e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown "Expected " + statement.mNumParameters + " bind arguments but " 982942085b8eed6a15522e0c030d72958c3030bbf36Sylvain Becuwe + count + " were provided."); 983e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 984e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (count == 0) { 985e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return; 986e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 987e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 988738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat final long statementPtr = statement.mStatementPtr; 989e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < count; i++) { 990e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Object arg = bindArgs[i]; 991e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown switch (DatabaseUtils.getTypeOfObject(arg)) { 992e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_NULL: 993e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindNull(mConnectionPtr, statementPtr, i + 1); 994e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 995e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_INTEGER: 996e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindLong(mConnectionPtr, statementPtr, i + 1, 997e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown ((Number)arg).longValue()); 998e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 999e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_FLOAT: 1000e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindDouble(mConnectionPtr, statementPtr, i + 1, 1001e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown ((Number)arg).doubleValue()); 1002e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 1003e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_BLOB: 1004e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindBlob(mConnectionPtr, statementPtr, i + 1, (byte[])arg); 1005e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 1006e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown case Cursor.FIELD_TYPE_STRING: 1007e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown default: 1008e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (arg instanceof Boolean) { 1009e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Provide compatibility with legacy applications which may pass 1010e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Boolean values in bind args. 1011e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindLong(mConnectionPtr, statementPtr, i + 1, 1012e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown ((Boolean)arg).booleanValue() ? 1 : 0); 1013e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1014e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown nativeBindString(mConnectionPtr, statementPtr, i + 1, arg.toString()); 1015e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1016e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown break; 1017e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1018e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1019e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1020e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1021e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void throwIfStatementForbidden(PreparedStatement statement) { 1022e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mOnlyAllowReadOnlyOperations && !statement.mReadOnly) { 1023e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown throw new SQLiteException("Cannot execute this statement because it " 1024e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + "might modify the database but the connection is read-only."); 1025e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1026e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1027e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1028e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static boolean isCacheable(int statementType) { 1029e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statementType == DatabaseUtils.STATEMENT_UPDATE 1030e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown || statementType == DatabaseUtils.STATEMENT_SELECT) { 1031e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return true; 1032e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1033e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return false; 1034e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1035e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1036e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void applyBlockGuardPolicy(PreparedStatement statement) { 1037e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mConfiguration.isInMemoryDb()) { 1038e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement.mReadOnly) { 1039e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown BlockGuard.getThreadPolicy().onReadFromDisk(); 1040e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1041e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown BlockGuard.getThreadPolicy().onWriteToDisk(); 1042e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1043e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1044e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1045e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1046e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1047e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Dumps debugging information about this connection. 1048e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1049e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param printer The printer to receive the dump, not null. 1050a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * @param verbose True to dump more verbose information. 1051e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1052a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public void dump(Printer printer, boolean verbose) { 1053a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown dumpUnsafe(printer, verbose); 1054e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1055e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1056e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1057e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Dumps debugging information about this connection, in the case where the 1058e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * caller might not actually own the connection. 1059e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1060e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This function is written so that it may be called by a thread that does not 1061e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * own the connection. We need to be very careful because the connection state is 1062e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * not synchronized. 1063e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1064e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * At worst, the method may return stale or slightly wrong data, however 1065e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * it should not crash. This is ok as it is only used for diagnostic purposes. 1066e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1067e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param printer The printer to receive the dump, not null. 1068a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown * @param verbose True to dump more verbose information. 1069e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1070a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown void dumpUnsafe(Printer printer, boolean verbose) { 1071e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println("Connection #" + mConnectionId + ":"); 1072a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (verbose) { 1073738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat printer.println(" connectionPtr: 0x" + Long.toHexString(mConnectionPtr)); 1074a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1075e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" isPrimaryConnection: " + mIsPrimaryConnection); 1076e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" onlyAllowReadOnlyOperations: " + mOnlyAllowReadOnlyOperations); 1077e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1078cefeb29d537e591756620f780a4ef45f502542fbJeff Brown mRecentOperations.dump(printer, verbose); 1079a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 1080a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (verbose) { 1081a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown mPreparedStatementCache.dump(printer); 1082a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1083e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1084e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1085e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1086e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Describes the currently executing operation, in the case where the 1087e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * caller might not actually own the connection. 1088e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1089e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * This function is written so that it may be called by a thread that does not 1090e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * own the connection. We need to be very careful because the connection state is 1091e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * not synchronized. 1092e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1093e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * At worst, the method may return stale or slightly wrong data, however 1094e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * it should not crash. This is ok as it is only used for diagnostic purposes. 1095e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1096e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return A description of the current operation including how long it has been running, 1097e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * or null if none. 1098e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1099e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String describeCurrentOperationUnsafe() { 1100e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mRecentOperations.describeCurrentOperation(); 1101e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1102e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1103e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1104e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Collects statistics about database connection memory usage. 1105e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1106e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @param dbStatsList The list to populate. 1107e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1108e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void collectDbStats(ArrayList<DbStats> dbStatsList) { 1109e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Get information about the main database. 1110e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int lookaside = nativeGetDbLookaside(mConnectionPtr); 1111e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown long pageCount = 0; 1112e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown long pageSize = 0; 1113e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 111475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown pageCount = executeForLong("PRAGMA page_count;", null, null); 111575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown pageSize = executeForLong("PRAGMA page_size;", null, null); 1116e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 1117e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Ignore. 1118e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1119e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dbStatsList.add(getMainDbStatsUnsafe(lookaside, pageCount, pageSize)); 1120e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1121e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Get information about attached databases. 1122e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // We ignore the first row in the database list because it corresponds to 1123e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // the main database which we have already described. 1124e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown CursorWindow window = new CursorWindow("collectDbStats"); 1125e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 112675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown executeForCursorWindow("PRAGMA database_list;", null, window, 0, 0, false, null); 1127e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 1; i < window.getNumRows(); i++) { 1128e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String name = window.getString(i, 1); 1129e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String path = window.getString(i, 2); 1130e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown pageCount = 0; 1131e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown pageSize = 0; 1132e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown try { 113375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown pageCount = executeForLong("PRAGMA " + name + ".page_count;", null, null); 113475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown pageSize = executeForLong("PRAGMA " + name + ".page_size;", null, null); 1135e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 1136e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Ignore. 1137e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1138e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String label = " (attached) " + name; 1139e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!path.isEmpty()) { 1140e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown label += ": " + path; 1141e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1142e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dbStatsList.add(new DbStats(label, pageCount, pageSize, 0, 0, 0, 0)); 1143e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1144e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } catch (SQLiteException ex) { 1145e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Ignore. 1146e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } finally { 1147e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown window.close(); 1148e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1149e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1150e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1151e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1152e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Collects statistics about database connection memory usage, in the case where the 1153e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * caller might not actually own the connection. 1154e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1155e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * @return The statistics object, never null. 1156e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1157e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown void collectDbStatsUnsafe(ArrayList<DbStats> dbStatsList) { 1158e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown dbStatsList.add(getMainDbStatsUnsafe(0, 0, 0)); 1159e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1160e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1161e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private DbStats getMainDbStatsUnsafe(int lookaside, long pageCount, long pageSize) { 1162e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The prepared statement cache is thread-safe so we can access its statistics 1163e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // even if we do not own the database connection. 1164e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String label = mConfiguration.path; 1165e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mIsPrimaryConnection) { 1166e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown label += " (" + mConnectionId + ")"; 1167e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1168e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return new DbStats(label, pageCount, pageSize, lookaside, 1169e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.hitCount(), 1170e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.missCount(), 1171e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementCache.size()); 1172e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1173e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1174e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown @Override 1175e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String toString() { 1176e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return "SQLiteConnection: " + mConfiguration.path + " (" + mConnectionId + ")"; 1177e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1178e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1179738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat private PreparedStatement obtainPreparedStatement(String sql, long statementPtr, 1180e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int numParameters, int type, boolean readOnly) { 1181e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown PreparedStatement statement = mPreparedStatementPool; 1182e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement != null) { 1183e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementPool = statement.mPoolNext; 1184e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mPoolNext = null; 1185e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mInCache = false; 1186e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1187e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement = new PreparedStatement(); 1188e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1189e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mSql = sql; 1190e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mStatementPtr = statementPtr; 1191e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mNumParameters = numParameters; 1192e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mType = type; 1193e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mReadOnly = readOnly; 1194e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return statement; 1195e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1196e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1197e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private void recyclePreparedStatement(PreparedStatement statement) { 1198e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mSql = null; 1199e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown statement.mPoolNext = mPreparedStatementPool; 1200e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mPreparedStatementPool = statement; 1201e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1202e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1203e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static String trimSqlForDisplay(String sql) { 12044f47b40e05245c395370aaf3e861ff24f3028766Andreas Gampe // Note: Creating and caching a regular expression is expensive at preload-time 12054f47b40e05245c395370aaf3e861ff24f3028766Andreas Gampe // and stops compile-time initialization. This pattern is only used when 12064f47b40e05245c395370aaf3e861ff24f3028766Andreas Gampe // dumping the connection, which is a rare (mainly error) case. So: 12074f47b40e05245c395370aaf3e861ff24f3028766Andreas Gampe // DO NOT CACHE. 12084f47b40e05245c395370aaf3e861ff24f3028766Andreas Gampe return sql.replaceAll("[\\s]*\\n+[\\s]*", " "); 1209e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1210e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1211e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown /** 1212e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Holder type for a prepared statement. 1213e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * 1214e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Although this object holds a pointer to a native statement object, it 1215e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * does not have a finalizer. This is deliberate. The {@link SQLiteConnection} 1216e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * owns the statement object and will take care of freeing it when needed. 1217e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * In particular, closing the connection requires a guarantee of deterministic 1218e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * resource disposal because all native statement objects must be freed before 1219e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * the native database object can be closed. So no finalizers here. 1220e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */ 1221e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final class PreparedStatement { 1222e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Next item in pool. 1223e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public PreparedStatement mPoolNext; 1224e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1225e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The SQL from which the statement was prepared. 1226e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String mSql; 1227e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1228e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The native sqlite3_stmt object pointer. 1229e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Lifetime is managed explicitly by the connection. 1230738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat public long mStatementPtr; 1231e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1232e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The number of parameters that the prepared statement has. 1233e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int mNumParameters; 1234e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1235e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // The statement type. 1236e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public int mType; 1237e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1238e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // True if the statement is read-only. 1239e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean mReadOnly; 1240e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1241e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // True if the statement is in the cache. 1242e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean mInCache; 1243a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 1244a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // True if the statement is in use (currently executing). 1245a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // We need this flag because due to the use of custom functions in triggers, it's 1246a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // possible for SQLite calls to be re-entrant. Consequently we need to prevent 1247a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown // in use statements from being finalized until they are no longer in use. 1248a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public boolean mInUse; 1249e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1250e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1251e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final class PreparedStatementCache 1252e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown extends LruCache<String, PreparedStatement> { 1253e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public PreparedStatementCache(int size) { 1254e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown super(size); 1255e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1256e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1257e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown @Override 1258e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown protected void entryRemoved(boolean evicted, String key, 1259e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown PreparedStatement oldValue, PreparedStatement newValue) { 1260e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown oldValue.mInCache = false; 1261a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (!oldValue.mInUse) { 1262a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown finalizePreparedStatement(oldValue); 1263a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1264e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1265e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1266e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public void dump(Printer printer) { 1267e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" Prepared statement cache:"); 1268e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Map<String, PreparedStatement> cache = snapshot(); 1269e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!cache.isEmpty()) { 1270e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int i = 0; 1271e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (Map.Entry<String, PreparedStatement> entry : cache.entrySet()) { 1272e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown PreparedStatement statement = entry.getValue(); 1273e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (statement.mInCache) { // might be false due to a race with entryRemoved 1274e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown String sql = entry.getKey(); 1275e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" " + i + ": statementPtr=0x" 1276738702d28ab7e0e89e3c6e18fd46cc1361917eb9Ashok Bhat + Long.toHexString(statement.mStatementPtr) 1277e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + ", numParameters=" + statement.mNumParameters 1278e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + ", type=" + statement.mType 1279e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + ", readOnly=" + statement.mReadOnly 1280e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown + ", sql=\"" + trimSqlForDisplay(sql) + "\""); 1281e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1282e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown i += 1; 1283e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1284e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1285e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" <none>"); 1286e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1287e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1288e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1289e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1290e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final class OperationLog { 12912a293b61cb0efbf24994d74ed980f58b820bb35aJeff Brown private static final int MAX_RECENT_OPERATIONS = 20; 1292a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private static final int COOKIE_GENERATION_SHIFT = 8; 1293a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private static final int COOKIE_INDEX_MASK = 0xff; 1294e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1295e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private final Operation[] mOperations = new Operation[MAX_RECENT_OPERATIONS]; 1296e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private int mIndex; 1297a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private int mGeneration; 1298e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1299a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public int beginOperation(String kind, String sql, Object[] bindArgs) { 1300e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1301e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int index = (mIndex + 1) % MAX_RECENT_OPERATIONS; 1302e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Operation operation = mOperations[index]; 1303e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation == null) { 1304e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation = new Operation(); 1305e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mOperations[index] = operation; 1306e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1307e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mFinished = false; 1308e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mException = null; 1309e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation.mBindArgs != null) { 1310e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs.clear(); 1311e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1312e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1313e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mStartTime = System.currentTimeMillis(); 1314e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mKind = kind; 1315e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mSql = sql; 1316e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (bindArgs != null) { 1317e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation.mBindArgs == null) { 1318e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs = new ArrayList<Object>(); 1319e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1320e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs.clear(); 1321e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1322e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < bindArgs.length; i++) { 1323e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Object arg = bindArgs[i]; 1324e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (arg != null && arg instanceof byte[]) { 1325e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown // Don't hold onto the real byte array longer than necessary. 1326e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs.add(EMPTY_BYTE_ARRAY); 1327e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1328e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation.mBindArgs.add(arg); 1329e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1330e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1331e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1332a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mCookie = newOperationCookieLocked(index); 1333e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown mIndex = index; 1334a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return operation.mCookie; 1335e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1336e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1337e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1338a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public void failOperation(int cookie, Exception ex) { 1339e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1340a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final Operation operation = getOperationLocked(cookie); 1341a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (operation != null) { 1342a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mException = ex; 1343a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1344e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1345e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1346e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1347a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public void endOperation(int cookie) { 1348e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1349a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (endOperationDeferLogLocked(cookie)) { 1350a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown logOperationLocked(cookie, null); 1351a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1352e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1353e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1354e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1355a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public boolean endOperationDeferLog(int cookie) { 1356a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown synchronized (mOperations) { 1357a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return endOperationDeferLogLocked(cookie); 1358a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1359e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1360e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1361a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public void logOperation(int cookie, String detail) { 1362e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1363a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown logOperationLocked(cookie, detail); 1364e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1365e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1366e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1367a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private boolean endOperationDeferLogLocked(int cookie) { 1368a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final Operation operation = getOperationLocked(cookie); 1369a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown if (operation != null) { 1370a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mEndTime = System.currentTimeMillis(); 1371a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mFinished = true; 1372a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return SQLiteDebug.DEBUG_LOG_SLOW_QUERIES && SQLiteDebug.shouldLogSlowQuery( 1373a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown operation.mEndTime - operation.mStartTime); 1374e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1375a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return false; 1376e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1377e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1378a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private void logOperationLocked(int cookie, String detail) { 1379a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final Operation operation = getOperationLocked(cookie); 1380e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown StringBuilder msg = new StringBuilder(); 1381cefeb29d537e591756620f780a4ef45f502542fbJeff Brown operation.describe(msg, false); 1382e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (detail != null) { 1383e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", ").append(detail); 1384e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1385e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Log.d(TAG, msg.toString()); 1386e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1387e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1388a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private int newOperationCookieLocked(int index) { 1389a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int generation = mGeneration++; 1390a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return generation << COOKIE_GENERATION_SHIFT | index; 1391a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1392a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 1393a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown private Operation getOperationLocked(int cookie) { 1394a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final int index = cookie & COOKIE_INDEX_MASK; 1395a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown final Operation operation = mOperations[index]; 1396a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown return operation.mCookie == cookie ? operation : null; 1397a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown } 1398a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown 1399e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String describeCurrentOperation() { 1400e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1401e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Operation operation = mOperations[mIndex]; 1402e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation != null && !operation.mFinished) { 1403e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown StringBuilder msg = new StringBuilder(); 1404cefeb29d537e591756620f780a4ef45f502542fbJeff Brown operation.describe(msg, false); 1405e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return msg.toString(); 1406e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1407e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return null; 1408e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1409e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1410e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1411cefeb29d537e591756620f780a4ef45f502542fbJeff Brown public void dump(Printer printer, boolean verbose) { 1412e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown synchronized (mOperations) { 1413e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" Most recently executed operations:"); 1414e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int index = mIndex; 1415e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown Operation operation = mOperations[index]; 1416e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (operation != null) { 1417e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown int n = 0; 1418e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown do { 1419e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown StringBuilder msg = new StringBuilder(); 1420e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(" ").append(n).append(": ["); 1421e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(operation.getFormattedStartTime()); 1422e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("] "); 1423cefeb29d537e591756620f780a4ef45f502542fbJeff Brown operation.describe(msg, verbose); 1424e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(msg.toString()); 1425e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1426e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (index > 0) { 1427e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown index -= 1; 1428e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1429e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown index = MAX_RECENT_OPERATIONS - 1; 1430e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1431e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown n += 1; 1432e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown operation = mOperations[index]; 1433e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } while (operation != null && n < MAX_RECENT_OPERATIONS); 1434e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1435e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown printer.println(" <none>"); 1436e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1437e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1438e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1439e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1440e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1441e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private static final class Operation { 1442e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public long mStartTime; 1443e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public long mEndTime; 1444e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String mKind; 1445e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public String mSql; 1446e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public ArrayList<Object> mBindArgs; 1447e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public boolean mFinished; 1448e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown public Exception mException; 1449a9be4154e8dac0de3db5ee42e878beb0639e70e6Jeff Brown public int mCookie; 1450e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1451cefeb29d537e591756620f780a4ef45f502542fbJeff Brown public void describe(StringBuilder msg, boolean verbose) { 1452e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(mKind); 1453e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mFinished) { 1454e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(" took ").append(mEndTime - mStartTime).append("ms"); 1455e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1456e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(" started ").append(System.currentTimeMillis() - mStartTime) 1457e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown .append("ms ago"); 1458e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1459e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(" - ").append(getStatus()); 1460e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mSql != null) { 1461e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", sql=\"").append(trimSqlForDisplay(mSql)).append("\""); 1462e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1463cefeb29d537e591756620f780a4ef45f502542fbJeff Brown if (verbose && mBindArgs != null && mBindArgs.size() != 0) { 1464e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", bindArgs=["); 1465e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final int count = mBindArgs.size(); 1466e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown for (int i = 0; i < count; i++) { 1467e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown final Object arg = mBindArgs.get(i); 1468e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (i != 0) { 1469e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", "); 1470e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1471e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (arg == null) { 1472e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("null"); 1473e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else if (arg instanceof byte[]) { 1474e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("<byte[]>"); 1475e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else if (arg instanceof String) { 1476e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("\"").append((String)arg).append("\""); 1477e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } else { 1478e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(arg); 1479e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1480e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1481e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append("]"); 1482e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1483e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (mException != null) { 1484e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown msg.append(", exception=\"").append(mException.getMessage()).append("\""); 1485e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1486e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1487e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1488e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private String getStatus() { 1489e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown if (!mFinished) { 1490e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return "running"; 1491e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1492e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown return mException != null ? "failed" : "succeeded"; 1493e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1494e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 1495e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown private String getFormattedStartTime() { 14964f47b40e05245c395370aaf3e861ff24f3028766Andreas Gampe // Note: SimpleDateFormat is not thread-safe, cannot be compile-time created, and is 14974f47b40e05245c395370aaf3e861ff24f3028766Andreas Gampe // relatively expensive to create during preloading. This method is only used 14984f47b40e05245c395370aaf3e861ff24f3028766Andreas Gampe // when dumping a connection, which is a rare (mainly error) case. So: 14994f47b40e05245c395370aaf3e861ff24f3028766Andreas Gampe // DO NOT CACHE. 15004f47b40e05245c395370aaf3e861ff24f3028766Andreas Gampe return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(mStartTime)); 1501e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1502e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown } 1503e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown} 1504