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; 24 25import java.io.File; 26import java.util.HashSet; 27import java.util.Set; 28 29public class SQLiteCursorTest extends AndroidTestCase { 30 private SQLiteDatabase mDatabase; 31 private File mDatabaseFile; 32 private static final String TABLE_NAME = "testCursor"; 33 @Override 34 protected void setUp() throws Exception { 35 super.setUp(); 36 37 File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE); 38 mDatabaseFile = new File(dbDir, "sqlitecursor_test.db"); 39 if (mDatabaseFile.exists()) { 40 mDatabaseFile.delete(); 41 } 42 mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null); 43 assertNotNull(mDatabase); 44 // create a test table 45 mDatabase.execSQL("CREATE TABLE " + TABLE_NAME + " (i int, j int);"); 46 } 47 48 @Override 49 protected void tearDown() throws Exception { 50 mDatabase.close(); 51 mDatabaseFile.delete(); 52 super.tearDown(); 53 } 54 55 /** 56 * this test could take a while to execute. so, designate it as LargeTest 57 */ 58 @LargeTest 59 public void testFillWindow() { 60 // create schema 61 final String testTable = "testV"; 62 mDatabase.beginTransaction(); 63 mDatabase.execSQL("CREATE TABLE " + testTable + " (col1 int, desc text not null);"); 64 mDatabase.setTransactionSuccessful(); 65 mDatabase.endTransaction(); 66 67 // populate the table with data 68 // create a big string that will almost fit a page but not quite. 69 // since sqlite wants to make sure each row is in a page, this string will allocate 70 // a new database page for each row. 71 StringBuilder buff = new StringBuilder(); 72 for (int i = 0; i < 500; i++) { 73 buff.append(i % 10 + ""); 74 } 75 ContentValues values = new ContentValues(); 76 values.put("desc", buff.toString()); 77 78 // insert more than 1MB of data in the table. this should ensure that the entire tabledata 79 // will need more than one CursorWindow 80 int N = 5000; 81 Set<Integer> rows = new HashSet<Integer>(); 82 mDatabase.beginTransaction(); 83 for (int j = 0; j < N; j++) { 84 values.put("col1", j); 85 mDatabase.insert(testTable, null, values); 86 rows.add(j); // store in a hashtable so we can verify the results from cursor later on 87 } 88 mDatabase.setTransactionSuccessful(); 89 mDatabase.endTransaction(); 90 assertEquals(N, rows.size()); 91 Cursor c1 = mDatabase.rawQuery("select * from " + testTable, null); 92 assertEquals(N, c1.getCount()); 93 c1.close(); 94 95 // scroll through ALL data in the table using a cursor. should cause multiple calls to 96 // native_fill_window (and re-fills of the CursorWindow object) 97 Cursor c = mDatabase.query(testTable, new String[]{"col1", "desc"}, 98 null, null, null, null, null); 99 int i = 0; 100 while (c.moveToNext()) { 101 int val = c.getInt(0); 102 assertTrue(rows.contains(val)); 103 assertTrue(rows.remove(val)); 104 } 105 // did I see all the rows in the table? 106 assertTrue(rows.isEmpty()); 107 108 // change data and make sure the cursor picks up new data & count 109 rows = new HashSet<Integer>(); 110 mDatabase.beginTransaction(); 111 int M = N + 1000; 112 for (int j = 0; j < M; j++) { 113 rows.add(j); 114 if (j < N) { 115 continue; 116 } 117 values.put("col1", j); 118 mDatabase.insert(testTable, null, values); 119 } 120 mDatabase.setTransactionSuccessful(); 121 mDatabase.endTransaction(); 122 assertEquals(M, rows.size()); 123 c.requery(); 124 i = 0; 125 while (c.moveToNext()) { 126 int val = c.getInt(0); 127 assertTrue(rows.contains(val)); 128 assertTrue(rows.remove(val)); 129 } 130 // did I see all data from the modified table 131 assertTrue(rows.isEmpty()); 132 133 // move cursor back to 1st row and scroll to about halfway in the result set 134 // and then delete 75% of data - and then do requery 135 c.moveToFirst(); 136 int K = N / 2; 137 for (int p = 0; p < K && c.moveToNext(); p++) { 138 // nothing to do - just scrolling to about half-point in the resultset 139 } 140 mDatabase.beginTransaction(); 141 mDatabase.delete(testTable, "col1 < ?", new String[]{ (3 * M / 4) + ""}); 142 mDatabase.setTransactionSuccessful(); 143 mDatabase.endTransaction(); 144 c.requery(); 145 assertEquals(M / 4, c.getCount()); 146 while (c.moveToNext()) { 147 // just move the cursor to next row - to make sure it can go through the entire 148 // resultset without any problems 149 } 150 c.close(); 151 } 152} 153