blob: f6b1d04c8487d3c1254652e60aff3c2a8888b355 [file] [log] [blame]
Vasu Nori65a88832010-07-16 15:14:08 -07001/*
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
Vasu Norib18f27d2010-08-12 18:16:35 -070019import android.content.ContentValues;
Vasu Nori65a88832010-07-16 15:14:08 -070020import android.content.Context;
Vasu Norib18f27d2010-08-12 18:16:35 -070021import android.database.Cursor;
Vasu Nori65a88832010-07-16 15:14:08 -070022import android.test.AndroidTestCase;
Vasu Noric2ce7212010-10-05 17:45:37 -070023import android.test.suitebuilder.annotation.LargeTest;
Vasu Nori65a88832010-07-16 15:14:08 -070024import android.test.suitebuilder.annotation.SmallTest;
Vasu Norib18f27d2010-08-12 18:16:35 -070025import android.util.Log;
Vasu Nori65a88832010-07-16 15:14:08 -070026
27import java.io.File;
Vasu Norib18f27d2010-08-12 18:16:35 -070028import java.util.HashSet;
29import java.util.Set;
Vasu Nori65a88832010-07-16 15:14:08 -070030
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 }
Vasu Norib18f27d2010-08-12 18:16:35 -0700100
Vasu Nori790762c2010-10-05 16:53:57 -0700101 /**
102 * this test could take a while to execute. so, designate it as LargetTest
103 */
104 @LargeTest
Vasu Norib18f27d2010-08-12 18:16:35 -0700105 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 }
Vasu Nori65a88832010-07-16 15:14:08 -0700198}