SQLiteCursorTest.java revision e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6
1/*
2 * Copyright (C) 2010 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.sqlite;
18
19import android.content.ContentValues;
20import android.content.Context;
21import android.database.Cursor;
22import android.test.AndroidTestCase;
23import android.test.suitebuilder.annotation.LargeTest;
24import android.test.suitebuilder.annotation.SmallTest;
25import android.test.suitebuilder.annotation.Suppress;
26import android.util.Log;
27
28import java.io.File;
29import java.util.HashSet;
30import java.util.Set;
31
32public class SQLiteCursorTest extends AndroidTestCase {
33    private SQLiteDatabase mDatabase;
34    private File mDatabaseFile;
35    private static final String TABLE_NAME = "testCursor";
36    @Override
37    protected void setUp() throws Exception {
38        super.setUp();
39
40        File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
41        mDatabaseFile = new File(dbDir, "sqlitecursor_test.db");
42        if (mDatabaseFile.exists()) {
43            mDatabaseFile.delete();
44        }
45        mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
46        assertNotNull(mDatabase);
47        // create a test table
48        mDatabase.execSQL("CREATE TABLE " + TABLE_NAME + " (i int, j int);");
49    }
50
51    @Override
52    protected void tearDown() throws Exception {
53        mDatabase.close();
54        mDatabaseFile.delete();
55        super.tearDown();
56    }
57
58    @Suppress
59    @SmallTest
60    public void testQueryObjReassignment() {
61        mDatabase.enableWriteAheadLogging();
62        // have a few connections in the database connection pool
63        DatabaseConnectionPool pool = mDatabase.mConnectionPool;
64        pool.setMaxPoolSize(5);
65        SQLiteCursor cursor =
66                (SQLiteCursor) mDatabase.rawQuery("select * from " + TABLE_NAME, null);
67        assertNotNull(cursor);
68        // it should use a pooled database connection
69        SQLiteDatabase db = cursor.getDatabase();
70        assertTrue(db.mConnectionNum > 0);
71        assertFalse(mDatabase.equals(db));
72        assertEquals(mDatabase, db.mParentConnObj);
73        assertTrue(pool.getConnectionList().contains(db));
74        assertTrue(db.isOpen());
75        // do a requery. cursor should continue to use the above pooled connection
76        cursor.requery();
77        SQLiteDatabase dbAgain = cursor.getDatabase();
78        assertEquals(db, dbAgain);
79        // disable WAL so that the pooled connection held by the above cursor is closed
80        mDatabase.disableWriteAheadLogging();
81        assertFalse(db.isOpen());
82        assertNull(mDatabase.mConnectionPool);
83        // requery - which should make the cursor use mDatabase connection since the pooled
84        // connection is no longer available
85        cursor.requery();
86        SQLiteDatabase db1 = cursor.getDatabase();
87        assertTrue(db1.mConnectionNum == 0);
88        assertEquals(mDatabase, db1);
89        assertNull(mDatabase.mConnectionPool);
90        assertTrue(db1.isOpen());
91        assertFalse(mDatabase.equals(db));
92        // enable WAL and requery - this time a pooled connection should be used
93        mDatabase.enableWriteAheadLogging();
94        cursor.requery();
95        db = cursor.getDatabase();
96        assertTrue(db.mConnectionNum > 0);
97        assertFalse(mDatabase.equals(db));
98        assertEquals(mDatabase, db.mParentConnObj);
99        assertTrue(mDatabase.mConnectionPool.getConnectionList().contains(db));
100        assertTrue(db.isOpen());
101    }
102
103    /**
104     * this test could take a while to execute. so, designate it as LargetTest
105     */
106    @LargeTest
107    public void testFillWindow() {
108        // create schema
109        final String testTable = "testV";
110        mDatabase.beginTransaction();
111        mDatabase.execSQL("CREATE TABLE " + testTable + " (col1 int, desc text not null);");
112        mDatabase.setTransactionSuccessful();
113        mDatabase.endTransaction();
114
115        // populate the table with data
116        // create a big string that will almost fit a page but not quite.
117        // since sqlite wants to make sure each row is in a page, this string will allocate
118        // a new database page for each row.
119        StringBuilder buff = new StringBuilder();
120        for (int i = 0; i < 500; i++) {
121            buff.append(i % 10 + "");
122        }
123        ContentValues values = new ContentValues();
124        values.put("desc", buff.toString());
125
126        // insert more than 1MB of data in the table. this should ensure that the entire tabledata
127        // will need more than one CursorWindow
128        int N = 5000;
129        Set<Integer> rows = new HashSet<Integer>();
130        mDatabase.beginTransaction();
131        for (int j = 0; j < N; j++) {
132            values.put("col1", j);
133            mDatabase.insert(testTable, null, values);
134            rows.add(j); // store in a hashtable so we can verify the results from cursor later on
135        }
136        mDatabase.setTransactionSuccessful();
137        mDatabase.endTransaction();
138        assertEquals(N, rows.size());
139        Cursor c1 = mDatabase.rawQuery("select * from " + testTable, null);
140        assertEquals(N, c1.getCount());
141        c1.close();
142
143        // scroll through ALL data in the table using a cursor. should cause multiple calls to
144        // native_fill_window (and re-fills of the CursorWindow object)
145        Cursor c = mDatabase.query(testTable, new String[]{"col1", "desc"},
146                null, null, null, null, null);
147        int i = 0;
148        while (c.moveToNext()) {
149            int val = c.getInt(0);
150            assertTrue(rows.contains(val));
151            assertTrue(rows.remove(val));
152        }
153        // did I see all the rows in the table?
154        assertTrue(rows.isEmpty());
155
156        // change data and make sure the cursor picks up new data & count
157        rows = new HashSet<Integer>();
158        mDatabase.beginTransaction();
159        int M = N + 1000;
160        for (int j = 0; j < M; j++) {
161            rows.add(j);
162            if (j < N) {
163                continue;
164            }
165            values.put("col1", j);
166            mDatabase.insert(testTable, null, values);
167        }
168        mDatabase.setTransactionSuccessful();
169        mDatabase.endTransaction();
170        assertEquals(M, rows.size());
171        c.requery();
172        i = 0;
173        while (c.moveToNext()) {
174            int val = c.getInt(0);
175            assertTrue(rows.contains(val));
176            assertTrue(rows.remove(val));
177        }
178        // did I see all data from the modified table
179        assertTrue(rows.isEmpty());
180
181        // move cursor back to 1st row and scroll to about halfway in the result set
182        // and then delete 75% of data - and then do requery
183        c.moveToFirst();
184        int K = N / 2;
185        for (int p = 0; p < K && c.moveToNext(); p++) {
186            // nothing to do - just scrolling to about half-point in the resultset
187        }
188        mDatabase.beginTransaction();
189        mDatabase.delete(testTable, "col1 < ?", new String[]{ (3 * M / 4) + ""});
190        mDatabase.setTransactionSuccessful();
191        mDatabase.endTransaction();
192        c.requery();
193        assertEquals(M / 4, c.getCount());
194        while (c.moveToNext()) {
195            // just move the cursor to next row - to make sure it can go through the entire
196            // resultset without any problems
197        }
198        c.close();
199    }
200}
201