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)