Skip to content

First attempt to add DatabaseErrorHandler #84

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/net/sqlcipher/DatabaseErrorHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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 net.sqlcipher.database;

import net.sqlcipher.database.SQLiteDatabase;

/**
* An interface to let the apps define the actions to take when the following errors are detected
* database corruption
*/
public interface DatabaseErrorHandler {

/**
* defines the method to be invoked when database corruption is detected.
* @param dbObj the {@link SQLiteDatabase} object representing the database on which corruption
* is detected.
*/
void onCorruption(SQLiteDatabase dbObj);
}
70 changes: 70 additions & 0 deletions src/net/sqlcipher/DefaultDatabaseErrorHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* 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 net.sqlcipher.database;

import java.io.File;
import java.util.List;

import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteException;

import android.util.Log;
import android.util.Pair;

/**
* Default class used to define the actions to take when the database corruption is reported
* by sqlite.
* <p>
* If null is specified for DatabaeErrorHandler param in the above calls, then this class is used
* as the default {@link DatabaseErrorHandler}.
*/
public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler {

private static final String TAG = "DefaultDatabaseErrorHandler";

/**
* defines the default method to be invoked when database corruption is detected.
* @param dbObj the {@link SQLiteDatabase} object representing the database on which corruption
* is detected.
*/
public void onCorruption(SQLiteDatabase dbObj) {
Log.e(TAG, "Corruption reported by sqlite on database: " + dbObj.getPath());

if (dbObj.isOpen()) {
try {
dbObj.close();
} catch (SQLiteException e) {
/* ignore */
}
}

deleteDatabaseFile(dbObj.getPath());
}

private void deleteDatabaseFile(String fileName) {
if (fileName.equalsIgnoreCase(":memory:") || fileName.trim().length() == 0) {
return;
}
Log.e(TAG, "deleting the database file: " + fileName);
try {
new File(fileName).delete();
} catch (Exception e) {
/* print warning and ignore exception */
Log.w(TAG, "delete failed: " + e.getMessage());
}
}
}
21 changes: 12 additions & 9 deletions src/net/sqlcipher/database/SQLiteDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,11 @@ public Cursor newCursor(SQLiteDatabase db,
* @throws SQLiteException if the database cannot be opened
*/
public static SQLiteDatabase openDatabase(String path, String password, CursorFactory factory, int flags, SQLiteDatabaseHook databaseHook) {
return openDatabase(path, password, factory, flags, databaseHook, new DefaultDatabaseErrorHandler());
}

public static SQLiteDatabase openDatabase(String path, String password, CursorFactory factory, int flags, SQLiteDatabaseHook databaseHook,
DatabaseErrorHandler errorHandler) {
SQLiteDatabase sqliteDatabase = null;
try {
// Open the database.
Expand All @@ -906,15 +911,8 @@ public static SQLiteDatabase openDatabase(String path, String password, CursorFa
sqliteDatabase.enableSqlProfiling(path);
}
} catch (SQLiteDatabaseCorruptException e) {
// Try to recover from this, if we can.
// TODO: should we do this for other open failures?
Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
// EventLog.writeEvent(EVENT_DB_CORRUPT, path);
if (!path.equalsIgnoreCase(":memory")) {
// delete is only for non-memory database files
new File(path).delete();
}
sqliteDatabase = new SQLiteDatabase(path, password, factory, flags, databaseHook);
errorHandler.onCorruption(sqliteDatabase);
sqliteDatabase = openDatabase(path, password, factory, flags, databaseHook, errorHandler);
}
ActiveDatabases.getInstance().mActiveDatabases.add(
new WeakReference<SQLiteDatabase>(sqliteDatabase));
Expand All @@ -928,6 +926,11 @@ public static SQLiteDatabase openOrCreateDatabase(File file, String password, Cu
public static SQLiteDatabase openOrCreateDatabase(String path, String password, CursorFactory factory, SQLiteDatabaseHook databaseHook) {
return openDatabase(path, password, factory, CREATE_IF_NECESSARY, databaseHook);
}

public static SQLiteDatabase openOrCreateDatabase(String path, String password, CursorFactory factory, SQLiteDatabaseHook databaseHook,
DatabaseErrorHandler errorHandler) {
return openDatabase(path, password, factory, CREATE_IF_NECESSARY, databaseHook, errorHandler);
}

/**
* Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
Expand Down
34 changes: 32 additions & 2 deletions src/net/sqlcipher/database/SQLiteOpenHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.io.File;

import android.content.Context;
import net.sqlcipher.database.DefaultDatabaseErrorHandler;
import net.sqlcipher.database.SQLiteDatabase.CursorFactory;
import android.util.Log;

Expand All @@ -42,24 +43,53 @@ public abstract class SQLiteOpenHelper {
private SQLiteDatabase mDatabase = null;
private boolean mIsInitializing = false;

private final DatabaseErrorHandler mErrorHandler;

/**
* Create a helper object to create, open, and/or manage a database.
* This method always returns very quickly. The database is not actually
* created or opened until one of {@link #getWritableDatabase} or
* {@link #getReadableDatabase} is called.
*
* @param context to use to open or create the database
* @param name of the database file, or null for an in-memory database
* @param factory to use for creating cursor objects, or null for the default
* @param version number of the database (starting at 1); if the database is older,
* {@link #onUpgrade} will be used to upgrade the database; if the database is
* newer, {@link #onDowngrade} will be used to downgrade the database
*/
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
this(context, name, factory, version, new DefaultDatabaseErrorHandler());
}

/**
* Create a helper object to create, open, and/or manage a database.
* The database is not actually created or opened until one of
* {@link #getWritableDatabase} or {@link #getReadableDatabase} is called.
*
* <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
* used to handle corruption when sqlite reports database corruption.</p>
*
* @param context to use to open or create the database
* @param name of the database file, or null for an in-memory database
* @param factory to use for creating cursor objects, or null for the default
* @param version number of the database (starting at 1); if the database is older,
* {@link #onUpgrade} will be used to upgrade the database
* @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
* corruption.
*/
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
DatabaseErrorHandler errorHandler) {
if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
if (errorHandler == null) {
throw new IllegalArgumentException("DatabaseErrorHandler param value can't be null.");
}

mContext = context;
mName = name;
mFactory = factory;
mNewVersion = version;
mErrorHandler = errorHandler;
}

/**
Expand Down Expand Up @@ -104,7 +134,7 @@ public synchronized SQLiteDatabase getWritableDatabase(String password) {
if (!dbPathFile.exists())
dbPathFile.getParentFile().mkdirs();

db = SQLiteDatabase.openOrCreateDatabase(path, password, mFactory);
db = SQLiteDatabase.openOrCreateDatabase(path, password, mFactory, null, mErrorHandler);

// db = SQLiteDatabase.openDatabase(path,mFactory , SQLiteDatabase.OPEN_READWRITE);

Expand Down