LCOV - code coverage report
Current view: directory - dom/indexedDB - OpenDatabaseHelper.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 964 364 37.8 %
Date: 2012-06-02 Functions: 70 36 51.4 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is Indexed Database.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is
      17                 :  * The Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Ben Turner <bent.mozilla@gmail.com>
      23                 :  *   Kyle Huey <me@kylehuey.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "OpenDatabaseHelper.h"
      40                 : 
      41                 : #include "nsIFile.h"
      42                 : 
      43                 : #include "mozilla/storage.h"
      44                 : #include "nsContentUtils.h"
      45                 : #include "nsEscape.h"
      46                 : #include "nsThreadUtils.h"
      47                 : #include "snappy/snappy.h"
      48                 : #include "test_quota.h"
      49                 : 
      50                 : #include "IDBEvents.h"
      51                 : #include "IDBFactory.h"
      52                 : #include "IndexedDatabaseManager.h"
      53                 : 
      54                 : using namespace mozilla;
      55                 : USING_INDEXEDDB_NAMESPACE
      56                 : 
      57                 : namespace {
      58                 : 
      59                 : // If JS_STRUCTURED_CLONE_VERSION changes then we need to update our major
      60                 : // schema version.
      61                 : PR_STATIC_ASSERT(JS_STRUCTURED_CLONE_VERSION == 1);
      62                 : 
      63                 : // Major schema version. Bump for almost everything.
      64                 : const PRUint32 kMajorSchemaVersion = 12;
      65                 : 
      66                 : // Minor schema version. Should almost always be 0 (maybe bump on release
      67                 : // branches if we have to).
      68                 : const PRUint32 kMinorSchemaVersion = 0;
      69                 : 
      70                 : // The schema version we store in the SQLite database is a (signed) 32-bit
      71                 : // integer. The major version is left-shifted 4 bits so the max value is
      72                 : // 0xFFFFFFF. The minor version occupies the lower 4 bits and its max is 0xF.
      73                 : PR_STATIC_ASSERT(kMajorSchemaVersion <= 0xFFFFFFF);
      74                 : PR_STATIC_ASSERT(kMajorSchemaVersion <= 0xF);
      75                 : 
      76                 : inline
      77                 : PRInt32
      78               0 : MakeSchemaVersion(PRUint32 aMajorSchemaVersion,
      79                 :                   PRUint32 aMinorSchemaVersion)
      80                 : {
      81               0 :   return PRInt32((aMajorSchemaVersion << 4) + aMinorSchemaVersion);
      82                 : }
      83                 : 
      84                 : const PRInt32 kSQLiteSchemaVersion = PRInt32((kMajorSchemaVersion << 4) +
      85                 :                                              kMinorSchemaVersion);
      86                 : 
      87                 : inline
      88                 : PRUint32 GetMajorSchemaVersion(PRInt32 aSchemaVersion)
      89                 : {
      90                 :   return PRUint32(aSchemaVersion) >> 4;
      91                 : }
      92                 : 
      93                 : inline
      94                 : PRUint32 GetMinorSchemaVersion(PRInt32 aSchemaVersion)
      95                 : {
      96                 :   return PRUint32(aSchemaVersion) & 0xF;
      97                 : }
      98                 : 
      99                 : nsresult
     100              76 : GetDatabaseFilename(const nsAString& aName,
     101                 :                     nsAString& aDatabaseFilename)
     102                 : {
     103              76 :   aDatabaseFilename.AppendInt(HashString(aName));
     104                 : 
     105             152 :   nsCString escapedName;
     106              76 :   if (!NS_Escape(NS_ConvertUTF16toUTF8(aName), escapedName, url_XPAlphas)) {
     107               0 :     NS_WARNING("Can't escape database name!");
     108               0 :     return NS_ERROR_UNEXPECTED;
     109                 :   }
     110                 : 
     111              76 :   const char* forwardIter = escapedName.BeginReading();
     112              76 :   const char* backwardIter = escapedName.EndReading() - 1;
     113                 : 
     114             152 :   nsCString substring;
     115            1127 :   while (forwardIter <= backwardIter && substring.Length() < 21) {
     116             975 :     if (substring.Length() % 2) {
     117             450 :       substring.Append(*backwardIter--);
     118                 :     }
     119                 :     else {
     120             525 :       substring.Append(*forwardIter++);
     121                 :     }
     122                 :   }
     123                 : 
     124              76 :   aDatabaseFilename.Append(NS_ConvertASCIItoUTF16(substring));
     125                 : 
     126              76 :   return NS_OK;
     127                 : }
     128                 : 
     129                 : nsresult
     130              52 : CreateFileTables(mozIStorageConnection* aDBConn)
     131                 : {
     132                 :   // Table `file`
     133              52 :   nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     134                 :     "CREATE TABLE file ("
     135                 :       "id INTEGER PRIMARY KEY, "
     136                 :       "refcount INTEGER NOT NULL"
     137                 :     ");"
     138              52 :   ));
     139              52 :   NS_ENSURE_SUCCESS(rv, rv);
     140                 : 
     141              52 :   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     142                 :     "CREATE TRIGGER object_data_insert_trigger "
     143                 :     "AFTER INSERT ON object_data "
     144                 :     "FOR EACH ROW "
     145                 :     "WHEN NEW.file_ids IS NOT NULL "
     146                 :     "BEGIN "
     147                 :       "SELECT update_refcount(NULL, NEW.file_ids); "
     148                 :     "END;"
     149              52 :   ));
     150              52 :   NS_ENSURE_SUCCESS(rv, rv);
     151                 : 
     152              52 :   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     153                 :     "CREATE TRIGGER object_data_update_trigger "
     154                 :     "AFTER UPDATE OF file_ids ON object_data "
     155                 :     "FOR EACH ROW "
     156                 :     "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
     157                 :     "BEGIN "
     158                 :       "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
     159                 :     "END;"
     160              52 :   ));
     161              52 :   NS_ENSURE_SUCCESS(rv, rv);
     162                 : 
     163              52 :   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     164                 :     "CREATE TRIGGER object_data_delete_trigger "
     165                 :     "AFTER DELETE ON object_data "
     166                 :     "FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
     167                 :     "BEGIN "
     168                 :       "SELECT update_refcount(OLD.file_ids, NULL); "
     169                 :     "END;"
     170              52 :   ));
     171              52 :   NS_ENSURE_SUCCESS(rv, rv);
     172                 : 
     173              52 :   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     174                 :     "CREATE TRIGGER file_update_trigger "
     175                 :     "AFTER UPDATE ON file "
     176                 :     "FOR EACH ROW WHEN NEW.refcount = 0 "
     177                 :     "BEGIN "
     178                 :       "DELETE FROM file WHERE id = OLD.id; "
     179                 :     "END;"
     180              52 :   ));
     181              52 :   NS_ENSURE_SUCCESS(rv, rv);
     182                 : 
     183              52 :   return NS_OK;
     184                 : }
     185                 : 
     186                 : nsresult
     187              52 : CreateTables(mozIStorageConnection* aDBConn)
     188                 : {
     189              52 :   NS_PRECONDITION(!NS_IsMainThread(),
     190                 :                   "Creating tables on the main thread!");
     191              52 :   NS_PRECONDITION(aDBConn, "Passing a null database connection!");
     192                 : 
     193                 :   // Table `database`
     194              52 :   nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     195                 :     "CREATE TABLE database ("
     196                 :       "name TEXT NOT NULL, "
     197                 :       "version INTEGER NOT NULL DEFAULT 0"
     198                 :     ");"
     199              52 :   ));
     200              52 :   NS_ENSURE_SUCCESS(rv, rv);
     201                 : 
     202                 :   // Table `object_store`
     203              52 :   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     204                 :     "CREATE TABLE object_store ("
     205                 :       "id INTEGER PRIMARY KEY, "
     206                 :       "auto_increment INTEGER NOT NULL DEFAULT 0, "
     207                 :       "name TEXT NOT NULL, "
     208                 :       "key_path TEXT, "
     209                 :       "UNIQUE (name)"
     210                 :     ");"
     211              52 :   ));
     212              52 :   NS_ENSURE_SUCCESS(rv, rv);
     213                 : 
     214                 :   // Table `object_data`
     215              52 :   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     216                 :     "CREATE TABLE object_data ("
     217                 :       "id INTEGER PRIMARY KEY, "
     218                 :       "object_store_id INTEGER NOT NULL, "
     219                 :       "key_value BLOB DEFAULT NULL, "
     220                 :       "file_ids TEXT, "
     221                 :       "data BLOB NOT NULL, "
     222                 :       "UNIQUE (object_store_id, key_value), "
     223                 :       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
     224                 :         "CASCADE"
     225                 :     ");"
     226              52 :   ));
     227              52 :   NS_ENSURE_SUCCESS(rv, rv);
     228                 : 
     229                 :   // Table `index`
     230              52 :   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     231                 :     "CREATE TABLE object_store_index ("
     232                 :       "id INTEGER PRIMARY KEY, "
     233                 :       "object_store_id INTEGER NOT NULL, "
     234                 :       "name TEXT NOT NULL, "
     235                 :       "key_path TEXT NOT NULL, "
     236                 :       "unique_index INTEGER NOT NULL, "
     237                 :       "multientry INTEGER NOT NULL, "
     238                 :       "UNIQUE (object_store_id, name), "
     239                 :       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
     240                 :         "CASCADE"
     241                 :     ");"
     242              52 :   ));
     243              52 :   NS_ENSURE_SUCCESS(rv, rv);
     244                 : 
     245                 :   // Table `index_data`
     246              52 :   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     247                 :     "CREATE TABLE index_data ("
     248                 :       "index_id INTEGER NOT NULL, "
     249                 :       "value BLOB NOT NULL, "
     250                 :       "object_data_key BLOB NOT NULL, "
     251                 :       "object_data_id INTEGER NOT NULL, "
     252                 :       "PRIMARY KEY (index_id, value, object_data_key), "
     253                 :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
     254                 :         "CASCADE, "
     255                 :       "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
     256                 :         "CASCADE"
     257                 :     ");"
     258              52 :   ));
     259              52 :   NS_ENSURE_SUCCESS(rv, rv);
     260                 : 
     261                 :   // Need this to make cascading deletes from object_data and object_store fast.
     262              52 :   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     263                 :     "CREATE INDEX index_data_object_data_id_index "
     264                 :     "ON index_data (object_data_id);"
     265              52 :   ));
     266              52 :   NS_ENSURE_SUCCESS(rv, rv);
     267                 : 
     268                 :   // Table `unique_index_data`
     269              52 :   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     270                 :     "CREATE TABLE unique_index_data ("
     271                 :       "index_id INTEGER NOT NULL, "
     272                 :       "value BLOB NOT NULL, "
     273                 :       "object_data_key BLOB NOT NULL, "
     274                 :       "object_data_id INTEGER NOT NULL, "
     275                 :       "PRIMARY KEY (index_id, value, object_data_key), "
     276                 :       "UNIQUE (index_id, value), "
     277                 :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
     278                 :         "CASCADE "
     279                 :       "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
     280                 :         "CASCADE"
     281                 :     ");"
     282              52 :   ));
     283              52 :   NS_ENSURE_SUCCESS(rv, rv);
     284                 : 
     285                 :   // Need this to make cascading deletes from object_data and object_store fast.
     286              52 :   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     287                 :     "CREATE INDEX unique_index_data_object_data_id_index "
     288                 :     "ON unique_index_data (object_data_id);"
     289              52 :   ));
     290              52 :   NS_ENSURE_SUCCESS(rv, rv);
     291                 : 
     292              52 :   rv = CreateFileTables(aDBConn);
     293              52 :   NS_ENSURE_SUCCESS(rv, rv);
     294                 : 
     295              52 :   rv = aDBConn->SetSchemaVersion(kSQLiteSchemaVersion);
     296              52 :   NS_ENSURE_SUCCESS(rv, rv);
     297                 : 
     298              52 :   return NS_OK;
     299                 : }
     300                 : 
     301                 : nsresult
     302               0 : UpgradeSchemaFrom4To5(mozIStorageConnection* aConnection)
     303                 : {
     304                 :   nsresult rv;
     305                 : 
     306                 :   // All we changed is the type of the version column, so lets try to
     307                 :   // convert that to an integer, and if we fail, set it to 0.
     308               0 :   nsCOMPtr<mozIStorageStatement> stmt;
     309               0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     310                 :     "SELECT name, version, dataVersion "
     311                 :     "FROM database"
     312               0 :   ), getter_AddRefs(stmt));
     313               0 :   NS_ENSURE_SUCCESS(rv, rv);
     314                 : 
     315               0 :   nsString name;
     316                 :   PRInt32 intVersion;
     317                 :   PRInt64 dataVersion;
     318                 : 
     319                 :   {
     320               0 :     mozStorageStatementScoper scoper(stmt);
     321                 : 
     322                 :     bool hasResults;
     323               0 :     rv = stmt->ExecuteStep(&hasResults);
     324               0 :     NS_ENSURE_SUCCESS(rv, rv);
     325               0 :     NS_ENSURE_TRUE(hasResults, NS_ERROR_FAILURE);
     326                 : 
     327               0 :     nsString version;
     328               0 :     rv = stmt->GetString(1, version);
     329               0 :     NS_ENSURE_SUCCESS(rv, rv);
     330                 : 
     331               0 :     intVersion = version.ToInteger(&rv, 10);
     332               0 :     if (NS_FAILED(rv)) {
     333               0 :       intVersion = 0;
     334                 :     }
     335                 : 
     336               0 :     rv = stmt->GetString(0, name);
     337               0 :     NS_ENSURE_SUCCESS(rv, rv);
     338                 : 
     339               0 :     rv = stmt->GetInt64(2, &dataVersion);
     340               0 :     NS_ENSURE_SUCCESS(rv, rv);
     341                 :   }
     342                 : 
     343               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     344                 :     "DROP TABLE database"
     345               0 :   ));
     346               0 :   NS_ENSURE_SUCCESS(rv, rv);
     347                 : 
     348               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     349                 :     "CREATE TABLE database ("
     350                 :       "name TEXT NOT NULL, "
     351                 :       "version INTEGER NOT NULL DEFAULT 0, "
     352                 :       "dataVersion INTEGER NOT NULL"
     353                 :     ");"
     354               0 :   ));
     355               0 :   NS_ENSURE_SUCCESS(rv, rv);
     356                 : 
     357               0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     358                 :     "INSERT INTO database (name, version, dataVersion) "
     359                 :     "VALUES (:name, :version, :dataVersion)"
     360               0 :   ), getter_AddRefs(stmt));
     361               0 :   NS_ENSURE_SUCCESS(rv, rv);
     362                 : 
     363                 :   {
     364               0 :     mozStorageStatementScoper scoper(stmt);
     365                 : 
     366               0 :     rv = stmt->BindStringParameter(0, name);
     367               0 :     NS_ENSURE_SUCCESS(rv, rv);
     368                 : 
     369               0 :     rv = stmt->BindInt32Parameter(1, intVersion);
     370               0 :     NS_ENSURE_SUCCESS(rv, rv);
     371                 : 
     372               0 :     rv = stmt->BindInt64Parameter(2, dataVersion);
     373               0 :     NS_ENSURE_SUCCESS(rv, rv);
     374                 : 
     375               0 :     rv = stmt->Execute();
     376               0 :     NS_ENSURE_SUCCESS(rv, rv);
     377                 :   }
     378                 : 
     379               0 :   rv = aConnection->SetSchemaVersion(5);
     380               0 :   NS_ENSURE_SUCCESS(rv, rv);
     381                 : 
     382               0 :   return NS_OK;
     383                 : }
     384                 : 
     385                 : nsresult
     386               0 : UpgradeSchemaFrom5To6(mozIStorageConnection* aConnection)
     387                 : {
     388                 :   // First, drop all the indexes we're no longer going to use.
     389               0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     390                 :     "DROP INDEX key_index;"
     391               0 :   ));
     392               0 :   NS_ENSURE_SUCCESS(rv, rv);
     393                 : 
     394               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     395                 :     "DROP INDEX ai_key_index;"
     396               0 :   ));
     397               0 :   NS_ENSURE_SUCCESS(rv, rv);
     398                 : 
     399               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     400                 :     "DROP INDEX value_index;"
     401               0 :   ));
     402               0 :   NS_ENSURE_SUCCESS(rv, rv);
     403                 : 
     404               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     405                 :     "DROP INDEX ai_value_index;"
     406               0 :   ));
     407               0 :   NS_ENSURE_SUCCESS(rv, rv);
     408                 : 
     409                 :   // Now, reorder the columns of object_data to put the blob data last. We do
     410                 :   // this by copying into a temporary table, dropping the original, then copying
     411                 :   // back into a newly created table.
     412               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     413                 :     "CREATE TEMPORARY TABLE temp_upgrade ("
     414                 :       "id INTEGER PRIMARY KEY, "
     415                 :       "object_store_id, "
     416                 :       "key_value, "
     417                 :       "data "
     418                 :     ");"
     419               0 :   ));
     420               0 :   NS_ENSURE_SUCCESS(rv, rv);
     421                 : 
     422               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     423                 :     "INSERT INTO temp_upgrade "
     424                 :       "SELECT id, object_store_id, key_value, data "
     425                 :       "FROM object_data;"
     426               0 :   ));
     427               0 :   NS_ENSURE_SUCCESS(rv, rv);
     428                 : 
     429               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     430                 :     "DROP TABLE object_data;"
     431               0 :   ));
     432               0 :   NS_ENSURE_SUCCESS(rv, rv);
     433                 : 
     434               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     435                 :     "CREATE TABLE object_data ("
     436                 :       "id INTEGER PRIMARY KEY, "
     437                 :       "object_store_id INTEGER NOT NULL, "
     438                 :       "key_value DEFAULT NULL, "
     439                 :       "data BLOB NOT NULL, "
     440                 :       "UNIQUE (object_store_id, key_value), "
     441                 :       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
     442                 :         "CASCADE"
     443                 :     ");"
     444               0 :   ));
     445               0 :   NS_ENSURE_SUCCESS(rv, rv);
     446                 : 
     447               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     448                 :     "INSERT INTO object_data "
     449                 :       "SELECT id, object_store_id, key_value, data "
     450                 :       "FROM temp_upgrade;"
     451               0 :   ));
     452               0 :   NS_ENSURE_SUCCESS(rv, rv);
     453                 : 
     454               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     455                 :     "DROP TABLE temp_upgrade;"
     456               0 :   ));
     457               0 :   NS_ENSURE_SUCCESS(rv, rv);
     458                 : 
     459                 :   // We need to add a unique constraint to our ai_object_data table. Copy all
     460                 :   // the data out of it using a temporary table as before.
     461               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     462                 :     "CREATE TEMPORARY TABLE temp_upgrade ("
     463                 :       "id INTEGER PRIMARY KEY, "
     464                 :       "object_store_id, "
     465                 :       "data "
     466                 :     ");"
     467               0 :   ));
     468               0 :   NS_ENSURE_SUCCESS(rv, rv);
     469                 : 
     470               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     471                 :     "INSERT INTO temp_upgrade "
     472                 :       "SELECT id, object_store_id, data "
     473                 :       "FROM ai_object_data;"
     474               0 :   ));
     475               0 :   NS_ENSURE_SUCCESS(rv, rv);
     476                 : 
     477               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     478                 :     "DROP TABLE ai_object_data;"
     479               0 :   ));
     480               0 :   NS_ENSURE_SUCCESS(rv, rv);
     481                 : 
     482               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     483                 :     "CREATE TABLE ai_object_data ("
     484                 :       "id INTEGER PRIMARY KEY AUTOINCREMENT, "
     485                 :       "object_store_id INTEGER NOT NULL, "
     486                 :       "data BLOB NOT NULL, "
     487                 :       "UNIQUE (object_store_id, id), "
     488                 :       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
     489                 :         "CASCADE"
     490                 :     ");"
     491               0 :   ));
     492               0 :   NS_ENSURE_SUCCESS(rv, rv);
     493                 : 
     494               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     495                 :     "INSERT INTO ai_object_data "
     496                 :       "SELECT id, object_store_id, data "
     497                 :       "FROM temp_upgrade;"
     498               0 :   ));
     499               0 :   NS_ENSURE_SUCCESS(rv, rv);
     500                 : 
     501               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     502                 :     "DROP TABLE temp_upgrade;"
     503               0 :   ));
     504               0 :   NS_ENSURE_SUCCESS(rv, rv);
     505                 : 
     506                 :   // Fix up the index_data table. We're reordering the columns as well as
     507                 :   // changing the primary key from being a simple id to being a composite.
     508               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     509                 :     "CREATE TEMPORARY TABLE temp_upgrade ("
     510                 :       "index_id, "
     511                 :       "value, "
     512                 :       "object_data_key, "
     513                 :       "object_data_id "
     514                 :     ");"
     515               0 :   ));
     516               0 :   NS_ENSURE_SUCCESS(rv, rv);
     517                 : 
     518               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     519                 :     "INSERT INTO temp_upgrade "
     520                 :       "SELECT index_id, value, object_data_key, object_data_id "
     521                 :       "FROM index_data;"
     522               0 :   ));
     523               0 :   NS_ENSURE_SUCCESS(rv, rv);
     524                 : 
     525               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     526                 :     "DROP TABLE index_data;"
     527               0 :   ));
     528               0 :   NS_ENSURE_SUCCESS(rv, rv);
     529                 : 
     530               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     531                 :     "CREATE TABLE index_data ("
     532                 :       "index_id INTEGER NOT NULL, "
     533                 :       "value NOT NULL, "
     534                 :       "object_data_key NOT NULL, "
     535                 :       "object_data_id INTEGER NOT NULL, "
     536                 :       "PRIMARY KEY (index_id, value, object_data_key), "
     537                 :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
     538                 :         "CASCADE, "
     539                 :       "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
     540                 :         "CASCADE"
     541                 :     ");"
     542               0 :   ));
     543               0 :   NS_ENSURE_SUCCESS(rv, rv);
     544                 : 
     545               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     546                 :     "INSERT OR IGNORE INTO index_data "
     547                 :       "SELECT index_id, value, object_data_key, object_data_id "
     548                 :       "FROM temp_upgrade;"
     549               0 :   ));
     550               0 :   NS_ENSURE_SUCCESS(rv, rv);
     551                 : 
     552               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     553                 :     "DROP TABLE temp_upgrade;"
     554               0 :   ));
     555               0 :   NS_ENSURE_SUCCESS(rv, rv);
     556                 : 
     557               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     558                 :     "CREATE INDEX index_data_object_data_id_index "
     559                 :     "ON index_data (object_data_id);"
     560               0 :   ));
     561               0 :   NS_ENSURE_SUCCESS(rv, rv);
     562                 : 
     563                 :   // Fix up the unique_index_data table. We're reordering the columns as well as
     564                 :   // changing the primary key from being a simple id to being a composite.
     565               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     566                 :     "CREATE TEMPORARY TABLE temp_upgrade ("
     567                 :       "index_id, "
     568                 :       "value, "
     569                 :       "object_data_key, "
     570                 :       "object_data_id "
     571                 :     ");"
     572               0 :   ));
     573               0 :   NS_ENSURE_SUCCESS(rv, rv);
     574                 : 
     575               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     576                 :     "INSERT INTO temp_upgrade "
     577                 :       "SELECT index_id, value, object_data_key, object_data_id "
     578                 :       "FROM unique_index_data;"
     579               0 :   ));
     580               0 :   NS_ENSURE_SUCCESS(rv, rv);
     581                 : 
     582               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     583                 :     "DROP TABLE unique_index_data;"
     584               0 :   ));
     585               0 :   NS_ENSURE_SUCCESS(rv, rv);
     586                 : 
     587               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     588                 :     "CREATE TABLE unique_index_data ("
     589                 :       "index_id INTEGER NOT NULL, "
     590                 :       "value NOT NULL, "
     591                 :       "object_data_key NOT NULL, "
     592                 :       "object_data_id INTEGER NOT NULL, "
     593                 :       "PRIMARY KEY (index_id, value, object_data_key), "
     594                 :       "UNIQUE (index_id, value), "
     595                 :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
     596                 :         "CASCADE "
     597                 :       "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
     598                 :         "CASCADE"
     599                 :     ");"
     600               0 :   ));
     601               0 :   NS_ENSURE_SUCCESS(rv, rv);
     602                 : 
     603               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     604                 :     "INSERT INTO unique_index_data "
     605                 :       "SELECT index_id, value, object_data_key, object_data_id "
     606                 :       "FROM temp_upgrade;"
     607               0 :   ));
     608               0 :   NS_ENSURE_SUCCESS(rv, rv);
     609                 : 
     610               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     611                 :     "DROP TABLE temp_upgrade;"
     612               0 :   ));
     613               0 :   NS_ENSURE_SUCCESS(rv, rv);
     614                 : 
     615               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     616                 :     "CREATE INDEX unique_index_data_object_data_id_index "
     617                 :     "ON unique_index_data (object_data_id);"
     618               0 :   ));
     619               0 :   NS_ENSURE_SUCCESS(rv, rv);
     620                 : 
     621                 :   // Fix up the ai_index_data table. We're reordering the columns as well as
     622                 :   // changing the primary key from being a simple id to being a composite.
     623               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     624                 :     "CREATE TEMPORARY TABLE temp_upgrade ("
     625                 :       "index_id, "
     626                 :       "value, "
     627                 :       "ai_object_data_id "
     628                 :     ");"
     629               0 :   ));
     630               0 :   NS_ENSURE_SUCCESS(rv, rv);
     631                 : 
     632               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     633                 :     "INSERT INTO temp_upgrade "
     634                 :       "SELECT index_id, value, ai_object_data_id "
     635                 :       "FROM ai_index_data;"
     636               0 :   ));
     637               0 :   NS_ENSURE_SUCCESS(rv, rv);
     638                 : 
     639               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     640                 :     "DROP TABLE ai_index_data;"
     641               0 :   ));
     642               0 :   NS_ENSURE_SUCCESS(rv, rv);
     643                 : 
     644               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     645                 :     "CREATE TABLE ai_index_data ("
     646                 :       "index_id INTEGER NOT NULL, "
     647                 :       "value NOT NULL, "
     648                 :       "ai_object_data_id INTEGER NOT NULL, "
     649                 :       "PRIMARY KEY (index_id, value, ai_object_data_id), "
     650                 :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
     651                 :         "CASCADE, "
     652                 :       "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
     653                 :         "CASCADE"
     654                 :     ");"
     655               0 :   ));
     656               0 :   NS_ENSURE_SUCCESS(rv, rv);
     657                 : 
     658               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     659                 :     "INSERT OR IGNORE INTO ai_index_data "
     660                 :       "SELECT index_id, value, ai_object_data_id "
     661                 :       "FROM temp_upgrade;"
     662               0 :   ));
     663               0 :   NS_ENSURE_SUCCESS(rv, rv);
     664                 : 
     665               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     666                 :     "DROP TABLE temp_upgrade;"
     667               0 :   ));
     668               0 :   NS_ENSURE_SUCCESS(rv, rv);
     669                 : 
     670               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     671                 :     "CREATE INDEX ai_index_data_ai_object_data_id_index "
     672                 :     "ON ai_index_data (ai_object_data_id);"
     673               0 :   ));
     674               0 :   NS_ENSURE_SUCCESS(rv, rv);
     675                 : 
     676                 :   // Fix up the ai_unique_index_data table. We're reordering the columns as well
     677                 :   // as changing the primary key from being a simple id to being a composite.
     678               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     679                 :     "CREATE TEMPORARY TABLE temp_upgrade ("
     680                 :       "index_id, "
     681                 :       "value, "
     682                 :       "ai_object_data_id "
     683                 :     ");"
     684               0 :   ));
     685               0 :   NS_ENSURE_SUCCESS(rv, rv);
     686                 : 
     687               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     688                 :     "INSERT INTO temp_upgrade "
     689                 :       "SELECT index_id, value, ai_object_data_id "
     690                 :       "FROM ai_unique_index_data;"
     691               0 :   ));
     692               0 :   NS_ENSURE_SUCCESS(rv, rv);
     693                 : 
     694               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     695                 :     "DROP TABLE ai_unique_index_data;"
     696               0 :   ));
     697               0 :   NS_ENSURE_SUCCESS(rv, rv);
     698                 : 
     699               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     700                 :     "CREATE TABLE ai_unique_index_data ("
     701                 :       "index_id INTEGER NOT NULL, "
     702                 :       "value NOT NULL, "
     703                 :       "ai_object_data_id INTEGER NOT NULL, "
     704                 :       "UNIQUE (index_id, value), "
     705                 :       "PRIMARY KEY (index_id, value, ai_object_data_id), "
     706                 :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
     707                 :         "CASCADE, "
     708                 :       "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
     709                 :         "CASCADE"
     710                 :     ");"
     711               0 :   ));
     712               0 :   NS_ENSURE_SUCCESS(rv, rv);
     713                 : 
     714               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     715                 :     "INSERT INTO ai_unique_index_data "
     716                 :       "SELECT index_id, value, ai_object_data_id "
     717                 :       "FROM temp_upgrade;"
     718               0 :   ));
     719               0 :   NS_ENSURE_SUCCESS(rv, rv);
     720                 : 
     721               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     722                 :     "DROP TABLE temp_upgrade;"
     723               0 :   ));
     724               0 :   NS_ENSURE_SUCCESS(rv, rv);
     725                 : 
     726               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     727                 :     "CREATE INDEX ai_unique_index_data_ai_object_data_id_index "
     728                 :     "ON ai_unique_index_data (ai_object_data_id);"
     729               0 :   ));
     730               0 :   NS_ENSURE_SUCCESS(rv, rv);
     731                 : 
     732               0 :   rv = aConnection->SetSchemaVersion(6);
     733               0 :   NS_ENSURE_SUCCESS(rv, rv);
     734                 : 
     735               0 :   return NS_OK;
     736                 : }
     737                 : 
     738                 : nsresult
     739               0 : UpgradeSchemaFrom6To7(mozIStorageConnection* aConnection)
     740                 : {
     741               0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     742                 :     "CREATE TEMPORARY TABLE temp_upgrade ("
     743                 :       "id, "
     744                 :       "name, "
     745                 :       "key_path, "
     746                 :       "auto_increment"
     747                 :     ");"
     748               0 :   ));
     749               0 :   NS_ENSURE_SUCCESS(rv, rv);
     750                 : 
     751               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     752                 :     "INSERT INTO temp_upgrade "
     753                 :       "SELECT id, name, key_path, auto_increment "
     754                 :       "FROM object_store;"
     755               0 :   ));
     756               0 :   NS_ENSURE_SUCCESS(rv, rv);
     757                 : 
     758               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     759                 :     "DROP TABLE object_store;"
     760               0 :   ));
     761               0 :   NS_ENSURE_SUCCESS(rv, rv);
     762                 : 
     763               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     764                 :     "CREATE TABLE object_store ("
     765                 :       "id INTEGER PRIMARY KEY, "
     766                 :       "auto_increment INTEGER NOT NULL DEFAULT 0, "
     767                 :       "name TEXT NOT NULL, "
     768                 :       "key_path TEXT, "
     769                 :       "UNIQUE (name)"
     770                 :     ");"
     771               0 :   ));
     772               0 :   NS_ENSURE_SUCCESS(rv, rv);
     773                 : 
     774               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     775                 :     "INSERT INTO object_store "
     776                 :       "SELECT id, auto_increment, name, nullif(key_path, '') "
     777                 :       "FROM temp_upgrade;"
     778               0 :   ));
     779               0 :   NS_ENSURE_SUCCESS(rv, rv);
     780                 : 
     781               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     782                 :     "DROP TABLE temp_upgrade;"
     783               0 :   ));
     784               0 :   NS_ENSURE_SUCCESS(rv, rv);
     785                 : 
     786               0 :   rv = aConnection->SetSchemaVersion(7);
     787               0 :   NS_ENSURE_SUCCESS(rv, rv);
     788                 : 
     789               0 :   return NS_OK;
     790                 : }
     791                 : 
     792                 : nsresult
     793               0 : UpgradeSchemaFrom7To8(mozIStorageConnection* aConnection)
     794                 : {
     795               0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     796                 :     "CREATE TEMPORARY TABLE temp_upgrade ("
     797                 :       "id, "
     798                 :       "object_store_id, "
     799                 :       "name, "
     800                 :       "key_path, "
     801                 :       "unique_index, "
     802                 :       "object_store_autoincrement"
     803                 :     ");"
     804               0 :   ));
     805               0 :   NS_ENSURE_SUCCESS(rv, rv);
     806                 : 
     807               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     808                 :     "INSERT INTO temp_upgrade "
     809                 :       "SELECT id, object_store_id, name, key_path, "
     810                 :       "unique_index, object_store_autoincrement "
     811                 :       "FROM object_store_index;"
     812               0 :   ));
     813               0 :   NS_ENSURE_SUCCESS(rv, rv);
     814                 : 
     815               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     816                 :     "DROP TABLE object_store_index;"
     817               0 :   ));
     818               0 :   NS_ENSURE_SUCCESS(rv, rv);
     819                 : 
     820               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     821                 :     "CREATE TABLE object_store_index ("
     822                 :       "id INTEGER, "
     823                 :       "object_store_id INTEGER NOT NULL, "
     824                 :       "name TEXT NOT NULL, "
     825                 :       "key_path TEXT NOT NULL, "
     826                 :       "unique_index INTEGER NOT NULL, "
     827                 :       "multientry INTEGER NOT NULL, "
     828                 :       "object_store_autoincrement INTERGER NOT NULL, "
     829                 :       "PRIMARY KEY (id), "
     830                 :       "UNIQUE (object_store_id, name), "
     831                 :       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
     832                 :         "CASCADE"
     833                 :     ");"
     834               0 :   ));
     835               0 :   NS_ENSURE_SUCCESS(rv, rv);
     836                 : 
     837               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     838                 :     "INSERT INTO object_store_index "
     839                 :       "SELECT id, object_store_id, name, key_path, "
     840                 :       "unique_index, 0, object_store_autoincrement "
     841                 :       "FROM temp_upgrade;"
     842               0 :   ));
     843               0 :   NS_ENSURE_SUCCESS(rv, rv);
     844                 : 
     845               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     846                 :     "DROP TABLE temp_upgrade;"
     847               0 :   ));
     848               0 :   NS_ENSURE_SUCCESS(rv, rv);
     849                 : 
     850               0 :   rv = aConnection->SetSchemaVersion(8);
     851               0 :   NS_ENSURE_SUCCESS(rv, rv);
     852                 : 
     853               0 :   return NS_OK;
     854                 : }
     855                 : 
     856                 : class CompressDataBlobsFunction : public mozIStorageFunction
     857               0 : {
     858                 : public:
     859                 :   NS_DECL_ISUPPORTS
     860                 : 
     861                 :   NS_IMETHOD
     862               0 :   OnFunctionCall(mozIStorageValueArray* aArguments,
     863                 :                  nsIVariant** aResult)
     864                 :   {
     865                 :     PRUint32 argc;
     866               0 :     nsresult rv = aArguments->GetNumEntries(&argc);
     867               0 :     NS_ENSURE_SUCCESS(rv, rv);
     868                 : 
     869               0 :     if (argc != 1) {
     870               0 :       NS_WARNING("Don't call me with the wrong number of arguments!");
     871               0 :       return NS_ERROR_UNEXPECTED;
     872                 :     }
     873                 : 
     874                 :     PRInt32 type;
     875               0 :     rv = aArguments->GetTypeOfIndex(0, &type);
     876               0 :     NS_ENSURE_SUCCESS(rv, rv);
     877                 : 
     878               0 :     if (type != mozIStorageStatement::VALUE_TYPE_BLOB) {
     879               0 :       NS_WARNING("Don't call me with the wrong type of arguments!");
     880               0 :       return NS_ERROR_UNEXPECTED;
     881                 :     }
     882                 : 
     883                 :     const PRUint8* uncompressed;
     884                 :     PRUint32 uncompressedLength;
     885               0 :     rv = aArguments->GetSharedBlob(0, &uncompressedLength, &uncompressed);
     886               0 :     NS_ENSURE_SUCCESS(rv, rv);
     887                 : 
     888               0 :     size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
     889               0 :     nsAutoArrayPtr<char> compressed(new char[compressedLength]);
     890                 : 
     891                 :     snappy::RawCompress(reinterpret_cast<const char*>(uncompressed),
     892                 :                         uncompressedLength, compressed.get(),
     893               0 :                         &compressedLength);
     894                 : 
     895               0 :     std::pair<const void *, int> data(static_cast<void*>(compressed.get()),
     896               0 :                                       int(compressedLength));
     897                 : 
     898                 :     // XXX This copies the buffer again... There doesn't appear to be any way to
     899                 :     //     preallocate space and write directly to a BlobVariant at the moment.
     900               0 :     nsCOMPtr<nsIVariant> result = new mozilla::storage::BlobVariant(data);
     901                 : 
     902               0 :     result.forget(aResult);
     903               0 :     return NS_OK;
     904                 :   }
     905                 : };
     906                 : 
     907               0 : NS_IMPL_ISUPPORTS1(CompressDataBlobsFunction, mozIStorageFunction)
     908                 : 
     909                 : nsresult
     910               0 : UpgradeSchemaFrom8To9_0(mozIStorageConnection* aConnection)
     911                 : {
     912                 :   // We no longer use the dataVersion column.
     913               0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     914                 :     "UPDATE database SET dataVersion = 0;"
     915               0 :   ));
     916               0 :   NS_ENSURE_SUCCESS(rv, rv);
     917                 : 
     918               0 :   nsCOMPtr<mozIStorageFunction> compressor = new CompressDataBlobsFunction();
     919                 : 
     920               0 :   NS_NAMED_LITERAL_CSTRING(compressorName, "compress");
     921                 : 
     922               0 :   rv = aConnection->CreateFunction(compressorName, 1, compressor);
     923               0 :   NS_ENSURE_SUCCESS(rv, rv);
     924                 : 
     925                 :   // Turn off foreign key constraints before we do anything here.
     926               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     927                 :     "UPDATE object_data SET data = compress(data);"
     928               0 :   ));
     929               0 :   NS_ENSURE_SUCCESS(rv, rv);
     930                 : 
     931               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     932                 :     "UPDATE ai_object_data SET data = compress(data);"
     933               0 :   ));
     934               0 :   NS_ENSURE_SUCCESS(rv, rv);
     935                 : 
     936               0 :   rv = aConnection->RemoveFunction(compressorName);
     937               0 :   NS_ENSURE_SUCCESS(rv, rv);
     938                 : 
     939               0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(9, 0));
     940               0 :   NS_ENSURE_SUCCESS(rv, rv);
     941                 : 
     942               0 :   return NS_OK;
     943                 : }
     944                 : 
     945                 : nsresult
     946               0 : UpgradeSchemaFrom9_0To10_0(mozIStorageConnection* aConnection)
     947                 : {
     948               0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     949                 :     "ALTER TABLE object_data ADD COLUMN file_ids TEXT;"
     950               0 :   ));
     951               0 :   NS_ENSURE_SUCCESS(rv, rv);
     952                 : 
     953               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     954                 :     "ALTER TABLE ai_object_data ADD COLUMN file_ids TEXT;"
     955               0 :   ));
     956               0 :   NS_ENSURE_SUCCESS(rv, rv);
     957                 : 
     958               0 :   rv = CreateFileTables(aConnection);
     959               0 :   NS_ENSURE_SUCCESS(rv, rv);
     960                 : 
     961               0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(10, 0));
     962               0 :   NS_ENSURE_SUCCESS(rv, rv);
     963                 : 
     964               0 :   return NS_OK;
     965                 : }
     966                 : 
     967                 : nsresult
     968               0 : UpgradeSchemaFrom10_0To11_0(mozIStorageConnection* aConnection)
     969                 : {
     970               0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     971                 :     "CREATE TEMPORARY TABLE temp_upgrade ("
     972                 :       "id, "
     973                 :       "object_store_id, "
     974                 :       "name, "
     975                 :       "key_path, "
     976                 :       "unique_index, "
     977                 :       "multientry"
     978                 :     ");"
     979               0 :   ));
     980               0 :   NS_ENSURE_SUCCESS(rv, rv);
     981                 : 
     982               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     983                 :     "INSERT INTO temp_upgrade "
     984                 :       "SELECT id, object_store_id, name, key_path, "
     985                 :       "unique_index, multientry "
     986                 :       "FROM object_store_index;"
     987               0 :   ));
     988               0 :   NS_ENSURE_SUCCESS(rv, rv);
     989                 : 
     990               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     991                 :     "DROP TABLE object_store_index;"
     992               0 :   ));
     993               0 :   NS_ENSURE_SUCCESS(rv, rv);
     994                 : 
     995               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     996                 :     "CREATE TABLE object_store_index ("
     997                 :       "id INTEGER PRIMARY KEY, "
     998                 :       "object_store_id INTEGER NOT NULL, "
     999                 :       "name TEXT NOT NULL, "
    1000                 :       "key_path TEXT NOT NULL, "
    1001                 :       "unique_index INTEGER NOT NULL, "
    1002                 :       "multientry INTEGER NOT NULL, "
    1003                 :       "UNIQUE (object_store_id, name), "
    1004                 :       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
    1005                 :         "CASCADE"
    1006                 :     ");"
    1007               0 :   ));
    1008               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1009                 : 
    1010               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1011                 :     "INSERT INTO object_store_index "
    1012                 :       "SELECT id, object_store_id, name, key_path, "
    1013                 :       "unique_index, multientry "
    1014                 :       "FROM temp_upgrade;"
    1015               0 :   ));
    1016               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1017                 : 
    1018               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1019                 :     "DROP TABLE temp_upgrade;"
    1020               0 :   ));
    1021               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1022                 : 
    1023               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1024                 :     "DROP TRIGGER object_data_insert_trigger;"
    1025               0 :   ));
    1026               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1027                 : 
    1028               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1029                 :     "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
    1030                 :       "SELECT object_store_id, id, data, file_ids "
    1031                 :       "FROM ai_object_data;"
    1032               0 :   ));
    1033               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1034                 : 
    1035               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1036                 :     "CREATE TRIGGER object_data_insert_trigger "
    1037                 :     "AFTER INSERT ON object_data "
    1038                 :     "FOR EACH ROW "
    1039                 :     "WHEN NEW.file_ids IS NOT NULL "
    1040                 :     "BEGIN "
    1041                 :       "SELECT update_refcount(NULL, NEW.file_ids); "
    1042                 :     "END;"
    1043               0 :   ));
    1044               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1045                 : 
    1046               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1047                 :     "INSERT INTO index_data (index_id, value, object_data_key, object_data_id) "
    1048                 :       "SELECT ai_index_data.index_id, ai_index_data.value, ai_index_data.ai_object_data_id, object_data.id "
    1049                 :       "FROM ai_index_data "
    1050                 :       "INNER JOIN object_store_index ON "
    1051                 :         "object_store_index.id = ai_index_data.index_id "
    1052                 :       "INNER JOIN object_data ON "
    1053                 :         "object_data.object_store_id = object_store_index.object_store_id AND "
    1054                 :         "object_data.key_value = ai_index_data.ai_object_data_id;"
    1055               0 :   ));
    1056               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1057                 : 
    1058               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1059                 :     "INSERT INTO unique_index_data (index_id, value, object_data_key, object_data_id) "
    1060                 :       "SELECT ai_unique_index_data.index_id, ai_unique_index_data.value, ai_unique_index_data.ai_object_data_id, object_data.id "
    1061                 :       "FROM ai_unique_index_data "
    1062                 :       "INNER JOIN object_store_index ON "
    1063                 :         "object_store_index.id = ai_unique_index_data.index_id "
    1064                 :       "INNER JOIN object_data ON "
    1065                 :         "object_data.object_store_id = object_store_index.object_store_id AND "
    1066                 :         "object_data.key_value = ai_unique_index_data.ai_object_data_id;"
    1067               0 :   ));
    1068               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1069                 : 
    1070               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1071                 :     "UPDATE object_store "
    1072                 :       "SET auto_increment = (SELECT max(id) FROM ai_object_data) + 1 "
    1073                 :       "WHERE auto_increment;"
    1074               0 :   ));
    1075               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1076                 : 
    1077               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1078                 :     "DROP TABLE ai_unique_index_data;"
    1079               0 :   ));
    1080               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1081                 : 
    1082               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1083                 :     "DROP TABLE ai_index_data;"
    1084               0 :   ));
    1085               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1086                 : 
    1087               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1088                 :     "DROP TABLE ai_object_data;"
    1089               0 :   ));
    1090               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1091                 : 
    1092               0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(11, 0));
    1093               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1094                 : 
    1095               0 :   return NS_OK;
    1096                 : }
    1097                 : 
    1098                 : class EncodeKeysFunction : public mozIStorageFunction
    1099               0 : {
    1100                 : public:
    1101                 :   NS_DECL_ISUPPORTS
    1102                 : 
    1103                 :   NS_IMETHOD
    1104               0 :   OnFunctionCall(mozIStorageValueArray* aArguments,
    1105                 :                  nsIVariant** aResult)
    1106                 :   {
    1107                 :     PRUint32 argc;
    1108               0 :     nsresult rv = aArguments->GetNumEntries(&argc);
    1109               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1110                 : 
    1111               0 :     if (argc != 1) {
    1112               0 :       NS_WARNING("Don't call me with the wrong number of arguments!");
    1113               0 :       return NS_ERROR_UNEXPECTED;
    1114                 :     }
    1115                 : 
    1116                 :     PRInt32 type;
    1117               0 :     rv = aArguments->GetTypeOfIndex(0, &type);
    1118               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1119                 : 
    1120               0 :     Key key;
    1121               0 :     if (type == mozIStorageStatement::VALUE_TYPE_INTEGER) {
    1122                 :       PRInt64 intKey;
    1123               0 :       aArguments->GetInt64(0, &intKey);
    1124               0 :       key.SetFromInteger(intKey);
    1125                 :     }
    1126               0 :     else if (type == mozIStorageStatement::VALUE_TYPE_TEXT) {
    1127               0 :       nsString stringKey;
    1128               0 :       aArguments->GetString(0, stringKey);
    1129               0 :       key.SetFromString(stringKey);
    1130                 :     }
    1131                 :     else {
    1132               0 :       NS_WARNING("Don't call me with the wrong type of arguments!");
    1133               0 :       return NS_ERROR_UNEXPECTED;
    1134                 :     }
    1135                 : 
    1136               0 :     const nsCString& buffer = key.GetBuffer();
    1137                 : 
    1138               0 :     std::pair<const void *, int> data(static_cast<const void*>(buffer.get()),
    1139               0 :                                       int(buffer.Length()));
    1140                 : 
    1141               0 :     nsCOMPtr<nsIVariant> result = new mozilla::storage::BlobVariant(data);
    1142                 : 
    1143               0 :     result.forget(aResult);
    1144               0 :     return NS_OK;
    1145                 :   }
    1146                 : };
    1147                 : 
    1148               0 : NS_IMPL_ISUPPORTS1(EncodeKeysFunction, mozIStorageFunction)
    1149                 : 
    1150                 : nsresult
    1151               0 : UpgradeSchemaFrom11_0To12_0(mozIStorageConnection* aConnection)
    1152                 : {
    1153               0 :   NS_NAMED_LITERAL_CSTRING(encoderName, "encode");
    1154                 : 
    1155               0 :   nsCOMPtr<mozIStorageFunction> encoder = new EncodeKeysFunction();
    1156                 : 
    1157               0 :   nsresult rv = aConnection->CreateFunction(encoderName, 1, encoder);
    1158               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1159                 : 
    1160               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1161                 :     "CREATE TEMPORARY TABLE temp_upgrade ("
    1162                 :       "id INTEGER PRIMARY KEY, "
    1163                 :       "object_store_id, "
    1164                 :       "key_value, "
    1165                 :       "data, "
    1166                 :       "file_ids "
    1167                 :     ");"
    1168               0 :   ));
    1169               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1170                 : 
    1171               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1172                 :     "INSERT INTO temp_upgrade "
    1173                 :       "SELECT id, object_store_id, encode(key_value), data, file_ids "
    1174                 :       "FROM object_data;"
    1175               0 :   ));
    1176               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1177                 : 
    1178               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1179                 :     "DROP TABLE object_data;"
    1180               0 :   ));
    1181               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1182                 : 
    1183               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1184                 :     "CREATE TABLE object_data ("
    1185                 :       "id INTEGER PRIMARY KEY, "
    1186                 :       "object_store_id INTEGER NOT NULL, "
    1187                 :       "key_value BLOB DEFAULT NULL, "
    1188                 :       "file_ids TEXT, "
    1189                 :       "data BLOB NOT NULL, "
    1190                 :       "UNIQUE (object_store_id, key_value), "
    1191                 :       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
    1192                 :         "CASCADE"
    1193                 :     ");"
    1194               0 :   ));
    1195               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1196                 : 
    1197               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1198                 :     "INSERT INTO object_data "
    1199                 :       "SELECT id, object_store_id, key_value, file_ids, data "
    1200                 :       "FROM temp_upgrade;"
    1201               0 :   ));
    1202               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1203                 : 
    1204               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1205                 :     "DROP TABLE temp_upgrade;"
    1206               0 :   ));
    1207               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1208                 : 
    1209               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1210                 :     "CREATE TRIGGER object_data_insert_trigger "
    1211                 :     "AFTER INSERT ON object_data "
    1212                 :     "FOR EACH ROW "
    1213                 :     "WHEN NEW.file_ids IS NOT NULL "
    1214                 :     "BEGIN "
    1215                 :       "SELECT update_refcount(NULL, NEW.file_ids); "
    1216                 :     "END;"
    1217               0 :   ));
    1218               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1219                 : 
    1220               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1221                 :     "CREATE TRIGGER object_data_update_trigger "
    1222                 :     "AFTER UPDATE OF file_ids ON object_data "
    1223                 :     "FOR EACH ROW "
    1224                 :     "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
    1225                 :     "BEGIN "
    1226                 :       "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
    1227                 :     "END;"
    1228               0 :   ));
    1229               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1230                 : 
    1231               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1232                 :     "CREATE TRIGGER object_data_delete_trigger "
    1233                 :     "AFTER DELETE ON object_data "
    1234                 :     "FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
    1235                 :     "BEGIN "
    1236                 :       "SELECT update_refcount(OLD.file_ids, NULL); "
    1237                 :     "END;"
    1238               0 :   ));
    1239               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1240                 : 
    1241               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1242                 :     "CREATE TEMPORARY TABLE temp_upgrade ("
    1243                 :       "index_id, "
    1244                 :       "value, "
    1245                 :       "object_data_key, "
    1246                 :       "object_data_id "
    1247                 :     ");"
    1248               0 :   ));
    1249               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1250                 : 
    1251               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1252                 :     "INSERT INTO temp_upgrade "
    1253                 :       "SELECT index_id, encode(value), encode(object_data_key), object_data_id "
    1254                 :       "FROM index_data;"
    1255               0 :   ));
    1256               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1257                 : 
    1258               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1259                 :     "DROP TABLE index_data;"
    1260               0 :   ));
    1261               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1262                 : 
    1263               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1264                 :     "CREATE TABLE index_data ("
    1265                 :       "index_id INTEGER NOT NULL, "
    1266                 :       "value BLOB NOT NULL, "
    1267                 :       "object_data_key BLOB NOT NULL, "
    1268                 :       "object_data_id INTEGER NOT NULL, "
    1269                 :       "PRIMARY KEY (index_id, value, object_data_key), "
    1270                 :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
    1271                 :         "CASCADE, "
    1272                 :       "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
    1273                 :         "CASCADE"
    1274                 :     ");"
    1275               0 :   ));
    1276               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1277                 : 
    1278               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1279                 :     "INSERT INTO index_data "
    1280                 :       "SELECT index_id, value, object_data_key, object_data_id "
    1281                 :       "FROM temp_upgrade;"
    1282               0 :   ));
    1283               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1284                 : 
    1285               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1286                 :     "DROP TABLE temp_upgrade;"
    1287               0 :   ));
    1288               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1289                 : 
    1290               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1291                 :     "CREATE INDEX index_data_object_data_id_index "
    1292                 :     "ON index_data (object_data_id);"
    1293               0 :   ));
    1294               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1295                 : 
    1296               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1297                 :     "CREATE TEMPORARY TABLE temp_upgrade ("
    1298                 :       "index_id, "
    1299                 :       "value, "
    1300                 :       "object_data_key, "
    1301                 :       "object_data_id "
    1302                 :     ");"
    1303               0 :   ));
    1304               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1305                 : 
    1306               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1307                 :     "INSERT INTO temp_upgrade "
    1308                 :       "SELECT index_id, encode(value), encode(object_data_key), object_data_id "
    1309                 :       "FROM unique_index_data;"
    1310               0 :   ));
    1311               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1312                 : 
    1313               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1314                 :     "DROP TABLE unique_index_data;"
    1315               0 :   ));
    1316               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1317                 : 
    1318               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1319                 :     "CREATE TABLE unique_index_data ("
    1320                 :       "index_id INTEGER NOT NULL, "
    1321                 :       "value BLOB NOT NULL, "
    1322                 :       "object_data_key BLOB NOT NULL, "
    1323                 :       "object_data_id INTEGER NOT NULL, "
    1324                 :       "PRIMARY KEY (index_id, value, object_data_key), "
    1325                 :       "UNIQUE (index_id, value), "
    1326                 :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
    1327                 :         "CASCADE "
    1328                 :       "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
    1329                 :         "CASCADE"
    1330                 :     ");"
    1331               0 :   ));
    1332               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1333                 : 
    1334               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1335                 :     "INSERT INTO unique_index_data "
    1336                 :       "SELECT index_id, value, object_data_key, object_data_id "
    1337                 :       "FROM temp_upgrade;"
    1338               0 :   ));
    1339               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1340                 : 
    1341               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1342                 :     "DROP TABLE temp_upgrade;"
    1343               0 :   ));
    1344               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1345                 : 
    1346               0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1347                 :     "CREATE INDEX unique_index_data_object_data_id_index "
    1348                 :     "ON unique_index_data (object_data_id);"
    1349               0 :   ));
    1350               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1351                 : 
    1352               0 :   rv = aConnection->RemoveFunction(encoderName);
    1353               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1354                 : 
    1355               0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(12, 0));
    1356               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1357                 : 
    1358               0 :   return NS_OK;
    1359                 : }
    1360                 : 
    1361                 : class VersionChangeEventsRunnable;
    1362                 : 
    1363                 : class SetVersionHelper : public AsyncConnectionHelper,
    1364                 :                          public IDBTransactionListener
    1365             284 : {
    1366                 :   friend class VersionChangeEventsRunnable;
    1367                 : public:
    1368              71 :   SetVersionHelper(IDBTransaction* aTransaction,
    1369                 :                    IDBOpenDBRequest* aRequest,
    1370                 :                    OpenDatabaseHelper* aHelper,
    1371                 :                    PRUint64 aRequestedVersion,
    1372                 :                    PRUint64 aCurrentVersion)
    1373                 :   : AsyncConnectionHelper(aTransaction, aRequest),
    1374                 :     mOpenRequest(aRequest), mOpenHelper(aHelper),
    1375                 :     mRequestedVersion(aRequestedVersion),
    1376              71 :     mCurrentVersion(aCurrentVersion)
    1377                 :   {
    1378              71 :     mTransaction->SetTransactionListener(this);
    1379              71 :   }
    1380                 : 
    1381                 :   NS_DECL_ISUPPORTS_INHERITED
    1382                 : 
    1383                 :   nsresult GetSuccessResult(JSContext* aCx,
    1384                 :                             jsval* aVal);
    1385                 : 
    1386                 : protected:
    1387                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
    1388                 :   nsresult Init();
    1389                 : 
    1390                 :   // SetVersionHelper never fires an error event at the request.  It hands that
    1391                 :   // responsibility back to the OpenDatabaseHelper
    1392               0 :   void OnError() { }
    1393                 : 
    1394                 :   // Need an upgradeneeded event here.
    1395                 :   already_AddRefed<nsDOMEvent> CreateSuccessEvent();
    1396                 : 
    1397                 :   nsresult NotifyTransactionComplete(IDBTransaction* aTransaction);
    1398                 : 
    1399               3 :   PRUint64 RequestedVersion() const
    1400                 :   {
    1401               3 :     return mRequestedVersion;
    1402                 :   }
    1403                 : 
    1404                 : private:
    1405                 :   // In-params
    1406                 :   nsRefPtr<IDBOpenDBRequest> mOpenRequest;
    1407                 :   nsRefPtr<OpenDatabaseHelper> mOpenHelper;
    1408                 :   PRUint64 mRequestedVersion;
    1409                 :   PRUint64 mCurrentVersion;
    1410                 : };
    1411                 : 
    1412                 : class DeleteDatabaseHelper : public AsyncConnectionHelper
    1413               0 : {
    1414                 :   friend class VersionChangeEventsRunnable;
    1415                 : public:
    1416               0 :   DeleteDatabaseHelper(IDBOpenDBRequest* aRequest,
    1417                 :                        OpenDatabaseHelper* aHelper,
    1418                 :                        PRUint64 aCurrentVersion,
    1419                 :                        const nsAString& aName,
    1420                 :                        const nsACString& aASCIIOrigin)
    1421                 :   : AsyncConnectionHelper(static_cast<IDBDatabase*>(nsnull), aRequest),
    1422                 :     mOpenHelper(aHelper), mOpenRequest(aRequest),
    1423                 :     mCurrentVersion(aCurrentVersion), mName(aName),
    1424               0 :     mASCIIOrigin(aASCIIOrigin)
    1425               0 :   { }
    1426                 : 
    1427                 :   nsresult GetSuccessResult(JSContext* aCx,
    1428                 :                             jsval* aVal);
    1429                 : 
    1430               0 :   void ReleaseMainThreadObjects()
    1431                 :   {
    1432               0 :     mOpenHelper = nsnull;
    1433               0 :     mOpenRequest = nsnull;
    1434                 : 
    1435               0 :     AsyncConnectionHelper::ReleaseMainThreadObjects();
    1436               0 :   }
    1437                 : 
    1438                 : protected:
    1439                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
    1440                 :   nsresult Init();
    1441                 : 
    1442                 :   // DeleteDatabaseHelper never fires events at the request.  It hands that
    1443                 :   // responsibility back to the OpenDatabaseHelper
    1444               0 :   void OnError()
    1445                 :   {
    1446               0 :     mOpenHelper->NotifyDeleteFinished();
    1447               0 :   }
    1448               0 :   nsresult OnSuccess()
    1449                 :   {
    1450               0 :     return mOpenHelper->NotifyDeleteFinished();
    1451                 :   }
    1452                 : 
    1453               0 :   PRUint64 RequestedVersion() const
    1454                 :   {
    1455               0 :     return 0;
    1456                 :   }
    1457                 : private:
    1458                 :   // In-params
    1459                 :   nsRefPtr<OpenDatabaseHelper> mOpenHelper;
    1460                 :   nsRefPtr<IDBOpenDBRequest> mOpenRequest;
    1461                 :   PRUint64 mCurrentVersion;
    1462                 :   nsString mName;
    1463                 :   nsCString mASCIIOrigin;
    1464                 : };
    1465                 : 
    1466                 : // Responsible for firing "versionchange" events at all live and non-closed
    1467                 : // databases, and for firing a "blocked" event at the requesting database if any
    1468                 : // databases fail to close.
    1469                 : class VersionChangeEventsRunnable : public nsRunnable
    1470              12 : {
    1471                 : public:
    1472               3 :   VersionChangeEventsRunnable(
    1473                 :                             IDBDatabase* aRequestingDatabase,
    1474                 :                             IDBOpenDBRequest* aRequest,
    1475                 :                             nsTArray<nsRefPtr<IDBDatabase> >& aWaitingDatabases,
    1476                 :                             PRInt64 aOldVersion,
    1477                 :                             PRInt64 aNewVersion)
    1478                 :   : mRequestingDatabase(aRequestingDatabase),
    1479                 :     mRequest(aRequest),
    1480                 :     mOldVersion(aOldVersion),
    1481               3 :     mNewVersion(aNewVersion)
    1482                 :   {
    1483               3 :     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1484               3 :     NS_ASSERTION(aRequestingDatabase, "Null pointer!");
    1485               3 :     NS_ASSERTION(aRequest, "Null pointer!");
    1486                 : 
    1487               3 :     if (!mWaitingDatabases.SwapElements(aWaitingDatabases)) {
    1488               0 :       NS_ERROR("This should never fail!");
    1489                 :     }
    1490               3 :   }
    1491                 : 
    1492               3 :   NS_IMETHOD Run()
    1493                 :   {
    1494               3 :     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1495                 : 
    1496                 :     // Fire version change events at all of the databases that are not already
    1497                 :     // closed. Also kick bfcached documents out of bfcache.
    1498               3 :     PRUint32 count = mWaitingDatabases.Length();
    1499               7 :     for (PRUint32 index = 0; index < count; index++) {
    1500               4 :       nsRefPtr<IDBDatabase>& database = mWaitingDatabases[index];
    1501                 : 
    1502               4 :       if (database->IsClosed()) {
    1503               0 :         continue;
    1504                 :       }
    1505                 : 
    1506                 :       // First check if the document the IDBDatabase is part of is bfcached.
    1507               8 :       nsCOMPtr<nsIDocument> ownerDoc = database->GetOwnerDocument();
    1508                 :       nsIBFCacheEntry* bfCacheEntry;
    1509               4 :       if (ownerDoc && (bfCacheEntry = ownerDoc->GetBFCacheEntry())) {
    1510               0 :         bfCacheEntry->RemoveFromBFCacheSync();
    1511               0 :         NS_ASSERTION(database->IsClosed(),
    1512                 :                      "Kicking doc out of bfcache should have closed database");
    1513               0 :         continue;
    1514                 :       }
    1515                 : 
    1516                 :       // Otherwise fire a versionchange event.
    1517                 :       nsRefPtr<nsDOMEvent> event = 
    1518               8 :         IDBVersionChangeEvent::Create(mOldVersion, mNewVersion);
    1519               4 :       NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
    1520                 : 
    1521                 :       bool dummy;
    1522               8 :       database->DispatchEvent(event, &dummy);
    1523                 :     }
    1524                 : 
    1525                 :     // Now check to see if any didn't close. If there are some running still
    1526                 :     // then fire the blocked event.
    1527               5 :     for (PRUint32 index = 0; index < count; index++) {
    1528               3 :       if (!mWaitingDatabases[index]->IsClosed()) {
    1529                 :         nsRefPtr<nsDOMEvent> event =
    1530               2 :           IDBVersionChangeEvent::CreateBlocked(mOldVersion, mNewVersion);
    1531               1 :         NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
    1532                 : 
    1533                 :         bool dummy;
    1534               1 :         mRequest->DispatchEvent(event, &dummy);
    1535                 : 
    1536               1 :         break;
    1537                 :       }
    1538                 :     }
    1539                 : 
    1540               3 :     return NS_OK;
    1541                 :   }
    1542                 : 
    1543                 :   template <class T>
    1544                 :   static
    1545               3 :   void QueueVersionChange(nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
    1546                 :                           void* aClosure);
    1547                 : private:
    1548                 :   nsRefPtr<IDBDatabase> mRequestingDatabase;
    1549                 :   nsRefPtr<IDBOpenDBRequest> mRequest;
    1550                 :   nsTArray<nsRefPtr<IDBDatabase> > mWaitingDatabases;
    1551                 :   PRInt64 mOldVersion;
    1552                 :   PRInt64 mNewVersion;
    1553                 : };
    1554                 : 
    1555                 : } // anonymous namespace
    1556                 : 
    1557            1561 : NS_IMPL_THREADSAFE_ISUPPORTS1(OpenDatabaseHelper, nsIRunnable);
    1558                 : 
    1559                 : nsresult
    1560              76 : OpenDatabaseHelper::Init()
    1561                 : {
    1562             152 :   nsCString str(mASCIIOrigin);
    1563              76 :   str.Append("*");
    1564              76 :   str.Append(NS_ConvertUTF16toUTF8(mName));
    1565                 : 
    1566             152 :   nsCOMPtr<nsIAtom> atom = do_GetAtom(str);
    1567              76 :   NS_ENSURE_TRUE(atom, NS_ERROR_FAILURE);
    1568                 : 
    1569              76 :   atom.swap(mDatabaseId);
    1570              76 :   return NS_OK;
    1571                 : }
    1572                 : 
    1573                 : nsresult
    1574              76 : OpenDatabaseHelper::Dispatch(nsIEventTarget* aTarget)
    1575                 : {
    1576              76 :   NS_ASSERTION(mState == eCreated, "We've already been dispatched?");
    1577              76 :   mState = eDBWork;
    1578                 : 
    1579              76 :   return aTarget->Dispatch(this, NS_DISPATCH_NORMAL);
    1580                 : }
    1581                 : 
    1582                 : nsresult
    1583               0 : OpenDatabaseHelper::RunImmediately()
    1584                 : {
    1585               0 :   NS_ASSERTION(mState == eCreated, "We've already been dispatched?");
    1586               0 :   NS_ASSERTION(NS_FAILED(mResultCode),
    1587                 :                "Should only be short-circuiting if we failed!");
    1588               0 :   NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!");
    1589                 : 
    1590               0 :   mState = eFiringEvents;
    1591               0 :   return this->Run();
    1592                 : }
    1593                 : 
    1594                 : nsresult
    1595              76 : OpenDatabaseHelper::DoDatabaseWork()
    1596                 : {
    1597                 : #ifdef DEBUG
    1598                 :   {
    1599                 :     bool correctThread;
    1600              76 :     NS_ASSERTION(NS_SUCCEEDED(IndexedDatabaseManager::Get()->IOThread()->
    1601                 :                               IsOnCurrentThread(&correctThread)) &&
    1602                 :                  correctThread,
    1603                 :                  "Running on the wrong thread!");
    1604                 :   }
    1605                 : #endif
    1606                 : 
    1607              76 :   mState = eFiringEvents; // In case we fail somewhere along the line.
    1608                 : 
    1609              76 :   if (IndexedDatabaseManager::IsShuttingDown()) {
    1610               0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1611                 :   }
    1612                 : 
    1613              76 :   NS_ASSERTION(mOpenDBRequest, "This should never be null!");
    1614                 : 
    1615                 :   // This will be null for non-window contexts.
    1616              76 :   nsPIDOMWindow* window = mOpenDBRequest->GetOwner();
    1617                 : 
    1618             152 :   AutoEnterWindow autoWindow(window);
    1619                 : 
    1620             152 :   nsCOMPtr<nsIFile> dbDirectory;
    1621                 : 
    1622              76 :   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
    1623              76 :   NS_ASSERTION(mgr, "This should never be null!");
    1624                 : 
    1625                 :   nsresult rv = mgr->EnsureOriginIsInitialized(mASCIIOrigin,
    1626              76 :                                                getter_AddRefs(dbDirectory));
    1627              76 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1628                 : 
    1629             152 :   nsAutoString filename;
    1630              76 :   rv = GetDatabaseFilename(mName, filename);
    1631              76 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1632                 :   
    1633             152 :   nsCOMPtr<nsIFile> dbFile;
    1634              76 :   rv = dbDirectory->Clone(getter_AddRefs(dbFile));
    1635              76 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1636                 : 
    1637              76 :   rv = dbFile->Append(filename + NS_LITERAL_STRING(".sqlite"));
    1638              76 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1639                 : 
    1640              76 :   rv = dbFile->GetPath(mDatabaseFilePath);
    1641              76 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1642                 : 
    1643             152 :   nsCOMPtr<nsIFile> fileManagerDirectory;
    1644              76 :   rv = dbDirectory->Clone(getter_AddRefs(fileManagerDirectory));
    1645              76 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1646                 : 
    1647              76 :   rv = fileManagerDirectory->Append(filename);
    1648              76 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1649                 : 
    1650             152 :   nsCOMPtr<mozIStorageConnection> connection;
    1651                 :   rv = CreateDatabaseConnection(mName, dbFile, fileManagerDirectory,
    1652              76 :                                 getter_AddRefs(connection));
    1653              76 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1654                 : 
    1655                 :   rv = IDBFactory::LoadDatabaseInformation(connection, mDatabaseId,
    1656              76 :                                            &mCurrentVersion, mObjectStores);
    1657              76 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1658                 : 
    1659              76 :   if (mForDeletion) {
    1660               0 :     mState = eDeletePending;
    1661               0 :     return NS_OK;
    1662                 :   }
    1663                 : 
    1664              99 :   for (PRUint32 i = 0; i < mObjectStores.Length(); i++) {
    1665              23 :     nsRefPtr<ObjectStoreInfo>& objectStoreInfo = mObjectStores[i];
    1666              41 :     for (PRUint32 j = 0; j < objectStoreInfo->indexes.Length(); j++) {
    1667              18 :       IndexInfo& indexInfo = objectStoreInfo->indexes[j];
    1668              18 :       mLastIndexId = NS_MAX(indexInfo.id, mLastIndexId);
    1669                 :     }
    1670              23 :     mLastObjectStoreId = NS_MAX(objectStoreInfo->id, mLastObjectStoreId);
    1671                 :   }
    1672                 : 
    1673                 :   // See if we need to do a VERSION_CHANGE transaction
    1674                 : 
    1675                 :   // Optional version semantics.
    1676              76 :   if (!mRequestedVersion) {
    1677                 :     // If the requested version was not specified and the database was created,
    1678                 :     // treat it as if version 1 were requested.
    1679               0 :     if (mCurrentVersion == 0) {
    1680               0 :       mRequestedVersion = 1;
    1681                 :     }
    1682                 :     else {
    1683                 :       // Otherwise, treat it as if the current version were requested.
    1684               0 :       mRequestedVersion = mCurrentVersion;
    1685                 :     }
    1686                 :   }
    1687                 : 
    1688              76 :   if (mCurrentVersion > mRequestedVersion) {
    1689               1 :     return NS_ERROR_DOM_INDEXEDDB_VERSION_ERR;
    1690                 :   }
    1691                 : 
    1692              75 :   if (mCurrentVersion != mRequestedVersion) {
    1693              71 :     mState = eSetVersionPending;
    1694                 :   }
    1695                 : 
    1696              75 :   mFileManager = mgr->GetOrCreateFileManager(mASCIIOrigin, mName);
    1697              75 :   NS_ENSURE_TRUE(mFileManager, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1698                 : 
    1699              75 :   if (!mFileManager->Inited()) {
    1700              52 :     rv = mFileManager->Init(fileManagerDirectory, connection);
    1701              52 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1702                 :   }
    1703                 : 
    1704              75 :   if (!mFileManager->Loaded()) {
    1705              52 :     rv = mFileManager->Load(connection);
    1706              52 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1707                 :   }
    1708                 : 
    1709              75 :   return NS_OK;
    1710                 : }
    1711                 : 
    1712                 : // static
    1713                 : nsresult
    1714              76 : OpenDatabaseHelper::CreateDatabaseConnection(
    1715                 :                                         const nsAString& aName,
    1716                 :                                         nsIFile* aDBFile,
    1717                 :                                         nsIFile* aFileManagerDirectory,
    1718                 :                                         mozIStorageConnection** aConnection)
    1719                 : {
    1720              76 :   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
    1721                 : 
    1722             152 :   NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota");
    1723                 : 
    1724                 :   nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
    1725             152 :     do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
    1726              76 :   NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
    1727                 : 
    1728             152 :   nsCOMPtr<mozIStorageConnection> connection;
    1729              76 :   nsresult rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
    1730              76 :                                         getter_AddRefs(connection));
    1731              76 :   if (rv == NS_ERROR_FILE_CORRUPTED) {
    1732                 :     // If we're just opening the database during origin initialization, then
    1733                 :     // we don't want to erase any files. The failure here will fail origin
    1734                 :     // initialization too.
    1735               0 :     if (aName.IsVoid()) {
    1736               0 :       return rv;
    1737                 :     }
    1738                 : 
    1739                 :     // Nuke the database file.  The web services can recreate their data.
    1740               0 :     rv = aDBFile->Remove(false);
    1741               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1742                 : 
    1743                 :     bool exists;
    1744               0 :     rv = aFileManagerDirectory->Exists(&exists);
    1745               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1746                 : 
    1747               0 :     if (exists) {
    1748                 :       bool isDirectory;
    1749               0 :       rv = aFileManagerDirectory->IsDirectory(&isDirectory);
    1750               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1751               0 :       NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1752                 : 
    1753               0 :       rv = aFileManagerDirectory->Remove(true);
    1754               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1755                 :     }
    1756                 : 
    1757               0 :     rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
    1758               0 :                                  getter_AddRefs(connection));
    1759                 :   }
    1760              76 :   NS_ENSURE_SUCCESS(rv, rv);
    1761                 : 
    1762              76 :   rv = connection->EnableModule(NS_LITERAL_CSTRING("filesystem"));
    1763              76 :   NS_ENSURE_SUCCESS(rv, rv);
    1764                 : 
    1765                 :   // Check to make sure that the database schema is correct.
    1766                 :   PRInt32 schemaVersion;
    1767              76 :   rv = connection->GetSchemaVersion(&schemaVersion);
    1768              76 :   NS_ENSURE_SUCCESS(rv, rv);
    1769                 : 
    1770                 :   // Unknown schema will fail origin initialization too
    1771              76 :   if (!schemaVersion && aName.IsVoid()) {
    1772               0 :     NS_WARNING("Unable to open IndexedDB database, schema is not set!");
    1773               0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1774                 :   }
    1775                 : 
    1776              76 :   if (schemaVersion > kSQLiteSchemaVersion) {
    1777               0 :     NS_WARNING("Unable to open IndexedDB database, schema is too high!");
    1778               0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1779                 :   }
    1780                 : 
    1781              76 :   bool vacuumNeeded = false;
    1782                 : 
    1783              76 :   if (schemaVersion != kSQLiteSchemaVersion) {
    1784                 :     mozStorageTransaction transaction(connection, false,
    1785             104 :                                   mozIStorageConnection::TRANSACTION_IMMEDIATE);
    1786                 : 
    1787              52 :     if (!schemaVersion) {
    1788                 :       // Brand new file, initialize our tables.
    1789              52 :       rv = CreateTables(connection);
    1790              52 :       NS_ENSURE_SUCCESS(rv, rv);
    1791                 : 
    1792              52 :       NS_ASSERTION(NS_SUCCEEDED(connection->GetSchemaVersion(&schemaVersion)) &&
    1793                 :                    schemaVersion == kSQLiteSchemaVersion,
    1794                 :                    "CreateTables set a bad schema version!");
    1795                 : 
    1796             104 :       nsCOMPtr<mozIStorageStatement> stmt;
    1797             104 :       nsresult rv = connection->CreateStatement(NS_LITERAL_CSTRING(
    1798                 :         "INSERT INTO database (name) "
    1799                 :         "VALUES (:name)"
    1800             104 :       ), getter_AddRefs(stmt));
    1801              52 :       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1802                 : 
    1803              52 :       rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), aName);
    1804              52 :       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1805                 : 
    1806              52 :       rv = stmt->Execute();
    1807              52 :       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1808                 :     }
    1809                 :     else  {
    1810                 :       // This logic needs to change next time we change the schema!
    1811                 :       PR_STATIC_ASSERT(kSQLiteSchemaVersion == PRInt32((12 << 4) + 0));
    1812                 : 
    1813               0 :       while (schemaVersion != kSQLiteSchemaVersion) {
    1814               0 :         if (schemaVersion == 4) {
    1815               0 :           rv = UpgradeSchemaFrom4To5(connection);
    1816                 :         }
    1817               0 :         else if (schemaVersion == 5) {
    1818               0 :           rv = UpgradeSchemaFrom5To6(connection);
    1819                 :         }
    1820               0 :         else if (schemaVersion == 6) {
    1821               0 :           rv = UpgradeSchemaFrom6To7(connection);
    1822                 :         }
    1823               0 :         else if (schemaVersion == 7) {
    1824               0 :           rv = UpgradeSchemaFrom7To8(connection);
    1825                 :         }
    1826               0 :         else if (schemaVersion == 8) {
    1827               0 :           rv = UpgradeSchemaFrom8To9_0(connection);
    1828               0 :           vacuumNeeded = true;
    1829                 :         }
    1830               0 :         else if (schemaVersion == MakeSchemaVersion(9, 0)) {
    1831               0 :           rv = UpgradeSchemaFrom9_0To10_0(connection);
    1832                 :         }
    1833               0 :         else if (schemaVersion == MakeSchemaVersion(10, 0)) {
    1834               0 :           rv = UpgradeSchemaFrom10_0To11_0(connection);
    1835                 :         }
    1836               0 :         else if (schemaVersion == MakeSchemaVersion(11, 0)) {
    1837               0 :           rv = UpgradeSchemaFrom11_0To12_0(connection);
    1838                 :         }
    1839                 :         else {
    1840                 :           NS_WARNING("Unable to open IndexedDB database, no upgrade path is "
    1841               0 :                      "available!");
    1842               0 :           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1843                 :         }
    1844               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1845                 : 
    1846               0 :         rv = connection->GetSchemaVersion(&schemaVersion);
    1847               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1848                 :       }
    1849                 : 
    1850               0 :       NS_ASSERTION(schemaVersion == kSQLiteSchemaVersion, "Huh?!");
    1851                 :     }
    1852                 : 
    1853              52 :     rv = transaction.Commit();
    1854              52 :     NS_ENSURE_SUCCESS(rv, rv);
    1855                 :   }
    1856                 : 
    1857              76 :   if (vacuumNeeded) {
    1858               0 :     rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1859                 :       "VACUUM;"
    1860               0 :     ));
    1861               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1862                 :   }
    1863                 : 
    1864                 :   // Turn on foreign key constraints.
    1865             152 :   rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1866                 :     "PRAGMA foreign_keys = ON;"
    1867              76 :   ));
    1868              76 :   NS_ENSURE_SUCCESS(rv, rv);
    1869                 : 
    1870              76 :   connection.forget(aConnection);
    1871              76 :   return NS_OK;
    1872                 : }
    1873                 : 
    1874                 : nsresult
    1875              71 : OpenDatabaseHelper::StartSetVersion()
    1876                 : {
    1877              71 :   NS_ASSERTION(mState == eSetVersionPending, "Why are we here?");
    1878                 : 
    1879                 :   // In case we fail, fire error events
    1880              71 :   mState = eFiringEvents;
    1881                 : 
    1882              71 :   nsresult rv = EnsureSuccessResult();
    1883              71 :   NS_ENSURE_SUCCESS(rv, rv);
    1884                 : 
    1885             142 :   nsTArray<nsString> storesToOpen;
    1886                 :   nsRefPtr<IDBTransaction> transaction =
    1887                 :     IDBTransaction::Create(mDatabase, storesToOpen,
    1888             142 :                            IDBTransaction::VERSION_CHANGE, true);
    1889              71 :   NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1890                 : 
    1891                 :   nsRefPtr<SetVersionHelper> helper =
    1892                 :     new SetVersionHelper(transaction, mOpenDBRequest, this, mRequestedVersion,
    1893             213 :                          mCurrentVersion);
    1894                 : 
    1895              71 :   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
    1896              71 :   NS_ASSERTION(mgr, "This should never be null!");
    1897                 : 
    1898                 :   rv = mgr->AcquireExclusiveAccess(mDatabase, helper,
    1899                 :             &VersionChangeEventsRunnable::QueueVersionChange<SetVersionHelper>,
    1900              71 :                                    helper);
    1901              71 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1902                 : 
    1903                 :   // The SetVersionHelper is responsible for dispatching us back to the
    1904                 :   // main thread again and changing the state to eSetVersionCompleted.
    1905              71 :   mState = eSetVersionPending;
    1906                 : 
    1907              71 :   return NS_OK;
    1908                 : }
    1909                 : 
    1910                 : nsresult
    1911               0 : OpenDatabaseHelper::StartDelete()
    1912                 : {
    1913               0 :   NS_ASSERTION(mState == eDeletePending, "Why are we here?");
    1914                 : 
    1915                 :   // In case we fail, fire error events
    1916               0 :   mState = eFiringEvents;
    1917                 : 
    1918               0 :   nsresult rv = EnsureSuccessResult();
    1919               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1920                 : 
    1921                 :   nsRefPtr<DeleteDatabaseHelper> helper =
    1922                 :     new DeleteDatabaseHelper(mOpenDBRequest, this, mCurrentVersion, mName,
    1923               0 :                              mASCIIOrigin);
    1924                 : 
    1925               0 :   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
    1926               0 :   NS_ASSERTION(mgr, "This should never be null!");
    1927                 : 
    1928                 :   rv = mgr->AcquireExclusiveAccess(mDatabase, helper,
    1929                 :         &VersionChangeEventsRunnable::QueueVersionChange<DeleteDatabaseHelper>,
    1930               0 :                                    helper);
    1931               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1932                 : 
    1933                 :   // The DeleteDatabaseHelper is responsible for dispatching us back to the
    1934                 :   // main thread again and changing the state to eDeleteCompleted.
    1935               0 :   mState = eDeletePending;
    1936               0 :   return NS_OK;
    1937                 : }
    1938                 : 
    1939                 : NS_IMETHODIMP
    1940             223 : OpenDatabaseHelper::Run()
    1941                 : {
    1942             223 :   NS_ASSERTION(mState != eCreated, "Dispatch was not called?!?");
    1943                 : 
    1944             223 :   if (NS_IsMainThread()) {
    1945                 :     // If we need to queue up a SetVersionHelper, do that here.
    1946             147 :     if (mState == eSetVersionPending) {
    1947              71 :       nsresult rv = StartSetVersion();
    1948                 : 
    1949              71 :       if (NS_SUCCEEDED(rv)) {
    1950              71 :         return rv;
    1951                 :       }
    1952                 : 
    1953               0 :       SetError(rv);
    1954                 :       // fall through and run the default error processing
    1955                 :     }
    1956              76 :     else if (mState == eDeletePending) {
    1957               0 :       nsresult rv = StartDelete();
    1958                 : 
    1959               0 :       if (NS_SUCCEEDED(rv)) {
    1960               0 :         return rv;
    1961                 :       }
    1962                 : 
    1963               0 :       SetError(rv);
    1964                 :       // fall through and run the default error processing
    1965                 :     }
    1966                 : 
    1967                 :     // We've done whatever work we need to do on the DB thread, and any
    1968                 :     // SetVersion/DeleteDatabase stuff is done by now.
    1969              76 :     NS_ASSERTION(mState == eFiringEvents ||
    1970                 :                  mState == eSetVersionCompleted ||
    1971                 :                  mState == eDeleteCompleted, "Why are we here?");
    1972                 : 
    1973              76 :     switch (mState) {
    1974                 :       case eSetVersionCompleted: {
    1975                 :         // Allow transaction creation/other version change transactions to proceed
    1976                 :         // before we fire events.  Other version changes will be postd to the end
    1977                 :         // of the event loop, and will be behind whatever the page does in
    1978                 :         // its error/success event handlers.
    1979              71 :         mDatabase->ExitSetVersionTransaction();
    1980                 : 
    1981              71 :         mState = eFiringEvents;
    1982              71 :         break;
    1983                 :       }
    1984                 : 
    1985                 :       case eDeleteCompleted: {
    1986                 :         // Destroy the database now (we should have the only ref).
    1987               0 :         mDatabase = nsnull;
    1988                 : 
    1989               0 :         DatabaseInfo::Remove(mDatabaseId);
    1990                 : 
    1991               0 :         IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
    1992               0 :         NS_ASSERTION(mgr, "This should never fail!");
    1993                 : 
    1994               0 :         mgr->InvalidateFileManager(mASCIIOrigin, mName);
    1995                 : 
    1996               0 :         mState = eFiringEvents;
    1997               0 :         break;
    1998                 :       }
    1999                 : 
    2000                 :       case eFiringEvents: {
    2001                 :         // Notify the request that we're done, but only if we didn't just
    2002                 :         // finish a [SetVersion/DeleteDatabase]Helper.  In that case, the
    2003                 :         // helper tells the request that it is done, and we avoid calling
    2004                 :         // NotifyHelperCompleted twice.
    2005                 : 
    2006               5 :         nsresult rv = mOpenDBRequest->NotifyHelperCompleted(this);
    2007               5 :         if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
    2008               0 :           mResultCode = rv;
    2009                 :         }
    2010               5 :         break;
    2011                 :       }
    2012                 : 
    2013                 :       default:
    2014               0 :         NS_NOTREACHED("Shouldn't get here!");
    2015                 :     }
    2016                 : 
    2017              76 :     NS_ASSERTION(mState == eFiringEvents, "Why are we here?");
    2018                 : 
    2019              76 :     if (NS_FAILED(mResultCode)) {
    2020               2 :       DispatchErrorEvent();
    2021                 :     } else {
    2022              74 :       DispatchSuccessEvent();
    2023                 :     }
    2024                 : 
    2025              76 :     IndexedDatabaseManager* manager = IndexedDatabaseManager::Get();
    2026              76 :     NS_ASSERTION(manager, "This should never be null!");
    2027                 : 
    2028              76 :     manager->AllowNextSynchronizedOp(mASCIIOrigin, mDatabaseId);
    2029                 : 
    2030              76 :     ReleaseMainThreadObjects();
    2031                 : 
    2032              76 :     return NS_OK;
    2033                 :   }
    2034                 : 
    2035                 :   // If we're on the DB thread, do that
    2036              76 :   NS_ASSERTION(mState == eDBWork, "Why are we here?");
    2037              76 :   mResultCode = DoDatabaseWork();
    2038              76 :   NS_ASSERTION(mState != eDBWork, "We should be doing something else now.");
    2039                 : 
    2040              76 :   return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
    2041                 : }
    2042                 : 
    2043                 : nsresult
    2044              75 : OpenDatabaseHelper::EnsureSuccessResult()
    2045                 : {
    2046             150 :   nsRefPtr<DatabaseInfo> dbInfo;
    2047              75 :   if (DatabaseInfo::Get(mDatabaseId, getter_AddRefs(dbInfo))) {
    2048                 : 
    2049                 : #ifdef DEBUG
    2050                 :     {
    2051              21 :       NS_ASSERTION(dbInfo->name == mName &&
    2052                 :                    dbInfo->version == mCurrentVersion &&
    2053                 :                    dbInfo->id == mDatabaseId &&
    2054                 :                    dbInfo->filePath == mDatabaseFilePath,
    2055                 :                    "Metadata mismatch!");
    2056                 : 
    2057              21 :       PRUint32 objectStoreCount = mObjectStores.Length();
    2058              43 :       for (PRUint32 index = 0; index < objectStoreCount; index++) {
    2059              22 :         nsRefPtr<ObjectStoreInfo>& info = mObjectStores[index];
    2060                 : 
    2061              22 :         ObjectStoreInfo* otherInfo = dbInfo->GetObjectStore(info->name);
    2062              22 :         NS_ASSERTION(otherInfo, "ObjectStore not known!");
    2063                 : 
    2064              22 :         NS_ASSERTION(info->name == otherInfo->name &&
    2065                 :                      info->id == otherInfo->id &&
    2066                 :                      info->keyPath == otherInfo->keyPath,
    2067                 :                      "Metadata mismatch!");
    2068              22 :         NS_ASSERTION(dbInfo->ContainsStoreName(info->name),
    2069                 :                      "Object store names out of date!");
    2070              22 :         NS_ASSERTION(info->indexes.Length() == otherInfo->indexes.Length(),
    2071                 :                      "Bad index length!");
    2072                 : 
    2073              22 :         PRUint32 indexCount = info->indexes.Length();
    2074              40 :         for (PRUint32 indexIndex = 0; indexIndex < indexCount; indexIndex++) {
    2075              18 :           const IndexInfo& indexInfo = info->indexes[indexIndex];
    2076              18 :           const IndexInfo& otherIndexInfo = otherInfo->indexes[indexIndex];
    2077              18 :           NS_ASSERTION(indexInfo.id == otherIndexInfo.id,
    2078                 :                        "Bad index id!");
    2079              18 :           NS_ASSERTION(indexInfo.name == otherIndexInfo.name,
    2080                 :                        "Bad index name!");
    2081              18 :           NS_ASSERTION(indexInfo.keyPath == otherIndexInfo.keyPath,
    2082                 :                        "Bad index keyPath!");
    2083              18 :           NS_ASSERTION(indexInfo.unique == otherIndexInfo.unique,
    2084                 :                        "Bad index unique value!");
    2085                 :         }
    2086                 :       }
    2087                 :     }
    2088                 : #endif
    2089                 : 
    2090                 :   }
    2091                 :   else {
    2092             108 :     nsRefPtr<DatabaseInfo> newInfo(new DatabaseInfo());
    2093                 : 
    2094              54 :     newInfo->name = mName;
    2095              54 :     newInfo->origin = mASCIIOrigin;
    2096              54 :     newInfo->id = mDatabaseId;
    2097              54 :     newInfo->filePath = mDatabaseFilePath;
    2098                 : 
    2099              54 :     if (!DatabaseInfo::Put(newInfo)) {
    2100               0 :       NS_ERROR("Failed to add to hash!");
    2101               0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    2102                 :     }
    2103                 : 
    2104              54 :     newInfo.swap(dbInfo);
    2105                 : 
    2106                 :     nsresult rv = IDBFactory::SetDatabaseMetadata(dbInfo, mCurrentVersion,
    2107              54 :                                                   mObjectStores);
    2108              54 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2109                 : 
    2110              54 :     NS_ASSERTION(mObjectStores.IsEmpty(), "Should have swapped!");
    2111                 :   }
    2112                 : 
    2113              75 :   dbInfo->nextObjectStoreId = mLastObjectStoreId + 1;
    2114              75 :   dbInfo->nextIndexId = mLastIndexId + 1;
    2115                 : 
    2116                 :   nsRefPtr<IDBDatabase> database =
    2117                 :     IDBDatabase::Create(mOpenDBRequest,
    2118                 :                         dbInfo.forget(),
    2119                 :                         mASCIIOrigin,
    2120             150 :                         mFileManager);
    2121              75 :   if (!database) {
    2122               0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    2123                 :   }
    2124                 : 
    2125              75 :   NS_ASSERTION(!mDatabase, "Shouldn't have a database yet!");
    2126              75 :   mDatabase.swap(database);
    2127                 : 
    2128              75 :   return NS_OK;
    2129                 : }
    2130                 : 
    2131                 : nsresult
    2132               4 : OpenDatabaseHelper::GetSuccessResult(JSContext* aCx,
    2133                 :                                      jsval* aVal)
    2134                 : {
    2135                 :   // Be careful not to load the database twice.
    2136               4 :   if (!mDatabase) {
    2137               4 :     nsresult rv = EnsureSuccessResult();
    2138               4 :     NS_ENSURE_SUCCESS(rv, rv);
    2139                 :   }
    2140                 : 
    2141               4 :   return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, mDatabase),
    2142               4 :                     aVal);
    2143                 : }
    2144                 : 
    2145                 : nsresult
    2146              71 : OpenDatabaseHelper::NotifySetVersionFinished()
    2147                 : {
    2148              71 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread");
    2149              71 :   NS_ASSERTION(mState = eSetVersionPending, "How did we get here?");
    2150                 : 
    2151              71 :   mState = eSetVersionCompleted;
    2152                 :   
    2153                 :   // Dispatch ourself back to the main thread
    2154              71 :   return NS_DispatchToCurrentThread(this);
    2155                 : }
    2156                 : 
    2157                 : nsresult
    2158               0 : OpenDatabaseHelper::NotifyDeleteFinished()
    2159                 : {
    2160               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread");
    2161               0 :   NS_ASSERTION(mState == eDeletePending, "How did we get here?");
    2162                 : 
    2163               0 :   mState = eDeleteCompleted;
    2164                 :   
    2165                 :   // Dispatch ourself back to the main thread
    2166               0 :   return NS_DispatchToCurrentThread(this);
    2167                 : }
    2168                 : 
    2169                 : void
    2170              71 : OpenDatabaseHelper::BlockDatabase()
    2171                 : {
    2172              71 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    2173              71 :   NS_ASSERTION(mDatabase, "This is going bad fast.");
    2174                 : 
    2175              71 :   mDatabase->EnterSetVersionTransaction();
    2176              71 : }
    2177                 : 
    2178                 : void
    2179              74 : OpenDatabaseHelper::DispatchSuccessEvent()
    2180                 : {
    2181                 :   nsRefPtr<nsDOMEvent> event =
    2182              74 :     CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR),
    2183             148 :                        eDoesNotBubble, eNotCancelable);
    2184              74 :   if (!event) {
    2185               0 :     NS_ERROR("Failed to create event!");
    2186                 :     return;
    2187                 :   }
    2188                 : 
    2189                 :   bool dummy;
    2190              74 :   mOpenDBRequest->DispatchEvent(event, &dummy);
    2191                 : }
    2192                 : 
    2193                 : void
    2194               2 : OpenDatabaseHelper::DispatchErrorEvent()
    2195                 : {
    2196                 :   nsRefPtr<nsDOMEvent> event =
    2197               2 :     CreateGenericEvent(NS_LITERAL_STRING(ERROR_EVT_STR),
    2198               4 :                        eDoesBubble, eCancelable);
    2199               2 :   if (!event) {
    2200               0 :     NS_ERROR("Failed to create event!");
    2201                 :     return;
    2202                 :   }
    2203                 : 
    2204               2 :   PRUint16 errorCode = 0;
    2205                 :   DebugOnly<nsresult> rv =
    2206               4 :     mOpenDBRequest->GetErrorCode(&errorCode);
    2207               2 :   NS_ASSERTION(NS_SUCCEEDED(rv), "This shouldn't be failing at this point!");
    2208               2 :   if (!errorCode) {
    2209               1 :     mOpenDBRequest->SetError(mResultCode);
    2210                 :   }
    2211                 : 
    2212                 :   bool dummy;
    2213               2 :   mOpenDBRequest->DispatchEvent(event, &dummy);
    2214                 : }
    2215                 : 
    2216                 : void
    2217              76 : OpenDatabaseHelper::ReleaseMainThreadObjects()
    2218                 : {
    2219              76 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    2220                 : 
    2221              76 :   mOpenDBRequest = nsnull;
    2222              76 :   mDatabase = nsnull;
    2223              76 :   mDatabaseId = nsnull;
    2224                 : 
    2225              76 :   HelperBase::ReleaseMainThreadObjects();
    2226              76 : }
    2227                 : 
    2228            2278 : NS_IMPL_ISUPPORTS_INHERITED0(SetVersionHelper, AsyncConnectionHelper);
    2229                 : 
    2230                 : nsresult
    2231              71 : SetVersionHelper::Init()
    2232                 : {
    2233                 :   // Block transaction creation until we are done.
    2234              71 :   mOpenHelper->BlockDatabase();
    2235                 : 
    2236              71 :   return NS_OK;
    2237                 : }
    2238                 : 
    2239                 : nsresult
    2240              71 : SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
    2241                 : {
    2242              71 :   NS_ASSERTION(aConnection, "Passing a null connection!");
    2243                 : 
    2244             142 :   nsCOMPtr<mozIStorageStatement> stmt;
    2245              71 :   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
    2246                 :     "UPDATE database "
    2247                 :     "SET version = :version"
    2248             142 :   ), getter_AddRefs(stmt));
    2249              71 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2250                 : 
    2251             142 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("version"),
    2252              71 :                              mRequestedVersion);
    2253              71 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2254                 : 
    2255              71 :   if (NS_FAILED(stmt->Execute())) {
    2256               0 :     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
    2257                 :   }
    2258                 : 
    2259              71 :   return NS_OK;
    2260                 : }
    2261                 : 
    2262                 : nsresult
    2263              71 : SetVersionHelper::GetSuccessResult(JSContext* aCx,
    2264                 :                                    jsval* aVal)
    2265                 : {
    2266              71 :   DatabaseInfo* info = mDatabase->Info();
    2267              71 :   info->version = mRequestedVersion;
    2268                 : 
    2269              71 :   NS_ASSERTION(mTransaction, "Better have a transaction!");
    2270                 : 
    2271              71 :   mOpenRequest->SetTransaction(mTransaction);
    2272                 : 
    2273              71 :   return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, mDatabase),
    2274              71 :                     aVal);
    2275                 : }
    2276                 : 
    2277                 : // static
    2278                 : template <class T>
    2279                 : void
    2280                 : VersionChangeEventsRunnable::QueueVersionChange(
    2281                 :                                   nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
    2282                 :                                   void* aClosure)
    2283                 : {
    2284               3 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    2285               3 :   NS_ASSERTION(!aDatabases.IsEmpty(), "Why are we here?");
    2286                 : 
    2287               3 :   T* closure = static_cast<T*>(aClosure);
    2288                 : 
    2289                 :   nsRefPtr<VersionChangeEventsRunnable> eventsRunnable =
    2290                 :     new VersionChangeEventsRunnable(closure->mOpenHelper->Database(),
    2291                 :                                     closure->mOpenRequest,
    2292                 :                                     aDatabases,
    2293                 :                                     closure->mCurrentVersion,
    2294               9 :                                     closure->RequestedVersion());
    2295                 : 
    2296               3 :   NS_DispatchToCurrentThread(eventsRunnable);
    2297               3 : }
    2298                 : 
    2299                 : already_AddRefed<nsDOMEvent>
    2300              71 : SetVersionHelper::CreateSuccessEvent()
    2301                 : {
    2302              71 :   NS_ASSERTION(mCurrentVersion < mRequestedVersion, "Huh?");
    2303                 : 
    2304                 :   return IDBVersionChangeEvent::CreateUpgradeNeeded(mCurrentVersion,
    2305              71 :                                                     mRequestedVersion);
    2306                 : }
    2307                 : 
    2308                 : nsresult
    2309              71 : SetVersionHelper::NotifyTransactionComplete(IDBTransaction* aTransaction)
    2310                 : {
    2311              71 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    2312              71 :   NS_ASSERTION(aTransaction, "This is unexpected.");
    2313              71 :   NS_ASSERTION(mOpenRequest, "Why don't we have a request?");
    2314                 : 
    2315                 :   // If we hit an error, the OpenDatabaseHelper needs to get that error too.
    2316              71 :   nsresult rv = GetResultCode();
    2317              71 :   if (NS_FAILED(rv)) {
    2318               0 :     mOpenHelper->SetError(rv);
    2319                 :   }
    2320                 : 
    2321                 :   // If the transaction was aborted, we should throw an error message.
    2322              71 :   if (aTransaction->IsAborted()) {
    2323               1 :     mOpenHelper->SetError(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
    2324                 :   }
    2325                 : 
    2326              71 :   mOpenRequest->SetTransaction(nsnull);
    2327              71 :   mOpenRequest = nsnull;
    2328                 : 
    2329              71 :   rv = mOpenHelper->NotifySetVersionFinished();
    2330              71 :   mOpenHelper = nsnull;
    2331                 : 
    2332              71 :   return rv;
    2333                 : }
    2334                 : 
    2335                 : nsresult
    2336               0 : DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
    2337                 : {
    2338               0 :   NS_ASSERTION(!aConnection, "How did we get a connection here?");
    2339                 : 
    2340               0 :   nsCOMPtr<nsIFile> directory;
    2341                 :   nsresult rv = IDBFactory::GetDirectoryForOrigin(mASCIIOrigin,
    2342               0 :                                                   getter_AddRefs(directory));
    2343               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2344                 : 
    2345               0 :   NS_ASSERTION(directory, "What?");
    2346                 : 
    2347               0 :   nsAutoString filename;
    2348               0 :   rv = GetDatabaseFilename(mName, filename);
    2349               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2350                 : 
    2351               0 :   nsCOMPtr<nsIFile> dbFile;
    2352               0 :   rv = directory->Clone(getter_AddRefs(dbFile));
    2353               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2354                 : 
    2355               0 :   rv = dbFile->Append(filename + NS_LITERAL_STRING(".sqlite"));
    2356               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2357                 : 
    2358               0 :   bool exists = false;
    2359               0 :   rv = dbFile->Exists(&exists);
    2360               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2361                 : 
    2362                 :   int rc;
    2363                 : 
    2364               0 :   if (exists) {
    2365               0 :     nsString dbFilePath;
    2366               0 :     rv = dbFile->GetPath(dbFilePath);
    2367               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2368                 : 
    2369               0 :     rc = sqlite3_quota_remove(NS_ConvertUTF16toUTF8(dbFilePath).get());
    2370               0 :     if (rc != SQLITE_OK) {
    2371               0 :       NS_WARNING("Failed to delete db file!");
    2372               0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    2373                 :     }
    2374                 :   }
    2375                 : 
    2376               0 :   nsCOMPtr<nsIFile> fileManagerDirectory;
    2377               0 :   rv = directory->Clone(getter_AddRefs(fileManagerDirectory));
    2378               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2379                 : 
    2380               0 :   rv = fileManagerDirectory->Append(filename);
    2381               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2382                 : 
    2383               0 :   rv = fileManagerDirectory->Exists(&exists);
    2384               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2385                 : 
    2386               0 :   if (exists) {
    2387                 :     bool isDirectory;
    2388               0 :     rv = fileManagerDirectory->IsDirectory(&isDirectory);
    2389               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2390               0 :     NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2391                 : 
    2392               0 :     nsString fileManagerDirectoryPath;
    2393               0 :     rv = fileManagerDirectory->GetPath(fileManagerDirectoryPath);
    2394               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2395                 : 
    2396                 :     rc = sqlite3_quota_remove(
    2397               0 :       NS_ConvertUTF16toUTF8(fileManagerDirectoryPath).get());
    2398               0 :     if (rc != SQLITE_OK) {
    2399               0 :       NS_WARNING("Failed to delete file directory!");
    2400               0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    2401                 :     }
    2402                 : 
    2403               0 :     rv = fileManagerDirectory->Remove(true);
    2404               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2405                 :   }
    2406                 : 
    2407               0 :   return NS_OK;
    2408                 : }
    2409                 : 
    2410                 : nsresult
    2411               0 : DeleteDatabaseHelper::GetSuccessResult(JSContext* aCx, jsval* aVal)
    2412                 : {
    2413               0 :   return NS_OK;
    2414                 : }
    2415                 : 
    2416                 : nsresult
    2417               0 : DeleteDatabaseHelper::Init()
    2418                 : {
    2419                 :   // Note that there's no need to block the database here, since the page
    2420                 :   // never gets to touch it, and all other databases must be closed.
    2421                 : 
    2422               0 :   return NS_OK;
    2423                 : }

Generated by: LCOV version 1.7