DatabaseGeneralTest.java revision 062fc7ce369758d5a26f83f12b50b11cd88e5def
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.database;
18
19import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_COLUMNNAME_INDEX;
20import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_DEFAULT_INDEX;
21import android.content.ContentValues;
22import android.content.Context;
23import android.database.sqlite.SQLiteDatabase;
24import android.database.sqlite.SQLiteStatement;
25import android.os.Handler;
26import android.os.Parcel;
27import android.test.AndroidTestCase;
28import android.test.PerformanceTestCase;
29import android.test.suitebuilder.annotation.MediumTest;
30import android.test.suitebuilder.annotation.SmallTest;
31import android.util.Log;
32
33import junit.framework.Assert;
34
35import java.io.File;
36import java.util.Arrays;
37import java.util.Locale;
38
39public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceTestCase {
40    private static final String TAG = "DatabaseGeneralTest";
41
42    private static final String sString1 = "this is a test";
43    private static final String sString2 = "and yet another test";
44    private static final String sString3 = "this string is a little longer, but still a test";
45    private static final String PHONE_NUMBER = "16175551212";
46
47    private static final int CURRENT_DATABASE_VERSION = 42;
48    private SQLiteDatabase mDatabase;
49    private File mDatabaseFile;
50
51    @Override
52    protected void setUp() throws Exception {
53        super.setUp();
54        File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
55        mDatabaseFile = new File(dbDir, "database_test.db");
56        if (mDatabaseFile.exists()) {
57            mDatabaseFile.delete();
58        }
59        mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
60        assertNotNull(mDatabase);
61        mDatabase.setVersion(CURRENT_DATABASE_VERSION);
62    }
63
64    @Override
65    protected void tearDown() throws Exception {
66        mDatabase.close();
67        mDatabaseFile.delete();
68        super.tearDown();
69    }
70
71    public boolean isPerformanceOnly() {
72        return false;
73    }
74
75    // These test can only be run once.
76    public int startPerformance(Intermediates intermediates) {
77        return 1;
78    }
79
80    private void populateDefaultTable() {
81        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
82
83        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString1 + "');");
84        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString2 + "');");
85        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString3 + "');");
86    }
87
88    @MediumTest
89    public void testVersion() throws Exception {
90        assertEquals(CURRENT_DATABASE_VERSION, mDatabase.getVersion());
91        mDatabase.setVersion(11);
92        assertEquals(11, mDatabase.getVersion());
93    }
94
95    @MediumTest
96    public void testUpdate() throws Exception {
97        populateDefaultTable();
98
99        ContentValues values = new ContentValues(1);
100        values.put("data", "this is an updated test");
101        assertEquals(1, mDatabase.update("test", values, "_id=1", null));
102        Cursor c = mDatabase.query("test", null, "_id=1", null, null, null, null);
103        assertNotNull(c);
104        assertEquals(1, c.getCount());
105        c.moveToFirst();
106        String value = c.getString(c.getColumnIndexOrThrow("data"));
107        assertEquals("this is an updated test", value);
108    }
109
110    @MediumTest
111    public void testPhoneNumbersEqual() throws Exception {
112        mDatabase.execSQL("CREATE TABLE phones (num TEXT);");
113        mDatabase.execSQL("INSERT INTO phones (num) VALUES ('911');");
114        mDatabase.execSQL("INSERT INTO phones (num) VALUES ('5555');");
115        mDatabase.execSQL("INSERT INTO phones (num) VALUES ('+" + PHONE_NUMBER + "');");
116
117        String number;
118        Cursor c;
119
120        c = mDatabase.query("phones", null,
121                "PHONE_NUMBERS_EQUAL(num, '504-555-7683')", null, null, null, null);
122        assertTrue(c == null || c.getCount() == 0);
123        c.close();
124
125        c = mDatabase.query("phones", null,
126                "PHONE_NUMBERS_EQUAL(num, '911')", null, null, null, null);
127        assertNotNull(c);
128        assertEquals(1, c.getCount());
129        c.moveToFirst();
130        number = c.getString(c.getColumnIndexOrThrow("num"));
131        assertEquals("911", number);
132        c.close();
133
134        c = mDatabase.query("phones", null,
135                "PHONE_NUMBERS_EQUAL(num, '5555')", null, null, null, null);
136        assertNotNull(c);
137        assertEquals(1, c.getCount());
138        c.moveToFirst();
139        number = c.getString(c.getColumnIndexOrThrow("num"));
140        assertEquals("5555", number);
141        c.close();
142
143        c = mDatabase.query("phones", null,
144                "PHONE_NUMBERS_EQUAL(num, '180055555555')", null, null, null, null);
145        assertTrue(c == null || c.getCount() == 0);
146        c.close();
147
148        c = mDatabase.query("phones", null,
149                "PHONE_NUMBERS_EQUAL(num, '+" + PHONE_NUMBER + "')", null, null, null, null);
150        assertNotNull(c);
151        assertEquals(1, c.getCount());
152        c.moveToFirst();
153        number = c.getString(c.getColumnIndexOrThrow("num"));
154        assertEquals("+" + PHONE_NUMBER, number);
155        c.close();
156
157        c = mDatabase.query("phones", null,
158                "PHONE_NUMBERS_EQUAL(num, '+1 (617).555-1212')", null, null, null, null);
159        assertNotNull(c);
160        assertEquals(1, c.getCount());
161        c.moveToFirst();
162        number = c.getString(c.getColumnIndexOrThrow("num"));
163        assertEquals("+" + PHONE_NUMBER, number);
164        c.close();
165
166        c = mDatabase.query("phones", null,
167                "PHONE_NUMBERS_EQUAL(num, '" + PHONE_NUMBER + "')", null, null, null, null);
168        assertNotNull(c);
169        assertEquals(1, c.getCount());
170        c.moveToFirst();
171        number = c.getString(c.getColumnIndexOrThrow("num"));
172        assertEquals("+" + PHONE_NUMBER, number);
173        c.close();
174
175        /*
176        c = mDatabase.query("phones", null,
177                "PHONE_NUMBERS_EQUAL(num, '5551212')", null, null, null, null);
178        assertNotNull(c);
179        assertEquals(1, c.getCount());
180        c.moveToFirst();
181        number = c.getString(c.getColumnIndexOrThrow("num"));
182        assertEquals("+" + PHONE_NUMBER, number);
183        c.close();
184        */
185
186        c = mDatabase.query("phones", null,
187                "PHONE_NUMBERS_EQUAL(num, '011" + PHONE_NUMBER + "')", null, null, null, null);
188        assertNotNull(c);
189        assertEquals(1, c.getCount());
190        c.moveToFirst();
191        number = c.getString(c.getColumnIndexOrThrow("num"));
192        assertEquals("+" + PHONE_NUMBER, number);
193        c.close();
194
195        c = mDatabase.query("phones", null,
196                "PHONE_NUMBERS_EQUAL(num, '00" + PHONE_NUMBER + "')", null, null, null, null);
197        assertNotNull(c);
198        assertEquals(1, c.getCount());
199        c.moveToFirst();
200        number = c.getString(c.getColumnIndexOrThrow("num"));
201        assertEquals("+" + PHONE_NUMBER, number);
202        c.close();
203    }
204
205    private void phoneNumberCompare(String phone1, String phone2, boolean equal,
206            boolean useStrictComparation) {
207        String[] temporalPhoneNumbers = new String[2];
208        temporalPhoneNumbers[0] = phone1;
209        temporalPhoneNumbers[1] = phone2;
210
211        Cursor cursor = mDatabase.rawQuery(
212                String.format(
213                        "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?, %d) " +
214                        "THEN 'equal' ELSE 'not equal' END",
215                        (useStrictComparation ? 1 : 0)),
216                temporalPhoneNumbers);
217        try {
218            assertNotNull(cursor);
219            assertTrue(cursor.moveToFirst());
220            if (equal) {
221                assertEquals(String.format("Unexpectedly, \"%s != %s\".", phone1, phone2),
222                        "equal", cursor.getString(0));
223            } else {
224                assertEquals(String.format("Unexpectedly, \"%s\" == \"%s\".", phone1, phone2),
225                        "not equal", cursor.getString(0));
226            }
227        } finally {
228            if (cursor != null) {
229                cursor.close();
230            }
231        }
232    }
233
234    private void assertPhoneNumberEqual(String phone1, String phone2) throws Exception {
235        assertPhoneNumberEqual(phone1, phone2, true);
236        assertPhoneNumberEqual(phone1, phone2, false);
237    }
238
239    private void assertPhoneNumberEqual(String phone1, String phone2, boolean useStrict)
240            throws Exception {
241        phoneNumberCompare(phone1, phone2, true, useStrict);
242    }
243
244    private void assertPhoneNumberNotEqual(String phone1, String phone2) throws Exception {
245        assertPhoneNumberNotEqual(phone1, phone2, true);
246        assertPhoneNumberNotEqual(phone1, phone2, false);
247    }
248
249    private void assertPhoneNumberNotEqual(String phone1, String phone2, boolean useStrict)
250            throws Exception {
251        phoneNumberCompare(phone1, phone2, false, useStrict);
252    }
253
254    /**
255     * Tests international matching issues for the PHONE_NUMBERS_EQUAL function.
256     *
257     * @throws Exception
258     */
259    @SmallTest
260    public void testPhoneNumbersEqualInternationl() throws Exception {
261        assertPhoneNumberEqual("1", "1");
262        assertPhoneNumberEqual("123123", "123123");
263        assertPhoneNumberNotEqual("123123", "923123");
264        assertPhoneNumberNotEqual("123123", "123129");
265        assertPhoneNumberNotEqual("123123", "1231234");
266        assertPhoneNumberNotEqual("123123", "0123123", false);
267        assertPhoneNumberNotEqual("123123", "0123123", true);
268        assertPhoneNumberEqual("650-253-0000", "6502530000");
269        assertPhoneNumberEqual("650-253-0000", "650 253 0000");
270        assertPhoneNumberEqual("650 253 0000", "6502530000");
271        assertPhoneNumberEqual("+1 650-253-0000", "6502530000");
272        assertPhoneNumberEqual("001 650-253-0000", "6502530000");
273        assertPhoneNumberEqual("0111 650-253-0000", "6502530000");
274
275        // Russian trunk digit
276        assertPhoneNumberEqual("+79161234567", "89161234567");
277
278        // French trunk digit
279        assertPhoneNumberEqual("+33123456789", "0123456789");
280
281        // Trunk digit for city codes in the Netherlands
282        assertPhoneNumberEqual("+31771234567", "0771234567");
283
284        // Test broken caller ID seen on call from Thailand to the US
285        assertPhoneNumberEqual("+66811234567", "166811234567");
286
287        // Test the same in-country number with different country codes
288        assertPhoneNumberNotEqual("+33123456789", "+1123456789");
289
290        // Test one number with country code and the other without
291        assertPhoneNumberEqual("5125551212", "+15125551212");
292
293        // Test two NANP numbers that only differ in the area code
294        assertPhoneNumberNotEqual("5125551212", "6505551212");
295
296        // Japanese phone numbers
297        assertPhoneNumberEqual("090-1234-5678", "+819012345678");
298        assertPhoneNumberEqual("090(1234)5678", "+819012345678");
299        assertPhoneNumberEqual("090-1234-5678", "+81-90-1234-5678");
300
301        // Equador
302        assertPhoneNumberEqual("+593(800)123-1234", "8001231234");
303        assertPhoneNumberEqual("+593-2-1234-123", "21234123");
304
305        // Two continuous 0 at the beginning of the phone string should not be
306        // treated as trunk prefix in the strict comparation.
307        assertPhoneNumberEqual("008001231234", "8001231234", false);
308        assertPhoneNumberNotEqual("008001231234", "8001231234", true);
309
310        // Confirm that the bug found before does not re-appear in the strict compalation
311        assertPhoneNumberEqual("080-1234-5678", "+819012345678", false);
312        assertPhoneNumberNotEqual("080-1234-5678", "+819012345678", true);
313    }
314
315    @MediumTest
316    public void testCopyString() throws Exception {
317        mDatabase.execSQL("CREATE TABLE guess (numi INTEGER, numf FLOAT, str TEXT);");
318        mDatabase.execSQL(
319                "INSERT INTO guess (numi,numf,str) VALUES (0,0.0,'ZoomZoomZoomZoom');");
320        mDatabase.execSQL("INSERT INTO guess (numi,numf,str) VALUES (2000000000,3.1415926535,'');");
321        String chinese = "\u4eac\u4ec5 \u5c3d\u5f84\u60ca";
322        String[] arr = new String[1];
323        arr[0] = chinese;
324        mDatabase.execSQL("INSERT INTO guess (numi,numf,str) VALUES (-32768,-1.0,?)", arr);
325
326        Cursor c;
327
328        c = mDatabase.rawQuery("SELECT * FROM guess", null);
329
330        c.moveToFirst();
331
332        CharArrayBuffer buf = new CharArrayBuffer(14);
333
334        String compareTo = c.getString(c.getColumnIndexOrThrow("numi"));
335        int numiIdx = c.getColumnIndexOrThrow("numi");
336        int numfIdx = c.getColumnIndexOrThrow("numf");
337        int strIdx = c.getColumnIndexOrThrow("str");
338
339        c.copyStringToBuffer(numiIdx, buf);
340        assertEquals(1, buf.sizeCopied);
341        assertEquals(compareTo, new String(buf.data, 0, buf.sizeCopied));
342
343        c.copyStringToBuffer(strIdx, buf);
344        assertEquals("ZoomZoomZoomZoom", new String(buf.data, 0, buf.sizeCopied));
345
346        c.moveToNext();
347        compareTo = c.getString(numfIdx);
348
349        c.copyStringToBuffer(numfIdx, buf);
350        assertEquals(compareTo, new String(buf.data, 0, buf.sizeCopied));
351        c.copyStringToBuffer(strIdx, buf);
352        assertEquals(0, buf.sizeCopied);
353
354        c.moveToNext();
355        c.copyStringToBuffer(numfIdx, buf);
356        assertEquals(-1.0, Double.valueOf(
357                new String(buf.data, 0, buf.sizeCopied)).doubleValue());
358
359        c.copyStringToBuffer(strIdx, buf);
360        compareTo = c.getString(strIdx);
361        assertEquals(chinese, compareTo);
362
363        assertEquals(chinese, new String(buf.data, 0, buf.sizeCopied));
364        c.close();
365    }
366
367    @MediumTest
368    public void testSchemaChange1() throws Exception {
369        SQLiteDatabase db1 = mDatabase;
370        Cursor cursor;
371
372        db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);");
373
374        cursor = db1.query("db1", null, null, null, null, null, null);
375        assertNotNull("Cursor is null", cursor);
376
377        db1.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);");
378
379        assertEquals(0, cursor.getCount());
380        cursor.deactivate();
381    }
382
383    @MediumTest
384    public void testSchemaChange2() throws Exception {
385        SQLiteDatabase db1 = mDatabase;
386        SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile, null);
387        Cursor cursor;
388
389        db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);");
390
391        cursor = db1.query("db1", null, null, null, null, null, null);
392        assertNotNull("Cursor is null", cursor);
393        assertEquals(0, cursor.getCount());
394        cursor.deactivate();
395        // this cause exception because we're still using sqlite_prepate16 and not
396        // sqlite_prepare16_v2. The v2 variant added the ability to check the
397        // schema version and handle the case when the schema has changed
398        // Marco Nelissen claim it was 2x slower to compile SQL statements so
399        // I reverted back to the v1 variant.
400        /* db2.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);");
401
402        cursor = db1.query("db1", null, null, null, null, null, null);
403        assertNotNull("Cursor is null", cursor);
404        assertEquals(0, cursor.count());
405        cursor.deactivate();
406        */
407    }
408
409    @MediumTest
410    public void testSchemaChange3() throws Exception {
411        SQLiteDatabase db1 = mDatabase;
412        SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile, null);
413        Cursor cursor;
414
415
416        db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);");
417        db1.execSQL("INSERT INTO db1 (data) VALUES ('test');");
418
419        cursor = db1.query("db1", null, null, null, null, null, null);
420        // this cause exception because we're still using sqlite_prepate16 and not
421        // sqlite_prepare16_v2. The v2 variant added the ability to check the
422        // schema version and handle the case when the schema has changed
423        // Marco Nelissen claim it was 2x slower to compile SQL statements so
424        // I reverted back to the v1 variant.
425        /* db2.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);");
426
427        assertNotNull("Cursor is null", cursor);
428        assertEquals(1, cursor.count());
429        assertTrue(cursor.first());
430        assertEquals("test", cursor.getString(cursor.getColumnIndexOrThrow("data")));
431        cursor.deactivate();
432        */
433    }
434
435    private class ChangeObserver extends ContentObserver {
436        private int mCursorNotificationCount = 0;
437        private int mNotificationCount = 0;
438
439        public int getCursorNotificationCount() {
440            return mCursorNotificationCount;
441        }
442
443        public int getNotificationCount() {
444            return mNotificationCount;
445        }
446
447        public ChangeObserver(boolean cursor) {
448            super(new Handler());
449            mCursor = cursor;
450        }
451
452        @Override
453        public boolean deliverSelfNotifications() {
454            return true;
455        }
456
457        @Override
458        public void onChange(boolean selfChange) {
459            if (mCursor) {
460                mCursorNotificationCount++;
461            } else {
462                mNotificationCount++;
463            }
464        }
465
466        boolean mCursor;
467    }
468
469    @MediumTest
470    public void testNotificationTest1() throws Exception {
471        /*
472        Cursor c = mContentResolver.query(Notes.CONTENT_URI,
473                new String[] {Notes._ID, Notes.NOTE},
474                null, null);
475        c.registerContentObserver(new MyContentObserver(true));
476        int count = c.count();
477
478        MyContentObserver observer = new MyContentObserver(false);
479        mContentResolver.registerContentObserver(Notes.CONTENT_URI, true, observer);
480
481        Uri uri;
482
483        HashMap<String, String> values = new HashMap<String, String>();
484        values.put(Notes.NOTE, "test note1");
485        uri = mContentResolver.insert(Notes.CONTENT_URI, values);
486        assertEquals(1, mCursorNotificationCount);
487        assertEquals(1, mNotificationCount);
488
489        c.requery();
490        assertEquals(count + 1, c.count());
491        c.first();
492        assertEquals("test note1", c.getString(c.getColumnIndex(Notes.NOTE)));
493        c.updateString(c.getColumnIndex(Notes.NOTE), "test note2");
494        c.commitUpdates();
495
496        assertEquals(2, mCursorNotificationCount);
497        assertEquals(2, mNotificationCount);
498
499        mContentResolver.delete(uri, null);
500
501        assertEquals(3, mCursorNotificationCount);
502        assertEquals(3, mNotificationCount);
503
504        mContentResolver.unregisterContentObserver(observer);
505        */
506    }
507
508    @MediumTest
509    public void testSelectionArgs() throws Exception {
510        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
511        ContentValues values = new ContentValues(1);
512        values.put("data", "don't forget to handled 's");
513        mDatabase.insert("test", "data", values);
514        values.clear();
515        values.put("data", "no apostrophes here");
516        mDatabase.insert("test", "data", values);
517        Cursor c = mDatabase.query(
518                "test", null, "data GLOB ?", new String[]{"*'*"}, null, null, null);
519        assertEquals(1, c.getCount());
520        assertTrue(c.moveToFirst());
521        assertEquals("don't forget to handled 's", c.getString(1));
522        c.close();
523
524        // make sure code should checking null string properly so that
525        // it won't crash
526        try {
527            mDatabase.query("test", new String[]{"_id"},
528                    "_id=?", null, null, null, null);
529            fail("expected exception not thrown");
530        } catch (IllegalArgumentException e) {
531            // expected
532        }
533    }
534
535    @MediumTest
536    public void testTokenize() throws Exception {
537        Cursor c;
538        mDatabase.execSQL("CREATE TABLE tokens (" +
539                "token TEXT COLLATE unicode," +
540                "source INTEGER," +
541                "token_index INTEGER," +
542                "tag TEXT" +
543                ");");
544        mDatabase.execSQL("CREATE TABLE tokens_no_index (" +
545                "token TEXT COLLATE unicode," +
546                "source INTEGER" +
547                ");");
548
549        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
550                "SELECT _TOKENIZE(NULL, NULL, NULL, NULL)", null));
551        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
552                "SELECT _TOKENIZE('tokens', NULL, NULL, NULL)", null));
553        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
554                "SELECT _TOKENIZE('tokens', 10, NULL, NULL)", null));
555        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
556                "SELECT _TOKENIZE('tokens', 10, 'some string', NULL)", null));
557
558        Assert.assertEquals(3, DatabaseUtils.longForQuery(mDatabase,
559                "SELECT _TOKENIZE('tokens', 11, 'some string ok', ' ', 1, 'foo')", null));
560        Assert.assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
561                "SELECT _TOKENIZE('tokens', 11, 'second field', ' ', 1, 'bar')", null));
562
563        Assert.assertEquals(3, DatabaseUtils.longForQuery(mDatabase,
564                "SELECT _TOKENIZE('tokens_no_index', 20, 'some string ok', ' ')", null));
565        Assert.assertEquals(3, DatabaseUtils.longForQuery(mDatabase,
566                "SELECT _TOKENIZE('tokens_no_index', 21, 'foo bar baz', ' ', 0)", null));
567
568        // test Chinese
569        String chinese = new String("\u4eac\u4ec5 \u5c3d\u5f84\u60ca");
570        Assert.assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
571                "SELECT _TOKENIZE('tokens', 12,'" + chinese + "', ' ', 1)", null));
572
573        String icustr = new String("Fr\u00e9d\u00e9ric Hj\u00f8nnev\u00e5g");
574
575        Assert.assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
576                "SELECT _TOKENIZE('tokens', 13, '" + icustr + "', ' ', 1)", null));
577
578        Assert.assertEquals(9, DatabaseUtils.longForQuery(mDatabase,
579                "SELECT count(*) from tokens;", null));
580
581        String key = DatabaseUtils.getHexCollationKey("Frederic Hjonneva");
582        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
583                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
584        Assert.assertEquals(13, DatabaseUtils.longForQuery(mDatabase,
585                "SELECT source from tokens where token GLOB '" + key + "*'", null));
586        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
587                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
588        key = DatabaseUtils.getHexCollationKey("Hjonneva");
589        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
590                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
591        Assert.assertEquals(13, DatabaseUtils.longForQuery(mDatabase,
592                "SELECT source from tokens where token GLOB '" + key + "*'", null));
593        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
594                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
595
596        key = DatabaseUtils.getHexCollationKey("some string ok");
597        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
598                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
599        Assert.assertEquals(11, DatabaseUtils.longForQuery(mDatabase,
600                "SELECT source from tokens where token GLOB '" + key + "*'", null));
601        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
602                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
603        Assert.assertEquals("foo", DatabaseUtils.stringForQuery(mDatabase,
604                "SELECT tag from tokens where token GLOB '" + key + "*'", null));
605        key = DatabaseUtils.getHexCollationKey("string");
606        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
607                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
608        Assert.assertEquals(11, DatabaseUtils.longForQuery(mDatabase,
609                "SELECT source from tokens where token GLOB '" + key + "*'", null));
610        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
611                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
612        Assert.assertEquals("foo", DatabaseUtils.stringForQuery(mDatabase,
613                "SELECT tag from tokens where token GLOB '" + key + "*'", null));
614        key = DatabaseUtils.getHexCollationKey("ok");
615        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
616                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
617        Assert.assertEquals(11, DatabaseUtils.longForQuery(mDatabase,
618                "SELECT source from tokens where token GLOB '" + key + "*'", null));
619        Assert.assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
620                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
621        Assert.assertEquals("foo", DatabaseUtils.stringForQuery(mDatabase,
622                "SELECT tag from tokens where token GLOB '" + key + "*'", null));
623
624        key = DatabaseUtils.getHexCollationKey("second field");
625        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
626                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
627        Assert.assertEquals(11, DatabaseUtils.longForQuery(mDatabase,
628                "SELECT source from tokens where token GLOB '" + key + "*'", null));
629        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
630                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
631        Assert.assertEquals("bar", DatabaseUtils.stringForQuery(mDatabase,
632                "SELECT tag from tokens where token GLOB '" + key + "*'", null));
633        key = DatabaseUtils.getHexCollationKey("field");
634        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
635                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
636        Assert.assertEquals(11, DatabaseUtils.longForQuery(mDatabase,
637                "SELECT source from tokens where token GLOB '" + key + "*'", null));
638        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
639                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
640        Assert.assertEquals("bar", DatabaseUtils.stringForQuery(mDatabase,
641                "SELECT tag from tokens where token GLOB '" + key + "*'", null));
642
643        key = DatabaseUtils.getHexCollationKey(chinese);
644        String[] a = new String[1];
645        a[0] = key;
646        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
647                "SELECT count(*) from tokens where token= ?", a));
648        Assert.assertEquals(12, DatabaseUtils.longForQuery(mDatabase,
649                "SELECT source from tokens where token= ?", a));
650        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
651                "SELECT token_index from tokens where token= ?", a));
652        a[0] += "*";
653        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
654             "SELECT count(*) from tokens where token GLOB ?", a));
655        Assert.assertEquals(12, DatabaseUtils.longForQuery(mDatabase,
656                "SELECT source from tokens where token GLOB ?", a));
657        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
658                "SELECT token_index from tokens where token GLOB ?", a));
659
660       Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
661                "SELECT count(*) from tokens where token= '" + key + "'", null));
662       Assert.assertEquals(12, DatabaseUtils.longForQuery(mDatabase,
663               "SELECT source from tokens where token= '" + key + "'", null));
664       Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
665               "SELECT token_index from tokens where token= '" + key + "'", null));
666
667        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
668                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
669        Assert.assertEquals(12, DatabaseUtils.longForQuery(mDatabase,
670                "SELECT source from tokens where token GLOB '" + key + "*'", null));
671        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
672                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
673
674        key = DatabaseUtils.getHexCollationKey("\u4eac\u4ec5");
675        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
676                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
677        Assert.assertEquals(12, DatabaseUtils.longForQuery(mDatabase,
678                "SELECT source from tokens where token GLOB '" + key + "*'", null));
679        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
680                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
681
682        key = DatabaseUtils.getHexCollationKey("\u5c3d\u5f84\u60ca");
683        Log.d("DatabaseGeneralTest", "key = " + key);
684        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
685                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
686        Assert.assertEquals(12, DatabaseUtils.longForQuery(mDatabase,
687                "SELECT source from tokens where token GLOB '" + key + "*'", null));
688        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
689                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
690
691        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
692                "SELECT count(*) from tokens where token GLOB 'ab*'", null));
693
694        key = DatabaseUtils.getHexCollationKey("some string ok");
695        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
696                "SELECT count(*) from tokens_no_index where token GLOB '" + key + "*'", null));
697        Assert.assertEquals(20, DatabaseUtils.longForQuery(mDatabase,
698                "SELECT source from tokens_no_index where token GLOB '" + key + "*'", null));
699
700        key = DatabaseUtils.getHexCollationKey("bar");
701        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
702                "SELECT count(*) from tokens_no_index where token GLOB '" + key + "*'", null));
703        Assert.assertEquals(21, DatabaseUtils.longForQuery(mDatabase,
704                "SELECT source from tokens_no_index where token GLOB '" + key + "*'", null));
705    }
706
707    @MediumTest
708    public void testTransactions() throws Exception {
709        mDatabase.execSQL("CREATE TABLE test (num INTEGER);");
710        mDatabase.execSQL("INSERT INTO test (num) VALUES (0)");
711
712        // Make sure that things work outside an explicit transaction.
713        setNum(1);
714        checkNum(1);
715
716        // Test a single-level transaction.
717        setNum(0);
718        mDatabase.beginTransaction();
719        setNum(1);
720        mDatabase.setTransactionSuccessful();
721        mDatabase.endTransaction();
722        checkNum(1);
723        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
724
725        // Test a rolled-back transaction.
726        setNum(0);
727        mDatabase.beginTransaction();
728        setNum(1);
729        mDatabase.endTransaction();
730        checkNum(0);
731        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
732
733        // We should get an error if we end a non-existent transaction.
734        assertThrowsIllegalState(new Runnable() { public void run() {
735            mDatabase.endTransaction();
736        }});
737
738        // We should get an error if a set a non-existent transaction as clean.
739        assertThrowsIllegalState(new Runnable() { public void run() {
740            mDatabase.setTransactionSuccessful();
741        }});
742
743        mDatabase.beginTransaction();
744        mDatabase.setTransactionSuccessful();
745        // We should get an error if we mark a transaction as clean twice.
746        assertThrowsIllegalState(new Runnable() { public void run() {
747            mDatabase.setTransactionSuccessful();
748        }});
749        // We should get an error if we begin a transaction after marking the parent as clean.
750        assertThrowsIllegalState(new Runnable() { public void run() {
751            mDatabase.beginTransaction();
752        }});
753        mDatabase.endTransaction();
754        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
755
756        // Test a two-level transaction.
757        setNum(0);
758        mDatabase.beginTransaction();
759        mDatabase.beginTransaction();
760        setNum(1);
761        mDatabase.setTransactionSuccessful();
762        mDatabase.endTransaction();
763        mDatabase.setTransactionSuccessful();
764        mDatabase.endTransaction();
765        checkNum(1);
766        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
767
768        // Test rolling back an inner transaction.
769        setNum(0);
770        mDatabase.beginTransaction();
771        mDatabase.beginTransaction();
772        setNum(1);
773        mDatabase.endTransaction();
774        mDatabase.setTransactionSuccessful();
775        mDatabase.endTransaction();
776        checkNum(0);
777        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
778
779        // Test rolling back an outer transaction.
780        setNum(0);
781        mDatabase.beginTransaction();
782        mDatabase.beginTransaction();
783        setNum(1);
784        mDatabase.setTransactionSuccessful();
785        mDatabase.endTransaction();
786        mDatabase.endTransaction();
787        checkNum(0);
788        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
789    }
790
791    private void setNum(int num) {
792        mDatabase.execSQL("UPDATE test SET num = " + num);
793    }
794
795    private void checkNum(int num) {
796        Assert.assertEquals(
797                num, DatabaseUtils.longForQuery(mDatabase, "SELECT num FROM test", null));
798    }
799
800    private void assertThrowsIllegalState(Runnable r) {
801        boolean ok = false;
802        try {
803            r.run();
804        } catch (IllegalStateException e) {
805            ok = true;
806        }
807        Assert.assertTrue(ok);
808    }
809
810    // Disable these until we can explicitly mark them as stress tests
811    public void xxtestMem1() throws Exception {
812        populateDefaultTable();
813
814        for (int i = 0; i < 50000; i++) {
815            Cursor cursor = mDatabase.query("test", null, null, null, null, null, null);
816            cursor.moveToFirst();
817            cursor.close();
818//                Log.i("~~~~", "Finished round " + i);
819        }
820    }
821
822    // Disable these until we can explicitly mark them as stress tests
823    public void xxtestMem2() throws Exception {
824        populateDefaultTable();
825
826        for (int i = 0; i < 50000; i++) {
827            Cursor cursor = mDatabase.query("test", null, null, null, null, null, null);
828            cursor.close();
829//                Log.i("~~~~", "Finished round " + i);
830        }
831    }
832
833    // Disable these until we can explicitly mark them as stress tests
834    public void xxtestMem3() throws Exception {
835        populateDefaultTable();
836
837        for (int i = 0; i < 50000; i++) {
838            Cursor cursor = mDatabase.query("test", null, null, null, null, null, null);
839            cursor.deactivate();
840//                Log.i("~~~~", "Finished round " + i);
841        }
842    }
843
844    @MediumTest
845    public void testContentValues() throws Exception {
846        ContentValues values = new ContentValues();
847        values.put("string", "value");
848        assertEquals("value", values.getAsString("string"));
849        byte[] bytes = new byte[42];
850        Arrays.fill(bytes, (byte) 0x28);
851        values.put("byteArray", bytes);
852        assertTrue(Arrays.equals(bytes, values.getAsByteArray("byteArray")));
853
854        // Write the ContentValues to a Parcel and then read them out
855        Parcel p = Parcel.obtain();
856        values.writeToParcel(p, 0);
857        p.setDataPosition(0);
858        values = ContentValues.CREATOR.createFromParcel(p);
859
860        // Read the values out again and make sure they're the same
861        assertTrue(Arrays.equals(bytes, values.getAsByteArray("byteArray")));
862        assertEquals("value", values.get("string"));
863    }
864
865    @MediumTest
866    public void testTableInfoPragma() throws Exception {
867        mDatabase.execSQL("CREATE TABLE pragma_test (" +
868                "i INTEGER DEFAULT 1234, " +
869                "j INTEGER, " +
870                "s TEXT DEFAULT 'hello', " +
871                "t TEXT, " +
872                "'select' TEXT DEFAULT \"hello\")");
873        try {
874            Cursor cur = mDatabase.rawQuery("PRAGMA table_info(pragma_test)", null);
875            Assert.assertEquals(5, cur.getCount());
876
877            Assert.assertTrue(cur.moveToNext());
878            Assert.assertEquals("i",
879                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
880            Assert.assertEquals("1234",
881                    cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
882
883            Assert.assertTrue(cur.moveToNext());
884            Assert.assertEquals("j",
885                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
886            Assert.assertNull(cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
887
888            Assert.assertTrue(cur.moveToNext());
889            Assert.assertEquals("s",
890                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
891            Assert.assertEquals("'hello'",
892                    cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
893
894            Assert.assertTrue(cur.moveToNext());
895            Assert.assertEquals("t",
896                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
897            Assert.assertNull(cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
898
899            Assert.assertTrue(cur.moveToNext());
900            Assert.assertEquals("select",
901                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
902            Assert.assertEquals("\"hello\"",
903                    cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
904
905            cur.close();
906        } catch (Throwable t) {
907            throw new RuntimeException(
908                    "If you see this test fail, it's likely that something about " +
909                    "sqlite's PRAGMA table_info(...) command has changed.", t);
910        }
911    }
912
913    @MediumTest
914    public void testInsertHelper() throws Exception {
915        Cursor cur;
916        ContentValues cv;
917        long row;
918
919        mDatabase.execSQL("CREATE TABLE insert_test (" +
920                "_id INTEGER PRIMARY KEY, " +
921                "s TEXT NOT NULL UNIQUE, " +
922                "t TEXT NOT NULL DEFAULT 'hello world', " +
923                "i INTEGER, " +
924                "j INTEGER NOT NULL DEFAULT 1234, " +
925                "'select' TEXT)");
926
927        DatabaseUtils.InsertHelper ih =
928            new DatabaseUtils.InsertHelper(mDatabase, "insert_test");
929
930        cv = new ContentValues();
931        cv.put("s", "one");
932        row = ih.insert(cv);
933        cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null);
934        Assert.assertTrue(cur.moveToFirst());
935        Assert.assertEquals("one", cur.getString(1));
936        Assert.assertEquals("hello world", cur.getString(2));
937        Assert.assertNull(cur.getString(3));
938        Assert.assertEquals(1234, cur.getLong(4));
939        Assert.assertNull(cur.getString(5));
940        cur.close();
941
942        cv = new ContentValues();
943        cv.put("s", "two");
944        cv.put("t", "goodbye world");
945        row = ih.insert(cv);
946        cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null);
947        Assert.assertTrue(cur.moveToFirst());
948        Assert.assertEquals("two", cur.getString(1));
949        Assert.assertEquals("goodbye world", cur.getString(2));
950        Assert.assertNull(cur.getString(3));
951        Assert.assertEquals(1234, cur.getLong(4));
952        Assert.assertNull(cur.getString(5));
953        cur.close();
954
955        cv = new ContentValues();
956        cv.put("t", "goodbye world");
957        row = ih.insert(cv);
958        Assert.assertEquals(-1, row);
959
960        cv = new ContentValues();
961        cv.put("s", "three");
962        cv.put("i", 2345);
963        cv.put("j", 3456);
964        cv.put("select", "tricky");
965        row = ih.insert(cv);
966        cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null);
967        Assert.assertTrue(cur.moveToFirst());
968        Assert.assertEquals("three", cur.getString(1));
969        Assert.assertEquals("hello world", cur.getString(2));
970        Assert.assertEquals(2345, cur.getLong(3));
971        Assert.assertEquals(3456, cur.getLong(4));
972        Assert.assertEquals("tricky", cur.getString(5));
973        cur.close();
974
975        cv = new ContentValues();
976        cv.put("s", "three");
977        cv.put("i", 6789);
978        row = ih.insert(cv);
979        Assert.assertEquals(-1, row);
980        row = ih.replace(cv);
981        cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null);
982        Assert.assertTrue(cur.moveToFirst());
983        Assert.assertEquals("three", cur.getString(1));
984        Assert.assertEquals("hello world", cur.getString(2));
985        Assert.assertEquals(6789, cur.getLong(3));
986        cur.close();
987
988        ih.close();
989    }
990
991    @MediumTest
992    public void testDbCloseReleasingAllCachedSql() {
993        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, text1 TEXT, text2 TEXT, " +
994                "num1 INTEGER, num2 INTEGER, image BLOB);");
995        final String statement = "DELETE FROM test WHERE _id=?;";
996        SQLiteStatement statementDoNotClose = mDatabase.compileStatement(statement);
997        assertTrue(statementDoNotClose.getUniqueId() > 0);
998        int nStatement = statementDoNotClose.getUniqueId();
999        assertTrue(statementDoNotClose.getUniqueId() == nStatement);
1000        /* do not close statementDoNotClose object.
1001         * That should leave it in SQLiteDatabase.mPrograms.
1002         * mDatabase.close() in tearDown() should release it.
1003         */
1004    }
1005
1006    @MediumTest
1007    public void testSemicolonsInStatements() throws Exception {
1008        mDatabase.execSQL("CREATE TABLE pragma_test (" +
1009                "i INTEGER DEFAULT 1234, " +
1010                "j INTEGER, " +
1011                "s TEXT DEFAULT 'hello', " +
1012                "t TEXT, " +
1013                "'select' TEXT DEFAULT \"hello\")");
1014        try {
1015            // ending the sql statement with  semicolons shouldn't be a problem.
1016            Cursor cur = mDatabase.rawQuery("PRAGMA database_list;", null);
1017            cur.close();
1018            // two semicolons in the statement shouldn't be a problem.
1019            cur = mDatabase.rawQuery("PRAGMA database_list;;", null);
1020            cur.close();
1021        } catch (Throwable t) {
1022            fail("unexpected, of course");
1023        }
1024    }
1025
1026    @MediumTest
1027    public void testUnionsWithBindArgs() {
1028        /* make sure unions with bindargs work http://b/issue?id=1061291 */
1029        mDatabase.execSQL("CREATE TABLE A (i int);");
1030        mDatabase.execSQL("create table B (k int);");
1031        mDatabase.execSQL("create table C (n int);");
1032        mDatabase.execSQL("insert into A values(1);");
1033        mDatabase.execSQL("insert into A values(2);");
1034        mDatabase.execSQL("insert into A values(3);");
1035        mDatabase.execSQL("insert into B values(201);");
1036        mDatabase.execSQL("insert into B values(202);");
1037        mDatabase.execSQL("insert into B values(203);");
1038        mDatabase.execSQL("insert into C values(901);");
1039        mDatabase.execSQL("insert into C values(902);");
1040        String s = "select i from A where i > 2 " +
1041                "UNION select k from B where k > 201 " +
1042                "UNION select n from C where n !=900;";
1043        Cursor c = mDatabase.rawQuery(s, null);
1044        int n = c.getCount();
1045        c.close();
1046        String s1 = "select i from A where i > ? " +
1047                "UNION select k from B where k > ? " +
1048                "UNION select n from C where n != ?;";
1049        Cursor c1 = mDatabase.rawQuery(s1, new String[]{"2", "201", "900"});
1050        assertEquals(n, c1.getCount());
1051        c1.close();
1052    }
1053
1054    /**
1055     * This test is available only when the platform has a locale with the language "ja".
1056     * It finishes without failure when it is not available.
1057     */
1058    @MediumTest
1059    public void testCollateLocalizedForJapanese() throws Exception {
1060        final String testName = "DatabaseGeneralTest#testCollateLocalizedForJapanese()";
1061        final Locale[] localeArray = Locale.getAvailableLocales();
1062        final String japanese = Locale.JAPANESE.getLanguage();
1063        final String english = Locale.ENGLISH.getLanguage();
1064        Locale japaneseLocale = null;
1065        Locale englishLocale = null;
1066        for (Locale locale : localeArray) {
1067            if (locale != null) {
1068                final String language = locale.getLanguage();
1069                if (language == null) {
1070                    continue;
1071                } else if (language.equals(japanese)) {
1072                    japaneseLocale = locale;
1073                } else if (language.equals(english)) {
1074                    englishLocale = locale;
1075                }
1076            }
1077
1078            if (japaneseLocale != null && englishLocale != null) {
1079                break;
1080            }
1081        }
1082
1083        if (japaneseLocale == null || englishLocale == null) {
1084            Log.d(TAG, testName + "n is silently skipped since " +
1085                    (englishLocale == null ?
1086                            (japaneseLocale == null ?
1087                                    "Both English and Japanese locales do not exist." :
1088                                    "English locale does not exist.") :
1089                            (japaneseLocale == null ?
1090                                    "Japanese locale does not exist." :
1091                                    "...why?")));
1092            return;
1093        }
1094
1095        Locale originalLocale = Locale.getDefault();
1096        try {
1097
1098            final String dbName = "collate_localized_test";
1099            mDatabase.execSQL("CREATE TABLE " + dbName + " (" +
1100                    "_id INTEGER PRIMARY KEY, " +
1101                    "s TEXT COLLATE LOCALIZED) ");
1102            DatabaseUtils.InsertHelper ih =
1103                new DatabaseUtils.InsertHelper(mDatabase, dbName);
1104            ContentValues cv = new ContentValues();
1105
1106            cv = new ContentValues();  //
1107            cv.put("s", "\uFF75\uFF77\uFF85\uFF9C");  // O-ki-na-wa in half-width Katakana
1108            ih.insert(cv);
1109
1110            cv = new ContentValues();  //
1111            cv.put("s", "\u306B\u307B\u3093");  // Ni-ho-n in Hiragana
1112            ih.insert(cv);
1113
1114            cv = new ContentValues();  //
1115            cv.put("s", "\u30A2\u30E1\u30EA\u30AB");  // A-me-ri-ca in hull-width Katakana
1116            ih.insert(cv);
1117
1118            // Assume setLocale() does REINDEX and an English locale does not consider
1119            // Japanese-specific LOCALIZED order.
1120            Locale.setDefault(englishLocale);
1121            Locale.setDefault(japaneseLocale);
1122
1123            Cursor cur = mDatabase.rawQuery(
1124                    "SELECT * FROM " + dbName + " ORDER BY s", null);
1125            assertTrue(cur.moveToFirst());
1126            assertEquals("\u30A2\u30E1\u30EA\u30AB", cur.getString(1));
1127            assertTrue(cur.moveToNext());
1128            assertEquals("\uFF75\uFF77\uFF85\uFF9C", cur.getString(1));
1129            assertTrue(cur.moveToNext());
1130            assertEquals("\u306B\u307B\u3093", cur.getString(1));
1131        } finally {
1132            if (originalLocale != null) {
1133                try {
1134                    Locale.setDefault(originalLocale);
1135                } catch (Exception e) {
1136                }
1137            }
1138        }
1139    }
1140}
1141