Loading api/current.xml +15 −1 Original line number Diff line number Diff line Loading @@ -61109,7 +61109,7 @@ type="android.database.sqlite.SQLiteCursor" static="false" final="false" deprecated="not deprecated" deprecated="deprecated" visibility="public" > <parameter name="db" type="android.database.sqlite.SQLiteDatabase"> Loading @@ -61121,6 +61121,20 @@ <parameter name="query" type="android.database.sqlite.SQLiteQuery"> </parameter> </constructor> <constructor name="SQLiteCursor" type="android.database.sqlite.SQLiteCursor" static="false" final="false" deprecated="not deprecated" visibility="public" > <parameter name="driver" type="android.database.sqlite.SQLiteCursorDriver"> </parameter> <parameter name="editTable" type="java.lang.String"> </parameter> <parameter name="query" type="android.database.sqlite.SQLiteQuery"> </parameter> </constructor> <method name="getColumnNames" return="java.lang.String[]" abstract="false" core/java/android/database/sqlite/SQLiteCursor.java +62 −28 Original line number Diff line number Diff line Loading @@ -44,19 +44,16 @@ public class SQLiteCursor extends AbstractWindowedCursor { static final int NO_COUNT = -1; /** The name of the table to edit */ private String mEditTable; private final String mEditTable; /** The names of the columns in the rows */ private String[] mColumns; private final String[] mColumns; /** The query object for the cursor */ private SQLiteQuery mQuery; /** The database the cursor was created from */ private SQLiteDatabase mDatabase; /** The compiled query this cursor came from */ private SQLiteCursorDriver mDriver; private final SQLiteCursorDriver mDriver; /** The number of rows in the cursor */ private int mCount = NO_COUNT; Loading @@ -65,7 +62,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { private Map<String, Integer> mColumnNameMap; /** Used to find out where a cursor was allocated in case it never got released. */ private Throwable mStackTrace; private final Throwable mStackTrace; /** * mMaxRead is the max items that each cursor window reads Loading Loading @@ -140,7 +137,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { break; } try { int count = mQuery.fillWindow(cw, mMaxRead, mCount); int count = getQuery().fillWindow(cw, mMaxRead, mCount); // return -1 means not finished if (count != 0) { if (count == NO_COUNT){ Loading Loading @@ -205,24 +202,46 @@ public class SQLiteCursor extends AbstractWindowedCursor { * has package scope. * * @param db a reference to a Database object that is already constructed * and opened * and opened. This param is not used any longer * @param editTable the name of the table used for this query * @param query the rest of the query terms * cursor is finalized * @deprecated use {@link #SQLiteCursor(SQLiteCursorDriver, String, SQLiteQuery)} instead */ @Deprecated public SQLiteCursor(SQLiteDatabase db, SQLiteCursorDriver driver, String editTable, SQLiteQuery query) { this(driver, editTable, query); } /** * Execute a query and provide access to its result set through a Cursor * interface. For a query such as: {@code SELECT name, birth, phone FROM * myTable WHERE ... LIMIT 1,20 ORDER BY...} the column names (name, birth, * phone) would be in the projection argument and everything from * {@code FROM} onward would be in the params argument. This constructor * has package scope. * * @param editTable the name of the table used for this query * @param query the {@link SQLiteQuery} object associated with this cursor object. */ public SQLiteCursor(SQLiteCursorDriver driver, String editTable, SQLiteQuery query) { // The AbstractCursor constructor needs to do some setup. super(); if (query == null) { throw new IllegalArgumentException("query object cannot be null"); } if (query.mDatabase == null) { throw new IllegalArgumentException("query.mDatabase cannot be null"); } mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace(); mDatabase = db; mDriver = driver; mEditTable = editTable; mColumnNameMap = null; mQuery = query; try { db.lock(); query.mDatabase.lock(); // Setup the list of columns int columnCount = mQuery.columnCountLocked(); Loading @@ -243,7 +262,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { } } } finally { db.unlock(); query.mDatabase.unlock(); } } Loading @@ -251,7 +270,9 @@ public class SQLiteCursor extends AbstractWindowedCursor { * @return the SQLiteDatabase that this cursor is associated with. */ public SQLiteDatabase getDatabase() { return mDatabase; synchronized (this) { return mQuery.mDatabase; } } @Override Loading Loading @@ -287,7 +308,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { } } mWindow.setStartPosition(startPos); mCount = mQuery.fillWindow(mWindow, mInitialRead, 0); mCount = getQuery().fillWindow(mWindow, mInitialRead, 0); // return -1 means not finished if (mCount == NO_COUNT){ mCount = startPos + mInitialRead; Loading @@ -296,6 +317,10 @@ public class SQLiteCursor extends AbstractWindowedCursor { } } private synchronized SQLiteQuery getQuery() { return mQuery; } @Override public int getColumnIndex(String columnName) { // Create mColumnNameMap on demand Loading Loading @@ -350,10 +375,12 @@ public class SQLiteCursor extends AbstractWindowedCursor { @Override public void close() { super.close(); synchronized (this) { deactivateCommon(); mQuery.close(); mDriver.cursorClosed(); } } /** * Show a warning against the use of requery() if called on the main thread. Loading @@ -361,7 +388,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { */ private void warnIfUiThread() { if (Looper.getMainLooper() == Looper.myLooper()) { String databasePath = mDatabase.getPath(); String databasePath = getQuery().mDatabase.getPath(); // We show the warning once per database in order not to spam logcat. if (!sAlreadyWarned.containsKey(databasePath)) { sAlreadyWarned.put(databasePath, true); Loading @@ -383,16 +410,25 @@ public class SQLiteCursor extends AbstractWindowedCursor { if (Config.LOGV) { timeStart = System.currentTimeMillis(); } /* * Synchronize on the database lock to ensure that mCount matches the * results of mQuery.requery(). */ mDatabase.lock(); try { synchronized (this) { if (mWindow != null) { mWindow.clear(); } mPos = -1; SQLiteDatabase db = mQuery.mDatabase.getDatabaseHandle(mQuery.mSql); if (!db.equals(mQuery.mDatabase)) { // since we need to use a different database connection handle, // re-compile the query db.lock(); try { // close the old mQuery object and open a new one mQuery.close(); mQuery = new SQLiteQuery(db, mQuery); } finally { db.unlock(); } } // This one will recreate the temp table, and get its count mDriver.cursorRequeried(this); mCount = NO_COUNT; Loading @@ -403,8 +439,6 @@ public class SQLiteCursor extends AbstractWindowedCursor { } finally { queryThreadUnlock(); } } finally { mDatabase.unlock(); } if (Config.LOGV) { Loading Loading @@ -452,14 +486,14 @@ public class SQLiteCursor extends AbstractWindowedCursor { if (mWindow != null) { int len = mQuery.mSql.length(); Log.e(TAG, "Finalizing a Cursor that has not been deactivated or closed. " + "database = " + mDatabase.getPath() + ", table = " + mEditTable + "database = " + mQuery.mDatabase.getPath() + ", table = " + mEditTable + ", query = " + mQuery.mSql.substring(0, (len > 100) ? 100 : len), mStackTrace); close(); SQLiteDebug.notifyActiveCursorFinalized(); } else { if (Config.LOGV) { Log.v(TAG, "Finalizing cursor on database = " + mDatabase.getPath() + Log.v(TAG, "Finalizing cursor on database = " + mQuery.mDatabase.getPath() + ", table = " + mEditTable + ", query = " + mQuery.mSql); } } Loading core/java/android/database/sqlite/SQLiteDatabase.java +50 −16 Original line number Diff line number Diff line Loading @@ -341,6 +341,12 @@ public class SQLiteDatabase extends SQLiteClosable { */ /* package */ final short mConnectionNum; /** on pooled database connections, this member points to the parent ( = main) * database connection handle. * package visibility only for testing purposes */ /* package */ SQLiteDatabase mParentConnObj = null; private static final String MEMORY_DB_PATH = ":memory:"; synchronized void addSQLiteClosable(SQLiteClosable closable) { Loading Loading @@ -2425,6 +2431,27 @@ public class SQLiteDatabase extends SQLiteClosable { } } /* package */ SQLiteDatabase getDatabaseHandle(String sql) { if (isPooledConnection()) { // this is a pooled database connection if (isOpen()) { // TODO: use another connection from the pool // if this connection is currently in use by some other thread // AND if there are free connections in the pool return this; } else { // the pooled connection is not open! could have been closed either due // to corruption on this or some other connection to the database // OR, maybe the connection pool is disabled after this connection has been // allocated to me. try to get some other pooled or main database connection return getParentDbConnObj().getDbConnection(sql); } } else { // this is NOT a pooled connection. can we get one? return getDbConnection(sql); } } /** * Sets the database connection handle pool size to the given value. * Database connection handle pool is enabled when the app calls Loading @@ -2450,7 +2477,13 @@ public class SQLiteDatabase extends SQLiteClosable { } /* package */ SQLiteDatabase createPoolConnection(short connectionNum) { return openDatabase(mPath, mFactory, mFlags, mErrorHandler, connectionNum); SQLiteDatabase db = openDatabase(mPath, mFactory, mFlags, mErrorHandler, connectionNum); db.mParentConnObj = this; return db; } private synchronized SQLiteDatabase getParentDbConnObj() { return mParentConnObj; } private boolean isPooledConnection() { Loading @@ -2459,29 +2492,30 @@ public class SQLiteDatabase extends SQLiteClosable { /* package */ SQLiteDatabase getDbConnection(String sql) { verifyDbIsOpen(); // this method should always be called with main database connection handle // NEVER with pooled database connection handle if (isPooledConnection()) { throw new IllegalStateException("incorrect database connection handle"); } if (Log.isLoggable(TAG, Log.DEBUG)) { // this method shoudl never be called with anything other than SELECT if (sql.substring(0, 6).equalsIgnoreCase("SELECT")) { throw new IllegalStateException("unexpected SQL statement: " + sql); } } // use the current connection handle if // 1. this is a pooled connection handle // 2. OR, if this thread is in a transaction // 3. OR, if there is NO connection handle pool setup SQLiteDatabase db = null; if (isPooledConnection() || (inTransaction() && mLock.isHeldByCurrentThread()) || (this.mConnectionPool == null)) { db = this; // 1. if this thread is in a transaction // 2. OR, if there is NO connection handle pool setup if ((inTransaction() && mLock.isHeldByCurrentThread()) || mConnectionPool == null) { return this; } else { // get a connection handle from the pool if (Log.isLoggable(TAG, Log.DEBUG)) { assert mConnectionPool != null; } db = mConnectionPool.get(sql); } if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "getDbConnection threadid = " + Thread.currentThread().getId() + ", request on # " + mConnectionNum + ", assigned # " + db.mConnectionNum + ", " + getPath()); return mConnectionPool.get(sql); } return db; } private void releaseDbConnection(SQLiteDatabase db) { Loading core/java/android/database/sqlite/SQLiteDirectCursorDriver.java +1 −1 Original line number Diff line number Diff line Loading @@ -53,7 +53,7 @@ public class SQLiteDirectCursorDriver implements SQLiteCursorDriver { // Create the cursor if (factory == null) { mCursor = new SQLiteCursor(mDatabase, this, mEditTable, query); mCursor = new SQLiteCursor(this, mEditTable, query); } else { mCursor = factory.newCursor(mDatabase, this, mEditTable, query); } Loading core/java/android/database/sqlite/SQLiteQuery.java +12 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,18 @@ public class SQLiteQuery extends SQLiteProgram { mBindArgs = bindArgs; } /** * Constructor used to create new instance to replace a given instance of this class. * This constructor is used when the current Query object is now associated with a different * {@link SQLiteDatabase} object. * * @param db The database that this query object is associated with * @param query the instance of {@link SQLiteQuery} to be replaced */ /* package */ SQLiteQuery(SQLiteDatabase db, SQLiteQuery query) { this(db, query.mSql, 0, query.mBindArgs); } /** * Reads rows into a buffer. This method acquires the database lock. * Loading Loading
api/current.xml +15 −1 Original line number Diff line number Diff line Loading @@ -61109,7 +61109,7 @@ type="android.database.sqlite.SQLiteCursor" static="false" final="false" deprecated="not deprecated" deprecated="deprecated" visibility="public" > <parameter name="db" type="android.database.sqlite.SQLiteDatabase"> Loading @@ -61121,6 +61121,20 @@ <parameter name="query" type="android.database.sqlite.SQLiteQuery"> </parameter> </constructor> <constructor name="SQLiteCursor" type="android.database.sqlite.SQLiteCursor" static="false" final="false" deprecated="not deprecated" visibility="public" > <parameter name="driver" type="android.database.sqlite.SQLiteCursorDriver"> </parameter> <parameter name="editTable" type="java.lang.String"> </parameter> <parameter name="query" type="android.database.sqlite.SQLiteQuery"> </parameter> </constructor> <method name="getColumnNames" return="java.lang.String[]" abstract="false"
core/java/android/database/sqlite/SQLiteCursor.java +62 −28 Original line number Diff line number Diff line Loading @@ -44,19 +44,16 @@ public class SQLiteCursor extends AbstractWindowedCursor { static final int NO_COUNT = -1; /** The name of the table to edit */ private String mEditTable; private final String mEditTable; /** The names of the columns in the rows */ private String[] mColumns; private final String[] mColumns; /** The query object for the cursor */ private SQLiteQuery mQuery; /** The database the cursor was created from */ private SQLiteDatabase mDatabase; /** The compiled query this cursor came from */ private SQLiteCursorDriver mDriver; private final SQLiteCursorDriver mDriver; /** The number of rows in the cursor */ private int mCount = NO_COUNT; Loading @@ -65,7 +62,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { private Map<String, Integer> mColumnNameMap; /** Used to find out where a cursor was allocated in case it never got released. */ private Throwable mStackTrace; private final Throwable mStackTrace; /** * mMaxRead is the max items that each cursor window reads Loading Loading @@ -140,7 +137,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { break; } try { int count = mQuery.fillWindow(cw, mMaxRead, mCount); int count = getQuery().fillWindow(cw, mMaxRead, mCount); // return -1 means not finished if (count != 0) { if (count == NO_COUNT){ Loading Loading @@ -205,24 +202,46 @@ public class SQLiteCursor extends AbstractWindowedCursor { * has package scope. * * @param db a reference to a Database object that is already constructed * and opened * and opened. This param is not used any longer * @param editTable the name of the table used for this query * @param query the rest of the query terms * cursor is finalized * @deprecated use {@link #SQLiteCursor(SQLiteCursorDriver, String, SQLiteQuery)} instead */ @Deprecated public SQLiteCursor(SQLiteDatabase db, SQLiteCursorDriver driver, String editTable, SQLiteQuery query) { this(driver, editTable, query); } /** * Execute a query and provide access to its result set through a Cursor * interface. For a query such as: {@code SELECT name, birth, phone FROM * myTable WHERE ... LIMIT 1,20 ORDER BY...} the column names (name, birth, * phone) would be in the projection argument and everything from * {@code FROM} onward would be in the params argument. This constructor * has package scope. * * @param editTable the name of the table used for this query * @param query the {@link SQLiteQuery} object associated with this cursor object. */ public SQLiteCursor(SQLiteCursorDriver driver, String editTable, SQLiteQuery query) { // The AbstractCursor constructor needs to do some setup. super(); if (query == null) { throw new IllegalArgumentException("query object cannot be null"); } if (query.mDatabase == null) { throw new IllegalArgumentException("query.mDatabase cannot be null"); } mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace(); mDatabase = db; mDriver = driver; mEditTable = editTable; mColumnNameMap = null; mQuery = query; try { db.lock(); query.mDatabase.lock(); // Setup the list of columns int columnCount = mQuery.columnCountLocked(); Loading @@ -243,7 +262,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { } } } finally { db.unlock(); query.mDatabase.unlock(); } } Loading @@ -251,7 +270,9 @@ public class SQLiteCursor extends AbstractWindowedCursor { * @return the SQLiteDatabase that this cursor is associated with. */ public SQLiteDatabase getDatabase() { return mDatabase; synchronized (this) { return mQuery.mDatabase; } } @Override Loading Loading @@ -287,7 +308,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { } } mWindow.setStartPosition(startPos); mCount = mQuery.fillWindow(mWindow, mInitialRead, 0); mCount = getQuery().fillWindow(mWindow, mInitialRead, 0); // return -1 means not finished if (mCount == NO_COUNT){ mCount = startPos + mInitialRead; Loading @@ -296,6 +317,10 @@ public class SQLiteCursor extends AbstractWindowedCursor { } } private synchronized SQLiteQuery getQuery() { return mQuery; } @Override public int getColumnIndex(String columnName) { // Create mColumnNameMap on demand Loading Loading @@ -350,10 +375,12 @@ public class SQLiteCursor extends AbstractWindowedCursor { @Override public void close() { super.close(); synchronized (this) { deactivateCommon(); mQuery.close(); mDriver.cursorClosed(); } } /** * Show a warning against the use of requery() if called on the main thread. Loading @@ -361,7 +388,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { */ private void warnIfUiThread() { if (Looper.getMainLooper() == Looper.myLooper()) { String databasePath = mDatabase.getPath(); String databasePath = getQuery().mDatabase.getPath(); // We show the warning once per database in order not to spam logcat. if (!sAlreadyWarned.containsKey(databasePath)) { sAlreadyWarned.put(databasePath, true); Loading @@ -383,16 +410,25 @@ public class SQLiteCursor extends AbstractWindowedCursor { if (Config.LOGV) { timeStart = System.currentTimeMillis(); } /* * Synchronize on the database lock to ensure that mCount matches the * results of mQuery.requery(). */ mDatabase.lock(); try { synchronized (this) { if (mWindow != null) { mWindow.clear(); } mPos = -1; SQLiteDatabase db = mQuery.mDatabase.getDatabaseHandle(mQuery.mSql); if (!db.equals(mQuery.mDatabase)) { // since we need to use a different database connection handle, // re-compile the query db.lock(); try { // close the old mQuery object and open a new one mQuery.close(); mQuery = new SQLiteQuery(db, mQuery); } finally { db.unlock(); } } // This one will recreate the temp table, and get its count mDriver.cursorRequeried(this); mCount = NO_COUNT; Loading @@ -403,8 +439,6 @@ public class SQLiteCursor extends AbstractWindowedCursor { } finally { queryThreadUnlock(); } } finally { mDatabase.unlock(); } if (Config.LOGV) { Loading Loading @@ -452,14 +486,14 @@ public class SQLiteCursor extends AbstractWindowedCursor { if (mWindow != null) { int len = mQuery.mSql.length(); Log.e(TAG, "Finalizing a Cursor that has not been deactivated or closed. " + "database = " + mDatabase.getPath() + ", table = " + mEditTable + "database = " + mQuery.mDatabase.getPath() + ", table = " + mEditTable + ", query = " + mQuery.mSql.substring(0, (len > 100) ? 100 : len), mStackTrace); close(); SQLiteDebug.notifyActiveCursorFinalized(); } else { if (Config.LOGV) { Log.v(TAG, "Finalizing cursor on database = " + mDatabase.getPath() + Log.v(TAG, "Finalizing cursor on database = " + mQuery.mDatabase.getPath() + ", table = " + mEditTable + ", query = " + mQuery.mSql); } } Loading
core/java/android/database/sqlite/SQLiteDatabase.java +50 −16 Original line number Diff line number Diff line Loading @@ -341,6 +341,12 @@ public class SQLiteDatabase extends SQLiteClosable { */ /* package */ final short mConnectionNum; /** on pooled database connections, this member points to the parent ( = main) * database connection handle. * package visibility only for testing purposes */ /* package */ SQLiteDatabase mParentConnObj = null; private static final String MEMORY_DB_PATH = ":memory:"; synchronized void addSQLiteClosable(SQLiteClosable closable) { Loading Loading @@ -2425,6 +2431,27 @@ public class SQLiteDatabase extends SQLiteClosable { } } /* package */ SQLiteDatabase getDatabaseHandle(String sql) { if (isPooledConnection()) { // this is a pooled database connection if (isOpen()) { // TODO: use another connection from the pool // if this connection is currently in use by some other thread // AND if there are free connections in the pool return this; } else { // the pooled connection is not open! could have been closed either due // to corruption on this or some other connection to the database // OR, maybe the connection pool is disabled after this connection has been // allocated to me. try to get some other pooled or main database connection return getParentDbConnObj().getDbConnection(sql); } } else { // this is NOT a pooled connection. can we get one? return getDbConnection(sql); } } /** * Sets the database connection handle pool size to the given value. * Database connection handle pool is enabled when the app calls Loading @@ -2450,7 +2477,13 @@ public class SQLiteDatabase extends SQLiteClosable { } /* package */ SQLiteDatabase createPoolConnection(short connectionNum) { return openDatabase(mPath, mFactory, mFlags, mErrorHandler, connectionNum); SQLiteDatabase db = openDatabase(mPath, mFactory, mFlags, mErrorHandler, connectionNum); db.mParentConnObj = this; return db; } private synchronized SQLiteDatabase getParentDbConnObj() { return mParentConnObj; } private boolean isPooledConnection() { Loading @@ -2459,29 +2492,30 @@ public class SQLiteDatabase extends SQLiteClosable { /* package */ SQLiteDatabase getDbConnection(String sql) { verifyDbIsOpen(); // this method should always be called with main database connection handle // NEVER with pooled database connection handle if (isPooledConnection()) { throw new IllegalStateException("incorrect database connection handle"); } if (Log.isLoggable(TAG, Log.DEBUG)) { // this method shoudl never be called with anything other than SELECT if (sql.substring(0, 6).equalsIgnoreCase("SELECT")) { throw new IllegalStateException("unexpected SQL statement: " + sql); } } // use the current connection handle if // 1. this is a pooled connection handle // 2. OR, if this thread is in a transaction // 3. OR, if there is NO connection handle pool setup SQLiteDatabase db = null; if (isPooledConnection() || (inTransaction() && mLock.isHeldByCurrentThread()) || (this.mConnectionPool == null)) { db = this; // 1. if this thread is in a transaction // 2. OR, if there is NO connection handle pool setup if ((inTransaction() && mLock.isHeldByCurrentThread()) || mConnectionPool == null) { return this; } else { // get a connection handle from the pool if (Log.isLoggable(TAG, Log.DEBUG)) { assert mConnectionPool != null; } db = mConnectionPool.get(sql); } if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "getDbConnection threadid = " + Thread.currentThread().getId() + ", request on # " + mConnectionNum + ", assigned # " + db.mConnectionNum + ", " + getPath()); return mConnectionPool.get(sql); } return db; } private void releaseDbConnection(SQLiteDatabase db) { Loading
core/java/android/database/sqlite/SQLiteDirectCursorDriver.java +1 −1 Original line number Diff line number Diff line Loading @@ -53,7 +53,7 @@ public class SQLiteDirectCursorDriver implements SQLiteCursorDriver { // Create the cursor if (factory == null) { mCursor = new SQLiteCursor(mDatabase, this, mEditTable, query); mCursor = new SQLiteCursor(this, mEditTable, query); } else { mCursor = factory.newCursor(mDatabase, this, mEditTable, query); } Loading
core/java/android/database/sqlite/SQLiteQuery.java +12 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,18 @@ public class SQLiteQuery extends SQLiteProgram { mBindArgs = bindArgs; } /** * Constructor used to create new instance to replace a given instance of this class. * This constructor is used when the current Query object is now associated with a different * {@link SQLiteDatabase} object. * * @param db The database that this query object is associated with * @param query the instance of {@link SQLiteQuery} to be replaced */ /* package */ SQLiteQuery(SQLiteDatabase db, SQLiteQuery query) { this(db, query.mSql, 0, query.mBindArgs); } /** * Reads rows into a buffer. This method acquires the database lock. * Loading