Merge "random but useful stuff"
This commit is contained in:
@@ -64401,6 +64401,19 @@
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<method name="bindAllArgsAsStrings"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="bindArgs" type="java.lang.String[]">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="bindBlob"
|
||||
return="void"
|
||||
abstract="false"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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: " +
|
||||
|
||||
@@ -40,8 +40,6 @@ public interface SQLiteCursorDriver {
|
||||
|
||||
/**
|
||||
* Called by a SQLiteCursor when it is requeryed.
|
||||
*
|
||||
* @return The new count value.
|
||||
*/
|
||||
void cursorRequeried(Cursor cursor);
|
||||
|
||||
|
||||
@@ -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);
|
||||
sql.append('(');
|
||||
|
||||
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('?');
|
||||
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(')');
|
||||
} else {
|
||||
sql.append("(" + nullColumnHack + ") ");
|
||||
values.append("NULL");
|
||||
}
|
||||
|
||||
sql.append(" VALUES(");
|
||||
sql.append(values);
|
||||
sql.append(");");
|
||||
|
||||
SQLiteStatement statement = null;
|
||||
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());
|
||||
}
|
||||
sql.append(" VALUES (");
|
||||
for (i = 0; i < size; i++) {
|
||||
sql.append((i > 0) ? ",?" : "?");
|
||||
}
|
||||
} else {
|
||||
sql.append(nullColumnHack + ") VALUES (NULL");
|
||||
}
|
||||
sql.append(')');
|
||||
|
||||
// Run the program and then cleanup
|
||||
SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs);
|
||||
try {
|
||||
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();
|
||||
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 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);
|
||||
// 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);
|
||||
// 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 (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()));
|
||||
}
|
||||
}
|
||||
} catch (SQLiteException e) {
|
||||
// ignore. we don't care about exceptions when we are taking adb
|
||||
// bugreport!
|
||||
}
|
||||
// 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!
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
Reference in New Issue
Block a user