summaryrefslogtreecommitdiffstats
path: root/core/tests
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-01-12 15:03:26 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-01-12 15:03:26 -0800
commit986f00faf44b0d9ed5b1384746ca4254037fc180 (patch)
treeee51ba282c84cc22d2391ff307fdfda10af9b92e /core/tests
parent156936975dec49022681f218b8221ef9e3d87011 (diff)
parente5360fbf3efe85427f7e7f59afe7bbeddb4949ac (diff)
downloadframeworks_base-986f00faf44b0d9ed5b1384746ca4254037fc180.zip
frameworks_base-986f00faf44b0d9ed5b1384746ca4254037fc180.tar.gz
frameworks_base-986f00faf44b0d9ed5b1384746ca4254037fc180.tar.bz2
Merge "Rewrite SQLite database wrappers."
Diffstat (limited to 'core/tests')
-rw-r--r--core/tests/coretests/src/android/database/sqlite/DatabaseConnectionPoolTest.java368
-rw-r--r--core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java48
-rw-r--r--core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java971
-rw-r--r--core/tests/coretests/src/android/database/sqlite/SQLiteStatementTest.java213
-rw-r--r--core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java81
5 files changed, 1 insertions, 1680 deletions
diff --git a/core/tests/coretests/src/android/database/sqlite/DatabaseConnectionPoolTest.java b/core/tests/coretests/src/android/database/sqlite/DatabaseConnectionPoolTest.java
deleted file mode 100644
index 525dd2d..0000000
--- a/core/tests/coretests/src/android/database/sqlite/DatabaseConnectionPoolTest.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.database.sqlite;
-
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabaseTest.ClassToTestSqlCompilationAndCaching;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-public class DatabaseConnectionPoolTest extends AndroidTestCase {
- private static final String TAG = "DatabaseConnectionPoolTest";
-
- private static final int MAX_CONN = 5;
- private static final String TEST_SQL = "select * from test where i = ? AND j = 1";
- private static final String[] TEST_SQLS = new String[] {
- TEST_SQL, TEST_SQL + 1, TEST_SQL + 2, TEST_SQL + 3, TEST_SQL + 4
- };
-
- private SQLiteDatabase mDatabase;
- private File mDatabaseFile;
- private DatabaseConnectionPool mTestPool;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
- mDatabaseFile = new File(dbDir, "database_test.db");
- if (mDatabaseFile.exists()) {
- mDatabaseFile.delete();
- }
- mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
- assertNotNull(mDatabase);
- mDatabase.execSQL("create table test (i int, j int);");
- mTestPool = new DatabaseConnectionPool(mDatabase);
- assertNotNull(mTestPool);
- }
-
- @Override
- protected void tearDown() throws Exception {
- mTestPool.close();
- mDatabase.close();
- mDatabaseFile.delete();
- super.tearDown();
- }
-
- @SmallTest
- public void testGetAndRelease() {
- mTestPool.setMaxPoolSize(MAX_CONN);
- // connections should be lazily created.
- assertEquals(0, mTestPool.getSize());
- // MAX pool size should be set to MAX_CONN
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- // get a connection
- SQLiteDatabase db = mTestPool.get(TEST_SQL);
- // pool size should be one - since only one should be allocated for the above get()
- assertEquals(1, mTestPool.getSize());
- assertEquals(mDatabase, db.mParentConnObj);
- // no free connections should be available
- assertEquals(0, mTestPool.getFreePoolSize());
- assertFalse(mTestPool.isDatabaseObjFree(db));
- // release the connection
- mTestPool.release(db);
- assertEquals(1, mTestPool.getFreePoolSize());
- assertEquals(1, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- assertTrue(mTestPool.isDatabaseObjFree(db));
- // release the same object again and expect IllegalStateException
- try {
- mTestPool.release(db);
- fail("illegalStateException expected");
- } catch (IllegalStateException e ) {
- // expected.
- }
- }
-
- /**
- * get all connections from the pool and ask for one more.
- * should get one of the connections already got so far.
- */
- @SmallTest
- public void testGetAllConnAndOneMore() {
- mTestPool.setMaxPoolSize(MAX_CONN);
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- ArrayList<SQLiteDatabase> dbObjs = new ArrayList<SQLiteDatabase>();
- for (int i = 0; i < MAX_CONN; i++) {
- SQLiteDatabase db = mTestPool.get(TEST_SQL);
- assertFalse(dbObjs.contains(db));
- dbObjs.add(db);
- assertEquals(mDatabase, db.mParentConnObj);
- }
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- // pool is maxed out and no free connections. ask for one more connection
- SQLiteDatabase db1 = mTestPool.get(TEST_SQL);
- // make sure db1 is one of the existing ones
- assertTrue(dbObjs.contains(db1));
- // pool size should remain at MAX_CONN
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- // release db1 but since it is allocated 2 times, it should still remain 'busy'
- mTestPool.release(db1);
- assertFalse(mTestPool.isDatabaseObjFree(db1));
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- // release all connections
- for (int i = 0; i < MAX_CONN; i++) {
- mTestPool.release(dbObjs.get(i));
- }
- // all objects in the pool should be freed now
- assertEquals(MAX_CONN, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- }
-
- /**
- * same as above except that each connection has different SQL statement associated with it.
- */
- @SmallTest
- public void testConnRetrievalForPreviouslySeenSql() {
- mTestPool.setMaxPoolSize(MAX_CONN);
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
-
- HashMap<String, SQLiteDatabase> dbObjs = new HashMap<String, SQLiteDatabase>();
- for (int i = 0; i < MAX_CONN; i++) {
- SQLiteDatabase db = mTestPool.get(TEST_SQLS[i]);
- executeSqlOnDatabaseConn(db, TEST_SQLS[i]);
- assertFalse(dbObjs.values().contains(db));
- dbObjs.put(TEST_SQLS[i], db);
- }
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- // pool is maxed out and no free connections. ask for one more connection
- // use a previously seen SQL statement
- String testSql = TEST_SQLS[MAX_CONN - 1];
- SQLiteDatabase db1 = mTestPool.get(testSql);
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- // make sure db1 is one of the existing ones
- assertTrue(dbObjs.values().contains(db1));
- assertEquals(db1, dbObjs.get(testSql));
- // do the same again
- SQLiteDatabase db2 = mTestPool.get(testSql);
- // make sure db1 is one of the existing ones
- assertEquals(db2, dbObjs.get(testSql));
-
- // pool size should remain at MAX_CONN
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
-
- // release db1 but since the same connection is allocated 3 times,
- // it should still remain 'busy'
- mTestPool.release(db1);
- assertFalse(mTestPool.isDatabaseObjFree(dbObjs.get(testSql)));
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
-
- // release db2 but since the same connection is allocated 2 times,
- // it should still remain 'busy'
- mTestPool.release(db2);
- assertFalse(mTestPool.isDatabaseObjFree(dbObjs.get(testSql)));
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
-
- // release all connections
- for (int i = 0; i < MAX_CONN; i++) {
- mTestPool.release(dbObjs.get(TEST_SQLS[i]));
- }
- // all objects in the pool should be freed now
- assertEquals(MAX_CONN, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- }
-
- private void executeSqlOnDatabaseConn(SQLiteDatabase db, String sql) {
- // get the given sql be compiled on the given database connection.
- // this will help DatabaseConenctionPool figure out if a given SQL statement
- // is already cached by a database connection.
- ClassToTestSqlCompilationAndCaching c =
- ClassToTestSqlCompilationAndCaching.create(db, sql);
- c.close();
- }
-
- /**
- * get a connection for a SQL statement 'blah'. (connection_s)
- * make sure the pool has at least one free connection even after this get().
- * and get a connection for the same SQL again.
- * this connection should be different from connection_s.
- * even though there is a connection with the given SQL pre-compiled, since is it not free
- * AND since the pool has free connections available, should get a new connection.
- */
- @SmallTest
- public void testGetConnForTheSameSql() {
- mTestPool.setMaxPoolSize(MAX_CONN);
-
- SQLiteDatabase db = mTestPool.get(TEST_SQL);
- executeSqlOnDatabaseConn(db, TEST_SQL);
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(1, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
-
- assertFalse(mTestPool.isDatabaseObjFree(db));
-
- SQLiteDatabase db1 = mTestPool.get(TEST_SQL);
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(2, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
-
- assertFalse(mTestPool.isDatabaseObjFree(db1));
- assertFalse(db1.equals(db));
-
- mTestPool.release(db);
- assertEquals(1, mTestPool.getFreePoolSize());
- assertEquals(2, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
-
- mTestPool.release(db1);
- assertEquals(2, mTestPool.getFreePoolSize());
- assertEquals(2, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- }
-
- /**
- * get the same connection N times and release it N times.
- * this tests DatabaseConnectionPool.PoolObj.mNumHolders
- */
- @SmallTest
- public void testGetSameConnNtimesAndReleaseItNtimes() {
- mTestPool.setMaxPoolSize(MAX_CONN);
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
-
- HashMap<String, SQLiteDatabase> dbObjs = new HashMap<String, SQLiteDatabase>();
- for (int i = 0; i < MAX_CONN; i++) {
- SQLiteDatabase db = mTestPool.get(TEST_SQLS[i]);
- executeSqlOnDatabaseConn(db, TEST_SQLS[i]);
- assertFalse(dbObjs.values().contains(db));
- dbObjs.put(TEST_SQLS[i], db);
- }
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- // every connection in the pool should have numHolders = 1
- for (int i = 0; i < MAX_CONN; i ++) {
- assertEquals(1, mTestPool.getPool().get(i).getNumHolders());
- }
- // pool is maxed out and no free connections. ask for one more connection
- // use a previously seen SQL statement
- String testSql = TEST_SQLS[MAX_CONN - 1];
- SQLiteDatabase db1 = mTestPool.get(testSql);
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- // make sure db1 is one of the existing ones
- assertTrue(dbObjs.values().contains(db1));
- assertEquals(db1, dbObjs.get(testSql));
- assertFalse(mTestPool.isDatabaseObjFree(db1));
- DatabaseConnectionPool.PoolObj poolObj = mTestPool.getPool().get(db1.mConnectionNum - 1);
- int numHolders = poolObj.getNumHolders();
- assertEquals(2, numHolders);
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- // get the same connection N times more
- int N = 100;
- for (int i = 0; i < N; i++) {
- SQLiteDatabase db2 = mTestPool.get(testSql);
- assertEquals(db1, db2);
- assertFalse(mTestPool.isDatabaseObjFree(db2));
- // numHolders for this object should be now up by 1
- int prev = numHolders;
- numHolders = poolObj.getNumHolders();
- assertEquals(prev + 1, numHolders);
- }
- // release it N times
- for (int i = 0; i < N; i++) {
- mTestPool.release(db1);
- int prev = numHolders;
- numHolders = poolObj.getNumHolders();
- assertEquals(prev - 1, numHolders);
- assertFalse(mTestPool.isDatabaseObjFree(db1));
- }
- // the connection should still have 2 more holders
- assertFalse(mTestPool.isDatabaseObjFree(db1));
- assertEquals(2, poolObj.getNumHolders());
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- // release 2 more times
- mTestPool.release(db1);
- mTestPool.release(db1);
- assertEquals(0, poolObj.getNumHolders());
- assertEquals(1, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- assertTrue(mTestPool.isDatabaseObjFree(db1));
- }
-
- @SmallTest
- public void testStressTest() {
- mTestPool.setMaxPoolSize(MAX_CONN);
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
-
- HashMap<SQLiteDatabase, Integer> dbMap = new HashMap<SQLiteDatabase, Integer>();
- for (int i = 0; i < MAX_CONN; i++) {
- SQLiteDatabase db = mTestPool.get(TEST_SQLS[i]);
- assertFalse(dbMap.containsKey(db));
- dbMap.put(db, 1);
- executeSqlOnDatabaseConn(db, TEST_SQLS[i]);
- }
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- // ask for lot more connections but since the pool is maxed out, we should start receiving
- // connections that we already got so far
- for (int i = MAX_CONN; i < 1000; i++) {
- SQLiteDatabase db = mTestPool.get(TEST_SQL + i);
- assertTrue(dbMap.containsKey(db));
- int k = dbMap.get(db);
- dbMap.put(db, ++k);
- }
- assertEquals(0, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- // print the distribution of the database connection handles received, should be uniform.
- for (SQLiteDatabase d : dbMap.keySet()) {
- Log.i(TAG, "connection # " + d.mConnectionNum + ", numHolders: " + dbMap.get(d));
- }
- // print the pool info
- Log.i(TAG, mTestPool.toString());
- // release all
- for (SQLiteDatabase d : dbMap.keySet()) {
- int num = dbMap.get(d);
- for (int i = 0; i < num; i++) {
- mTestPool.release(d);
- }
- }
- assertEquals(MAX_CONN, mTestPool.getFreePoolSize());
- assertEquals(MAX_CONN, mTestPool.getSize());
- assertEquals(MAX_CONN, mTestPool.getMaxPoolSize());
- }
-}
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
index f6b1d04..9ccc6e8 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
@@ -21,8 +21,6 @@ import android.content.Context;
import android.database.Cursor;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
import java.io.File;
import java.util.HashSet;
@@ -54,52 +52,8 @@ public class SQLiteCursorTest extends AndroidTestCase {
super.tearDown();
}
- @SmallTest
- public void testQueryObjReassignment() {
- mDatabase.enableWriteAheadLogging();
- // have a few connections in the database connection pool
- DatabaseConnectionPool pool = mDatabase.mConnectionPool;
- pool.setMaxPoolSize(5);
- SQLiteCursor cursor =
- (SQLiteCursor) mDatabase.rawQuery("select * from " + TABLE_NAME, null);
- assertNotNull(cursor);
- // it should use a pooled database connection
- SQLiteDatabase db = cursor.getDatabase();
- assertTrue(db.mConnectionNum > 0);
- assertFalse(mDatabase.equals(db));
- assertEquals(mDatabase, db.mParentConnObj);
- assertTrue(pool.getConnectionList().contains(db));
- assertTrue(db.isOpen());
- // do a requery. cursor should continue to use the above pooled connection
- cursor.requery();
- SQLiteDatabase dbAgain = cursor.getDatabase();
- assertEquals(db, dbAgain);
- // disable WAL so that the pooled connection held by the above cursor is closed
- mDatabase.disableWriteAheadLogging();
- assertFalse(db.isOpen());
- assertNull(mDatabase.mConnectionPool);
- // requery - which should make the cursor use mDatabase connection since the pooled
- // connection is no longer available
- cursor.requery();
- SQLiteDatabase db1 = cursor.getDatabase();
- assertTrue(db1.mConnectionNum == 0);
- assertEquals(mDatabase, db1);
- assertNull(mDatabase.mConnectionPool);
- assertTrue(db1.isOpen());
- assertFalse(mDatabase.equals(db));
- // enable WAL and requery - this time a pooled connection should be used
- mDatabase.enableWriteAheadLogging();
- cursor.requery();
- db = cursor.getDatabase();
- assertTrue(db.mConnectionNum > 0);
- assertFalse(mDatabase.equals(db));
- assertEquals(mDatabase, db.mParentConnObj);
- assertTrue(mDatabase.mConnectionPool.getConnectionList().contains(db));
- assertTrue(db.isOpen());
- }
-
/**
- * this test could take a while to execute. so, designate it as LargetTest
+ * this test could take a while to execute. so, designate it as LargeTest
*/
@LargeTest
public void testFillWindow() {
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
deleted file mode 100644
index 5ef8d11..0000000
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
+++ /dev/null
@@ -1,971 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.database.sqlite;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.DatabaseErrorHandler;
-import android.database.DatabaseUtils;
-import android.database.DefaultDatabaseErrorHandler;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteDatabase.CursorFactory;
-import android.database.sqlite.SQLiteStatement;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.util.Log;
-import android.util.Pair;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-public class SQLiteDatabaseTest extends AndroidTestCase {
- private static final String TAG = "DatabaseGeneralTest";
- private static final String TEST_TABLE = "test";
- private static final int CURRENT_DATABASE_VERSION = 42;
- private SQLiteDatabase mDatabase;
- private File mDatabaseFile;
- private static final int INSERT = 1;
- private static final int UPDATE = 2;
- private static final int DELETE = 3;
- private static final String DB_NAME = "database_test.db";
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- dbSetUp();
- }
-
- @Override
- protected void tearDown() throws Exception {
- dbTeardown();
- super.tearDown();
- }
-
- private void dbTeardown() throws Exception {
- mDatabase.close();
- mDatabaseFile.delete();
- }
-
- private void dbSetUp() throws Exception {
- File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
- mDatabaseFile = new File(dbDir, DB_NAME);
- if (mDatabaseFile.exists()) {
- mDatabaseFile.delete();
- }
- mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null, null);
- assertNotNull(mDatabase);
- mDatabase.setVersion(CURRENT_DATABASE_VERSION);
- }
-
- @SmallTest
- public void testEnableWriteAheadLogging() {
- mDatabase.disableWriteAheadLogging();
- assertNull(mDatabase.mConnectionPool);
- mDatabase.enableWriteAheadLogging();
- DatabaseConnectionPool pool = mDatabase.mConnectionPool;
- assertNotNull(pool);
- // make the same call again and make sure the pool already setup is not re-created
- mDatabase.enableWriteAheadLogging();
- assertEquals(pool, mDatabase.mConnectionPool);
- }
-
- @SmallTest
- public void testDisableWriteAheadLogging() {
- mDatabase.execSQL("create table test (i int);");
- mDatabase.enableWriteAheadLogging();
- assertNotNull(mDatabase.mConnectionPool);
- // get a pooled database connection
- SQLiteDatabase db = mDatabase.getDbConnection("select * from test");
- assertNotNull(db);
- assertFalse(mDatabase.equals(db));
- assertTrue(db.isOpen());
- // disable WAL - which should close connection pool and all pooled connections
- mDatabase.disableWriteAheadLogging();
- assertNull(mDatabase.mConnectionPool);
- assertFalse(db.isOpen());
- }
-
- @SmallTest
- public void testCursorsWithClosedDbConnAfterDisableWriteAheadLogging() {
- mDatabase.disableWriteAheadLogging();
- mDatabase.beginTransactionNonExclusive();
- mDatabase.execSQL("create table test (i int);");
- mDatabase.execSQL("insert into test values(1);");
- mDatabase.setTransactionSuccessful();
- mDatabase.endTransaction();
- mDatabase.enableWriteAheadLogging();
- assertNotNull(mDatabase.mConnectionPool);
- assertEquals(0, mDatabase.mConnectionPool.getSize());
- assertEquals(0, mDatabase.mConnectionPool.getFreePoolSize());
- // get a cursor which should use pooled database connection
- Cursor c = mDatabase.rawQuery("select * from test", null);
- assertEquals(1, c.getCount());
- assertEquals(1, mDatabase.mConnectionPool.getSize());
- assertEquals(1, mDatabase.mConnectionPool.getFreePoolSize());
- SQLiteDatabase db = mDatabase.mConnectionPool.getConnectionList().get(0);
- assertTrue(mDatabase.mConnectionPool.isDatabaseObjFree(db));
- // disable WAL - which should close connection pool and all pooled connections
- mDatabase.disableWriteAheadLogging();
- assertNull(mDatabase.mConnectionPool);
- assertFalse(db.isOpen());
- // cursor data should still be accessible because it is fetching data from CursorWindow
- c.moveToNext();
- assertEquals(1, c.getInt(0));
- c.requery();
- assertEquals(1, c.getCount());
- c.moveToNext();
- assertEquals(1, c.getInt(0));
- c.close();
- }
-
- /**
- * a transaction should be started before a standalone-update/insert/delete statement
- */
- @SmallTest
- public void testStartXactBeforeUpdateSql() throws InterruptedException {
- runTestForStartXactBeforeUpdateSql(INSERT);
- runTestForStartXactBeforeUpdateSql(UPDATE);
- runTestForStartXactBeforeUpdateSql(DELETE);
- }
- private void runTestForStartXactBeforeUpdateSql(int stmtType) throws InterruptedException {
- createTableAndClearCache();
-
- ContentValues values = new ContentValues();
- // make some changes to data in TEST_TABLE
- for (int i = 0; i < 5; i++) {
- values.put("i", i);
- values.put("j", "i" + System.currentTimeMillis());
- mDatabase.insert(TEST_TABLE, null, values);
- switch (stmtType) {
- case UPDATE:
- values.put("j", "u" + System.currentTimeMillis());
- mDatabase.update(TEST_TABLE, values, "i = " + i, null);
- break;
- case DELETE:
- mDatabase.delete(TEST_TABLE, "i = 1", null);
- break;
- }
- }
- // do a query. even though query uses a different database connection,
- // it should still see the above changes to data because the above standalone
- // insert/update/deletes are done in transactions automatically.
- String sql = "select count(*) from " + TEST_TABLE;
- SQLiteStatement stmt = mDatabase.compileStatement(sql);
- final int expectedValue = (stmtType == DELETE) ? 4 : 5;
- assertEquals(expectedValue, stmt.simpleQueryForLong());
- stmt.close();
- Cursor c = mDatabase.rawQuery(sql, null);
- assertEquals(1, c.getCount());
- c.moveToFirst();
- assertEquals(expectedValue, c.getLong(0));
- c.close();
-
- // do 5 more changes in a transaction but do a query before and after the commit
- mDatabase.beginTransaction();
- for (int i = 10; i < 15; i++) {
- values.put("i", i);
- values.put("j", "i" + System.currentTimeMillis());
- mDatabase.insert(TEST_TABLE, null, values);
- switch (stmtType) {
- case UPDATE:
- values.put("j", "u" + System.currentTimeMillis());
- mDatabase.update(TEST_TABLE, values, "i = " + i, null);
- break;
- case DELETE:
- mDatabase.delete(TEST_TABLE, "i = 1", null);
- break;
- }
- }
- mDatabase.setTransactionSuccessful();
- // do a query before commit - should still have 5 rows
- // this query should run in a different thread to force it to use a different database
- // connection
- Thread t = new Thread() {
- @Override public void run() {
- String sql = "select count(*) from " + TEST_TABLE;
- SQLiteStatement stmt = getDb().compileStatement(sql);
- assertEquals(expectedValue, stmt.simpleQueryForLong());
- stmt.close();
- Cursor c = getDb().rawQuery(sql, null);
- assertEquals(1, c.getCount());
- c.moveToFirst();
- assertEquals(expectedValue, c.getLong(0));
- c.close();
- }
- };
- t.start();
- // wait until the above thread is done
- t.join();
- // commit and then query. should see changes from the transaction
- mDatabase.endTransaction();
- stmt = mDatabase.compileStatement(sql);
- final int expectedValue2 = (stmtType == DELETE) ? 9 : 10;
- assertEquals(expectedValue2, stmt.simpleQueryForLong());
- stmt.close();
- c = mDatabase.rawQuery(sql, null);
- assertEquals(1, c.getCount());
- c.moveToFirst();
- assertEquals(expectedValue2, c.getLong(0));
- c.close();
- }
- private synchronized SQLiteDatabase getDb() {
- return mDatabase;
- }
-
- /**
- * Test to ensure that readers are able to read the database data (old versions)
- * EVEN WHEN the writer is in a transaction on the same database.
- *<p>
- * This test starts 1 Writer and 2 Readers and sets up connection pool for readers
- * by calling the method {@link SQLiteDatabase#enableWriteAheadLogging()}.
- * <p>
- * Writer does the following in a tight loop
- * <pre>
- * begin transaction
- * insert into table_1
- * insert into table_2
- * commit
- * </pre>
- * <p>
- * As long a the writer is alive, Readers do the following in a tight loop at the same time
- * <pre>
- * Reader_K does "select count(*) from table_K" where K = 1 or 2
- * </pre>
- * <p>
- * The test is run for TIME_TO_RUN_WAL_TEST_FOR sec.
- * <p>
- * The test is repeated for different connection-pool-sizes (1..3)
- * <p>
- * And at the end of of each test, the following statistics are printed
- * <ul>
- * <li>connection-pool-size</li>
- * <li>number-of-transactions by writer</li>
- * <li>number of reads by reader_K while the writer is IN or NOT-IN xaction</li>
- * </ul>
- */
- @LargeTest
- @Suppress // run this test only if you need to collect the numbers from this test
- public void testConcurrencyEffectsOfConnPool() throws Exception {
- // run the test with sqlite WAL enable
- runConnectionPoolTest(true);
-
- // run the same test WITHOUT sqlite WAL enabled
- runConnectionPoolTest(false);
- }
-
- private void runConnectionPoolTest(boolean useWal) throws Exception {
- int M = 3;
- StringBuilder[] buff = new StringBuilder[M];
- for (int i = 0; i < M; i++) {
- if (useWal) {
- // set up connection pool
- mDatabase.enableWriteAheadLogging();
- mDatabase.mConnectionPool.setMaxPoolSize(i + 1);
- } else {
- mDatabase.disableWriteAheadLogging();
- }
- mDatabase.execSQL("CREATE TABLE t1 (i int, j int);");
- mDatabase.execSQL("CREATE TABLE t2 (i int, j int);");
- mDatabase.beginTransaction();
- for (int k = 0; k < 5; k++) {
- mDatabase.execSQL("insert into t1 values(?,?);", new String[] {k+"", k+""});
- mDatabase.execSQL("insert into t2 values(?,?);", new String[] {k+"", k+""});
- }
- mDatabase.setTransactionSuccessful();
- mDatabase.endTransaction();
-
- // start a writer
- Writer w = new Writer(mDatabase);
-
- // initialize an array of counters to be passed to the readers
- Reader r1 = new Reader(mDatabase, "t1", w, 0);
- Reader r2 = new Reader(mDatabase, "t2", w, 1);
- w.start();
- r1.start();
- r2.start();
-
- // wait for all threads to die
- w.join();
- r1.join();
- r2.join();
-
- // print the stats
- int[][] counts = getCounts();
- buff[i] = new StringBuilder();
- buff[i].append("connpool-size = ");
- buff[i].append(i + 1);
- buff[i].append(", num xacts by writer = ");
- buff[i].append(getNumXacts());
- buff[i].append(", num-reads-in-xact/NOT-in-xact by reader1 = ");
- buff[i].append(counts[0][1] + "/" + counts[0][0]);
- buff[i].append(", by reader2 = ");
- buff[i].append(counts[1][1] + "/" + counts[1][0]);
-
- Log.i(TAG, "done testing for conn-pool-size of " + (i+1));
-
- dbTeardown();
- dbSetUp();
- }
- Log.i(TAG, "duration of test " + TIME_TO_RUN_WAL_TEST_FOR + " sec");
- for (int i = 0; i < M; i++) {
- Log.i(TAG, buff[i].toString());
- }
- }
-
- private boolean inXact = false;
- private int numXacts;
- private static final int TIME_TO_RUN_WAL_TEST_FOR = 15; // num sec this test should run
- private int[][] counts = new int[2][2];
-
- private synchronized boolean inXact() {
- return inXact;
- }
-
- private synchronized void setInXactFlag(boolean flag) {
- inXact = flag;
- }
-
- private synchronized void setCounts(int readerNum, int[] numReads) {
- counts[readerNum][0] = numReads[0];
- counts[readerNum][1] = numReads[1];
- }
-
- private synchronized int[][] getCounts() {
- return counts;
- }
-
- private synchronized void setNumXacts(int num) {
- numXacts = num;
- }
-
- private synchronized int getNumXacts() {
- return numXacts;
- }
-
- private class Writer extends Thread {
- private SQLiteDatabase db = null;
- public Writer(SQLiteDatabase db) {
- this.db = db;
- }
- @Override public void run() {
- // in a loop, for N sec, do the following
- // BEGIN transaction
- // insert into table t1, t2
- // Commit
- long now = System.currentTimeMillis();
- int k;
- for (k = 0;(System.currentTimeMillis() - now) / 1000 < TIME_TO_RUN_WAL_TEST_FOR; k++) {
- db.beginTransactionNonExclusive();
- setInXactFlag(true);
- for (int i = 0; i < 10; i++) {
- db.execSQL("insert into t1 values(?,?);", new String[] {i+"", i+""});
- db.execSQL("insert into t2 values(?,?);", new String[] {i+"", i+""});
- }
- db.setTransactionSuccessful();
- setInXactFlag(false);
- db.endTransaction();
- }
- setNumXacts(k);
- }
- }
-
- private class Reader extends Thread {
- private SQLiteDatabase db = null;
- private String table = null;
- private Writer w = null;
- private int readerNum;
- private int[] numReads = new int[2];
- public Reader(SQLiteDatabase db, String table, Writer w, int readerNum) {
- this.db = db;
- this.table = table;
- this.w = w;
- this.readerNum = readerNum;
- }
- @Override public void run() {
- // while the write is alive, in a loop do the query on a table
- while (w.isAlive()) {
- for (int i = 0; i < 10; i++) {
- DatabaseUtils.longForQuery(db, "select count(*) from " + this.table, null);
- // update count of reads
- numReads[inXact() ? 1 : 0] += 1;
- }
- }
- setCounts(readerNum, numReads);
- }
- }
-
- public static class ClassToTestSqlCompilationAndCaching extends SQLiteProgram {
- private ClassToTestSqlCompilationAndCaching(SQLiteDatabase db, String sql) {
- super(db, sql);
- }
- public static ClassToTestSqlCompilationAndCaching create(SQLiteDatabase db, String sql) {
- db.lock();
- try {
- return new ClassToTestSqlCompilationAndCaching(db, sql);
- } finally {
- db.unlock();
- }
- }
- }
-
- @SmallTest
- public void testLruCachingOfSqliteCompiledSqlObjs() {
- createTableAndClearCache();
- // set cache size
- int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
- mDatabase.setMaxSqlCacheSize(N);
-
- // do N+1 queries - and when the 0th entry is removed from LRU cache due to the
- // insertion of (N+1)th entry, make sure 0th entry is closed
- ArrayList<Integer> stmtObjs = new ArrayList<Integer>();
- ArrayList<String> sqlStrings = new ArrayList<String>();
- int stmt0 = 0;
- for (int i = 0; i < N+1; i++) {
- String s = "insert into test values(" + i + ",?);";
- sqlStrings.add(s);
- ClassToTestSqlCompilationAndCaching c =
- ClassToTestSqlCompilationAndCaching.create(mDatabase, s);
- int n = c.getSqlStatementId();
- stmtObjs.add(i, n);
- if (i == 0) {
- // save the statementId of this obj. we want to make sure it is thrown out of
- // the cache at the end of this test.
- stmt0 = n;
- }
- c.close();
- }
- // is 0'th entry out of the cache? it should be in the list of statementIds
- // corresponding to the pre-compiled sql statements to be finalized.
- assertTrue(mDatabase.getQueuedUpStmtList().contains(stmt0));
- for (int i = 1; i < N+1; i++) {
- SQLiteCompiledSql compSql = mDatabase.getCompiledStatementForSql(sqlStrings.get(i));
- assertNotNull(compSql);
- assertTrue(stmtObjs.contains(compSql.nStatement));
- }
- }
-
- @MediumTest
- public void testDbCloseReleasingAllCachedSql() {
- mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, text1 TEXT, text2 TEXT, " +
- "num1 INTEGER, num2 INTEGER, image BLOB);");
- final String statement = "DELETE FROM test WHERE _id=?;";
- SQLiteStatement statementDoNotClose = mDatabase.compileStatement(statement);
- statementDoNotClose.bindLong(1, 1);
- /* do not close statementDoNotClose object.
- * That should leave it in SQLiteDatabase.mPrograms.
- * mDatabase.close() in tearDown() should release it.
- */
- }
-
- private void createTableAndClearCache() {
- mDatabase.disableWriteAheadLogging();
- mDatabase.execSQL("DROP TABLE IF EXISTS " + TEST_TABLE);
- mDatabase.execSQL("CREATE TABLE " + TEST_TABLE + " (i int, j int);");
- mDatabase.enableWriteAheadLogging();
- mDatabase.lock();
- // flush the above statement from cache and close all the pending statements to be released
- mDatabase.deallocCachedSqlStatements();
- mDatabase.closePendingStatements();
- mDatabase.unlock();
- assertEquals(0, mDatabase.getQueuedUpStmtList().size());
- }
-
- /**
- * test to make sure the statement finalizations are not done right away but
- * piggy-backed onto the next sql statement execution on the same database.
- */
- @SmallTest
- public void testStatementClose() {
- createTableAndClearCache();
- // fill up statement cache in mDatabase
- int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
- mDatabase.setMaxSqlCacheSize(N);
- SQLiteStatement stmt;
- int stmt0Id = 0;
- for (int i = 0; i < N; i ++) {
- ClassToTestSqlCompilationAndCaching c =
- ClassToTestSqlCompilationAndCaching.create(mDatabase,
- "insert into test values(" + i + ", ?);");
- // keep track of 0th entry
- if (i == 0) {
- stmt0Id = c.getSqlStatementId();
- }
- c.close();
- }
-
- // add one more to the cache - and the above 'stmt0Id' should fall out of cache
- ClassToTestSqlCompilationAndCaching stmt1 =
- ClassToTestSqlCompilationAndCaching.create(mDatabase,
- "insert into test values(100, ?);");
- stmt1.close();
-
- // the above close() should have queuedUp the statement for finalization
- ArrayList<Integer> statementIds = mDatabase.getQueuedUpStmtList();
- assertTrue(statementIds.contains(stmt0Id));
-
- // execute something to see if this statement gets finalized
- mDatabase.execSQL("delete from test where i = 10;");
- statementIds = mDatabase.getQueuedUpStmtList();
- assertFalse(statementIds.contains(stmt0Id));
- }
-
- /**
- * same as above - except that the statement to be finalized is from Thread # 1.
- * and it is eventually finalized in Thread # 2 when it executes a SQL statement.
- * @throws InterruptedException
- */
- @LargeTest
- public void testStatementCloseDiffThread() throws InterruptedException {
- createTableAndClearCache();
- final int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
- mDatabase.setMaxSqlCacheSize(N);
- // fill up statement cache in mDatabase in a thread
- Thread t1 = new Thread() {
- @Override public void run() {
- SQLiteStatement stmt;
- for (int i = 0; i < N; i++) {
- ClassToTestSqlCompilationAndCaching c =
- ClassToTestSqlCompilationAndCaching.create(getDb(),
- "insert into test values(" + i + ", ?);");
- // keep track of 0th entry
- if (i == 0) {
- stmt0Id = c.getSqlStatementId();
- }
- c.close();
- }
- }
- };
- t1.start();
- // wait for the thread to finish
- t1.join();
- // mDatabase shouldn't have any statements to be released
- assertEquals(0, mDatabase.getQueuedUpStmtList().size());
-
- // add one more to the cache - and the above 'stmt0Id' should fall out of cache
- // just for the heck of it, do it in a separate thread
- Thread t2 = new Thread() {
- @Override public void run() {
- ClassToTestSqlCompilationAndCaching stmt1 =
- ClassToTestSqlCompilationAndCaching.create(getDb(),
- "insert into test values(100, ?);");
- stmt1.bindLong(1, 1);
- stmt1.close();
- }
- };
- t2.start();
- t2.join();
-
- // close() in the above thread should have queuedUp the stmt0Id for finalization
- ArrayList<Integer> statementIds = getDb().getQueuedUpStmtList();
- assertTrue(statementIds.contains(getStmt0Id()));
- assertEquals(1, statementIds.size());
-
- // execute something to see if this statement gets finalized
- // again do it in a separate thread
- Thread t3 = new Thread() {
- @Override public void run() {
- getDb().execSQL("delete from test where i = 10;");
- }
- };
- t3.start();
- t3.join();
-
- // is the statement finalized?
- statementIds = getDb().getQueuedUpStmtList();
- assertFalse(statementIds.contains(getStmt0Id()));
- }
-
- private volatile int stmt0Id = 0;
- private synchronized int getStmt0Id() {
- return this.stmt0Id;
- }
-
- /**
- * same as above - except that the queue of statements to be finalized are finalized
- * by database close() operation.
- */
- @LargeTest
- public void testStatementCloseByDbClose() throws InterruptedException {
- createTableAndClearCache();
- // fill up statement cache in mDatabase in a thread
- Thread t1 = new Thread() {
- @Override public void run() {
- int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
- getDb().setMaxSqlCacheSize(N);
- SQLiteStatement stmt;
- for (int i = 0; i < N; i ++) {
- ClassToTestSqlCompilationAndCaching c =
- ClassToTestSqlCompilationAndCaching.create(getDb(),
- "insert into test values(" + i + ", ?);");
- // keep track of 0th entry
- if (i == 0) {
- stmt0Id = c.getSqlStatementId();
- }
- c.close();
- }
- }
- };
- t1.start();
- // wait for the thread to finish
- t1.join();
-
- // add one more to the cache - and the above 'stmt0Id' should fall out of cache
- // just for the heck of it, do it in a separate thread
- Thread t2 = new Thread() {
- @Override public void run() {
- ClassToTestSqlCompilationAndCaching stmt1 =
- ClassToTestSqlCompilationAndCaching.create(getDb(),
- "insert into test values(100, ?);");
- stmt1.bindLong(1, 1);
- stmt1.close();
- }
- };
- t2.start();
- t2.join();
-
- // close() in the above thread should have queuedUp the statement for finalization
- ArrayList<Integer> statementIds = getDb().getQueuedUpStmtList();
- assertTrue(getStmt0Id() > 0);
- assertTrue(statementIds.contains(stmt0Id));
- assertEquals(1, statementIds.size());
-
- // close the database. everything from mClosedStatementIds in mDatabase
- // should be finalized and cleared from the list
- // again do it in a separate thread
- Thread t3 = new Thread() {
- @Override public void run() {
- getDb().close();
- }
- };
- t3.start();
- t3.join();
-
- // check mClosedStatementIds in mDatabase. it should be empty
- statementIds = getDb().getQueuedUpStmtList();
- assertEquals(0, statementIds.size());
- }
-
- /**
- * This test tests usage execSQL() to begin transaction works in the following way
- * Thread #1 does
- * execSQL("begin transaction");
- * insert()
- * Thread # 2
- * query()
- * Thread#1 ("end transaction")
- * Thread # 2 query will execute - because java layer will not have locked the SQLiteDatabase
- * object and sqlite will consider this query to be part of the transaction.
- *
- * but if thread # 1 uses beginTransaction() instead of execSQL() to start transaction,
- * then Thread # 2's query will have been blocked by java layer
- * until Thread#1 ends transaction.
- *
- * @throws InterruptedException
- */
- @SmallTest
- public void testExecSqlToStartAndEndTransaction() throws InterruptedException {
- runExecSqlToStartAndEndTransaction("END");
- // same as above, instead now do "COMMIT" or "ROLLBACK" instead of "END" transaction
- runExecSqlToStartAndEndTransaction("COMMIT");
- runExecSqlToStartAndEndTransaction("ROLLBACK");
- }
- private void runExecSqlToStartAndEndTransaction(String str) throws InterruptedException {
- createTableAndClearCache();
- // disable WAL just so queries and updates use the same database connection
- mDatabase.disableWriteAheadLogging();
- mDatabase.execSQL("BEGIN transaction");
- // even though mDatabase.beginTransaction() is not called to start transaction,
- // mDatabase connection should now be in transaction as a result of
- // mDatabase.execSQL("BEGIN transaction")
- // but mDatabase.mLock should not be held by any thread
- assertTrue(mDatabase.inTransaction());
- assertFalse(mDatabase.isDbLockedByCurrentThread());
- assertFalse(mDatabase.isDbLockedByOtherThreads());
- assertTrue(mDatabase.amIInTransaction());
- mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(10, 999);");
- assertTrue(mDatabase.inTransaction());
- assertFalse(mDatabase.isDbLockedByCurrentThread());
- assertFalse(mDatabase.isDbLockedByOtherThreads());
- assertTrue(mDatabase.amIInTransaction());
- Thread t = new Thread() {
- @Override public void run() {
- assertTrue(mDatabase.amIInTransaction());
- assertEquals(999, DatabaseUtils.longForQuery(getDb(),
- "select j from " + TEST_TABLE + " WHERE i = 10", null));
- assertTrue(getDb().inTransaction());
- assertFalse(getDb().isDbLockedByCurrentThread());
- assertFalse(getDb().isDbLockedByOtherThreads());
- assertTrue(mDatabase.amIInTransaction());
- }
- };
- t.start();
- t.join();
- assertTrue(mDatabase.amIInTransaction());
- assertTrue(mDatabase.inTransaction());
- assertFalse(mDatabase.isDbLockedByCurrentThread());
- assertFalse(mDatabase.isDbLockedByOtherThreads());
- mDatabase.execSQL(str);
- assertFalse(mDatabase.amIInTransaction());
- assertFalse(mDatabase.inTransaction());
- assertFalse(mDatabase.isDbLockedByCurrentThread());
- assertFalse(mDatabase.isDbLockedByOtherThreads());
- }
-
- /**
- * test the following
- * http://b/issue?id=2871037
- * Cursor cursor = db.query(...);
- * // with WAL enabled, the above uses a pooled database connection
- * db.beginTransaction()
- * try {
- * db.insert(......);
- * cursor.requery();
- * // since the cursor uses pooled database connection, the above requery
- * // will not return the results that were inserted above since the insert is
- * // done using main database connection AND the transaction is not committed yet.
- * // fix is to make the above cursor use the main database connection - and NOT
- * // the pooled database connection
- * db.setTransactionSuccessful()
- * } finally {
- * db.endTransaction()
- * }
- *
- * @throws InterruptedException
- */
- @SmallTest
- public void testTransactionAndWalInterplay1() throws InterruptedException {
- createTableAndClearCache();
- mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(10, 999);");
- String sql = "select * from " + TEST_TABLE;
- Cursor c = mDatabase.rawQuery(sql, null);
- // should have 1 row in the table
- assertEquals(1, c.getCount());
- mDatabase.beginTransactionNonExclusive();
- try {
- mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(100, 9909);");
- assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
- "select count(*) from " + TEST_TABLE, null));
- // requery on the previously opened cursor
- // cursor should now use the main database connection and see 2 rows
- c.requery();
- assertEquals(2, c.getCount());
- mDatabase.setTransactionSuccessful();
- } finally {
- mDatabase.endTransaction();
- }
- c.close();
-
- // do the same test but now do the requery in a separate thread.
- createTableAndClearCache();
- mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(10, 999);");
- final Cursor c1 = mDatabase.rawQuery("select count(*) from " + TEST_TABLE, null);
- // should have 1 row in the table
- assertEquals(1, c1.getCount());
- mDatabase.beginTransactionNonExclusive();
- try {
- mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(100, 9909);");
- assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
- "select count(*) from " + TEST_TABLE, null));
- // query in a different thread. that causes the cursor to use a pooled connection
- // and since this thread hasn't committed its changes, the cursor should still see only
- // 1 row
- Thread t = new Thread() {
- @Override public void run() {
- c1.requery();
- assertEquals(1, c1.getCount());
- }
- };
- t.start();
- t.join();
- // should be 2 rows now - including the the row inserted above
- mDatabase.setTransactionSuccessful();
- } finally {
- mDatabase.endTransaction();
- }
- c1.close();
- }
-
- /**
- * This test is same as {@link #testTransactionAndWalInterplay1()} except the following:
- * instead of mDatabase.beginTransactionNonExclusive(), use execSQL("BEGIN transaction")
- * and instead of mDatabase.endTransaction(), use execSQL("END");
- */
- @SmallTest
- public void testTransactionAndWalInterplay2() throws InterruptedException {
- createTableAndClearCache();
- mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(10, 999);");
- String sql = "select * from " + TEST_TABLE;
- Cursor c = mDatabase.rawQuery(sql, null);
- // should have 1 row in the table
- assertEquals(1, c.getCount());
- mDatabase.execSQL("BEGIN transaction");
- try {
- mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(100, 9909);");
- assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
- "select count(*) from " + TEST_TABLE, null));
- // requery on the previously opened cursor
- // cursor should now use the main database connection and see 2 rows
- c.requery();
- assertEquals(2, c.getCount());
- } finally {
- mDatabase.execSQL("commit;");
- }
- c.close();
-
- // do the same test but now do the requery in a separate thread.
- createTableAndClearCache();
- mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(10, 999);");
- final Cursor c1 = mDatabase.rawQuery("select count(*) from " + TEST_TABLE, null);
- // should have 1 row in the table
- assertEquals(1, c1.getCount());
- mDatabase.execSQL("BEGIN transaction");
- try {
- mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(100, 9909);");
- assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
- "select count(*) from " + TEST_TABLE, null));
- // query in a different thread. but since the transaction is started using
- // execSQ() instead of beginTransaction(), cursor's query is considered part of
- // the same transaction - and hence it should see the above inserted row
- Thread t = new Thread() {
- @Override public void run() {
- c1.requery();
- assertEquals(1, c1.getCount());
- }
- };
- t.start();
- t.join();
- // should be 2 rows now - including the the row inserted above
- } finally {
- mDatabase.execSQL("commit");
- }
- c1.close();
- }
-
- /**
- * This test is same as {@link #testTransactionAndWalInterplay2()} except the following:
- * instead of committing the data, do rollback and make sure the data seen by the query
- * within the transaction is now gone.
- */
- @SmallTest
- public void testTransactionAndWalInterplay3() {
- createTableAndClearCache();
- mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(10, 999);");
- String sql = "select * from " + TEST_TABLE;
- Cursor c = mDatabase.rawQuery(sql, null);
- // should have 1 row in the table
- assertEquals(1, c.getCount());
- mDatabase.execSQL("BEGIN transaction");
- try {
- mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(100, 9909);");
- assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
- "select count(*) from " + TEST_TABLE, null));
- // requery on the previously opened cursor
- // cursor should now use the main database connection and see 2 rows
- c.requery();
- assertEquals(2, c.getCount());
- } finally {
- // rollback the change
- mDatabase.execSQL("rollback;");
- }
- // since the change is rolled back, do the same query again and should now find only 1 row
- c.requery();
- assertEquals(1, c.getCount());
- assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
- "select count(*) from " + TEST_TABLE, null));
- c.close();
- }
-
- @SmallTest
- public void testAttachDb() {
- String newDb = "/sdcard/mydata.db";
- File f = new File(newDb);
- if (f.exists()) {
- f.delete();
- }
- assertFalse(f.exists());
- SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(newDb, null);
- db.execSQL("create table test1 (i int);");
- db.execSQL("insert into test1 values(1);");
- db.execSQL("insert into test1 values(11);");
- Cursor c = null;
- try {
- c = db.rawQuery("select * from test1", null);
- int count = c.getCount();
- Log.i(TAG, "count: " + count);
- assertEquals(2, count);
- } finally {
- c.close();
- db.close();
- c = null;
- }
-
- mDatabase.execSQL("attach database ? as newDb" , new String[]{newDb});
- Cursor c1 = null;
- try {
- c1 = mDatabase.rawQuery("select * from newDb.test1", null);
- assertEquals(2, c1.getCount());
- } catch (Exception e) {
- fail("unexpected exception: " + e.getMessage());
- } finally {
- if (c1 != null) {
- c1.close();
- }
- }
- List<Pair<String, String>> dbs = mDatabase.getAttachedDbs();
- for (Pair<String, String> p: dbs) {
- Log.i(TAG, "attached dbs: " + p.first + " : " + p.second);
- }
- assertEquals(2, dbs.size());
- }
-
- /**
- * http://b/issue?id=2943028
- * SQLiteOpenHelper maintains a Singleton even if it is in bad state.
- */
- @SmallTest
- public void testCloseAndReopen() {
- mDatabase.close();
- TestOpenHelper helper = new TestOpenHelper(getContext(), DB_NAME, null,
- CURRENT_DATABASE_VERSION, new DefaultDatabaseErrorHandler());
- mDatabase = helper.getWritableDatabase();
- createTableAndClearCache();
- mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(10, 999);");
- Cursor c = mDatabase.query(TEST_TABLE, new String[]{"i", "j"}, null, null, null, null, null);
- assertEquals(1, c.getCount());
- c.close();
- mDatabase.close();
- assertFalse(mDatabase.isOpen());
- mDatabase = helper.getReadableDatabase();
- assertTrue(mDatabase.isOpen());
- c = mDatabase.query(TEST_TABLE, new String[]{"i", "j"}, null, null, null, null, null);
- assertEquals(1, c.getCount());
- c.close();
- }
- private class TestOpenHelper extends SQLiteOpenHelper {
- public TestOpenHelper(Context context, String name, CursorFactory factory, int version,
- DatabaseErrorHandler errorHandler) {
- super(context, name, factory, version, errorHandler);
- }
- @Override public void onCreate(SQLiteDatabase db) {}
- @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
- }
-}
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteStatementTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteStatementTest.java
deleted file mode 100644
index 955336a..0000000
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteStatementTest.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.database.sqlite;
-
-import android.content.Context;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.io.File;
-import java.util.Random;
-import java.util.concurrent.locks.ReentrantLock;
-
-public class SQLiteStatementTest extends AndroidTestCase {
- private SQLiteDatabase mDatabase;
- private File mDatabaseFile;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
- mDatabaseFile = new File(dbDir, "database_test.db");
- if (mDatabaseFile.exists()) {
- mDatabaseFile.delete();
- }
- mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
- assertNotNull(mDatabase);
- }
-
- @Override
- protected void tearDown() throws Exception {
- mDatabase.close();
- mDatabaseFile.delete();
- super.tearDown();
- }
-
- /**
- * Start 2 threads to repeatedly execute the above SQL statement.
- * Even though 2 threads are executing the same SQL, they each should get their own copy of
- * prepared SQL statement id and there SHOULD NOT be an error from sqlite or android.
- * @throws InterruptedException thrown if the test threads started by this test are interrupted
- */
- @LargeTest
- public void testUseOfSameSqlStatementBy2Threads() throws InterruptedException {
- mDatabase.execSQL("CREATE TABLE test_pstmt (i INTEGER PRIMARY KEY, j text);");
- final String stmt = "SELECT * FROM test_pstmt WHERE i = ?";
- class RunStmtThread extends Thread {
- @Override public void run() {
- // do it enough times to make sure there are no corner cases going untested
- for (int i = 0; i < 1000; i++) {
- SQLiteStatement s1 = mDatabase.compileStatement(stmt);
- s1.bindLong(1, i);
- s1.execute();
- s1.close();
- }
- }
- }
- RunStmtThread t1 = new RunStmtThread();
- t1.start();
- RunStmtThread t2 = new RunStmtThread();
- t2.start();
- while (t1.isAlive() || t2.isAlive()) {
- Thread.sleep(10);
- }
- }
-
- /**
- * A simple test: start 2 threads to repeatedly execute the same {@link SQLiteStatement}.
- * The 2 threads take turns to use the {@link SQLiteStatement}; i.e., it is NOT in use
- * by both the threads at the same time.
- *
- * @throws InterruptedException thrown if the test threads started by this test are interrupted
- */
- @LargeTest
- public void testUseOfSameSqliteStatementBy2Threads() throws InterruptedException {
- mDatabase.execSQL("CREATE TABLE test_pstmt (i INTEGER PRIMARY KEY, j text);");
- final String stmt = "SELECT * FROM test_pstmt WHERE i = ?";
- final SQLiteStatement s1 = mDatabase.compileStatement(stmt);
- class RunStmtThread extends Thread {
- @Override public void run() {
- // do it enough times to make sure there are no corner cases going untested
- for (int i = 0; i < 1000; i++) {
- lock();
- try {
- s1.bindLong(1, i);
- s1.execute();
- } finally {
- unlock();
- }
- Thread.yield();
- }
- }
- }
- RunStmtThread t1 = new RunStmtThread();
- t1.start();
- RunStmtThread t2 = new RunStmtThread();
- t2.start();
- while (t1.isAlive() || t2.isAlive()) {
- Thread.sleep(10);
- }
- }
- /** Synchronize on this when accessing the SqliteStatemet in the above */
- private final ReentrantLock mLock = new ReentrantLock(true);
- private void lock() {
- mLock.lock();
- }
- private void unlock() {
- mLock.unlock();
- }
-
- /**
- * Tests the following: a {@link SQLiteStatement} object should not refer to a
- * pre-compiled SQL statement id except in during the period of binding the arguments
- * and executing the SQL statement.
- */
- @LargeTest
- public void testReferenceToPrecompiledStatementId() {
- mDatabase.execSQL("create table t (i int, j text);");
- verifyReferenceToPrecompiledStatementId(false);
- verifyReferenceToPrecompiledStatementId(true);
-
- // a small stress test to make sure there are no side effects of
- // the acquire & release of pre-compiled statement id by SQLiteStatement object.
- for (int i = 0; i < 100; i++) {
- verifyReferenceToPrecompiledStatementId(false);
- verifyReferenceToPrecompiledStatementId(true);
- }
- }
-
- @SuppressWarnings("deprecation")
- private void verifyReferenceToPrecompiledStatementId(boolean wal) {
- if (wal) {
- mDatabase.enableWriteAheadLogging();
- } else {
- mDatabase.disableWriteAheadLogging();
- }
- // test with INSERT statement - doesn't use connection pool, if WAL is set
- SQLiteStatement stmt = mDatabase.compileStatement("insert into t values(?,?);");
- assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
- assertEquals(mDatabase, stmt.mDatabase);
- // sql statement should not be compiled yet
- assertEquals(0, stmt.nStatement);
- assertEquals(0, stmt.getSqlStatementId());
- int colValue = new Random().nextInt();
- stmt.bindLong(1, colValue);
- // verify that the sql statement is still not compiled
- assertEquals(0, stmt.getSqlStatementId());
- // should still be using the mDatabase connection - verify
- assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
- assertEquals(mDatabase, stmt.mDatabase);
- stmt.bindString(2, "blah" + colValue);
- // verify that the sql statement is still not compiled
- assertEquals(0, stmt.getSqlStatementId());
- assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
- assertEquals(mDatabase, stmt.mDatabase);
- stmt.executeInsert();
- // now that the statement is executed, pre-compiled statement should be released
- assertEquals(0, stmt.nStatement);
- assertEquals(0, stmt.getSqlStatementId());
- assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
- assertEquals(mDatabase, stmt.mDatabase);
- stmt.close();
- // pre-compiled SQL statement should still remain released from this object
- assertEquals(0, stmt.nStatement);
- assertEquals(0, stmt.getSqlStatementId());
- // but the database handle should still be the same
- assertEquals(mDatabase, stmt.mDatabase);
-
- // test with a SELECT statement - uses connection pool if WAL is set
- stmt = mDatabase.compileStatement("select i from t where j=?;");
- // sql statement should not be compiled yet
- assertEquals(0, stmt.nStatement);
- assertEquals(0, stmt.getSqlStatementId());
- assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
- assertEquals(mDatabase, stmt.mDatabase);
- stmt.bindString(1, "blah" + colValue);
- // verify that the sql statement is still not compiled
- assertEquals(0, stmt.nStatement);
- assertEquals(0, stmt.getSqlStatementId());
- assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
- assertEquals(mDatabase, stmt.mDatabase);
- // execute the statement
- Long l = stmt.simpleQueryForLong();
- assertEquals(colValue, l.intValue());
- // now that the statement is executed, pre-compiled statement should be released
- assertEquals(0, stmt.nStatement);
- assertEquals(0, stmt.getSqlStatementId());
- assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
- assertEquals(mDatabase, stmt.mDatabase);
- stmt.close();
- // pre-compiled SQL statement should still remain released from this object
- assertEquals(0, stmt.nStatement);
- assertEquals(0, stmt.getSqlStatementId());
- // but the database handle should still remain attached to the statement
- assertEquals(mDatabase.mNativeHandle, stmt.nHandle);
- assertEquals(mDatabase, stmt.mDatabase);
- }
-}
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java
deleted file mode 100644
index cd2005d..0000000
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.database.sqlite;
-
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabaseTest.ClassToTestSqlCompilationAndCaching;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.io.File;
-
-public class SQLiteUnfinalizedExceptionTest extends AndroidTestCase {
- private SQLiteDatabase mDatabase;
- private File mDatabaseFile;
- private static final String TABLE_NAME = "testCursor";
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
- mDatabaseFile = new File(dbDir, "UnfinalizedExceptionTest.db");
- if (mDatabaseFile.exists()) {
- mDatabaseFile.delete();
- }
- mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
- assertNotNull(mDatabase);
- }
-
- @Override
- protected void tearDown() throws Exception {
- mDatabase.close();
- mDatabaseFile.delete();
- super.tearDown();
- }
-
- @SmallTest
- public void testUnfinalizedExceptionNotExcpected() {
- mDatabase.execSQL("CREATE TABLE " + TABLE_NAME + " (i int, j int);");
- // the above statement should be in SQLiteDatabase.mPrograms
- // and should automatically be finalized when database is closed
- mDatabase.lock();
- try {
- mDatabase.closeDatabase();
- } finally {
- mDatabase.unlock();
- }
- }
-
- @SmallTest
- public void testUnfinalizedException() {
- mDatabase.execSQL("CREATE TABLE " + TABLE_NAME + " (i int, j int);");
- mDatabase.lock();
- mDatabase.closePendingStatements(); // clears the above from finalizer queue in mdatabase
- mDatabase.unlock();
- ClassToTestSqlCompilationAndCaching.create(mDatabase, "select * from " + TABLE_NAME);
- // since the above is NOT closed, closing database should fail
- mDatabase.lock();
- try {
- mDatabase.closeDatabase();
- fail("exception expected");
- } catch (SQLiteUnfinalizedObjectsException e) {
- // expected
- } finally {
- mDatabase.unlock();
- }
- }
-}