Make JNI function for setLocale() call register_localized_collators()
with the current locale, not previous one, every time it is possible.
Add a unit test verifying this fix.
BUG: 2514026
Change-Id: I4dd1b047e1ab4bf399e2c3ebc0304c0cfa3a0928
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index fb93014..4e8d05b 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -349,7 +349,7 @@
goto done;
}
- dbLocale = (rowCount >= 1) ? meta[1 * colCount + 0] : NULL;
+ dbLocale = (rowCount >= 1) ? meta[colCount] : NULL;
if (dbLocale != NULL && !strcmp(dbLocale, locale8)) {
// database locale is the same as the desired locale; set up the collators and go
@@ -360,7 +360,8 @@
if ((flags & OPEN_READONLY)) {
// read-only database, so we're going to have to put up with whatever we got
- err = register_localized_collators(handle, dbLocale ? dbLocale : locale8, UTF16_STORAGE);
+ // For registering new index. Not for modifing the read-only database.
+ err = register_localized_collators(handle, locale8, UTF16_STORAGE);
if (err != SQLITE_OK) throw_sqlite3_exception(env, handle);
goto done;
}
@@ -373,7 +374,7 @@
goto done;
}
- err = register_localized_collators(handle, dbLocale ? dbLocale : locale8, UTF16_STORAGE);
+ err = register_localized_collators(handle, locale8, UTF16_STORAGE);
if (err != SQLITE_OK) {
LOGE("register_localized_collators() failed setting locale\n");
throw_sqlite3_exception(env, handle);
diff --git a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
index ab142c9..656029d 100644
--- a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
@@ -16,15 +16,12 @@
package android.database;
+import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_COLUMNNAME_INDEX;
+import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_DEFAULT_INDEX;
import android.content.ContentValues;
import android.content.Context;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.CharArrayBuffer;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
-import android.os.Environment;
import android.os.Handler;
import android.os.Parcel;
import android.test.AndroidTestCase;
@@ -33,18 +30,14 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
-import java.io.File;
-import java.io.UnsupportedEncodingException;
-import java.text.Collator;
-import java.util.Arrays;
-
import junit.framework.Assert;
-import junit.framework.TestCase;
-import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_COLUMNNAME_INDEX;
-import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_DEFAULT_INDEX;
+import java.io.File;
+import java.util.Arrays;
+import java.util.Locale;
public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceTestCase {
+ private static final String TAG = "DatabaseGeneralTest";
private static final String sString1 = "this is a test";
private static final String sString2 = "and yet another test";
@@ -1029,4 +1022,91 @@
fail("unexpected, of course");
}
}
+
+ /**
+ * This test is available only when the platform has a locale with the language "ja".
+ * It finishes without failure when it is not available.
+ */
+ @MediumTest
+ public void testCollateLocalizedForJapanese() throws Exception {
+ final String testName = "DatabaseGeneralTest#testCollateLocalizedForJapanese()";
+ final Locale[] localeArray = Locale.getAvailableLocales();
+ final String japanese = Locale.JAPANESE.getLanguage();
+ final String english = Locale.ENGLISH.getLanguage();
+ Locale japaneseLocale = null;
+ Locale englishLocale = null;
+ for (Locale locale : localeArray) {
+ if (locale != null) {
+ final String language = locale.getLanguage();
+ if (language == null) {
+ continue;
+ } else if (language.equals(japanese)) {
+ japaneseLocale = locale;
+ } else if (language.equals(english)) {
+ englishLocale = locale;
+ }
+ }
+
+ if (japaneseLocale != null && englishLocale != null) {
+ break;
+ }
+ }
+
+ if (japaneseLocale == null || englishLocale == null) {
+ Log.d(TAG, testName + "n is silently skipped since " +
+ (englishLocale == null ?
+ (japaneseLocale == null ?
+ "Both English and Japanese locales do not exist." :
+ "English locale does not exist.") :
+ (japaneseLocale == null ?
+ "Japanese locale does not exist." :
+ "...why?")));
+ return;
+ }
+
+ Locale originalLocale = Locale.getDefault();
+ try {
+
+ final String dbName = "collate_localized_test";
+ mDatabase.execSQL("CREATE TABLE " + dbName + " (" +
+ "_id INTEGER PRIMARY KEY, " +
+ "s TEXT COLLATE LOCALIZED) ");
+ DatabaseUtils.InsertHelper ih =
+ new DatabaseUtils.InsertHelper(mDatabase, dbName);
+ ContentValues cv = new ContentValues();
+
+ cv = new ContentValues(); //
+ cv.put("s", "\uFF75\uFF77\uFF85\uFF9C"); // O-ki-na-wa in half-width Katakana
+ ih.insert(cv);
+
+ cv = new ContentValues(); //
+ cv.put("s", "\u306B\u307B\u3093"); // Ni-ho-n in Hiragana
+ ih.insert(cv);
+
+ cv = new ContentValues(); //
+ cv.put("s", "\u30A2\u30E1\u30EA\u30AB"); // A-me-ri-ca in hull-width Katakana
+ ih.insert(cv);
+
+ // Assume setLocale() does REINDEX and an English locale does not consider
+ // Japanese-specific LOCALIZED order.
+ Locale.setDefault(englishLocale);
+ Locale.setDefault(japaneseLocale);
+
+ Cursor cur = mDatabase.rawQuery(
+ "SELECT * FROM " + dbName + " ORDER BY s", null);
+ assertTrue(cur.moveToFirst());
+ assertEquals("\u30A2\u30E1\u30EA\u30AB", cur.getString(1));
+ assertTrue(cur.moveToNext());
+ assertEquals("\uFF75\uFF77\uFF85\uFF9C", cur.getString(1));
+ assertTrue(cur.moveToNext());
+ assertEquals("\u306B\u307B\u3093", cur.getString(1));
+ } finally {
+ if (originalLocale != null) {
+ try {
+ Locale.setDefault(originalLocale);
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
}