Loading core/java/android/database/sqlite/SQLiteConnection.java +130 −70 Original line number Diff line number Diff line Loading @@ -74,6 +74,12 @@ import java.util.regex.Pattern; * queues. * </p> * * <h2>Reentrance</h2> * <p> * This class must tolerate reentrant execution of SQLite operations because * triggers may call custom SQLite functions that perform additional queries. * </p> * * @hide */ public final class SQLiteConnection { Loading Loading @@ -205,13 +211,13 @@ public final class SQLiteConnection { } if (mConnectionPtr != 0) { mRecentOperations.beginOperation("close", null, null); final int cookie = mRecentOperations.beginOperation("close", null, null); try { mPreparedStatementCache.evictAll(); nativeClose(mConnectionPtr); mConnectionPtr = 0; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } } Loading Loading @@ -304,9 +310,9 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("prepare", sql, null); final int cookie = mRecentOperations.beginOperation("prepare", sql, null); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { if (outStatementInfo != null) { outStatementInfo.numParameters = statement.mNumParameters; Loading @@ -328,10 +334,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading @@ -349,9 +355,9 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("execute", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("execute", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -361,10 +367,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading @@ -384,9 +390,9 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("executeForLong", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("executeForLong", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -396,10 +402,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading @@ -419,9 +425,9 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("executeForString", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("executeForString", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -431,10 +437,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading @@ -456,9 +462,10 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("executeForBlobFileDescriptor", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("executeForBlobFileDescriptor", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -470,10 +477,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading @@ -493,9 +500,10 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("executeForChangedRowCount", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("executeForChangedRowCount", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -506,10 +514,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading @@ -529,9 +537,10 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("executeForLastInsertedRowId", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("executeForLastInsertedRowId", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -542,10 +551,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading Loading @@ -581,9 +590,10 @@ public final class SQLiteConnection { int actualPos = -1; int countedRows = -1; int filledRows = -1; mRecentOperations.beginOperation("executeForCursorWindow", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("executeForCursorWindow", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -600,11 +610,11 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { if (mRecentOperations.endOperationDeferLog()) { mRecentOperations.logOperation("window='" + window if (mRecentOperations.endOperationDeferLog(cookie)) { mRecentOperations.logOperation(cookie, "window='" + window + "', startPos=" + startPos + ", actualPos=" + actualPos + ", filledRows=" + filledRows Loading @@ -615,9 +625,16 @@ public final class SQLiteConnection { private PreparedStatement acquirePreparedStatement(String sql) { PreparedStatement statement = mPreparedStatementCache.get(sql); boolean skipCache = false; if (statement != null) { if (!statement.mInUse) { return statement; } // The statement is already in the cache but is in use (this statement appears // to be not only re-entrant but recursive!). So prepare a new copy of the // statement but do not cache it. skipCache = true; } final int statementPtr = nativePrepareStatement(mConnectionPtr, sql); try { Loading @@ -625,7 +642,7 @@ public final class SQLiteConnection { final int type = DatabaseUtils.getSqlStatementType(sql); final boolean readOnly = nativeIsReadOnly(mConnectionPtr, statementPtr); statement = obtainPreparedStatement(sql, statementPtr, numParameters, type, readOnly); if (isCacheable(type)) { if (!skipCache && isCacheable(type)) { mPreparedStatementCache.put(sql, statement); statement.mInCache = true; } Loading @@ -637,18 +654,20 @@ public final class SQLiteConnection { } throw ex; } statement.mInUse = true; return statement; } private void releasePreparedStatement(PreparedStatement statement) { statement.mInUse = false; if (statement.mInCache) { try { nativeResetStatementAndClearBindings(mConnectionPtr, statement.mStatementPtr); } catch (SQLiteException ex) { // The statement could not be reset due to an error. // The entryRemoved() callback for the cache will recursively call // releasePreparedStatement() again, but this time mInCache will be false // so the statement will be finalized and recycled. // The statement could not be reset due to an error. Remove it from the cache. // When remove() is called, the cache will invoke its entryRemoved() callback, // which will in turn call finalizePreparedStatement() to finalize and // recycle the statement. if (SQLiteDebug.DEBUG_SQL_CACHE) { Log.v(TAG, "Could not reset prepared statement due to an exception. " + "Removing it from the cache. SQL: " Loading @@ -657,10 +676,14 @@ public final class SQLiteConnection { mPreparedStatementCache.remove(statement.mSql); } } else { finalizePreparedStatement(statement); } } private void finalizePreparedStatement(PreparedStatement statement) { nativeFinalizeStatement(mConnectionPtr, statement.mStatementPtr); recyclePreparedStatement(statement); } } private void bindArguments(PreparedStatement statement, Object[] bindArgs) { final int count = bindArgs != null ? bindArgs.length : 0; Loading Loading @@ -735,9 +758,10 @@ public final class SQLiteConnection { * Dumps debugging information about this connection. * * @param printer The printer to receive the dump, not null. * @param verbose True to dump more verbose information. */ public void dump(Printer printer) { dumpUnsafe(printer); public void dump(Printer printer, boolean verbose) { dumpUnsafe(printer, verbose); } /** Loading @@ -752,16 +776,22 @@ public final class SQLiteConnection { * it should not crash. This is ok as it is only used for diagnostic purposes. * * @param printer The printer to receive the dump, not null. * @param verbose True to dump more verbose information. */ void dumpUnsafe(Printer printer) { void dumpUnsafe(Printer printer, boolean verbose) { printer.println("Connection #" + mConnectionId + ":"); printer.println(" isPrimaryConnection: " + mIsPrimaryConnection); if (verbose) { printer.println(" connectionPtr: 0x" + Integer.toHexString(mConnectionPtr)); } printer.println(" isPrimaryConnection: " + mIsPrimaryConnection); printer.println(" onlyAllowReadOnlyOperations: " + mOnlyAllowReadOnlyOperations); mRecentOperations.dump(printer); if (verbose) { mPreparedStatementCache.dump(printer); } } /** * Describes the currently executing operation, in the case where the Loading Loading @@ -917,6 +947,12 @@ public final class SQLiteConnection { // True if the statement is in the cache. public boolean mInCache; // True if the statement is in use (currently executing). // We need this flag because due to the use of custom functions in triggers, it's // possible for SQLite calls to be re-entrant. Consequently we need to prevent // in use statements from being finalized until they are no longer in use. public boolean mInUse; } private final class PreparedStatementCache Loading @@ -929,7 +965,9 @@ public final class SQLiteConnection { protected void entryRemoved(boolean evicted, String key, PreparedStatement oldValue, PreparedStatement newValue) { oldValue.mInCache = false; releasePreparedStatement(oldValue); if (!oldValue.mInUse) { finalizePreparedStatement(oldValue); } } public void dump(Printer printer) { Loading Loading @@ -958,11 +996,14 @@ public final class SQLiteConnection { private static final class OperationLog { private static final int MAX_RECENT_OPERATIONS = 10; private static final int COOKIE_GENERATION_SHIFT = 8; private static final int COOKIE_INDEX_MASK = 0xff; private final Operation[] mOperations = new Operation[MAX_RECENT_OPERATIONS]; private int mIndex; private int mGeneration; public void beginOperation(String kind, String sql, Object[] bindArgs) { public int beginOperation(String kind, String sql, Object[] bindArgs) { synchronized (mOperations) { final int index = (mIndex + 1) % MAX_RECENT_OPERATIONS; Operation operation = mOperations[index]; Loading Loading @@ -995,47 +1036,54 @@ public final class SQLiteConnection { } } } operation.mCookie = newOperationCookieLocked(index); mIndex = index; return operation.mCookie; } } public void failOperation(Exception ex) { public void failOperation(int cookie, Exception ex) { synchronized (mOperations) { final Operation operation = mOperations[mIndex]; final Operation operation = getOperationLocked(cookie); if (operation != null) { operation.mException = ex; } } } public boolean endOperationDeferLog() { public void endOperation(int cookie) { synchronized (mOperations) { return endOperationDeferLogLocked(); if (endOperationDeferLogLocked(cookie)) { logOperationLocked(cookie, null); } } private boolean endOperationDeferLogLocked() { final Operation operation = mOperations[mIndex]; operation.mEndTime = System.currentTimeMillis(); operation.mFinished = true; return SQLiteDebug.DEBUG_LOG_SLOW_QUERIES && SQLiteDebug.shouldLogSlowQuery( operation.mEndTime - operation.mStartTime); } public void endOperation() { public boolean endOperationDeferLog(int cookie) { synchronized (mOperations) { if (endOperationDeferLogLocked()) { logOperationLocked(null); } return endOperationDeferLogLocked(cookie); } } public void logOperation(String detail) { public void logOperation(int cookie, String detail) { synchronized (mOperations) { logOperationLocked(detail); logOperationLocked(cookie, detail); } } private void logOperationLocked(String detail) { final Operation operation = mOperations[mIndex]; private boolean endOperationDeferLogLocked(int cookie) { final Operation operation = getOperationLocked(cookie); if (operation != null) { operation.mEndTime = System.currentTimeMillis(); operation.mFinished = true; return SQLiteDebug.DEBUG_LOG_SLOW_QUERIES && SQLiteDebug.shouldLogSlowQuery( operation.mEndTime - operation.mStartTime); } return false; } private void logOperationLocked(int cookie, String detail) { final Operation operation = getOperationLocked(cookie); StringBuilder msg = new StringBuilder(); operation.describe(msg); if (detail != null) { Loading @@ -1044,6 +1092,17 @@ public final class SQLiteConnection { Log.d(TAG, msg.toString()); } private int newOperationCookieLocked(int index) { final int generation = mGeneration++; return generation << COOKIE_GENERATION_SHIFT | index; } private Operation getOperationLocked(int cookie) { final int index = cookie & COOKIE_INDEX_MASK; final Operation operation = mOperations[index]; return operation.mCookie == cookie ? operation : null; } public String describeCurrentOperation() { synchronized (mOperations) { final Operation operation = mOperations[mIndex]; Loading Loading @@ -1097,6 +1156,7 @@ public final class SQLiteConnection { public ArrayList<Object> mBindArgs; public boolean mFinished; public Exception mException; public int mCookie; public void describe(StringBuilder msg) { msg.append(mKind); Loading core/java/android/database/sqlite/SQLiteConnectionPool.java +5 −4 Original line number Diff line number Diff line Loading @@ -833,8 +833,9 @@ public final class SQLiteConnectionPool implements Closeable { * Dumps debugging information about this connection pool. * * @param printer The printer to receive the dump, not null. * @param verbose True to dump more verbose information. */ public void dump(Printer printer) { public void dump(Printer printer, boolean verbose) { Printer indentedPrinter = PrefixPrinter.create(printer, " "); synchronized (mLock) { printer.println("Connection pool for " + mConfiguration.path + ":"); Loading @@ -843,7 +844,7 @@ public final class SQLiteConnectionPool implements Closeable { printer.println(" Available primary connection:"); if (mAvailablePrimaryConnection != null) { mAvailablePrimaryConnection.dump(indentedPrinter); mAvailablePrimaryConnection.dump(indentedPrinter, verbose); } else { indentedPrinter.println("<none>"); } Loading @@ -852,7 +853,7 @@ public final class SQLiteConnectionPool implements Closeable { if (!mAvailableNonPrimaryConnections.isEmpty()) { final int count = mAvailableNonPrimaryConnections.size(); for (int i = 0; i < count; i++) { mAvailableNonPrimaryConnections.get(i).dump(indentedPrinter); mAvailableNonPrimaryConnections.get(i).dump(indentedPrinter, verbose); } } else { indentedPrinter.println("<none>"); Loading @@ -863,7 +864,7 @@ public final class SQLiteConnectionPool implements Closeable { for (Map.Entry<SQLiteConnection, Boolean> entry : mAcquiredConnections.entrySet()) { final SQLiteConnection connection = entry.getKey(); connection.dumpUnsafe(indentedPrinter); connection.dumpUnsafe(indentedPrinter, verbose); indentedPrinter.println(" Pending reconfiguration: " + entry.getValue()); } } else { Loading core/java/android/database/sqlite/SQLiteDatabase.java +4 −4 Original line number Diff line number Diff line Loading @@ -1665,17 +1665,17 @@ public class SQLiteDatabase extends SQLiteClosable { * Dump detailed information about all open databases in the current process. * Used by bug report. */ static void dumpAll(Printer printer) { static void dumpAll(Printer printer, boolean verbose) { for (SQLiteDatabase db : getActiveDatabases()) { db.dump(printer); db.dump(printer, verbose); } } private void dump(Printer printer) { private void dump(Printer printer, boolean verbose) { synchronized (mLock) { if (mConnectionPoolLocked != null) { printer.println(""); mConnectionPoolLocked.dump(printer); mConnectionPoolLocked.dump(printer, verbose); } } } Loading core/java/android/database/sqlite/SQLiteDebug.java +9 −1 Original line number Diff line number Diff line Loading @@ -190,9 +190,17 @@ public final class SQLiteDebug { /** * Dumps detailed information about all databases used by the process. * @param printer The printer for dumping database state. * @param args Command-line arguments supplied to dumpsys dbinfo */ public static void dump(Printer printer, String[] args) { SQLiteDatabase.dumpAll(printer); boolean verbose = false; for (String arg : args) { if (arg.equals("-v")) { verbose = true; } } SQLiteDatabase.dumpAll(printer, verbose); } /** Loading core/java/android/database/sqlite/SQLiteSession.java +38 −24 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/database/sqlite/SQLiteConnection.java +130 −70 Original line number Diff line number Diff line Loading @@ -74,6 +74,12 @@ import java.util.regex.Pattern; * queues. * </p> * * <h2>Reentrance</h2> * <p> * This class must tolerate reentrant execution of SQLite operations because * triggers may call custom SQLite functions that perform additional queries. * </p> * * @hide */ public final class SQLiteConnection { Loading Loading @@ -205,13 +211,13 @@ public final class SQLiteConnection { } if (mConnectionPtr != 0) { mRecentOperations.beginOperation("close", null, null); final int cookie = mRecentOperations.beginOperation("close", null, null); try { mPreparedStatementCache.evictAll(); nativeClose(mConnectionPtr); mConnectionPtr = 0; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } } Loading Loading @@ -304,9 +310,9 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("prepare", sql, null); final int cookie = mRecentOperations.beginOperation("prepare", sql, null); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { if (outStatementInfo != null) { outStatementInfo.numParameters = statement.mNumParameters; Loading @@ -328,10 +334,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading @@ -349,9 +355,9 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("execute", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("execute", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -361,10 +367,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading @@ -384,9 +390,9 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("executeForLong", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("executeForLong", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -396,10 +402,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading @@ -419,9 +425,9 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("executeForString", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("executeForString", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -431,10 +437,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading @@ -456,9 +462,10 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("executeForBlobFileDescriptor", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("executeForBlobFileDescriptor", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -470,10 +477,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading @@ -493,9 +500,10 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("executeForChangedRowCount", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("executeForChangedRowCount", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -506,10 +514,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading @@ -529,9 +537,10 @@ public final class SQLiteConnection { throw new IllegalArgumentException("sql must not be null."); } mRecentOperations.beginOperation("executeForLastInsertedRowId", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("executeForLastInsertedRowId", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -542,10 +551,10 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { mRecentOperations.endOperation(); mRecentOperations.endOperation(cookie); } } Loading Loading @@ -581,9 +590,10 @@ public final class SQLiteConnection { int actualPos = -1; int countedRows = -1; int filledRows = -1; mRecentOperations.beginOperation("executeForCursorWindow", sql, bindArgs); final int cookie = mRecentOperations.beginOperation("executeForCursorWindow", sql, bindArgs); try { PreparedStatement statement = acquirePreparedStatement(sql); final PreparedStatement statement = acquirePreparedStatement(sql); try { throwIfStatementForbidden(statement); bindArguments(statement, bindArgs); Loading @@ -600,11 +610,11 @@ public final class SQLiteConnection { releasePreparedStatement(statement); } } catch (RuntimeException ex) { mRecentOperations.failOperation(ex); mRecentOperations.failOperation(cookie, ex); throw ex; } finally { if (mRecentOperations.endOperationDeferLog()) { mRecentOperations.logOperation("window='" + window if (mRecentOperations.endOperationDeferLog(cookie)) { mRecentOperations.logOperation(cookie, "window='" + window + "', startPos=" + startPos + ", actualPos=" + actualPos + ", filledRows=" + filledRows Loading @@ -615,9 +625,16 @@ public final class SQLiteConnection { private PreparedStatement acquirePreparedStatement(String sql) { PreparedStatement statement = mPreparedStatementCache.get(sql); boolean skipCache = false; if (statement != null) { if (!statement.mInUse) { return statement; } // The statement is already in the cache but is in use (this statement appears // to be not only re-entrant but recursive!). So prepare a new copy of the // statement but do not cache it. skipCache = true; } final int statementPtr = nativePrepareStatement(mConnectionPtr, sql); try { Loading @@ -625,7 +642,7 @@ public final class SQLiteConnection { final int type = DatabaseUtils.getSqlStatementType(sql); final boolean readOnly = nativeIsReadOnly(mConnectionPtr, statementPtr); statement = obtainPreparedStatement(sql, statementPtr, numParameters, type, readOnly); if (isCacheable(type)) { if (!skipCache && isCacheable(type)) { mPreparedStatementCache.put(sql, statement); statement.mInCache = true; } Loading @@ -637,18 +654,20 @@ public final class SQLiteConnection { } throw ex; } statement.mInUse = true; return statement; } private void releasePreparedStatement(PreparedStatement statement) { statement.mInUse = false; if (statement.mInCache) { try { nativeResetStatementAndClearBindings(mConnectionPtr, statement.mStatementPtr); } catch (SQLiteException ex) { // The statement could not be reset due to an error. // The entryRemoved() callback for the cache will recursively call // releasePreparedStatement() again, but this time mInCache will be false // so the statement will be finalized and recycled. // The statement could not be reset due to an error. Remove it from the cache. // When remove() is called, the cache will invoke its entryRemoved() callback, // which will in turn call finalizePreparedStatement() to finalize and // recycle the statement. if (SQLiteDebug.DEBUG_SQL_CACHE) { Log.v(TAG, "Could not reset prepared statement due to an exception. " + "Removing it from the cache. SQL: " Loading @@ -657,10 +676,14 @@ public final class SQLiteConnection { mPreparedStatementCache.remove(statement.mSql); } } else { finalizePreparedStatement(statement); } } private void finalizePreparedStatement(PreparedStatement statement) { nativeFinalizeStatement(mConnectionPtr, statement.mStatementPtr); recyclePreparedStatement(statement); } } private void bindArguments(PreparedStatement statement, Object[] bindArgs) { final int count = bindArgs != null ? bindArgs.length : 0; Loading Loading @@ -735,9 +758,10 @@ public final class SQLiteConnection { * Dumps debugging information about this connection. * * @param printer The printer to receive the dump, not null. * @param verbose True to dump more verbose information. */ public void dump(Printer printer) { dumpUnsafe(printer); public void dump(Printer printer, boolean verbose) { dumpUnsafe(printer, verbose); } /** Loading @@ -752,16 +776,22 @@ public final class SQLiteConnection { * it should not crash. This is ok as it is only used for diagnostic purposes. * * @param printer The printer to receive the dump, not null. * @param verbose True to dump more verbose information. */ void dumpUnsafe(Printer printer) { void dumpUnsafe(Printer printer, boolean verbose) { printer.println("Connection #" + mConnectionId + ":"); printer.println(" isPrimaryConnection: " + mIsPrimaryConnection); if (verbose) { printer.println(" connectionPtr: 0x" + Integer.toHexString(mConnectionPtr)); } printer.println(" isPrimaryConnection: " + mIsPrimaryConnection); printer.println(" onlyAllowReadOnlyOperations: " + mOnlyAllowReadOnlyOperations); mRecentOperations.dump(printer); if (verbose) { mPreparedStatementCache.dump(printer); } } /** * Describes the currently executing operation, in the case where the Loading Loading @@ -917,6 +947,12 @@ public final class SQLiteConnection { // True if the statement is in the cache. public boolean mInCache; // True if the statement is in use (currently executing). // We need this flag because due to the use of custom functions in triggers, it's // possible for SQLite calls to be re-entrant. Consequently we need to prevent // in use statements from being finalized until they are no longer in use. public boolean mInUse; } private final class PreparedStatementCache Loading @@ -929,7 +965,9 @@ public final class SQLiteConnection { protected void entryRemoved(boolean evicted, String key, PreparedStatement oldValue, PreparedStatement newValue) { oldValue.mInCache = false; releasePreparedStatement(oldValue); if (!oldValue.mInUse) { finalizePreparedStatement(oldValue); } } public void dump(Printer printer) { Loading Loading @@ -958,11 +996,14 @@ public final class SQLiteConnection { private static final class OperationLog { private static final int MAX_RECENT_OPERATIONS = 10; private static final int COOKIE_GENERATION_SHIFT = 8; private static final int COOKIE_INDEX_MASK = 0xff; private final Operation[] mOperations = new Operation[MAX_RECENT_OPERATIONS]; private int mIndex; private int mGeneration; public void beginOperation(String kind, String sql, Object[] bindArgs) { public int beginOperation(String kind, String sql, Object[] bindArgs) { synchronized (mOperations) { final int index = (mIndex + 1) % MAX_RECENT_OPERATIONS; Operation operation = mOperations[index]; Loading Loading @@ -995,47 +1036,54 @@ public final class SQLiteConnection { } } } operation.mCookie = newOperationCookieLocked(index); mIndex = index; return operation.mCookie; } } public void failOperation(Exception ex) { public void failOperation(int cookie, Exception ex) { synchronized (mOperations) { final Operation operation = mOperations[mIndex]; final Operation operation = getOperationLocked(cookie); if (operation != null) { operation.mException = ex; } } } public boolean endOperationDeferLog() { public void endOperation(int cookie) { synchronized (mOperations) { return endOperationDeferLogLocked(); if (endOperationDeferLogLocked(cookie)) { logOperationLocked(cookie, null); } } private boolean endOperationDeferLogLocked() { final Operation operation = mOperations[mIndex]; operation.mEndTime = System.currentTimeMillis(); operation.mFinished = true; return SQLiteDebug.DEBUG_LOG_SLOW_QUERIES && SQLiteDebug.shouldLogSlowQuery( operation.mEndTime - operation.mStartTime); } public void endOperation() { public boolean endOperationDeferLog(int cookie) { synchronized (mOperations) { if (endOperationDeferLogLocked()) { logOperationLocked(null); } return endOperationDeferLogLocked(cookie); } } public void logOperation(String detail) { public void logOperation(int cookie, String detail) { synchronized (mOperations) { logOperationLocked(detail); logOperationLocked(cookie, detail); } } private void logOperationLocked(String detail) { final Operation operation = mOperations[mIndex]; private boolean endOperationDeferLogLocked(int cookie) { final Operation operation = getOperationLocked(cookie); if (operation != null) { operation.mEndTime = System.currentTimeMillis(); operation.mFinished = true; return SQLiteDebug.DEBUG_LOG_SLOW_QUERIES && SQLiteDebug.shouldLogSlowQuery( operation.mEndTime - operation.mStartTime); } return false; } private void logOperationLocked(int cookie, String detail) { final Operation operation = getOperationLocked(cookie); StringBuilder msg = new StringBuilder(); operation.describe(msg); if (detail != null) { Loading @@ -1044,6 +1092,17 @@ public final class SQLiteConnection { Log.d(TAG, msg.toString()); } private int newOperationCookieLocked(int index) { final int generation = mGeneration++; return generation << COOKIE_GENERATION_SHIFT | index; } private Operation getOperationLocked(int cookie) { final int index = cookie & COOKIE_INDEX_MASK; final Operation operation = mOperations[index]; return operation.mCookie == cookie ? operation : null; } public String describeCurrentOperation() { synchronized (mOperations) { final Operation operation = mOperations[mIndex]; Loading Loading @@ -1097,6 +1156,7 @@ public final class SQLiteConnection { public ArrayList<Object> mBindArgs; public boolean mFinished; public Exception mException; public int mCookie; public void describe(StringBuilder msg) { msg.append(mKind); Loading
core/java/android/database/sqlite/SQLiteConnectionPool.java +5 −4 Original line number Diff line number Diff line Loading @@ -833,8 +833,9 @@ public final class SQLiteConnectionPool implements Closeable { * Dumps debugging information about this connection pool. * * @param printer The printer to receive the dump, not null. * @param verbose True to dump more verbose information. */ public void dump(Printer printer) { public void dump(Printer printer, boolean verbose) { Printer indentedPrinter = PrefixPrinter.create(printer, " "); synchronized (mLock) { printer.println("Connection pool for " + mConfiguration.path + ":"); Loading @@ -843,7 +844,7 @@ public final class SQLiteConnectionPool implements Closeable { printer.println(" Available primary connection:"); if (mAvailablePrimaryConnection != null) { mAvailablePrimaryConnection.dump(indentedPrinter); mAvailablePrimaryConnection.dump(indentedPrinter, verbose); } else { indentedPrinter.println("<none>"); } Loading @@ -852,7 +853,7 @@ public final class SQLiteConnectionPool implements Closeable { if (!mAvailableNonPrimaryConnections.isEmpty()) { final int count = mAvailableNonPrimaryConnections.size(); for (int i = 0; i < count; i++) { mAvailableNonPrimaryConnections.get(i).dump(indentedPrinter); mAvailableNonPrimaryConnections.get(i).dump(indentedPrinter, verbose); } } else { indentedPrinter.println("<none>"); Loading @@ -863,7 +864,7 @@ public final class SQLiteConnectionPool implements Closeable { for (Map.Entry<SQLiteConnection, Boolean> entry : mAcquiredConnections.entrySet()) { final SQLiteConnection connection = entry.getKey(); connection.dumpUnsafe(indentedPrinter); connection.dumpUnsafe(indentedPrinter, verbose); indentedPrinter.println(" Pending reconfiguration: " + entry.getValue()); } } else { Loading
core/java/android/database/sqlite/SQLiteDatabase.java +4 −4 Original line number Diff line number Diff line Loading @@ -1665,17 +1665,17 @@ public class SQLiteDatabase extends SQLiteClosable { * Dump detailed information about all open databases in the current process. * Used by bug report. */ static void dumpAll(Printer printer) { static void dumpAll(Printer printer, boolean verbose) { for (SQLiteDatabase db : getActiveDatabases()) { db.dump(printer); db.dump(printer, verbose); } } private void dump(Printer printer) { private void dump(Printer printer, boolean verbose) { synchronized (mLock) { if (mConnectionPoolLocked != null) { printer.println(""); mConnectionPoolLocked.dump(printer); mConnectionPoolLocked.dump(printer, verbose); } } } Loading
core/java/android/database/sqlite/SQLiteDebug.java +9 −1 Original line number Diff line number Diff line Loading @@ -190,9 +190,17 @@ public final class SQLiteDebug { /** * Dumps detailed information about all databases used by the process. * @param printer The printer for dumping database state. * @param args Command-line arguments supplied to dumpsys dbinfo */ public static void dump(Printer printer, String[] args) { SQLiteDatabase.dumpAll(printer); boolean verbose = false; for (String arg : args) { if (arg.equals("-v")) { verbose = true; } } SQLiteDatabase.dumpAll(printer, verbose); } /** Loading
core/java/android/database/sqlite/SQLiteSession.java +38 −24 File changed.Preview size limit exceeded, changes collapsed. Show changes