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