diff options
author | Vasu Nori <vnori@google.com> | 2010-07-25 16:38:48 -0700 |
---|---|---|
committer | Vasu Nori <vnori@google.com> | 2010-07-26 13:00:07 -0700 |
commit | fb16cbd9b2e86d6878d4bff820422bc09c8938de (patch) | |
tree | 4bbcf44b1a14a7bdff5ce13cce5cb3eff2ac056c | |
parent | 037644fbe424315c5a3e9706453ce97413d636ff (diff) | |
download | frameworks_base-fb16cbd9b2e86d6878d4bff820422bc09c8938de.zip frameworks_base-fb16cbd9b2e86d6878d4bff820422bc09c8938de.tar.gz frameworks_base-fb16cbd9b2e86d6878d4bff820422bc09c8938de.tar.bz2 |
add new API in SQLiteStatement to deprecate another.
1. SQLIteStatement.executeUpdateDelete() replaces execute() - and returns the
number of rows changed.
2. let SQLiteDatabase.execSQL() call the above new API - which
means all CRUD statements by execSQL() are stored in prepared statement cache.
3. remove the following from SQLiteDatabase
lastrowId
lastchangecount()
native_execSQL()
Change-Id: I4e93a09dc381f425c3ae6ccc331a7bf227491e22
-rw-r--r-- | api/current.xml | 11 | ||||
-rw-r--r-- | core/java/android/database/sqlite/SQLiteDatabase.java | 59 | ||||
-rw-r--r-- | core/java/android/database/sqlite/SQLiteStatement.java | 26 | ||||
-rw-r--r-- | core/jni/android_database_SQLiteDatabase.cpp | 76 | ||||
-rw-r--r-- | core/jni/android_database_SQLiteStatement.cpp | 30 | ||||
-rw-r--r-- | core/tests/coretests/src/android/database/DatabaseGeneralTest.java | 61 |
6 files changed, 85 insertions, 178 deletions
diff --git a/api/current.xml b/api/current.xml index 96ca9e9..52b7217 100644 --- a/api/current.xml +++ b/api/current.xml @@ -63391,6 +63391,17 @@ visibility="public" > </method> +<method name="executeUpdateDelete" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="simpleQueryForLong" return="long" abstract="false" diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index cf4d07f..623821b 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -67,7 +67,7 @@ import java.util.regex.Pattern; * is the Unicode Collation Algorithm and not tailored to the current locale. */ public class SQLiteDatabase extends SQLiteClosable { - private static final String TAG = "Database"; + private static final String TAG = "SQLiteDatabase"; private static final int EVENT_DB_OPERATION = 52000; private static final int EVENT_DB_CORRUPT = 75004; @@ -1641,18 +1641,7 @@ public class SQLiteDatabase extends SQLiteClosable { } // Run the program and then cleanup - statement.execute(); - - long insertedRowId = lastInsertRow(); - if (insertedRowId == -1) { - Log.e(TAG, "Error inserting " + initialValues + " using " + sql); - } else { - if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "Inserting row " + insertedRowId + " from " - + initialValues + " using " + sql); - } - } - return insertedRowId; + return statement.executeInsert(); } catch (SQLiteDatabaseCorruptException e) { onCorruption(); throw e; @@ -1689,8 +1678,7 @@ public class SQLiteDatabase extends SQLiteClosable { DatabaseUtils.bindObjectToProgram(statement, i + 1, whereArgs[i]); } } - statement.execute(); - return lastChangeCount(); + return statement.executeUpdateDelete(); } catch (SQLiteDatabaseCorruptException e) { onCorruption(); throw e; @@ -1782,12 +1770,7 @@ public class SQLiteDatabase extends SQLiteClosable { } // Run the program and then cleanup - statement.execute(); - int numChangedRows = lastChangeCount(); - if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "Updated " + numChangedRows + " using " + values + " and " + sql); - } - return numChangedRows; + return statement.executeUpdateDelete(); } catch (SQLiteDatabaseCorruptException e) { onCorruption(); throw e; @@ -1834,13 +1817,18 @@ public class SQLiteDatabase extends SQLiteClosable { long timeStart = SystemClock.uptimeMillis(); lock(); logTimeStat(mLastSqlStatement, timeStart, GET_LOCK_LOG_PREFIX); + SQLiteStatement stmt = null; try { closePendingStatements(); - native_execSQL(sql); + stmt = compileStatement(sql); + stmt.execute(); } catch (SQLiteDatabaseCorruptException e) { onCorruption(); throw e; } finally { + if (stmt != null) { + stmt.close(); + } unlock(); } @@ -1914,7 +1902,7 @@ public class SQLiteDatabase extends SQLiteClosable { DatabaseUtils.bindObjectToProgram(statement, i + 1, bindArgs[i]); } } - statement.execute(); + statement.executeUpdateDelete(); } catch (SQLiteDatabaseCorruptException e) { onCorruption(); throw e; @@ -2025,7 +2013,7 @@ public class SQLiteDatabase extends SQLiteClosable { } if (durationMillis >= sQueryLogTimeInMillis) { samplePercent = 100; - } else {; + } else { samplePercent = (int) (100 * durationMillis / sQueryLogTimeInMillis) + 1; if (mRandom.nextInt(100) >= samplePercent) return; } @@ -2628,15 +2616,6 @@ public class SQLiteDatabase extends SQLiteClosable { private native void enableSqlProfiling(String path, short connectionNum); /** - * Native call to execute a raw SQL statement. {@link #lock} must be held - * when calling this method. - * - * @param sql The raw SQL string - * @throws SQLException - */ - /* package */ native void native_execSQL(String sql) throws SQLException; - - /** * Native call to set the locale. {@link #lock} must be held when calling * this method. * @throws SQLException @@ -2644,20 +2623,6 @@ public class SQLiteDatabase extends SQLiteClosable { /* package */ native void native_setLocale(String loc, int flags); /** - * Returns the row ID of the last row inserted into the database. - * - * @return the row ID of the last row inserted into the database. - */ - /* package */ native long lastInsertRow(); - - /** - * Returns the number of changes made in the last statement executed. - * - * @return the number of changes made in the last statement executed. - */ - /* package */ native int lastChangeCount(); - - /** * return the SQLITE_DBSTATUS_LOOKASIDE_USED documented here * http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html * @return int value of SQLITE_DBSTATUS_LOOKASIDE_USED diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java index b902803..7a683e4 100644 --- a/core/java/android/database/sqlite/SQLiteStatement.java +++ b/core/java/android/database/sqlite/SQLiteStatement.java @@ -48,18 +48,31 @@ public class SQLiteStatement extends SQLiteProgram } /** - * Execute this SQL statement, if it is not a query. For example, - * CREATE TABLE, DELTE, INSERT, etc. + * Execute this SQL statement, if it is not a SELECT / INSERT / DELETE / UPDATE, for example + * CREATE / DROP table, view, trigger, index etc. * * @throws android.database.SQLException If the SQL string is invalid for * some reason */ public void execute() { + executeUpdateDelete(); + } + + /** + * Execute this SQL statement, if the the number of rows affected by exection 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. + * @throws android.database.SQLException If the SQL string is invalid for + * some reason + */ + public int executeUpdateDelete() { synchronized(this) { long timeStart = acquireAndLock(WRITE); try { - native_execute(); + int numChanges = native_execute(); mDatabase.logTimeStat(mSql, timeStart); + return numChanges; } finally { releaseAndUnlock(); } @@ -79,9 +92,9 @@ public class SQLiteStatement extends SQLiteProgram synchronized(this) { long timeStart = acquireAndLock(WRITE); try { - native_execute(); + long lastInsertedRowId = native_executeInsert(); mDatabase.logTimeStat(mSql, timeStart); - return (mDatabase.lastChangeCount() > 0) ? mDatabase.lastInsertRow() : -1; + return lastInsertedRowId; } finally { releaseAndUnlock(); } @@ -182,7 +195,8 @@ public class SQLiteStatement extends SQLiteProgram nHandle = mDatabase.mNativeHandle; } - private final native void native_execute(); + private final native int native_execute(); + private final native long native_executeInsert(); private final native long native_1x1_long(); private final native String native_1x1_string(); } diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp index 290b532..003bbc1 100644 --- a/core/jni/android_database_SQLiteDatabase.cpp +++ b/core/jni/android_database_SQLiteDatabase.cpp @@ -15,7 +15,7 @@ */ #undef LOG_TAG -#define LOG_TAG "Database" +#define LOG_TAG "SqliteDatabaseCpp" #include <utils/Log.h> #include <utils/String8.h> @@ -245,77 +245,6 @@ static void dbclose(JNIEnv* env, jobject object) } } -/* public native void native_execSQL(String sql); */ -static void native_execSQL(JNIEnv* env, jobject object, jstring sqlString) -{ - int err; - int stepErr; - sqlite3_stmt * statement = NULL; - sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); - jchar const * sql = env->GetStringChars(sqlString, NULL); - jsize sqlLen = env->GetStringLength(sqlString); - - if (sql == NULL || sqlLen == 0) { - jniThrowException(env, "java/lang/IllegalArgumentException", - "You must supply an SQL string"); - return; - } - - err = sqlite3_prepare16_v2(handle, sql, sqlLen * 2, &statement, NULL); - - env->ReleaseStringChars(sqlString, sql); - - if (err != SQLITE_OK) { - char const * sql8 = env->GetStringUTFChars(sqlString, NULL); - LOGE("Failure %d (%s) on %p when preparing '%s'.\n", err, sqlite3_errmsg(handle), - handle, sql8); - throw_sqlite3_exception(env, handle, sql8); - env->ReleaseStringUTFChars(sqlString, sql8); - return; - } - - stepErr = sqlite3_step(statement); - err = sqlite3_finalize(statement); - - if (stepErr != SQLITE_DONE) { - if (stepErr == SQLITE_ROW) { - throw_sqlite3_exception(env, - "Queries cannot be performed using execSQL(), use query() instead."); - } else { - char const * sql8 = env->GetStringUTFChars(sqlString, NULL); - LOGE("Failure %d (%s) on %p when executing '%s'\n", err, sqlite3_errmsg(handle), - handle, sql8); - throw_sqlite3_exception(env, handle, sql8); - env->ReleaseStringUTFChars(sqlString, sql8); - - } - } else -#ifndef DB_LOG_STATEMENTS - IF_LOGV() -#endif - { - char const * sql8 = env->GetStringUTFChars(sqlString, NULL); - LOGV("Success on %p when executing '%s'\n", handle, sql8); - env->ReleaseStringUTFChars(sqlString, sql8); - } -} - -/* native long lastInsertRow(); */ -static jlong lastInsertRow(JNIEnv* env, jobject object) -{ - sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); - - return sqlite3_last_insert_rowid(handle); -} - -/* native int lastChangeCount(); */ -static jint lastChangeCount(JNIEnv* env, jobject object) -{ - sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); - - return sqlite3_changes(handle); -} - /* native int native_getDbLookaside(); */ static jint native_getDbLookaside(JNIEnv* env, jobject object) { @@ -522,9 +451,6 @@ static JNINativeMethod sMethods[] = {"dbclose", "()V", (void *)dbclose}, {"enableSqlTracing", "(Ljava/lang/String;S)V", (void *)enableSqlTracing}, {"enableSqlProfiling", "(Ljava/lang/String;S)V", (void *)enableSqlProfiling}, - {"native_execSQL", "(Ljava/lang/String;)V", (void *)native_execSQL}, - {"lastInsertRow", "()J", (void *)lastInsertRow}, - {"lastChangeCount", "()I", (void *)lastChangeCount}, {"native_setLocale", "(Ljava/lang/String;I)V", (void *)native_setLocale}, {"native_getDbLookaside", "()I", (void *)native_getDbLookaside}, {"releaseMemory", "()I", (void *)native_releaseMemory}, diff --git a/core/jni/android_database_SQLiteStatement.cpp b/core/jni/android_database_SQLiteStatement.cpp index 0341e0b..2212d9a 100644 --- a/core/jni/android_database_SQLiteStatement.cpp +++ b/core/jni/android_database_SQLiteStatement.cpp @@ -16,7 +16,7 @@ */ #undef LOG_TAG -#define LOG_TAG "Cursor" +#define LOG_TAG "SQLiteStatementCpp" #include <jni.h> #include <JNIHelp.h> @@ -48,24 +48,40 @@ static jfieldID gStatementField; (sqlite3 *)env->GetIntField(object, gHandleField) -static void native_execute(JNIEnv* env, jobject object) +static jint native_execute(JNIEnv* env, jobject object) { int err; sqlite3 * handle = GET_HANDLE(env, object); sqlite3_stmt * statement = GET_STATEMENT(env, object); + int numChanges = -1; // Execute the statement err = sqlite3_step(statement); - // Throw an exception if an error occured + // Throw an exception if an error occurred if (err == SQLITE_ROW) { - LOGV("Queries cannot be performed using execute(). use SQLiteDatabase.query() instead."); + throw_sqlite3_exception(env, + "Queries can be performed using SQLiteDatabase query or rawQuery methods only."); } else if (err != SQLITE_DONE) { throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle)); + } else { + numChanges = sqlite3_changes(handle); } - // Reset the statment so it's ready to use again + // Reset the statement so it's ready to use again sqlite3_reset(statement); + return numChanges; +} + +static jlong native_executeInsert(JNIEnv* env, jobject object) +{ + sqlite3 * handle = GET_HANDLE(env, object); + jint numChanges = native_execute(env, object); + if (numChanges > 0) { + return sqlite3_last_insert_rowid(handle); + } else { + return -1; + } } static jlong native_1x1_long(JNIEnv* env, jobject object) @@ -117,11 +133,11 @@ static jstring native_1x1_string(JNIEnv* env, jobject object) return value; } - static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ - {"native_execute", "()V", (void *)native_execute}, + {"native_execute", "()I", (void *)native_execute}, + {"native_executeInsert", "()J", (void *)native_executeInsert}, {"native_1x1_long", "()J", (void *)native_1x1_long}, {"native_1x1_string", "()Ljava/lang/String;", (void *)native_1x1_string}, }; diff --git a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java index e33421a..cd38bf0 100644 --- a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java +++ b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java @@ -21,6 +21,7 @@ import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_DEFA import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; import android.os.Handler; import android.os.Parcel; import android.test.AndroidTestCase; @@ -384,54 +385,28 @@ public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceT @MediumTest public void testSchemaChange2() throws Exception { - SQLiteDatabase db1 = mDatabase; - SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile, null); - Cursor cursor; - - db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);"); - - cursor = db1.query("db1", null, null, null, null, null, null); - assertNotNull("Cursor is null", cursor); + mDatabase.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);"); + Cursor cursor = mDatabase.query("db1", null, null, null, null, null, null); + assertNotNull(cursor); assertEquals(0, cursor.getCount()); - cursor.deactivate(); - // this cause exception because we're still using sqlite_prepate16 and not - // sqlite_prepare16_v2. The v2 variant added the ability to check the - // schema version and handle the case when the schema has changed - // Marco Nelissen claim it was 2x slower to compile SQL statements so - // I reverted back to the v1 variant. - /* db2.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);"); - - cursor = db1.query("db1", null, null, null, null, null, null); - assertNotNull("Cursor is null", cursor); - assertEquals(0, cursor.count()); - cursor.deactivate(); - */ + cursor.close(); } @MediumTest public void testSchemaChange3() throws Exception { - SQLiteDatabase db1 = mDatabase; - SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile, null); - Cursor cursor; - - - db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);"); - db1.execSQL("INSERT INTO db1 (data) VALUES ('test');"); - - cursor = db1.query("db1", null, null, null, null, null, null); - // this cause exception because we're still using sqlite_prepate16 and not - // sqlite_prepare16_v2. The v2 variant added the ability to check the - // schema version and handle the case when the schema has changed - // Marco Nelissen claim it was 2x slower to compile SQL statements so - // I reverted back to the v1 variant. - /* db2.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);"); - - assertNotNull("Cursor is null", cursor); - assertEquals(1, cursor.count()); - assertTrue(cursor.first()); - assertEquals("test", cursor.getString(cursor.getColumnIndexOrThrow("data"))); - cursor.deactivate(); - */ + mDatabase.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);"); + mDatabase.execSQL("INSERT INTO db1 (data) VALUES ('test');"); + mDatabase.execSQL("ALTER TABLE db1 ADD COLUMN blah int;"); + Cursor c = null; + try { + c = mDatabase.rawQuery("select blah from db1", null); + } catch (SQLiteException e) { + fail("unexpected exception: " + e.getMessage()); + } finally { + if (c != null) { + c.close(); + } + } } private class ChangeObserver extends ContentObserver { |