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