/* * Copyright (C) 2007 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; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteConstraintException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDoneException; import android.database.sqlite.SQLiteStatement; import android.test.AndroidTestCase; import android.test.PerformanceTestCase; import android.test.suitebuilder.annotation.MediumTest; import java.io.File; public class DatabaseStatementTest extends AndroidTestCase implements PerformanceTestCase { private static final String sString1 = "this is a test"; private static final String sString2 = "and yet another test"; private static final String sString3 = "this string is a little longer, but still a test"; private static final int CURRENT_DATABASE_VERSION = 42; private SQLiteDatabase mDatabase; private File mDatabaseFile; @Override protected void setUp() throws Exception { super.setUp(); File dbDir = getContext().getDir("tests", Context.MODE_PRIVATE); mDatabaseFile = new File(dbDir, "database_test.db"); if (mDatabaseFile.exists()) { mDatabaseFile.delete(); } mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null); assertNotNull(mDatabase); mDatabase.setVersion(CURRENT_DATABASE_VERSION); } @Override protected void tearDown() throws Exception { mDatabase.close(); mDatabaseFile.delete(); super.tearDown(); } public boolean isPerformanceOnly() { return false; } // These test can only be run once. public int startPerformance(Intermediates intermediates) { return 1; } private void populateDefaultTable() { mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);"); mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString1 + "');"); mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString2 + "');"); mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString3 + "');"); } @MediumTest public void testExecuteStatement() throws Exception { populateDefaultTable(); SQLiteStatement statement = mDatabase.compileStatement("DELETE FROM test"); statement.execute(); Cursor c = mDatabase.query("test", null, null, null, null, null, null); assertEquals(0, c.getCount()); c.deactivate(); statement.close(); } @MediumTest public void testSimpleQuery() throws Exception { mDatabase.execSQL("CREATE TABLE test (num INTEGER NOT NULL, str TEXT NOT NULL);"); mDatabase.execSQL("INSERT INTO test VALUES (1234, 'hello');"); SQLiteStatement statement1 = mDatabase.compileStatement("SELECT num FROM test WHERE str = ?"); SQLiteStatement statement2 = mDatabase.compileStatement("SELECT str FROM test WHERE num = ?"); try { statement1.bindString(1, "hello"); long value = statement1.simpleQueryForLong(); assertEquals(1234, value); statement1.bindString(1, "world"); statement1.simpleQueryForLong(); fail("shouldn't get here"); } catch (SQLiteDoneException e) { // expected } try { statement2.bindLong(1, 1234); String value = statement1.simpleQueryForString(); assertEquals("hello", value); statement2.bindLong(1, 5678); statement1.simpleQueryForString(); fail("shouldn't get here"); } catch (SQLiteDoneException e) { // expected } statement1.close(); statement2.close(); } @MediumTest public void testStatementLongBinding() throws Exception { mDatabase.execSQL("CREATE TABLE test (num INTEGER);"); SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)"); for (int i = 0; i < 10; i++) { statement.bindLong(1, i); statement.execute(); } statement.close(); Cursor c = mDatabase.query("test", null, null, null, null, null, null); int numCol = c.getColumnIndexOrThrow("num"); c.moveToFirst(); for (long i = 0; i < 10; i++) { long num = c.getLong(numCol); assertEquals(i, num); c.moveToNext(); } c.close(); } @MediumTest public void testStatementStringBinding() throws Exception { mDatabase.execSQL("CREATE TABLE test (num TEXT);"); SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)"); for (long i = 0; i < 10; i++) { statement.bindString(1, Long.toHexString(i)); statement.execute(); } statement.close(); Cursor c = mDatabase.query("test", null, null, null, null, null, null); int numCol = c.getColumnIndexOrThrow("num"); c.moveToFirst(); for (long i = 0; i < 10; i++) { String num = c.getString(numCol); assertEquals(Long.toHexString(i), num); c.moveToNext(); } c.close(); } @MediumTest public void testStatementClearBindings() throws Exception { mDatabase.execSQL("CREATE TABLE test (num INTEGER);"); SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)"); for (long i = 0; i < 10; i++) { statement.bindLong(1, i); statement.clearBindings(); statement.execute(); } statement.close(); Cursor c = mDatabase.query("test", null, null, null, null, null, "ROWID"); int numCol = c.getColumnIndexOrThrow("num"); assertTrue(c.moveToFirst()); for (long i = 0; i < 10; i++) { assertTrue(c.isNull(numCol)); c.moveToNext(); } c.close(); } @MediumTest public void testSimpleStringBinding() throws Exception { mDatabase.execSQL("CREATE TABLE test (num TEXT, value TEXT);"); String statement = "INSERT INTO test (num, value) VALUES (?,?)"; String[] args = new String[2]; for (int i = 0; i < 2; i++) { args[i] = Integer.toHexString(i); } mDatabase.execSQL(statement, args); Cursor c = mDatabase.query("test", null, null, null, null, null, null); int numCol = c.getColumnIndexOrThrow("num"); int valCol = c.getColumnIndexOrThrow("value"); c.moveToFirst(); String num = c.getString(numCol); assertEquals(Integer.toHexString(0), num); String val = c.getString(valCol); assertEquals(Integer.toHexString(1), val); c.close(); } @MediumTest public void testStatementMultipleBindings() throws Exception { mDatabase.execSQL("CREATE TABLE test (num INTEGER, str TEXT);"); SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num, str) VALUES (?, ?)"); for (long i = 0; i < 10; i++) { statement.bindLong(1, i); statement.bindString(2, Long.toHexString(i)); statement.execute(); } statement.close(); Cursor c = mDatabase.query("test", null, null, null, null, null, "ROWID"); int numCol = c.getColumnIndexOrThrow("num"); int strCol = c.getColumnIndexOrThrow("str"); assertTrue(c.moveToFirst()); for (long i = 0; i < 10; i++) { long num = c.getLong(numCol); String str = c.getString(strCol); assertEquals(i, num); assertEquals(Long.toHexString(i), str); c.moveToNext(); } c.close(); } private static class StatementTestThread extends Thread { private SQLiteDatabase mDatabase; private SQLiteStatement mStatement; public StatementTestThread(SQLiteDatabase db, SQLiteStatement statement) { super(); mDatabase = db; mStatement = statement; } @Override public void run() { mDatabase.beginTransaction(); for (long i = 0; i < 10; i++) { mStatement.bindLong(1, i); mStatement.bindString(2, Long.toHexString(i)); mStatement.execute(); } mDatabase.setTransactionSuccessful(); mDatabase.endTransaction(); Cursor c = mDatabase.query("test", null, null, null, null, null, "ROWID"); int numCol = c.getColumnIndexOrThrow("num"); int strCol = c.getColumnIndexOrThrow("str"); assertTrue(c.moveToFirst()); for (long i = 0; i < 10; i++) { long num = c.getLong(numCol); String str = c.getString(strCol); assertEquals(i, num); assertEquals(Long.toHexString(i), str); c.moveToNext(); } c.close(); } } @MediumTest public void testStatementMultiThreaded() throws Exception { mDatabase.execSQL("CREATE TABLE test (num INTEGER, str TEXT);"); SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num, str) VALUES (?, ?)"); StatementTestThread thread = new StatementTestThread(mDatabase, statement); thread.start(); try { thread.join(); } finally { statement.close(); } } @MediumTest public void testStatementConstraint() throws Exception { mDatabase.execSQL("CREATE TABLE test (num INTEGER NOT NULL);"); SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)"); // Try to insert NULL, which violates the constraint try { statement.clearBindings(); statement.execute(); fail("expected exception not thrown"); } catch (SQLiteConstraintException e) { // expected } // Make sure the statement can still be used statement.bindLong(1, 1); statement.execute(); statement.close(); Cursor c = mDatabase.query("test", null, null, null, null, null, null); int numCol = c.getColumnIndexOrThrow("num"); c.moveToFirst(); long num = c.getLong(numCol); assertEquals(1, num); c.close(); } }