Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e581966 authored by Vasu Nori's avatar Vasu Nori Committed by Android (Google) Code Review
Browse files

Merge "DatabaseCorruptionHandler causes NPE"

parents e24a605d 85f08f9e
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package android.database;

import java.io.File;
import java.util.ArrayList;

import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
@@ -46,7 +47,7 @@ public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler {
            // make the application crash on database open operation. To avoid this problem,
            // the application should provide its own {@link DatabaseErrorHandler} impl class
            // to delete ALL files of the database (including the attached databases).
            if (!dbObj.getPath().equalsIgnoreCase(":memory")) {
            if (!dbObj.getPath().equalsIgnoreCase(":memory:")) {
                // not memory database.
                try {
                    new File(dbObj.getPath()).delete();
@@ -57,8 +58,11 @@ public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler {
            return;
        }

        ArrayList<Pair<String, String>> attachedDbs = null;
        try {
            // Close the database, which will cause subsequent operations to fail.
            // before that, get the attached database list first.
            attachedDbs = dbObj.getAttachedDbs();
            try {
                dbObj.close();
            } catch (SQLiteException e) {
@@ -66,10 +70,13 @@ public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler {
            }
        } finally {
            // Delete all files of this corrupt database and/or attached databases
            for (Pair<String, String> p : dbObj.getAttachedDbs()) {
                Log.e(TAG, "deleting the database file: " + p.second);
                if (!p.second.equalsIgnoreCase(":memory:")) {
            if (attachedDbs != null) {
                for (Pair<String, String> p : attachedDbs) {
                    // delete file if it is a non-memory database file
                    if (p.second.equalsIgnoreCase(":memory:") || p.second.trim().length() == 0) {
                        continue;
                    }
                    Log.e(TAG, "deleting the database file: " + p.second);
                    try {
                        new File(p.second).delete();
                    } catch (Exception e) {
+94 −0
Original line number Diff line number Diff line
@@ -26,9 +26,11 @@ import android.os.Handler;
import android.os.Parcel;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import android.util.Pair;

import junit.framework.Assert;

@@ -1138,4 +1140,96 @@ public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceT
            assertTrue(e.getMessage().contains("cannot set cacheSize to a value less than"));
        }
    }

    @LargeTest
    public void testDefaultDatabaseErrorHandler() {
        DefaultDatabaseErrorHandler errorHandler = new DefaultDatabaseErrorHandler();

        // close the database. and call corruption handler.
        // it should delete the database file.
        File dbfile = new File(mDatabase.getPath());
        mDatabase.close();
        assertFalse(mDatabase.isOpen());
        assertTrue(dbfile.exists());
        try {
            errorHandler.onCorruption(mDatabase);
            assertFalse(dbfile.exists());
        } catch (Exception e) {
            fail("unexpected");
        }

        // create an in-memory database. and corruption handler shouldn't try to delete it
        SQLiteDatabase memoryDb = SQLiteDatabase.openOrCreateDatabase(":memory:", null);
        assertNotNull(memoryDb);
        memoryDb.close();
        assertFalse(memoryDb.isOpen());
        try {
            errorHandler.onCorruption(memoryDb);
        } catch (Exception e) {
            fail("unexpected");
        }

        // create a database, keep it open, call corruption handler. database file should be deleted
        SQLiteDatabase dbObj = SQLiteDatabase.openOrCreateDatabase(mDatabase.getPath(), null);
        assertTrue(dbfile.exists());
        assertNotNull(dbObj);
        assertTrue(dbObj.isOpen());
        try {
            errorHandler.onCorruption(dbObj);
            assertFalse(dbfile.exists());
        } catch (Exception e) {
            fail("unexpected");
        }

        // create a database, attach 2 more databases to it
        //    attached database # 1: ":memory:"
        //    attached database # 2: mDatabase.getPath() + "1";
        // call corruption handler. database files including the one for attached database # 2
        // should be deleted
        String attachedDb1File = mDatabase.getPath() + "1";
        dbObj = SQLiteDatabase.openOrCreateDatabase(mDatabase.getPath(), null);
        dbObj.execSQL("ATTACH DATABASE ':memory:' as memoryDb");
        dbObj.execSQL("ATTACH DATABASE '" +  attachedDb1File + "' as attachedDb1");
        assertTrue(dbfile.exists());
        assertTrue(new File(attachedDb1File).exists());
        assertNotNull(dbObj);
        assertTrue(dbObj.isOpen());
        ArrayList<Pair<String, String>> attachedDbs = dbObj.getAttachedDbs();
        try {
            errorHandler.onCorruption(dbObj);
            assertFalse(dbfile.exists());
            assertFalse(new File(attachedDb1File).exists());
        } catch (Exception e) {
            fail("unexpected");
        }

        // same as above, except this is a bit of stress testing. attach 5 database files
        // and make sure they are all removed.
        int N = 5;
        ArrayList<String> attachedDbFiles = new ArrayList<String>(N);
        for (int i = 0; i < N; i++) {
            attachedDbFiles.add(mDatabase.getPath() + i);
        }
        dbObj = SQLiteDatabase.openOrCreateDatabase(mDatabase.getPath(), null);
        dbObj.execSQL("ATTACH DATABASE ':memory:' as memoryDb");
        for (int i = 0; i < N; i++) {
            dbObj.execSQL("ATTACH DATABASE '" +  attachedDbFiles.get(i) + "' as attachedDb" + i);
        }
        assertTrue(dbfile.exists());
        for (int i = 0; i < N; i++) {
            assertTrue(new File(attachedDbFiles.get(i)).exists());
        }
        assertNotNull(dbObj);
        assertTrue(dbObj.isOpen());
        attachedDbs = dbObj.getAttachedDbs();
        try {
            errorHandler.onCorruption(dbObj);
            assertFalse(dbfile.exists());
            for (int i = 0; i < N; i++) {
                assertFalse(new File(attachedDbFiles.get(i)).exists());
            }
        } catch (Exception e) {
            fail("unexpected");
        }
    }
}