diff --git a/api/current.xml b/api/current.xml
index 4ded22f843616..3049bcb45aaa9 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -64538,7 +64538,29 @@
visibility="public"
>
+
+
+
+
+
+
mBindArgs = null;
/* package */ final int mStatementType;
+ /* package */ static final int STATEMENT_CACHEABLE = 16;
+ /* package */ static final int STATEMENT_DONT_PREPARE = 32;
+ /* package */ static final int STATEMENT_USE_POOLED_CONN = 64;
+ /* package */ static final int STATEMENT_TYPE_MASK = 0x0f;
/* package */ SQLiteProgram(SQLiteDatabase db, String sql) {
this(db, sql, null, true);
@@ -94,7 +98,25 @@ public abstract class SQLiteProgram extends SQLiteClosable {
/* package */ SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs,
boolean compileFlag) {
mSql = sql.trim();
- mStatementType = DatabaseUtils.getSqlStatementType(mSql);
+ int n = DatabaseUtils.getSqlStatementType(mSql);
+ switch (n) {
+ case DatabaseUtils.STATEMENT_UPDATE:
+ mStatementType = n | STATEMENT_CACHEABLE;
+ break;
+ case DatabaseUtils.STATEMENT_SELECT:
+ mStatementType = n | STATEMENT_CACHEABLE | STATEMENT_USE_POOLED_CONN;
+ break;
+ case DatabaseUtils.STATEMENT_ATTACH:
+ case DatabaseUtils.STATEMENT_BEGIN:
+ case DatabaseUtils.STATEMENT_COMMIT:
+ case DatabaseUtils.STATEMENT_ABORT:
+ case DatabaseUtils.STATEMENT_DDL:
+ case DatabaseUtils.STATEMENT_UNPREPARED:
+ mStatementType = n | STATEMENT_DONT_PREPARE;
+ break;
+ default:
+ mStatementType = n;
+ }
db.acquireReference();
db.addSQLiteClosable(this);
mDatabase = db;
@@ -112,8 +134,7 @@ public abstract class SQLiteProgram extends SQLiteClosable {
private void compileSql() {
// only cache CRUD statements
- if (mStatementType != DatabaseUtils.STATEMENT_SELECT &&
- mStatementType != DatabaseUtils.STATEMENT_UPDATE) {
+ if ((mStatementType & STATEMENT_CACHEABLE) == 0) {
mCompiledSql = new SQLiteCompiledSql(mDatabase, mSql);
nStatement = mCompiledSql.nStatement;
// since it is not in the cache, no need to acquire() it.
@@ -163,14 +184,19 @@ public abstract class SQLiteProgram extends SQLiteClosable {
if (mCompiledSql == null) {
return;
}
- synchronized(mDatabase.mCompiledQueries) {
- if (!mDatabase.mCompiledQueries.containsValue(mCompiledSql)) {
- // it is NOT in compiled-sql cache. i.e., responsibility of
- // releasing this statement is on me.
- mCompiledSql.releaseSqlStatement();
- } else {
- // it is in compiled-sql cache. reset its CompiledSql#mInUse flag
- mCompiledSql.release();
+ if ((mStatementType & STATEMENT_CACHEABLE) == 0) {
+ // this SQL statement was never in cache
+ mCompiledSql.releaseSqlStatement();
+ } else {
+ synchronized(mDatabase.mCompiledQueries) {
+ if (!mDatabase.mCompiledQueries.containsValue(mCompiledSql)) {
+ // it is NOT in compiled-sql cache. i.e., responsibility of
+ // releasing this statement is on me.
+ mCompiledSql.releaseSqlStatement();
+ } else {
+ // it is in compiled-sql cache. reset its CompiledSql#mInUse flag
+ mCompiledSql.release();
+ }
}
}
mCompiledSql = null;
@@ -347,6 +373,16 @@ public abstract class SQLiteProgram extends SQLiteClosable {
}
/* package */ synchronized void compileAndbindAllArgs() {
+ if ((mStatementType & STATEMENT_DONT_PREPARE) > 0) {
+ // no need to prepare this SQL statement
+ if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
+ if (mBindArgs != null) {
+ throw new IllegalArgumentException("no need to pass bindargs for this sql :" +
+ mSql);
+ }
+ }
+ return;
+ }
if (nStatement == 0) {
// SQL statement is not compiled yet. compile it now.
compileSql();
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 658fc58c03e63..bd05e247cdab6 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -71,7 +71,7 @@ public class SQLiteStatement extends SQLiteProgram
}
/**
- * Execute this SQL statement, if the the number of rows affected by exection of this SQL
+ * Execute this SQL statement, if the the number of rows affected by execution of this SQL
* statement is of any importance to the caller - for example, UPDATE / DELETE SQL statements.
*
* @return the number of rows affected by this SQL statement execution.
@@ -82,7 +82,15 @@ public class SQLiteStatement extends SQLiteProgram
synchronized(this) {
try {
long timeStart = acquireAndLock(WRITE);
- int numChanges = native_execute();
+ int numChanges = 0;
+ if ((mStatementType & STATEMENT_DONT_PREPARE) > 0) {
+ // since the statement doesn't have to be prepared,
+ // call the following native method which will not prepare
+ // the query plan
+ native_executeSql(mSql);
+ } else {
+ numChanges = native_execute();
+ }
mDatabase.logTimeStat(mSql, timeStart);
return numChanges;
} finally {
@@ -199,8 +207,8 @@ public class SQLiteStatement extends SQLiteProgram
mState = 0;
// use pooled database connection handles for SELECT SQL statements
mDatabase.verifyDbIsOpen();
- SQLiteDatabase db = (mStatementType != DatabaseUtils.STATEMENT_SELECT) ? mDatabase
- : mDatabase.getDbConnection(mSql);
+ SQLiteDatabase db = ((mStatementType & SQLiteProgram.STATEMENT_USE_POOLED_CONN) > 0)
+ ? mDatabase.getDbConnection(mSql) : mDatabase;
// use the database connection obtained above
mOrigDb = mDatabase;
mDatabase = db;
@@ -217,13 +225,14 @@ public class SQLiteStatement extends SQLiteProgram
* beginTransaction() methods in SQLiteDatabase call lockForced() before
* calling execSQL("BEGIN transaction").
*/
- if (mStatementType == DatabaseUtils.STATEMENT_BEGIN) {
+ if ((mStatementType & SQLiteProgram.STATEMENT_TYPE_MASK) == DatabaseUtils.STATEMENT_BEGIN) {
if (!mDatabase.isDbLockedByCurrentThread()) {
// transaction is NOT started by calling beginTransaction() methods in
// SQLiteDatabase
mDatabase.setTransactionUsingExecSqlFlag();
}
- } else if (mStatementType == DatabaseUtils.STATEMENT_UPDATE) {
+ } else if ((mStatementType & SQLiteProgram.STATEMENT_TYPE_MASK) ==
+ DatabaseUtils.STATEMENT_UPDATE) {
// got update SQL statement. if there is NO pending transaction, start one
if (!mDatabase.inTransaction()) {
mDatabase.beginTransactionNonExclusive();
@@ -257,8 +266,10 @@ public class SQLiteStatement extends SQLiteProgram
} else if (mState == LOCK_ACQUIRED) {
mDatabase.unlock();
}
- if (mStatementType == DatabaseUtils.STATEMENT_COMMIT ||
- mStatementType == DatabaseUtils.STATEMENT_ABORT) {
+ if ((mStatementType & SQLiteProgram.STATEMENT_TYPE_MASK) ==
+ DatabaseUtils.STATEMENT_COMMIT ||
+ (mStatementType & SQLiteProgram.STATEMENT_TYPE_MASK) ==
+ DatabaseUtils.STATEMENT_ABORT) {
mDatabase.resetTransactionUsingExecSqlFlag();
}
clearBindings();
@@ -275,4 +286,5 @@ public class SQLiteStatement extends SQLiteProgram
private final native long native_1x1_long();
private final native String native_1x1_string();
private final native ParcelFileDescriptor native_1x1_blob_ashmem() throws IOException;
+ private final native void native_executeSql(String sql);
}
diff --git a/core/jni/android_database_SQLiteStatement.cpp b/core/jni/android_database_SQLiteStatement.cpp
index 0f3114b61d653..97e0483021f6c 100644
--- a/core/jni/android_database_SQLiteStatement.cpp
+++ b/core/jni/android_database_SQLiteStatement.cpp
@@ -239,6 +239,17 @@ static jobject native_1x1_blob_ashmem(JNIEnv* env, jobject object)
return value;
}
+static void native_executeSql(JNIEnv* env, jobject object, jstring sql)
+{
+ char const* sqlString = env->GetStringUTFChars(sql, NULL);
+ sqlite3 * handle = GET_HANDLE(env, object);
+ int err = sqlite3_exec(handle, sqlString, NULL, NULL, NULL);
+ if (err != SQLITE_OK) {
+ throw_sqlite3_exception(env, handle);
+ }
+ env->ReleaseStringUTFChars(sql, sqlString);
+}
+
static JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
@@ -247,6 +258,7 @@ static JNINativeMethod sMethods[] =
{"native_1x1_long", "()J", (void *)native_1x1_long},
{"native_1x1_string", "()Ljava/lang/String;", (void *)native_1x1_string},
{"native_1x1_blob_ashmem", "()Landroid/os/ParcelFileDescriptor;", (void *)native_1x1_blob_ashmem},
+ {"native_executeSql", "(Ljava/lang/String;)V", (void *)native_executeSql},
};
int register_android_database_SQLiteStatement(JNIEnv * env)