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