Port the SQLite locale setting code to Java.

Make the database opening code more robust in the case of
read-only database connections.

Check whether a PRAGMA needs to be issues before doing it.
Mostly it's harmless but it can grab a transaction on the
database unnecessarily.

Change-Id: Iab2cdc96c785e767f82966b00597e19337163f2f
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index c8f911f..fca5f20 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -36,8 +36,8 @@
 
 #include "android_database_SQLiteCommon.h"
 
+// Set to 1 to use UTF16 storage for localized indexes.
 #define UTF16_STORAGE 0
-#define ANDROID_TABLE "android_metadata"
 
 namespace android {
 
@@ -245,139 +245,16 @@
     }
 }
 
-// Set locale in the android_metadata table, install localized collators, and rebuild indexes
-static void nativeSetLocale(JNIEnv* env, jclass clazz, jint connectionPtr, jstring localeStr) {
+static void nativeRegisterLocalizedCollators(JNIEnv* env, jclass clazz, jint connectionPtr,
+        jstring localeStr) {
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
 
-    if (connection->openFlags & SQLiteConnection::NO_LOCALIZED_COLLATORS) {
-        // We should probably throw IllegalStateException but the contract for
-        // setLocale says that we just do nothing.  Oh well.
-        return;
-    }
+    const char* locale = env->GetStringUTFChars(localeStr, NULL);
+    int err = register_localized_collators(connection->db, locale, UTF16_STORAGE);
+    env->ReleaseStringUTFChars(localeStr, locale);
 
-    int err;
-    char const* locale = env->GetStringUTFChars(localeStr, NULL);
-    sqlite3_stmt* stmt = NULL;
-    char** meta = NULL;
-    int rowCount, colCount;
-    char* dbLocale = NULL;
-
-    // create the table, if necessary and possible
-    if (!(connection->openFlags & SQLiteConnection::OPEN_READONLY)) {
-        err = sqlite3_exec(connection->db,
-                "CREATE TABLE IF NOT EXISTS " ANDROID_TABLE " (locale TEXT)",
-                NULL, NULL, NULL);
-        if (err != SQLITE_OK) {
-            ALOGE("CREATE TABLE " ANDROID_TABLE " failed");
-            throw_sqlite3_exception(env, connection->db);
-            goto done;
-        }
-    }
-
-    // try to read from the table
-    err = sqlite3_get_table(connection->db,
-            "SELECT locale FROM " ANDROID_TABLE " LIMIT 1",
-            &meta, &rowCount, &colCount, NULL);
     if (err != SQLITE_OK) {
-        ALOGE("SELECT locale FROM " ANDROID_TABLE " failed");
         throw_sqlite3_exception(env, connection->db);
-        goto done;
-    }
-
-    dbLocale = (rowCount >= 1) ? meta[colCount] : NULL;
-
-    if (dbLocale != NULL && !strcmp(dbLocale, locale)) {
-        // database locale is the same as the desired locale; set up the collators and go
-        err = register_localized_collators(connection->db, locale, UTF16_STORAGE);
-        if (err != SQLITE_OK) {
-            throw_sqlite3_exception(env, connection->db);
-        }
-        goto done;   // no database changes needed
-    }
-
-    if (connection->openFlags & SQLiteConnection::OPEN_READONLY) {
-        // read-only database, so we're going to have to put up with whatever we got
-        // For registering new index. Not for modifing the read-only database.
-        err = register_localized_collators(connection->db, locale, UTF16_STORAGE);
-        if (err != SQLITE_OK) {
-            throw_sqlite3_exception(env, connection->db);
-        }
-        goto done;
-    }
-
-    // need to update android_metadata and indexes atomically, so use a transaction...
-    err = sqlite3_exec(connection->db, "BEGIN TRANSACTION", NULL, NULL, NULL);
-    if (err != SQLITE_OK) {
-        ALOGE("BEGIN TRANSACTION failed setting locale");
-        throw_sqlite3_exception(env, connection->db);
-        goto done;
-    }
-
-    err = register_localized_collators(connection->db, locale, UTF16_STORAGE);
-    if (err != SQLITE_OK) {
-        ALOGE("register_localized_collators() failed setting locale");
-        throw_sqlite3_exception(env, connection->db);
-        goto rollback;
-    }
-
-    err = sqlite3_exec(connection->db, "DELETE FROM " ANDROID_TABLE, NULL, NULL, NULL);
-    if (err != SQLITE_OK) {
-        ALOGE("DELETE failed setting locale");
-        throw_sqlite3_exception(env, connection->db);
-        goto rollback;
-    }
-
-    static const char *sql = "INSERT INTO " ANDROID_TABLE " (locale) VALUES(?);";
-    err = sqlite3_prepare_v2(connection->db, sql, -1, &stmt, NULL);
-    if (err != SQLITE_OK) {
-        ALOGE("sqlite3_prepare_v2(\"%s\") failed", sql);
-        throw_sqlite3_exception(env, connection->db);
-        goto rollback;
-    }
-
-    err = sqlite3_bind_text(stmt, 1, locale, -1, SQLITE_TRANSIENT);
-    if (err != SQLITE_OK) {
-        ALOGE("sqlite3_bind_text() failed setting locale");
-        throw_sqlite3_exception(env, connection->db);
-        goto rollback;
-    }
-
-    err = sqlite3_step(stmt);
-    if (err != SQLITE_OK && err != SQLITE_DONE) {
-        ALOGE("sqlite3_step(\"%s\") failed setting locale", sql);
-        throw_sqlite3_exception(env, connection->db);
-        goto rollback;
-    }
-
-    err = sqlite3_exec(connection->db, "REINDEX LOCALIZED", NULL, NULL, NULL);
-    if (err != SQLITE_OK) {
-        ALOGE("REINDEX LOCALIZED failed");
-        throw_sqlite3_exception(env, connection->db);
-        goto rollback;
-    }
-
-    // all done, yay!
-    err = sqlite3_exec(connection->db, "COMMIT TRANSACTION", NULL, NULL, NULL);
-    if (err != SQLITE_OK) {
-        ALOGE("COMMIT TRANSACTION failed setting locale");
-        throw_sqlite3_exception(env, connection->db);
-        goto done;
-    }
-
-rollback:
-    if (err != SQLITE_OK) {
-        sqlite3_exec(connection->db, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
-    }
-
-done:
-    if (stmt) {
-        sqlite3_finalize(stmt);
-    }
-    if (meta) {
-        sqlite3_free_table(meta);
-    }
-    if (locale) {
-        env->ReleaseStringUTFChars(localeStr, locale);
     }
 }
 
@@ -898,8 +775,8 @@
             (void*)nativeClose },
     { "nativeRegisterCustomFunction", "(ILandroid/database/sqlite/SQLiteCustomFunction;)V",
             (void*)nativeRegisterCustomFunction },
-    { "nativeSetLocale", "(ILjava/lang/String;)V",
-            (void*)nativeSetLocale },
+    { "nativeRegisterLocalizedCollators", "(ILjava/lang/String;)V",
+            (void*)nativeRegisterLocalizedCollators },
     { "nativePrepareStatement", "(ILjava/lang/String;)I",
             (void*)nativePrepareStatement },
     { "nativeFinalizeStatement", "(II)V",