diff options
| author | Vasu Nori <vnori@google.com> | 2010-08-03 10:50:56 -0700 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-08-03 10:50:56 -0700 |
| commit | 6cd0cc46061e682b14447477147b2dd6969df155 (patch) | |
| tree | 106ee4d61c982c77a2f0835cde852e03f65a0ab5 /core | |
| parent | 5515b54d92945985b71a4ef9b8f507be152b5a50 (diff) | |
| parent | 0732f7912ccec9a1cc379b535ac0b56ae50972b3 (diff) | |
| download | frameworks_base-6cd0cc46061e682b14447477147b2dd6969df155.zip frameworks_base-6cd0cc46061e682b14447477147b2dd6969df155.tar.gz frameworks_base-6cd0cc46061e682b14447477147b2dd6969df155.tar.bz2 | |
Merge "random but useful stuff"
Diffstat (limited to 'core')
8 files changed, 233 insertions, 365 deletions
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java index 0687659..9ac45d8 100644 --- a/core/java/android/database/DatabaseUtils.java +++ b/core/java/android/database/DatabaseUtils.java @@ -678,14 +678,8 @@ public class DatabaseUtils { * first column of the first row. */ public static long longForQuery(SQLiteStatement prog, String[] selectionArgs) { - if (selectionArgs != null) { - int size = selectionArgs.length; - for (int i = 0; i < size; i++) { - bindObjectToProgram(prog, i + 1, selectionArgs[i]); - } - } - long value = prog.simpleQueryForLong(); - return value; + prog.bindAllArgsAsStrings(selectionArgs); + return prog.simpleQueryForLong(); } /** @@ -706,14 +700,8 @@ public class DatabaseUtils { * first column of the first row. */ public static String stringForQuery(SQLiteStatement prog, String[] selectionArgs) { - if (selectionArgs != null) { - int size = selectionArgs.length; - for (int i = 0; i < size; i++) { - bindObjectToProgram(prog, i + 1, selectionArgs[i]); - } - } - String value = prog.simpleQueryForString(); - return value; + prog.bindAllArgsAsStrings(selectionArgs); + return prog.simpleQueryForString(); } /** diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java index 9889a21..aa0a57d 100644 --- a/core/java/android/database/sqlite/SQLiteCompiledSql.java +++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java @@ -134,9 +134,6 @@ import android.util.Log; try { if (nStatement == 0) return; // finalizer should NEVER get called - if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) { - Log.v(TAG, "** warning ** Finalized DbObj (id#" + nStatement + ")"); - } int len = mSqlStmt.length(); Log.w(TAG, "Releasing statement in a finalizer. Please ensure " + "that you explicitly call close() on your cursor: " + diff --git a/core/java/android/database/sqlite/SQLiteCursorDriver.java b/core/java/android/database/sqlite/SQLiteCursorDriver.java index eda1b78..b3963f9 100644 --- a/core/java/android/database/sqlite/SQLiteCursorDriver.java +++ b/core/java/android/database/sqlite/SQLiteCursorDriver.java @@ -40,8 +40,6 @@ public interface SQLiteCursorDriver { /** * Called by a SQLiteCursor when it is requeryed. - * - * @return The new count value. */ void cursorRequeried(Cursor cursor); diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index a2fff73..dc3b469 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -39,14 +39,13 @@ import dalvik.system.BlockGuard; import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; import java.util.Random; -import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; @@ -351,6 +350,10 @@ public class SQLiteDatabase extends SQLiteClosable { private static final String MEMORY_DB_PATH = ":memory:"; + /** stores reference to all databases opened in the current process. */ + private static ArrayList<WeakReference<SQLiteDatabase>> mActiveDatabases = + new ArrayList<WeakReference<SQLiteDatabase>>(); + synchronized void addSQLiteClosable(SQLiteClosable closable) { // mPrograms is per instance of SQLiteDatabase and it doesn't actually touch the database // itself. so, there is no need to lock(). @@ -966,7 +969,9 @@ public class SQLiteDatabase extends SQLiteClosable { // END STOPSHIP // add this database to the list of databases opened in this process - ActiveDatabases.addActiveDatabase(sqliteDatabase); + synchronized(mActiveDatabases) { + mActiveDatabases.add(new WeakReference<SQLiteDatabase>(sqliteDatabase)); + } return sqliteDatabase; } @@ -1284,7 +1289,7 @@ public class SQLiteDatabase extends SQLiteClosable { */ public SQLiteStatement compileStatement(String sql) throws SQLException { verifyDbIsOpen(); - return new SQLiteStatement(this, sql); + return new SQLiteStatement(this, sql, null); } /** @@ -1634,68 +1639,41 @@ public class SQLiteDatabase extends SQLiteClosable { */ public long insertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, int conflictAlgorithm) { - verifyDbIsOpen(); - - // Measurements show most sql lengths <= 152 - StringBuilder sql = new StringBuilder(152); + StringBuilder sql = new StringBuilder(); sql.append("INSERT"); sql.append(CONFLICT_VALUES[conflictAlgorithm]); sql.append(" INTO "); sql.append(table); - // Measurements show most values lengths < 40 - StringBuilder values = new StringBuilder(40); - - Set<Map.Entry<String, Object>> entrySet = null; - if (initialValues != null && initialValues.size() > 0) { - entrySet = initialValues.valueSet(); - Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator(); - sql.append('('); - - boolean needSeparator = false; - while (entriesIter.hasNext()) { - if (needSeparator) { - sql.append(", "); - values.append(", "); - } - needSeparator = true; - Map.Entry<String, Object> entry = entriesIter.next(); - sql.append(entry.getKey()); - values.append('?'); + sql.append('('); + + Object[] bindArgs = null; + int size = (initialValues != null && initialValues.size() > 0) ? initialValues.size() : 0; + if (size > 0) { + bindArgs = new Object[size]; + int i = 0; + for (String colName : initialValues.keySet()) { + sql.append((i > 0) ? "," : ""); + sql.append(colName); + bindArgs[i++] = initialValues.get(colName); } - sql.append(')'); + sql.append(" VALUES ("); + for (i = 0; i < size; i++) { + sql.append((i > 0) ? ",?" : "?"); + } } else { - sql.append("(" + nullColumnHack + ") "); - values.append("NULL"); + sql.append(nullColumnHack + ") VALUES (NULL"); } + sql.append(')'); - sql.append(" VALUES("); - sql.append(values); - sql.append(");"); - - SQLiteStatement statement = null; + SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs); try { - statement = compileStatement(sql.toString()); - - // Bind the values - if (entrySet != null) { - int size = entrySet.size(); - Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator(); - for (int i = 0; i < size; i++) { - Map.Entry<String, Object> entry = entriesIter.next(); - DatabaseUtils.bindObjectToProgram(statement, i + 1, entry.getValue()); - } - } - - // Run the program and then cleanup return statement.executeInsert(); } catch (SQLiteDatabaseCorruptException e) { onCorruption(); throw e; } finally { - if (statement != null) { - statement.close(); - } + statement.close(); } } @@ -1710,26 +1688,15 @@ public class SQLiteDatabase extends SQLiteClosable { * whereClause. */ public int delete(String table, String whereClause, String[] whereArgs) { - verifyDbIsOpen(); - SQLiteStatement statement = null; + SQLiteStatement statement = new SQLiteStatement(this, "DELETE FROM " + table + + (!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs); try { - statement = compileStatement("DELETE FROM " + table - + (!TextUtils.isEmpty(whereClause) - ? " WHERE " + whereClause : "")); - if (whereArgs != null) { - int numArgs = whereArgs.length; - for (int i = 0; i < numArgs; i++) { - DatabaseUtils.bindObjectToProgram(statement, i + 1, whereArgs[i]); - } - } return statement.executeUpdateDelete(); } catch (SQLiteDatabaseCorruptException e) { onCorruption(); throw e; } finally { - if (statement != null) { - statement.close(); - } + statement.close(); } } @@ -1760,7 +1727,8 @@ public class SQLiteDatabase extends SQLiteClosable { */ public int updateWithOnConflict(String table, ContentValues values, String whereClause, String[] whereArgs, int conflictAlgorithm) { - if (values == null || values.size() == 0) { + int setValuesSize = values.size(); + if (values == null || setValuesSize == 0) { throw new IllegalArgumentException("Empty values"); } @@ -1770,58 +1738,34 @@ public class SQLiteDatabase extends SQLiteClosable { sql.append(table); sql.append(" SET "); - Set<Map.Entry<String, Object>> entrySet = values.valueSet(); - Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator(); - - while (entriesIter.hasNext()) { - Map.Entry<String, Object> entry = entriesIter.next(); - sql.append(entry.getKey()); + // move all bind args to one array + int bindArgsSize = (whereArgs == null) ? setValuesSize : (setValuesSize + whereArgs.length); + Object[] bindArgs = new Object[bindArgsSize]; + int i = 0; + for (String colName : values.keySet()) { + sql.append((i > 0) ? "," : ""); + sql.append(colName); + bindArgs[i++] = values.get(colName); sql.append("=?"); - if (entriesIter.hasNext()) { - sql.append(", "); + } + if (whereArgs != null) { + for (i = setValuesSize; i < bindArgsSize; i++) { + bindArgs[i] = whereArgs[i - setValuesSize]; } } - if (!TextUtils.isEmpty(whereClause)) { sql.append(" WHERE "); sql.append(whereClause); } - verifyDbIsOpen(); - SQLiteStatement statement = null; + SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs); try { - statement = compileStatement(sql.toString()); - - // Bind the values - int size = entrySet.size(); - entriesIter = entrySet.iterator(); - int bindArg = 1; - for (int i = 0; i < size; i++) { - Map.Entry<String, Object> entry = entriesIter.next(); - DatabaseUtils.bindObjectToProgram(statement, bindArg, entry.getValue()); - bindArg++; - } - - if (whereArgs != null) { - size = whereArgs.length; - for (int i = 0; i < size; i++) { - statement.bindString(bindArg, whereArgs[i]); - bindArg++; - } - } - - // Run the program and then cleanup return statement.executeUpdateDelete(); } catch (SQLiteDatabaseCorruptException e) { onCorruption(); throw e; - } catch (SQLException e) { - Log.e(TAG, "Error updating " + values + " using " + sql); - throw e; } finally { - if (statement != null) { - statement.close(); - } + statement.close(); } } @@ -1913,25 +1857,15 @@ public class SQLiteDatabase extends SQLiteClosable { } private void executeSql(String sql, Object[] bindArgs) throws SQLException { - verifyDbIsOpen(); long timeStart = SystemClock.uptimeMillis(); - SQLiteStatement statement = null; + SQLiteStatement statement = new SQLiteStatement(this, sql, bindArgs); try { - statement = compileStatement(sql); - if (bindArgs != null) { - int numArgs = bindArgs.length; - for (int i = 0; i < numArgs; i++) { - DatabaseUtils.bindObjectToProgram(statement, i + 1, bindArgs[i]); - } - } - statement.execute(); + statement.executeUpdateDelete(); } catch (SQLiteDatabaseCorruptException e) { onCorruption(); throw e; } finally { - if (statement != null) { - statement.close(); - } + statement.close(); } logTimeStat(sql, timeStart); } @@ -2450,82 +2384,78 @@ public class SQLiteDatabase extends SQLiteClosable { mConnectionPool.release(db); } - static class ActiveDatabases { - private static final ActiveDatabases activeDatabases = new ActiveDatabases(); - private HashSet<WeakReference<SQLiteDatabase>> mActiveDatabases = - new HashSet<WeakReference<SQLiteDatabase>>(); - private ActiveDatabases() {} // disable instantiation of this class - static ActiveDatabases getInstance() { - return activeDatabases; - } - private static void addActiveDatabase(SQLiteDatabase sqliteDatabase) { - activeDatabases.mActiveDatabases.add(new WeakReference<SQLiteDatabase>(sqliteDatabase)); - } - } - /** * this method is used to collect data about ALL open databases in the current process. - * bugreport is a user of this data. + * bugreport is a user of this data. */ /* package */ static ArrayList<DbStats> getDbStats() { ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>(); - for (WeakReference<SQLiteDatabase> w : ActiveDatabases.getInstance().mActiveDatabases) { + // make a local copy of mActiveDatabases - so that this method is not competing + // for synchronization lock on mActiveDatabases + ArrayList<WeakReference<SQLiteDatabase>> tempList = + new ArrayList<WeakReference<SQLiteDatabase>>(); + synchronized(mActiveDatabases) { + Collections.copy(tempList, mActiveDatabases); + } + for (WeakReference<SQLiteDatabase> w : tempList) { SQLiteDatabase db = w.get(); if (db == null || !db.isOpen()) { continue; } - try { - // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db - int lookasideUsed = db.native_getDbLookaside(); - - // get the lastnode of the dbname - String path = db.getPath(); - int indx = path.lastIndexOf("/"); - String lastnode = path.substring((indx != -1) ? ++indx : 0); - - // get list of attached dbs and for each db, get its size and pagesize - ArrayList<Pair<String, String>> attachedDbs = db.getAttachedDbs(); - if (attachedDbs == null) { - continue; - } - for (int i = 0; i < attachedDbs.size(); i++) { - Pair<String, String> p = attachedDbs.get(i); - long pageCount = DatabaseUtils.longForQuery(db, "PRAGMA " + p.first - + ".page_count;", null); - - // first entry in the attached db list is always the main database - // don't worry about prefixing the dbname with "main" - String dbName; - if (i == 0) { - dbName = lastnode; - } else { - // lookaside is only relevant for the main db - lookasideUsed = 0; - dbName = " (attached) " + p.first; - // if the attached db has a path, attach the lastnode from the path to above - if (p.second.trim().length() > 0) { - int idx = p.second.lastIndexOf("/"); - dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0); - } + synchronized (db) { + try { + // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db + int lookasideUsed = db.native_getDbLookaside(); + + // get the lastnode of the dbname + String path = db.getPath(); + int indx = path.lastIndexOf("/"); + String lastnode = path.substring((indx != -1) ? ++indx : 0); + + // get list of attached dbs and for each db, get its size and pagesize + ArrayList<Pair<String, String>> attachedDbs = db.getAttachedDbs(); + if (attachedDbs == null) { + continue; } - if (pageCount > 0) { - dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(), - lookasideUsed, db.mNumCacheHits, db.mNumCacheMisses, - db.mCompiledQueries.size())); + for (int i = 0; i < attachedDbs.size(); i++) { + Pair<String, String> p = attachedDbs.get(i); + long pageCount = DatabaseUtils.longForQuery(db, "PRAGMA " + p.first + + ".page_count;", null); + + // first entry in the attached db list is always the main database + // don't worry about prefixing the dbname with "main" + String dbName; + if (i == 0) { + dbName = lastnode; + } else { + // lookaside is only relevant for the main db + lookasideUsed = 0; + dbName = " (attached) " + p.first; + // if the attached db has a path, attach the lastnode from the path to above + if (p.second.trim().length() > 0) { + int idx = p.second.lastIndexOf("/"); + dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0); + } + } + if (pageCount > 0) { + dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(), + lookasideUsed, db.mNumCacheHits, db.mNumCacheMisses, + db.mCompiledQueries.size())); + } } - } - // if there are pooled connections, return the cache stats for them also. - if (db.mConnectionPool != null) { - for (SQLiteDatabase pDb : db.mConnectionPool.getConnectionList()) { - dbStatsList.add(new DbStats("(pooled # " + pDb.mConnectionNum + ") " - + lastnode, 0, 0, 0, pDb.mNumCacheHits, pDb.mNumCacheMisses, - pDb.mCompiledQueries.size())); + // if there are pooled connections, return the cache stats for them also. + if (db.mConnectionPool != null) { + for (SQLiteDatabase pDb : db.mConnectionPool.getConnectionList()) { + dbStatsList.add(new DbStats("(pooled # " + pDb.mConnectionNum + ") " + + lastnode, 0, 0, 0, pDb.mNumCacheHits, pDb.mNumCacheMisses, + pDb.mCompiledQueries.size())); + } } + } catch (SQLiteException e) { + // ignore. we don't care about exceptions when we are taking adb + // bugreport! } - } catch (SQLiteException e) { - // ignore. we don't care about exceptions when we are taking adb - // bugreport! } } return dbStatsList; @@ -2636,7 +2566,7 @@ public class SQLiteDatabase extends SQLiteClosable { * this method. * @throws SQLException */ - /* package */ native void native_setLocale(String loc, int flags); + private native void native_setLocale(String loc, int flags); /** * return the SQLITE_DBSTATUS_LOOKASIDE_USED documented here diff --git a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java index 6cdfa69..de2fca9 100644 --- a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java +++ b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java @@ -45,11 +45,6 @@ public class SQLiteDirectCursorDriver implements SQLiteCursorDriver { mDatabase.lock(); mDatabase.closePendingStatements(); query = new SQLiteQuery(mDatabase, mSql, 0, selectionArgs); - // Arg binding - int numArgs = selectionArgs == null ? 0 : selectionArgs.length; - for (int i = 0; i < numArgs; i++) { - query.bindString(i + 1, selectionArgs[i]); - } // Create the cursor if (factory == null) { @@ -73,10 +68,7 @@ public class SQLiteDirectCursorDriver implements SQLiteCursorDriver { } public void setBindArguments(String[] bindArgs) { - final int numArgs = bindArgs.length; - for (int i = 0; i < numArgs; i++) { - mQuery.bindString(i + 1, bindArgs[i]); - } + mQuery.bindAllArgsAsStrings(bindArgs); } public void cursorDeactivated() { diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java index a4ebe5a..231d8e6 100644 --- a/core/java/android/database/sqlite/SQLiteProgram.java +++ b/core/java/android/database/sqlite/SQLiteProgram.java @@ -17,10 +17,10 @@ package android.database.sqlite; import android.database.DatabaseUtils; +import android.database.Cursor; import android.util.Log; -import android.util.Pair; -import java.util.ArrayList; +import java.util.HashMap; /** * A base class for compiled SQLite programs. @@ -47,7 +47,7 @@ public abstract class SQLiteProgram extends SQLiteClosable { * @deprecated do not use this */ @Deprecated - protected int nHandle = 0; + protected int nHandle; /** * the SQLiteCompiledSql object for the given sql statement. @@ -60,7 +60,7 @@ public abstract class SQLiteProgram extends SQLiteClosable { * @deprecated do not use this */ @Deprecated - protected int nStatement = 0; + protected int nStatement; /** * In the case of {@link SQLiteStatement}, this member stores the bindargs passed @@ -84,23 +84,29 @@ public abstract class SQLiteProgram extends SQLiteClosable { * <p> * It is protected (in multi-threaded environment) by {@link SQLiteProgram}.this */ - private ArrayList<Pair<Integer, Object>> mBindArgs = null; - + /* package */ HashMap<Integer, Object> mBindArgs = null; /* package */ final int mStatementType; /* package */ SQLiteProgram(SQLiteDatabase db, String sql) { - this(db, sql, true); + this(db, sql, null, true); } - /* package */ SQLiteProgram(SQLiteDatabase db, String sql, boolean compileFlag) { + /* package */ SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs, + boolean compileFlag) { mSql = sql.trim(); mStatementType = DatabaseUtils.getSqlStatementType(mSql); db.acquireReference(); db.addSQLiteClosable(this); mDatabase = db; nHandle = db.mNativeHandle; + if (bindArgs != null) { + int size = bindArgs.length; + for (int i = 0; i < size; i++) { + this.addToBindArgs(i + 1, bindArgs[i]); + } + } if (compileFlag) { - compileSql(); + compileAndbindAllArgs(); } } @@ -218,6 +224,39 @@ public abstract class SQLiteProgram extends SQLiteClosable { // TODO is there a need for this? } + private void bind(int type, int index, Object value) { + mDatabase.verifyDbIsOpen(); + synchronized (this) { + addToBindArgs(index, (type == Cursor.FIELD_TYPE_NULL) ? null : value); + if (nStatement > 0) { + // bind only if the SQL statement is compiled + acquireReference(); + try { + switch (type) { + case Cursor.FIELD_TYPE_NULL: + native_bind_null(index); + break; + case Cursor.FIELD_TYPE_BLOB: + native_bind_blob(index, (byte[]) value); + break; + case Cursor.FIELD_TYPE_FLOAT: + native_bind_double(index, (Double) value); + break; + case Cursor.FIELD_TYPE_INTEGER: + native_bind_long(index, (Long) value); + break; + case Cursor.FIELD_TYPE_STRING: + default: + native_bind_string(index, (String) value); + break; + } + } finally { + releaseReference(); + } + } + } + } + /** * Bind a NULL value to this statement. The value remains bound until * {@link #clearBindings} is called. @@ -225,44 +264,18 @@ public abstract class SQLiteProgram extends SQLiteClosable { * @param index The 1-based index to the parameter to bind null to */ public void bindNull(int index) { - mDatabase.verifyDbIsOpen(); - synchronized (this) { - acquireReference(); - try { - if (this.nStatement == 0) { - // since the SQL statement is not compiled, don't do the binding yet. - // can be done before executing the SQL statement - addToBindArgs(index, null); - } else { - native_bind_null(index); - } - } finally { - releaseReference(); - } - } + bind(Cursor.FIELD_TYPE_NULL, index, null); } /** * Bind a long value to this statement. The value remains bound until * {@link #clearBindings} is called. - * + *addToBindArgs * @param index The 1-based index to the parameter to bind * @param value The value to bind */ public void bindLong(int index, long value) { - mDatabase.verifyDbIsOpen(); - synchronized (this) { - acquireReference(); - try { - if (this.nStatement == 0) { - addToBindArgs(index, value); - } else { - native_bind_long(index, value); - } - } finally { - releaseReference(); - } - } + bind(Cursor.FIELD_TYPE_INTEGER, index, value); } /** @@ -273,19 +286,7 @@ public abstract class SQLiteProgram extends SQLiteClosable { * @param value The value to bind */ public void bindDouble(int index, double value) { - mDatabase.verifyDbIsOpen(); - synchronized (this) { - acquireReference(); - try { - if (this.nStatement == 0) { - addToBindArgs(index, value); - } else { - native_bind_double(index, value); - } - } finally { - releaseReference(); - } - } + bind(Cursor.FIELD_TYPE_FLOAT, index, value); } /** @@ -299,19 +300,7 @@ public abstract class SQLiteProgram extends SQLiteClosable { if (value == null) { throw new IllegalArgumentException("the bind value at index " + index + " is null"); } - mDatabase.verifyDbIsOpen(); - synchronized (this) { - acquireReference(); - try { - if (this.nStatement == 0) { - addToBindArgs(index, value); - } else { - native_bind_string(index, value); - } - } finally { - releaseReference(); - } - } + bind(Cursor.FIELD_TYPE_STRING, index, value); } /** @@ -325,19 +314,7 @@ public abstract class SQLiteProgram extends SQLiteClosable { if (value == null) { throw new IllegalArgumentException("the bind value at index " + index + " is null"); } - mDatabase.verifyDbIsOpen(); - synchronized (this) { - acquireReference(); - try { - if (this.nStatement == 0) { - addToBindArgs(index, value); - } else { - native_bind_blob(index, value); - } - } finally { - releaseReference(); - } - } + bind(Cursor.FIELD_TYPE_BLOB, index, value); } /** @@ -374,28 +351,56 @@ public abstract class SQLiteProgram extends SQLiteClosable { private synchronized void addToBindArgs(int index, Object value) { if (mBindArgs == null) { - mBindArgs = new ArrayList<Pair<Integer, Object>>(); + mBindArgs = new HashMap<Integer, Object>(); } - mBindArgs.add(new Pair<Integer, Object>(index, value)); + mBindArgs.put(index, value); } /* package */ synchronized void compileAndbindAllArgs() { - assert nStatement == 0; - compileSql(); + if (nStatement == 0) { + // SQL statement is not compiled yet. compile it now. + compileSql(); + } if (mBindArgs == null) { return; } - for (Pair<Integer, Object> p : mBindArgs) { - if (p.second == null) { - native_bind_null(p.first); - } else if (p.second instanceof Long) { - native_bind_long(p.first, (Long)p.second); - } else if (p.second instanceof Double) { - native_bind_double(p.first, (Double)p.second); - } else if (p.second instanceof byte[]) { - native_bind_blob(p.first, (byte[])p.second); - } else { - native_bind_string(p.first, (String)p.second); + for (int index : mBindArgs.keySet()) { + Object value = mBindArgs.get(index); + if (value == null) { + native_bind_null(index); + } else if (value instanceof Double || value instanceof Float) { + native_bind_double(index, ((Number) value).doubleValue()); + } else if (value instanceof Number) { + native_bind_long(index, ((Number) value).longValue()); + } else if (value instanceof Boolean) { + Boolean bool = (Boolean)value; + native_bind_long(index, (bool) ? 1 : 0); + if (bool) { + native_bind_long(index, 1); + } else { + native_bind_long(index, 0); + } + } else if (value instanceof byte[]){ + native_bind_blob(index, (byte[]) value); + } else { + native_bind_string(index, value.toString()); + } + } + } + + /** + * Given an array of String bindArgs, this method binds all of them in one single call. + * + * @param bindArgs the String array of bind args. + */ + public void bindAllArgsAsStrings(String[] bindArgs) { + if (bindArgs == null) { + return; + } + int size = bindArgs.length; + synchronized(this) { + for (int i = 0; i < size; i++) { + bindString(i + 1, bindArgs[i]); } } } @@ -421,6 +426,6 @@ public abstract class SQLiteProgram extends SQLiteClosable { protected final native void native_bind_double(int index, double value); protected final native void native_bind_string(int index, String value); protected final native void native_bind_blob(int index, byte[] value); - /* package */ final native void native_clear_bindings(); + private final native void native_clear_bindings(); } diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java index 1732971..63a8ce9 100644 --- a/core/java/android/database/sqlite/SQLiteQuery.java +++ b/core/java/android/database/sqlite/SQLiteQuery.java @@ -18,7 +18,6 @@ package android.database.sqlite; import android.database.CursorWindow; import android.os.SystemClock; -import android.util.Log; /** * A SQLite program that represents a query that reads the resulting rows into a CursorWindow. @@ -28,28 +27,24 @@ import android.util.Log; * threads should perform its own synchronization when using the SQLiteQuery. */ public class SQLiteQuery extends SQLiteProgram { - private static final String TAG = "Cursor"; + private static final String TAG = "SQLiteQuery"; /** The index of the unbound OFFSET parameter */ - private int mOffsetIndex; - - /** Args to bind on requery */ - private String[] mBindArgs; + private int mOffsetIndex = 0; private boolean mClosed = false; /** * Create a persistent query object. - * + * * @param db The database that this query object is associated with * @param query The SQL string for this query. * @param offsetIndex The 1-based index to the OFFSET parameter, */ /* package */ SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, String[] bindArgs) { super(db, query); - mOffsetIndex = offsetIndex; - mBindArgs = bindArgs; + bindAllArgsAsStrings(bindArgs); } /** @@ -61,7 +56,8 @@ public class SQLiteQuery extends SQLiteProgram { * @param query the instance of {@link SQLiteQuery} to be replaced */ /* package */ SQLiteQuery(SQLiteDatabase db, SQLiteQuery query) { - this(db, query.mSql, 0, query.mBindArgs); + super(db, query.mSql); + this.mBindArgs = query.mBindArgs; } /** @@ -148,51 +144,13 @@ public class SQLiteQuery extends SQLiteProgram { * Called by SQLiteCursor when it is requeried. */ /* package */ void requery() { - if (mBindArgs != null) { - int len = mBindArgs.length; - try { - for (int i = 0; i < len; i++) { - super.bindString(i + 1, mBindArgs[i]); - } - } catch (SQLiteMisuseException e) { - StringBuilder errMsg = new StringBuilder("mSql " + mSql); - for (int i = 0; i < len; i++) { - errMsg.append(" "); - errMsg.append(mBindArgs[i]); - } - errMsg.append(" "); - IllegalStateException leakProgram = new IllegalStateException( - errMsg.toString(), e); - throw leakProgram; - } + if (mClosed) { + throw new IllegalStateException("requerying a closed cursor"); } + compileAndbindAllArgs(); } - @Override - public void bindNull(int index) { - mBindArgs[index - 1] = null; - if (!mClosed) super.bindNull(index); - } - - @Override - public void bindLong(int index, long value) { - mBindArgs[index - 1] = Long.toString(value); - if (!mClosed) super.bindLong(index, value); - } - - @Override - public void bindDouble(int index, double value) { - mBindArgs[index - 1] = Double.toString(value); - if (!mClosed) super.bindDouble(index, value); - } - - @Override - public void bindString(int index, String value) { - mBindArgs[index - 1] = value; - if (!mClosed) super.bindString(index, value); - } - - private final native int native_fill_window(CursorWindow window, + private final native int native_fill_window(CursorWindow window, int startPos, int offsetParam, int maxRead, int lastPos); private final native int native_column_count(); diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java index 619764a..97e39d6 100644 --- a/core/java/android/database/sqlite/SQLiteStatement.java +++ b/core/java/android/database/sqlite/SQLiteStatement.java @@ -37,10 +37,10 @@ public class SQLiteStatement extends SQLiteProgram private static final boolean WRITE = false; private SQLiteDatabase mOrigDb; - private int state; - /** possible value for {@link #state}. indicates that a transaction is started.} */ + private int mState; + /** possible value for {@link #mState}. indicates that a transaction is started.} */ private static final int TRANS_STARTED = 1; - /** possible value for {@link #state}. indicates that a lock is acquired.} */ + /** possible value for {@link #mState}. indicates that a lock is acquired.} */ private static final int LOCK_ACQUIRED = 2; /** @@ -49,8 +49,8 @@ public class SQLiteStatement extends SQLiteProgram * @param db * @param sql */ - /* package */ SQLiteStatement(SQLiteDatabase db, String sql) { - super(db, sql, false /* don't compile sql statement */); + /* package */ SQLiteStatement(SQLiteDatabase db, String sql, Object[] bindArgs) { + super(db, sql, bindArgs, false /* don't compile sql statement */); } /** @@ -166,7 +166,7 @@ public class SQLiteStatement extends SQLiteProgram * methods in this class. */ private long acquireAndLock(boolean rwFlag) { - state = 0; + mState = 0; // use pooled database connection handles for SELECT SQL statements mDatabase.verifyDbIsOpen(); SQLiteDatabase db = (mStatementType != DatabaseUtils.STATEMENT_SELECT) ? mDatabase @@ -197,13 +197,13 @@ public class SQLiteStatement extends SQLiteProgram // got update SQL statement. if there is NO pending transaction, start one if (!mDatabase.inTransaction()) { mDatabase.beginTransactionNonExclusive(); - state = TRANS_STARTED; + mState = TRANS_STARTED; } } // do I have database lock? if not, grab it. if (!mDatabase.isDbLockedByCurrentThread()) { mDatabase.lock(); - state = LOCK_ACQUIRED; + mState = LOCK_ACQUIRED; } acquireReference(); @@ -218,13 +218,13 @@ public class SQLiteStatement extends SQLiteProgram */ private void releaseAndUnlock() { releaseReference(); - if (state == TRANS_STARTED) { + if (mState == TRANS_STARTED) { try { mDatabase.setTransactionSuccessful(); } finally { mDatabase.endTransaction(); } - } else if (state == LOCK_ACQUIRED) { + } else if (mState == LOCK_ACQUIRED) { mDatabase.unlock(); } if (mStatementType == DatabaseUtils.STATEMENT_COMMIT || |
