Home | History | Annotate | Download | only in database
      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 package android.database;
     17 
     18 import java.io.File;
     19 import java.util.List;
     20 
     21 import android.database.sqlite.SQLiteDatabase;
     22 import android.database.sqlite.SQLiteException;
     23 import android.util.Log;
     24 import android.util.Pair;
     25 
     26 /**
     27  * Default class used to define the actions to take when the database corruption is reported
     28  * by sqlite.
     29  * <p>
     30  * An application can specify an implementation of {@link DatabaseErrorHandler} on the
     31  * following:
     32  * <ul>
     33  *   <li>{@link SQLiteDatabase#openOrCreateDatabase(String,
     34  *      android.database.sqlite.SQLiteDatabase.CursorFactory, DatabaseErrorHandler)}</li>
     35  *   <li>{@link SQLiteDatabase#openDatabase(String,
     36  *      android.database.sqlite.SQLiteDatabase.CursorFactory, int, DatabaseErrorHandler)}</li>
     37  * </ul>
     38  * The specified {@link DatabaseErrorHandler} is used to handle database corruption errors, if they
     39  * occur.
     40  * <p>
     41  * If null is specified for DatabaeErrorHandler param in the above calls, then this class is used
     42  * as the default {@link DatabaseErrorHandler}.
     43  */
     44 public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler {
     45 
     46     private static final String TAG = "DefaultDatabaseErrorHandler";
     47 
     48     /**
     49      * defines the default method to be invoked when database corruption is detected.
     50      * @param dbObj the {@link SQLiteDatabase} object representing the database on which corruption
     51      * is detected.
     52      */
     53     public void onCorruption(SQLiteDatabase dbObj) {
     54         Log.e(TAG, "Corruption reported by sqlite on database: " + dbObj.getPath());
     55 
     56         // is the corruption detected even before database could be 'opened'?
     57         if (!dbObj.isOpen()) {
     58             // database files are not even openable. delete this database file.
     59             // NOTE if the database has attached databases, then any of them could be corrupt.
     60             // and not deleting all of them could cause corrupted database file to remain and
     61             // make the application crash on database open operation. To avoid this problem,
     62             // the application should provide its own {@link DatabaseErrorHandler} impl class
     63             // to delete ALL files of the database (including the attached databases).
     64             deleteDatabaseFile(dbObj.getPath());
     65             return;
     66         }
     67 
     68         List<Pair<String, String>> attachedDbs = null;
     69         try {
     70             // Close the database, which will cause subsequent operations to fail.
     71             // before that, get the attached database list first.
     72             try {
     73                 attachedDbs = dbObj.getAttachedDbs();
     74             } catch (SQLiteException e) {
     75                 /* ignore */
     76             }
     77             try {
     78                 dbObj.close();
     79             } catch (SQLiteException e) {
     80                 /* ignore */
     81             }
     82         } finally {
     83             // Delete all files of this corrupt database and/or attached databases
     84             if (attachedDbs != null) {
     85                 for (Pair<String, String> p : attachedDbs) {
     86                     deleteDatabaseFile(p.second);
     87                 }
     88             } else {
     89                 // attachedDbs = null is possible when the database is so corrupt that even
     90                 // "PRAGMA database_list;" also fails. delete the main database file
     91                 deleteDatabaseFile(dbObj.getPath());
     92             }
     93         }
     94     }
     95 
     96     private void deleteDatabaseFile(String fileName) {
     97         if (fileName.equalsIgnoreCase(":memory:") || fileName.trim().length() == 0) {
     98             return;
     99         }
    100         Log.e(TAG, "deleting the database file: " + fileName);
    101         try {
    102             new File(fileName).delete();
    103         } catch (Exception e) {
    104             /* print warning and ignore exception */
    105             Log.w(TAG, "delete failed: " + e.getMessage());
    106         }
    107     }
    108 }
    109