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