diff --git a/mozilla/storage/public/mozIStorageConnection.idl b/mozilla/storage/public/mozIStorageConnection.idl index 0ec6a11135f..324727e0a75 100644 --- a/mozilla/storage/public/mozIStorageConnection.idl +++ b/mozilla/storage/public/mozIStorageConnection.idl @@ -67,7 +67,10 @@ interface mozIStorageConnection : nsISupports { void close(); /** - * whether the database is open or not + * Indicates if the connection is open and ready to use. This will be false + * if the connection failed to open, or it has been closed. It is strongly + * recommended that the database be backed up before removing the file by + * calling backupDB. */ readonly attribute boolean connectionReady; diff --git a/mozilla/storage/public/mozIStorageService.idl b/mozilla/storage/public/mozIStorageService.idl index 947f59dcd87..7f0af4fc37c 100644 --- a/mozilla/storage/public/mozIStorageService.idl +++ b/mozilla/storage/public/mozIStorageService.idl @@ -70,6 +70,11 @@ interface mozIStorageService : nsISupports { /** * Open a connection to the specified file. * + * Consumers should check mozIStorageConnection::connectionReady to ensure + * that they can use the database. If this value is false, it is strongly + * recommended that the database be backed up with + * mozIStorageConnection::backupDB so user data is not lost. + * * ========== * DANGER * ========== @@ -88,11 +93,13 @@ interface mozIStorageService : nsISupports { * containing virtual tables, it will think the database is corrupted and * throw NS_ERROR_FILE_CORRUPTED. * - * @param aDatabaseFile a nsIFile of the database to open. + * @param aDatabaseFile + * A nsIFile that represents the database that is to be opened.. * * @returns a mozIStorageConnection for the requested database file. * - * @throws NS_ERROR_FAILURE if any operation fails while opening the database. + * @throws NS_ERROR_OUT_OF_MEMORY + * If allocating a new storage object fails. */ mozIStorageConnection openDatabase(in nsIFile aDatabaseFile); @@ -104,6 +111,11 @@ interface mozIStorageService : nsISupports { * of SQLite that is incompatible with a shared cache, like virtual table * and full text indexing support. * + * Consumers should check mozIStorageConnection::connectionReady to ensure + * that they can use the database. If this value is false, it is strongly + * recommended that the database be backed up with + * mozIStorageConnection::backupDB so user data is not lost. + * * ========== * DANGER * ========== @@ -116,11 +128,13 @@ interface mozIStorageService : nsISupports { * The connection object returned by this function is not threadsafe. You must * use it only from the thread you created it from. * - * @param aDatabaseFile a nsIFile of the database to open. + * @param aDatabaseFile + * A nsIFile that represents the database that is to be opened.. * * @returns a mozIStorageConnection for the requested database file. * - * @throws NS_ERROR_FAILURE if any operation fails while opening the database. + * @throws NS_ERROR_OUT_OF_MEMORY + * If allocating a new storage object fails. */ mozIStorageConnection openUnsharedDatabase(in nsIFile aDatabaseFile); diff --git a/mozilla/storage/src/mozStorageService.cpp b/mozilla/storage/src/mozStorageService.cpp index e0b8700204a..63fffb785ea 100644 --- a/mozilla/storage/src/mozStorageService.cpp +++ b/mozilla/storage/src/mozStorageService.cpp @@ -135,10 +135,11 @@ mozStorageService::OpenDatabase(nsIFile *aDatabaseFile, mozIStorageConnection ** if (!msc) return NS_ERROR_OUT_OF_MEMORY; - rv = msc->Initialize (aDatabaseFile); - NS_ENSURE_SUCCESS(rv, rv); - + // We want to return a valid connection regardless if it succeeded or not so + // that consumers can backup the database if it failed. + (void)msc->Initialize(aDatabaseFile); NS_ADDREF(*_retval = msc); + return NS_OK; } @@ -158,11 +159,12 @@ mozStorageService::OpenUnsharedDatabase(nsIFile *aDatabaseFile, mozIStorageConne // lifetimes, unaffected by changes to the shared caches setting, so we can // disable shared caches temporarily while we initialize the new connection // without affecting the caches currently in use by other connections. + // We want to return a valid connection regardless if it succeeded or not so + // that consumers can backup the database if it failed. sqlite3_enable_shared_cache(0); - rv = msc->Initialize (aDatabaseFile); + (void)msc->Initialize(aDatabaseFile); sqlite3_enable_shared_cache(1); - NS_ENSURE_SUCCESS(rv, rv); - NS_ADDREF(*_retval = msc); + return NS_OK; } diff --git a/mozilla/storage/test/unit/corruptDB.sqlite b/mozilla/storage/test/unit/corruptDB.sqlite new file mode 100644 index 00000000000..b234246cac9 Binary files /dev/null and b/mozilla/storage/test/unit/corruptDB.sqlite differ diff --git a/mozilla/storage/test/unit/head_storage.js b/mozilla/storage/test/unit/head_storage.js index 39b10492ba5..1ab904ca401 100644 --- a/mozilla/storage/test/unit/head_storage.js +++ b/mozilla/storage/test/unit/head_storage.js @@ -81,6 +81,7 @@ var gDBConn = null; * whether or not to open a connection to the database that doesn't share * its cache; if true, we use mozIStorageService::openUnsharedDatabase * to create the connection; otherwise we use openDatabase. + * @returns the mozIStorageConnection for the file. */ function getOpenedDatabase(unshared) { @@ -92,6 +93,18 @@ function getOpenedDatabase(unshared) return gDBConn; } +/** + * Obtains a specific database to use. + * + * @param aFile + * The nsIFile representing the db file to open. + * @returns the mozIStorageConnection for the file. + */ +function getDatabase(aFile) +{ + return getService().openDatabase(aFile); +} + function createStatement(aSQL) { return getOpenedDatabase().createStatement(aSQL); diff --git a/mozilla/storage/test/unit/test_bug-416173.js b/mozilla/storage/test/unit/test_bug-416173.js new file mode 100644 index 00000000000..fa3f70977ec --- /dev/null +++ b/mozilla/storage/test/unit/test_bug-416173.js @@ -0,0 +1,68 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Storage Test Code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * This code is based off of like.test from the sqlite code + * + * Contributor(s): + * Shawn Wilsher (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// Tests to make sure that mozIStorageConnection::backupDB works when trying to +// open a corrupted database. + +const BACKUP_FILE_NAME = "test_storage.sqlite.backup"; + +function test_backup_bad_connection() +{ + var msc = getDatabase(do_get_file("storage/test/unit/corruptDB.sqlite")); + do_check_false(msc.connectionReady); + + var backup = msc.backupDB(BACKUP_FILE_NAME); + do_check_eq(BACKUP_FILE_NAME, backup.leafName); + do_check_true(backup.exists()); + + backup.remove(false); +} + +var tests = [test_backup_bad_connection]; + +function run_test() +{ + cleanup(); + + for (var i = 0; i < tests.length; i++) + tests[i](); + + cleanup(); +} +