dom/indexedDB/OpenDatabaseHelper.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/indexedDB/OpenDatabaseHelper.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2793 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include "mozilla/DebugOnly.h"
     1.9 +
    1.10 +#include "OpenDatabaseHelper.h"
    1.11 +
    1.12 +#include "nsIBFCacheEntry.h"
    1.13 +#include "nsIFile.h"
    1.14 +
    1.15 +#include <algorithm>
    1.16 +#include "mozilla/dom/quota/AcquireListener.h"
    1.17 +#include "mozilla/dom/quota/OriginOrPatternString.h"
    1.18 +#include "mozilla/dom/quota/QuotaManager.h"
    1.19 +#include "mozilla/storage.h"
    1.20 +#include "nsEscape.h"
    1.21 +#include "nsNetUtil.h"
    1.22 +#include "nsThreadUtils.h"
    1.23 +#include "snappy/snappy.h"
    1.24 +
    1.25 +#include "Client.h"
    1.26 +#include "IDBEvents.h"
    1.27 +#include "IDBFactory.h"
    1.28 +#include "IndexedDatabaseManager.h"
    1.29 +#include "ProfilerHelpers.h"
    1.30 +#include "ReportInternalError.h"
    1.31 +
    1.32 +using namespace mozilla;
    1.33 +using namespace mozilla::dom;
    1.34 +USING_INDEXEDDB_NAMESPACE
    1.35 +USING_QUOTA_NAMESPACE
    1.36 +
    1.37 +namespace {
    1.38 +
    1.39 +// If JS_STRUCTURED_CLONE_VERSION changes then we need to update our major
    1.40 +// schema version.
    1.41 +static_assert(JS_STRUCTURED_CLONE_VERSION == 2,
    1.42 +              "Need to update the major schema version.");
    1.43 +
    1.44 +// Major schema version. Bump for almost everything.
    1.45 +const uint32_t kMajorSchemaVersion = 14;
    1.46 +
    1.47 +// Minor schema version. Should almost always be 0 (maybe bump on release
    1.48 +// branches if we have to).
    1.49 +const uint32_t kMinorSchemaVersion = 0;
    1.50 +
    1.51 +// The schema version we store in the SQLite database is a (signed) 32-bit
    1.52 +// integer. The major version is left-shifted 4 bits so the max value is
    1.53 +// 0xFFFFFFF. The minor version occupies the lower 4 bits and its max is 0xF.
    1.54 +static_assert(kMajorSchemaVersion <= 0xFFFFFFF,
    1.55 +              "Major version needs to fit in 28 bits.");
    1.56 +static_assert(kMinorSchemaVersion <= 0xF,
    1.57 +              "Minor version needs to fit in 4 bits.");
    1.58 +
    1.59 +inline
    1.60 +int32_t
    1.61 +MakeSchemaVersion(uint32_t aMajorSchemaVersion,
    1.62 +                  uint32_t aMinorSchemaVersion)
    1.63 +{
    1.64 +  return int32_t((aMajorSchemaVersion << 4) + aMinorSchemaVersion);
    1.65 +}
    1.66 +
    1.67 +const int32_t kSQLiteSchemaVersion = int32_t((kMajorSchemaVersion << 4) +
    1.68 +                                             kMinorSchemaVersion);
    1.69 +
    1.70 +const uint32_t kGoldenRatioU32 = 0x9E3779B9U;
    1.71 +
    1.72 +inline
    1.73 +uint32_t
    1.74 +RotateBitsLeft32(uint32_t value, uint8_t bits)
    1.75 +{
    1.76 +  MOZ_ASSERT(bits < 32);
    1.77 +  return (value << bits) | (value >> (32 - bits));
    1.78 +}
    1.79 +
    1.80 +inline
    1.81 +uint32_t
    1.82 +HashName(const nsAString& aName)
    1.83 +{
    1.84 +  const char16_t* str = aName.BeginReading();
    1.85 +  size_t length = aName.Length();
    1.86 +
    1.87 +  uint32_t hash = 0;
    1.88 +  for (size_t i = 0; i < length; i++) {
    1.89 +    hash = kGoldenRatioU32 * (RotateBitsLeft32(hash, 5) ^ str[i]);
    1.90 +  }
    1.91 +
    1.92 +  return hash;
    1.93 +}
    1.94 +
    1.95 +nsresult
    1.96 +GetDatabaseFilename(const nsAString& aName,
    1.97 +                    nsAString& aDatabaseFilename)
    1.98 +{
    1.99 +  aDatabaseFilename.AppendInt(HashName(aName));
   1.100 +
   1.101 +  nsCString escapedName;
   1.102 +  if (!NS_Escape(NS_ConvertUTF16toUTF8(aName), escapedName, url_XPAlphas)) {
   1.103 +    NS_WARNING("Can't escape database name!");
   1.104 +    return NS_ERROR_UNEXPECTED;
   1.105 +  }
   1.106 +
   1.107 +  const char* forwardIter = escapedName.BeginReading();
   1.108 +  const char* backwardIter = escapedName.EndReading() - 1;
   1.109 +
   1.110 +  nsCString substring;
   1.111 +  while (forwardIter <= backwardIter && substring.Length() < 21) {
   1.112 +    if (substring.Length() % 2) {
   1.113 +      substring.Append(*backwardIter--);
   1.114 +    }
   1.115 +    else {
   1.116 +      substring.Append(*forwardIter++);
   1.117 +    }
   1.118 +  }
   1.119 +
   1.120 +  aDatabaseFilename.Append(NS_ConvertASCIItoUTF16(substring));
   1.121 +
   1.122 +  return NS_OK;
   1.123 +}
   1.124 +
   1.125 +nsresult
   1.126 +CreateFileTables(mozIStorageConnection* aDBConn)
   1.127 +{
   1.128 +  AssertIsOnIOThread();
   1.129 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   1.130 +
   1.131 +  PROFILER_LABEL("IndexedDB", "CreateFileTables");
   1.132 +
   1.133 +  // Table `file`
   1.134 +  nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.135 +    "CREATE TABLE file ("
   1.136 +      "id INTEGER PRIMARY KEY, "
   1.137 +      "refcount INTEGER NOT NULL"
   1.138 +    ");"
   1.139 +  ));
   1.140 +  NS_ENSURE_SUCCESS(rv, rv);
   1.141 +
   1.142 +  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.143 +    "CREATE TRIGGER object_data_insert_trigger "
   1.144 +    "AFTER INSERT ON object_data "
   1.145 +    "FOR EACH ROW "
   1.146 +    "WHEN NEW.file_ids IS NOT NULL "
   1.147 +    "BEGIN "
   1.148 +      "SELECT update_refcount(NULL, NEW.file_ids); "
   1.149 +    "END;"
   1.150 +  ));
   1.151 +  NS_ENSURE_SUCCESS(rv, rv);
   1.152 +
   1.153 +  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.154 +    "CREATE TRIGGER object_data_update_trigger "
   1.155 +    "AFTER UPDATE OF file_ids ON object_data "
   1.156 +    "FOR EACH ROW "
   1.157 +    "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
   1.158 +    "BEGIN "
   1.159 +      "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
   1.160 +    "END;"
   1.161 +  ));
   1.162 +  NS_ENSURE_SUCCESS(rv, rv);
   1.163 +
   1.164 +  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.165 +    "CREATE TRIGGER object_data_delete_trigger "
   1.166 +    "AFTER DELETE ON object_data "
   1.167 +    "FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
   1.168 +    "BEGIN "
   1.169 +      "SELECT update_refcount(OLD.file_ids, NULL); "
   1.170 +    "END;"
   1.171 +  ));
   1.172 +  NS_ENSURE_SUCCESS(rv, rv);
   1.173 +
   1.174 +  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.175 +    "CREATE TRIGGER file_update_trigger "
   1.176 +    "AFTER UPDATE ON file "
   1.177 +    "FOR EACH ROW WHEN NEW.refcount = 0 "
   1.178 +    "BEGIN "
   1.179 +      "DELETE FROM file WHERE id = OLD.id; "
   1.180 +    "END;"
   1.181 +  ));
   1.182 +  NS_ENSURE_SUCCESS(rv, rv);
   1.183 +
   1.184 +  return NS_OK;
   1.185 +}
   1.186 +
   1.187 +nsresult
   1.188 +CreateTables(mozIStorageConnection* aDBConn)
   1.189 +{
   1.190 +  AssertIsOnIOThread();
   1.191 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   1.192 +  NS_ASSERTION(aDBConn, "Passing a null database connection!");
   1.193 +
   1.194 +  PROFILER_LABEL("IndexedDB", "CreateTables");
   1.195 +
   1.196 +  // Table `database`
   1.197 +  nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.198 +    "CREATE TABLE database ("
   1.199 +      "name TEXT NOT NULL, "
   1.200 +      "version INTEGER NOT NULL DEFAULT 0"
   1.201 +    ");"
   1.202 +  ));
   1.203 +  NS_ENSURE_SUCCESS(rv, rv);
   1.204 +
   1.205 +  // Table `object_store`
   1.206 +  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.207 +    "CREATE TABLE object_store ("
   1.208 +      "id INTEGER PRIMARY KEY, "
   1.209 +      "auto_increment INTEGER NOT NULL DEFAULT 0, "
   1.210 +      "name TEXT NOT NULL, "
   1.211 +      "key_path TEXT, "
   1.212 +      "UNIQUE (name)"
   1.213 +    ");"
   1.214 +  ));
   1.215 +  NS_ENSURE_SUCCESS(rv, rv);
   1.216 +
   1.217 +  // Table `object_data`
   1.218 +  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.219 +    "CREATE TABLE object_data ("
   1.220 +      "id INTEGER PRIMARY KEY, "
   1.221 +      "object_store_id INTEGER NOT NULL, "
   1.222 +      "key_value BLOB DEFAULT NULL, "
   1.223 +      "file_ids TEXT, "
   1.224 +      "data BLOB NOT NULL, "
   1.225 +      "UNIQUE (object_store_id, key_value), "
   1.226 +      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
   1.227 +        "CASCADE"
   1.228 +    ");"
   1.229 +  ));
   1.230 +  NS_ENSURE_SUCCESS(rv, rv);
   1.231 +
   1.232 +  // Table `index`
   1.233 +  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.234 +    "CREATE TABLE object_store_index ("
   1.235 +      "id INTEGER PRIMARY KEY, "
   1.236 +      "object_store_id INTEGER NOT NULL, "
   1.237 +      "name TEXT NOT NULL, "
   1.238 +      "key_path TEXT NOT NULL, "
   1.239 +      "unique_index INTEGER NOT NULL, "
   1.240 +      "multientry INTEGER NOT NULL, "
   1.241 +      "UNIQUE (object_store_id, name), "
   1.242 +      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
   1.243 +        "CASCADE"
   1.244 +    ");"
   1.245 +  ));
   1.246 +  NS_ENSURE_SUCCESS(rv, rv);
   1.247 +
   1.248 +  // Table `index_data`
   1.249 +  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.250 +    "CREATE TABLE index_data ("
   1.251 +      "index_id INTEGER NOT NULL, "
   1.252 +      "value BLOB NOT NULL, "
   1.253 +      "object_data_key BLOB NOT NULL, "
   1.254 +      "object_data_id INTEGER NOT NULL, "
   1.255 +      "PRIMARY KEY (index_id, value, object_data_key), "
   1.256 +      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
   1.257 +        "CASCADE, "
   1.258 +      "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
   1.259 +        "CASCADE"
   1.260 +    ");"
   1.261 +  ));
   1.262 +  NS_ENSURE_SUCCESS(rv, rv);
   1.263 +
   1.264 +  // Need this to make cascading deletes from object_data and object_store fast.
   1.265 +  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.266 +    "CREATE INDEX index_data_object_data_id_index "
   1.267 +    "ON index_data (object_data_id);"
   1.268 +  ));
   1.269 +  NS_ENSURE_SUCCESS(rv, rv);
   1.270 +
   1.271 +  // Table `unique_index_data`
   1.272 +  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.273 +    "CREATE TABLE unique_index_data ("
   1.274 +      "index_id INTEGER NOT NULL, "
   1.275 +      "value BLOB NOT NULL, "
   1.276 +      "object_data_key BLOB NOT NULL, "
   1.277 +      "object_data_id INTEGER NOT NULL, "
   1.278 +      "PRIMARY KEY (index_id, value, object_data_key), "
   1.279 +      "UNIQUE (index_id, value), "
   1.280 +      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
   1.281 +        "CASCADE "
   1.282 +      "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
   1.283 +        "CASCADE"
   1.284 +    ");"
   1.285 +  ));
   1.286 +  NS_ENSURE_SUCCESS(rv, rv);
   1.287 +
   1.288 +  // Need this to make cascading deletes from object_data and object_store fast.
   1.289 +  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.290 +    "CREATE INDEX unique_index_data_object_data_id_index "
   1.291 +    "ON unique_index_data (object_data_id);"
   1.292 +  ));
   1.293 +  NS_ENSURE_SUCCESS(rv, rv);
   1.294 +
   1.295 +  rv = CreateFileTables(aDBConn);
   1.296 +  NS_ENSURE_SUCCESS(rv, rv);
   1.297 +
   1.298 +  rv = aDBConn->SetSchemaVersion(kSQLiteSchemaVersion);
   1.299 +  NS_ENSURE_SUCCESS(rv, rv);
   1.300 +
   1.301 +  return NS_OK;
   1.302 +}
   1.303 +
   1.304 +nsresult
   1.305 +UpgradeSchemaFrom4To5(mozIStorageConnection* aConnection)
   1.306 +{
   1.307 +  AssertIsOnIOThread();
   1.308 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   1.309 +
   1.310 +  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom4To5");
   1.311 +
   1.312 +  nsresult rv;
   1.313 +
   1.314 +  // All we changed is the type of the version column, so lets try to
   1.315 +  // convert that to an integer, and if we fail, set it to 0.
   1.316 +  nsCOMPtr<mozIStorageStatement> stmt;
   1.317 +  rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   1.318 +    "SELECT name, version, dataVersion "
   1.319 +    "FROM database"
   1.320 +  ), getter_AddRefs(stmt));
   1.321 +  NS_ENSURE_SUCCESS(rv, rv);
   1.322 +
   1.323 +  nsString name;
   1.324 +  int32_t intVersion;
   1.325 +  int64_t dataVersion;
   1.326 +
   1.327 +  {
   1.328 +    mozStorageStatementScoper scoper(stmt);
   1.329 +
   1.330 +    bool hasResults;
   1.331 +    rv = stmt->ExecuteStep(&hasResults);
   1.332 +    NS_ENSURE_SUCCESS(rv, rv);
   1.333 +    NS_ENSURE_TRUE(hasResults, NS_ERROR_FAILURE);
   1.334 +
   1.335 +    nsString version;
   1.336 +    rv = stmt->GetString(1, version);
   1.337 +    NS_ENSURE_SUCCESS(rv, rv);
   1.338 +
   1.339 +    intVersion = version.ToInteger(&rv);
   1.340 +    if (NS_FAILED(rv)) {
   1.341 +      intVersion = 0;
   1.342 +    }
   1.343 +
   1.344 +    rv = stmt->GetString(0, name);
   1.345 +    NS_ENSURE_SUCCESS(rv, rv);
   1.346 +
   1.347 +    rv = stmt->GetInt64(2, &dataVersion);
   1.348 +    NS_ENSURE_SUCCESS(rv, rv);
   1.349 +  }
   1.350 +
   1.351 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.352 +    "DROP TABLE database"
   1.353 +  ));
   1.354 +  NS_ENSURE_SUCCESS(rv, rv);
   1.355 +
   1.356 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.357 +    "CREATE TABLE database ("
   1.358 +      "name TEXT NOT NULL, "
   1.359 +      "version INTEGER NOT NULL DEFAULT 0, "
   1.360 +      "dataVersion INTEGER NOT NULL"
   1.361 +    ");"
   1.362 +  ));
   1.363 +  NS_ENSURE_SUCCESS(rv, rv);
   1.364 +
   1.365 +  rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   1.366 +    "INSERT INTO database (name, version, dataVersion) "
   1.367 +    "VALUES (:name, :version, :dataVersion)"
   1.368 +  ), getter_AddRefs(stmt));
   1.369 +  NS_ENSURE_SUCCESS(rv, rv);
   1.370 +
   1.371 +  {
   1.372 +    mozStorageStatementScoper scoper(stmt);
   1.373 +
   1.374 +    rv = stmt->BindStringParameter(0, name);
   1.375 +    NS_ENSURE_SUCCESS(rv, rv);
   1.376 +
   1.377 +    rv = stmt->BindInt32Parameter(1, intVersion);
   1.378 +    NS_ENSURE_SUCCESS(rv, rv);
   1.379 +
   1.380 +    rv = stmt->BindInt64Parameter(2, dataVersion);
   1.381 +    NS_ENSURE_SUCCESS(rv, rv);
   1.382 +
   1.383 +    rv = stmt->Execute();
   1.384 +    NS_ENSURE_SUCCESS(rv, rv);
   1.385 +  }
   1.386 +
   1.387 +  rv = aConnection->SetSchemaVersion(5);
   1.388 +  NS_ENSURE_SUCCESS(rv, rv);
   1.389 +
   1.390 +  return NS_OK;
   1.391 +}
   1.392 +
   1.393 +nsresult
   1.394 +UpgradeSchemaFrom5To6(mozIStorageConnection* aConnection)
   1.395 +{
   1.396 +  AssertIsOnIOThread();
   1.397 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   1.398 +
   1.399 +  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom5To6");
   1.400 +
   1.401 +  // First, drop all the indexes we're no longer going to use.
   1.402 +  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.403 +    "DROP INDEX key_index;"
   1.404 +  ));
   1.405 +  NS_ENSURE_SUCCESS(rv, rv);
   1.406 +
   1.407 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.408 +    "DROP INDEX ai_key_index;"
   1.409 +  ));
   1.410 +  NS_ENSURE_SUCCESS(rv, rv);
   1.411 +
   1.412 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.413 +    "DROP INDEX value_index;"
   1.414 +  ));
   1.415 +  NS_ENSURE_SUCCESS(rv, rv);
   1.416 +
   1.417 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.418 +    "DROP INDEX ai_value_index;"
   1.419 +  ));
   1.420 +  NS_ENSURE_SUCCESS(rv, rv);
   1.421 +
   1.422 +  // Now, reorder the columns of object_data to put the blob data last. We do
   1.423 +  // this by copying into a temporary table, dropping the original, then copying
   1.424 +  // back into a newly created table.
   1.425 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.426 +    "CREATE TEMPORARY TABLE temp_upgrade ("
   1.427 +      "id INTEGER PRIMARY KEY, "
   1.428 +      "object_store_id, "
   1.429 +      "key_value, "
   1.430 +      "data "
   1.431 +    ");"
   1.432 +  ));
   1.433 +  NS_ENSURE_SUCCESS(rv, rv);
   1.434 +
   1.435 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.436 +    "INSERT INTO temp_upgrade "
   1.437 +      "SELECT id, object_store_id, key_value, data "
   1.438 +      "FROM object_data;"
   1.439 +  ));
   1.440 +  NS_ENSURE_SUCCESS(rv, rv);
   1.441 +
   1.442 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.443 +    "DROP TABLE object_data;"
   1.444 +  ));
   1.445 +  NS_ENSURE_SUCCESS(rv, rv);
   1.446 +
   1.447 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.448 +    "CREATE TABLE object_data ("
   1.449 +      "id INTEGER PRIMARY KEY, "
   1.450 +      "object_store_id INTEGER NOT NULL, "
   1.451 +      "key_value DEFAULT NULL, "
   1.452 +      "data BLOB NOT NULL, "
   1.453 +      "UNIQUE (object_store_id, key_value), "
   1.454 +      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
   1.455 +        "CASCADE"
   1.456 +    ");"
   1.457 +  ));
   1.458 +  NS_ENSURE_SUCCESS(rv, rv);
   1.459 +
   1.460 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.461 +    "INSERT INTO object_data "
   1.462 +      "SELECT id, object_store_id, key_value, data "
   1.463 +      "FROM temp_upgrade;"
   1.464 +  ));
   1.465 +  NS_ENSURE_SUCCESS(rv, rv);
   1.466 +
   1.467 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.468 +    "DROP TABLE temp_upgrade;"
   1.469 +  ));
   1.470 +  NS_ENSURE_SUCCESS(rv, rv);
   1.471 +
   1.472 +  // We need to add a unique constraint to our ai_object_data table. Copy all
   1.473 +  // the data out of it using a temporary table as before.
   1.474 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.475 +    "CREATE TEMPORARY TABLE temp_upgrade ("
   1.476 +      "id INTEGER PRIMARY KEY, "
   1.477 +      "object_store_id, "
   1.478 +      "data "
   1.479 +    ");"
   1.480 +  ));
   1.481 +  NS_ENSURE_SUCCESS(rv, rv);
   1.482 +
   1.483 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.484 +    "INSERT INTO temp_upgrade "
   1.485 +      "SELECT id, object_store_id, data "
   1.486 +      "FROM ai_object_data;"
   1.487 +  ));
   1.488 +  NS_ENSURE_SUCCESS(rv, rv);
   1.489 +
   1.490 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.491 +    "DROP TABLE ai_object_data;"
   1.492 +  ));
   1.493 +  NS_ENSURE_SUCCESS(rv, rv);
   1.494 +
   1.495 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.496 +    "CREATE TABLE ai_object_data ("
   1.497 +      "id INTEGER PRIMARY KEY AUTOINCREMENT, "
   1.498 +      "object_store_id INTEGER NOT NULL, "
   1.499 +      "data BLOB NOT NULL, "
   1.500 +      "UNIQUE (object_store_id, id), "
   1.501 +      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
   1.502 +        "CASCADE"
   1.503 +    ");"
   1.504 +  ));
   1.505 +  NS_ENSURE_SUCCESS(rv, rv);
   1.506 +
   1.507 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.508 +    "INSERT INTO ai_object_data "
   1.509 +      "SELECT id, object_store_id, data "
   1.510 +      "FROM temp_upgrade;"
   1.511 +  ));
   1.512 +  NS_ENSURE_SUCCESS(rv, rv);
   1.513 +
   1.514 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.515 +    "DROP TABLE temp_upgrade;"
   1.516 +  ));
   1.517 +  NS_ENSURE_SUCCESS(rv, rv);
   1.518 +
   1.519 +  // Fix up the index_data table. We're reordering the columns as well as
   1.520 +  // changing the primary key from being a simple id to being a composite.
   1.521 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.522 +    "CREATE TEMPORARY TABLE temp_upgrade ("
   1.523 +      "index_id, "
   1.524 +      "value, "
   1.525 +      "object_data_key, "
   1.526 +      "object_data_id "
   1.527 +    ");"
   1.528 +  ));
   1.529 +  NS_ENSURE_SUCCESS(rv, rv);
   1.530 +
   1.531 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.532 +    "INSERT INTO temp_upgrade "
   1.533 +      "SELECT index_id, value, object_data_key, object_data_id "
   1.534 +      "FROM index_data;"
   1.535 +  ));
   1.536 +  NS_ENSURE_SUCCESS(rv, rv);
   1.537 +
   1.538 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.539 +    "DROP TABLE index_data;"
   1.540 +  ));
   1.541 +  NS_ENSURE_SUCCESS(rv, rv);
   1.542 +
   1.543 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.544 +    "CREATE TABLE index_data ("
   1.545 +      "index_id INTEGER NOT NULL, "
   1.546 +      "value NOT NULL, "
   1.547 +      "object_data_key NOT NULL, "
   1.548 +      "object_data_id INTEGER NOT NULL, "
   1.549 +      "PRIMARY KEY (index_id, value, object_data_key), "
   1.550 +      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
   1.551 +        "CASCADE, "
   1.552 +      "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
   1.553 +        "CASCADE"
   1.554 +    ");"
   1.555 +  ));
   1.556 +  NS_ENSURE_SUCCESS(rv, rv);
   1.557 +
   1.558 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.559 +    "INSERT OR IGNORE INTO index_data "
   1.560 +      "SELECT index_id, value, object_data_key, object_data_id "
   1.561 +      "FROM temp_upgrade;"
   1.562 +  ));
   1.563 +  NS_ENSURE_SUCCESS(rv, rv);
   1.564 +
   1.565 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.566 +    "DROP TABLE temp_upgrade;"
   1.567 +  ));
   1.568 +  NS_ENSURE_SUCCESS(rv, rv);
   1.569 +
   1.570 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.571 +    "CREATE INDEX index_data_object_data_id_index "
   1.572 +    "ON index_data (object_data_id);"
   1.573 +  ));
   1.574 +  NS_ENSURE_SUCCESS(rv, rv);
   1.575 +
   1.576 +  // Fix up the unique_index_data table. We're reordering the columns as well as
   1.577 +  // changing the primary key from being a simple id to being a composite.
   1.578 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.579 +    "CREATE TEMPORARY TABLE temp_upgrade ("
   1.580 +      "index_id, "
   1.581 +      "value, "
   1.582 +      "object_data_key, "
   1.583 +      "object_data_id "
   1.584 +    ");"
   1.585 +  ));
   1.586 +  NS_ENSURE_SUCCESS(rv, rv);
   1.587 +
   1.588 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.589 +    "INSERT INTO temp_upgrade "
   1.590 +      "SELECT index_id, value, object_data_key, object_data_id "
   1.591 +      "FROM unique_index_data;"
   1.592 +  ));
   1.593 +  NS_ENSURE_SUCCESS(rv, rv);
   1.594 +
   1.595 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.596 +    "DROP TABLE unique_index_data;"
   1.597 +  ));
   1.598 +  NS_ENSURE_SUCCESS(rv, rv);
   1.599 +
   1.600 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.601 +    "CREATE TABLE unique_index_data ("
   1.602 +      "index_id INTEGER NOT NULL, "
   1.603 +      "value NOT NULL, "
   1.604 +      "object_data_key NOT NULL, "
   1.605 +      "object_data_id INTEGER NOT NULL, "
   1.606 +      "PRIMARY KEY (index_id, value, object_data_key), "
   1.607 +      "UNIQUE (index_id, value), "
   1.608 +      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
   1.609 +        "CASCADE "
   1.610 +      "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
   1.611 +        "CASCADE"
   1.612 +    ");"
   1.613 +  ));
   1.614 +  NS_ENSURE_SUCCESS(rv, rv);
   1.615 +
   1.616 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.617 +    "INSERT INTO unique_index_data "
   1.618 +      "SELECT index_id, value, object_data_key, object_data_id "
   1.619 +      "FROM temp_upgrade;"
   1.620 +  ));
   1.621 +  NS_ENSURE_SUCCESS(rv, rv);
   1.622 +
   1.623 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.624 +    "DROP TABLE temp_upgrade;"
   1.625 +  ));
   1.626 +  NS_ENSURE_SUCCESS(rv, rv);
   1.627 +
   1.628 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.629 +    "CREATE INDEX unique_index_data_object_data_id_index "
   1.630 +    "ON unique_index_data (object_data_id);"
   1.631 +  ));
   1.632 +  NS_ENSURE_SUCCESS(rv, rv);
   1.633 +
   1.634 +  // Fix up the ai_index_data table. We're reordering the columns as well as
   1.635 +  // changing the primary key from being a simple id to being a composite.
   1.636 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.637 +    "CREATE TEMPORARY TABLE temp_upgrade ("
   1.638 +      "index_id, "
   1.639 +      "value, "
   1.640 +      "ai_object_data_id "
   1.641 +    ");"
   1.642 +  ));
   1.643 +  NS_ENSURE_SUCCESS(rv, rv);
   1.644 +
   1.645 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.646 +    "INSERT INTO temp_upgrade "
   1.647 +      "SELECT index_id, value, ai_object_data_id "
   1.648 +      "FROM ai_index_data;"
   1.649 +  ));
   1.650 +  NS_ENSURE_SUCCESS(rv, rv);
   1.651 +
   1.652 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.653 +    "DROP TABLE ai_index_data;"
   1.654 +  ));
   1.655 +  NS_ENSURE_SUCCESS(rv, rv);
   1.656 +
   1.657 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.658 +    "CREATE TABLE ai_index_data ("
   1.659 +      "index_id INTEGER NOT NULL, "
   1.660 +      "value NOT NULL, "
   1.661 +      "ai_object_data_id INTEGER NOT NULL, "
   1.662 +      "PRIMARY KEY (index_id, value, ai_object_data_id), "
   1.663 +      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
   1.664 +        "CASCADE, "
   1.665 +      "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
   1.666 +        "CASCADE"
   1.667 +    ");"
   1.668 +  ));
   1.669 +  NS_ENSURE_SUCCESS(rv, rv);
   1.670 +
   1.671 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.672 +    "INSERT OR IGNORE INTO ai_index_data "
   1.673 +      "SELECT index_id, value, ai_object_data_id "
   1.674 +      "FROM temp_upgrade;"
   1.675 +  ));
   1.676 +  NS_ENSURE_SUCCESS(rv, rv);
   1.677 +
   1.678 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.679 +    "DROP TABLE temp_upgrade;"
   1.680 +  ));
   1.681 +  NS_ENSURE_SUCCESS(rv, rv);
   1.682 +
   1.683 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.684 +    "CREATE INDEX ai_index_data_ai_object_data_id_index "
   1.685 +    "ON ai_index_data (ai_object_data_id);"
   1.686 +  ));
   1.687 +  NS_ENSURE_SUCCESS(rv, rv);
   1.688 +
   1.689 +  // Fix up the ai_unique_index_data table. We're reordering the columns as well
   1.690 +  // as changing the primary key from being a simple id to being a composite.
   1.691 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.692 +    "CREATE TEMPORARY TABLE temp_upgrade ("
   1.693 +      "index_id, "
   1.694 +      "value, "
   1.695 +      "ai_object_data_id "
   1.696 +    ");"
   1.697 +  ));
   1.698 +  NS_ENSURE_SUCCESS(rv, rv);
   1.699 +
   1.700 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.701 +    "INSERT INTO temp_upgrade "
   1.702 +      "SELECT index_id, value, ai_object_data_id "
   1.703 +      "FROM ai_unique_index_data;"
   1.704 +  ));
   1.705 +  NS_ENSURE_SUCCESS(rv, rv);
   1.706 +
   1.707 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.708 +    "DROP TABLE ai_unique_index_data;"
   1.709 +  ));
   1.710 +  NS_ENSURE_SUCCESS(rv, rv);
   1.711 +
   1.712 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.713 +    "CREATE TABLE ai_unique_index_data ("
   1.714 +      "index_id INTEGER NOT NULL, "
   1.715 +      "value NOT NULL, "
   1.716 +      "ai_object_data_id INTEGER NOT NULL, "
   1.717 +      "UNIQUE (index_id, value), "
   1.718 +      "PRIMARY KEY (index_id, value, ai_object_data_id), "
   1.719 +      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
   1.720 +        "CASCADE, "
   1.721 +      "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
   1.722 +        "CASCADE"
   1.723 +    ");"
   1.724 +  ));
   1.725 +  NS_ENSURE_SUCCESS(rv, rv);
   1.726 +
   1.727 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.728 +    "INSERT INTO ai_unique_index_data "
   1.729 +      "SELECT index_id, value, ai_object_data_id "
   1.730 +      "FROM temp_upgrade;"
   1.731 +  ));
   1.732 +  NS_ENSURE_SUCCESS(rv, rv);
   1.733 +
   1.734 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.735 +    "DROP TABLE temp_upgrade;"
   1.736 +  ));
   1.737 +  NS_ENSURE_SUCCESS(rv, rv);
   1.738 +
   1.739 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.740 +    "CREATE INDEX ai_unique_index_data_ai_object_data_id_index "
   1.741 +    "ON ai_unique_index_data (ai_object_data_id);"
   1.742 +  ));
   1.743 +  NS_ENSURE_SUCCESS(rv, rv);
   1.744 +
   1.745 +  rv = aConnection->SetSchemaVersion(6);
   1.746 +  NS_ENSURE_SUCCESS(rv, rv);
   1.747 +
   1.748 +  return NS_OK;
   1.749 +}
   1.750 +
   1.751 +nsresult
   1.752 +UpgradeSchemaFrom6To7(mozIStorageConnection* aConnection)
   1.753 +{
   1.754 +  AssertIsOnIOThread();
   1.755 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   1.756 +
   1.757 +  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom6To7");
   1.758 +
   1.759 +  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.760 +    "CREATE TEMPORARY TABLE temp_upgrade ("
   1.761 +      "id, "
   1.762 +      "name, "
   1.763 +      "key_path, "
   1.764 +      "auto_increment"
   1.765 +    ");"
   1.766 +  ));
   1.767 +  NS_ENSURE_SUCCESS(rv, rv);
   1.768 +
   1.769 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.770 +    "INSERT INTO temp_upgrade "
   1.771 +      "SELECT id, name, key_path, auto_increment "
   1.772 +      "FROM object_store;"
   1.773 +  ));
   1.774 +  NS_ENSURE_SUCCESS(rv, rv);
   1.775 +
   1.776 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.777 +    "DROP TABLE object_store;"
   1.778 +  ));
   1.779 +  NS_ENSURE_SUCCESS(rv, rv);
   1.780 +
   1.781 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.782 +    "CREATE TABLE object_store ("
   1.783 +      "id INTEGER PRIMARY KEY, "
   1.784 +      "auto_increment INTEGER NOT NULL DEFAULT 0, "
   1.785 +      "name TEXT NOT NULL, "
   1.786 +      "key_path TEXT, "
   1.787 +      "UNIQUE (name)"
   1.788 +    ");"
   1.789 +  ));
   1.790 +  NS_ENSURE_SUCCESS(rv, rv);
   1.791 +
   1.792 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.793 +    "INSERT INTO object_store "
   1.794 +      "SELECT id, auto_increment, name, nullif(key_path, '') "
   1.795 +      "FROM temp_upgrade;"
   1.796 +  ));
   1.797 +  NS_ENSURE_SUCCESS(rv, rv);
   1.798 +
   1.799 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.800 +    "DROP TABLE temp_upgrade;"
   1.801 +  ));
   1.802 +  NS_ENSURE_SUCCESS(rv, rv);
   1.803 +
   1.804 +  rv = aConnection->SetSchemaVersion(7);
   1.805 +  NS_ENSURE_SUCCESS(rv, rv);
   1.806 +
   1.807 +  return NS_OK;
   1.808 +}
   1.809 +
   1.810 +nsresult
   1.811 +UpgradeSchemaFrom7To8(mozIStorageConnection* aConnection)
   1.812 +{
   1.813 +  AssertIsOnIOThread();
   1.814 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   1.815 +
   1.816 +  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom7To8");
   1.817 +
   1.818 +  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.819 +    "CREATE TEMPORARY TABLE temp_upgrade ("
   1.820 +      "id, "
   1.821 +      "object_store_id, "
   1.822 +      "name, "
   1.823 +      "key_path, "
   1.824 +      "unique_index, "
   1.825 +      "object_store_autoincrement"
   1.826 +    ");"
   1.827 +  ));
   1.828 +  NS_ENSURE_SUCCESS(rv, rv);
   1.829 +
   1.830 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.831 +    "INSERT INTO temp_upgrade "
   1.832 +      "SELECT id, object_store_id, name, key_path, "
   1.833 +      "unique_index, object_store_autoincrement "
   1.834 +      "FROM object_store_index;"
   1.835 +  ));
   1.836 +  NS_ENSURE_SUCCESS(rv, rv);
   1.837 +
   1.838 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.839 +    "DROP TABLE object_store_index;"
   1.840 +  ));
   1.841 +  NS_ENSURE_SUCCESS(rv, rv);
   1.842 +
   1.843 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.844 +    "CREATE TABLE object_store_index ("
   1.845 +      "id INTEGER, "
   1.846 +      "object_store_id INTEGER NOT NULL, "
   1.847 +      "name TEXT NOT NULL, "
   1.848 +      "key_path TEXT NOT NULL, "
   1.849 +      "unique_index INTEGER NOT NULL, "
   1.850 +      "multientry INTEGER NOT NULL, "
   1.851 +      "object_store_autoincrement INTERGER NOT NULL, "
   1.852 +      "PRIMARY KEY (id), "
   1.853 +      "UNIQUE (object_store_id, name), "
   1.854 +      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
   1.855 +        "CASCADE"
   1.856 +    ");"
   1.857 +  ));
   1.858 +  NS_ENSURE_SUCCESS(rv, rv);
   1.859 +
   1.860 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.861 +    "INSERT INTO object_store_index "
   1.862 +      "SELECT id, object_store_id, name, key_path, "
   1.863 +      "unique_index, 0, object_store_autoincrement "
   1.864 +      "FROM temp_upgrade;"
   1.865 +  ));
   1.866 +  NS_ENSURE_SUCCESS(rv, rv);
   1.867 +
   1.868 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.869 +    "DROP TABLE temp_upgrade;"
   1.870 +  ));
   1.871 +  NS_ENSURE_SUCCESS(rv, rv);
   1.872 +
   1.873 +  rv = aConnection->SetSchemaVersion(8);
   1.874 +  NS_ENSURE_SUCCESS(rv, rv);
   1.875 +
   1.876 +  return NS_OK;
   1.877 +}
   1.878 +
   1.879 +class CompressDataBlobsFunction MOZ_FINAL : public mozIStorageFunction
   1.880 +{
   1.881 +public:
   1.882 +  NS_DECL_ISUPPORTS
   1.883 +
   1.884 +  NS_IMETHOD
   1.885 +  OnFunctionCall(mozIStorageValueArray* aArguments,
   1.886 +                 nsIVariant** aResult)
   1.887 +  {
   1.888 +    PROFILER_LABEL("IndexedDB", "CompressDataBlobsFunction::OnFunctionCall");
   1.889 +
   1.890 +    uint32_t argc;
   1.891 +    nsresult rv = aArguments->GetNumEntries(&argc);
   1.892 +    NS_ENSURE_SUCCESS(rv, rv);
   1.893 +
   1.894 +    if (argc != 1) {
   1.895 +      NS_WARNING("Don't call me with the wrong number of arguments!");
   1.896 +      return NS_ERROR_UNEXPECTED;
   1.897 +    }
   1.898 +
   1.899 +    int32_t type;
   1.900 +    rv = aArguments->GetTypeOfIndex(0, &type);
   1.901 +    NS_ENSURE_SUCCESS(rv, rv);
   1.902 +
   1.903 +    if (type != mozIStorageStatement::VALUE_TYPE_BLOB) {
   1.904 +      NS_WARNING("Don't call me with the wrong type of arguments!");
   1.905 +      return NS_ERROR_UNEXPECTED;
   1.906 +    }
   1.907 +
   1.908 +    const uint8_t* uncompressed;
   1.909 +    uint32_t uncompressedLength;
   1.910 +    rv = aArguments->GetSharedBlob(0, &uncompressedLength, &uncompressed);
   1.911 +    NS_ENSURE_SUCCESS(rv, rv);
   1.912 +
   1.913 +    size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
   1.914 +    char* compressed = (char*)moz_malloc(compressedLength);
   1.915 +    NS_ENSURE_TRUE(compressed, NS_ERROR_OUT_OF_MEMORY);
   1.916 +
   1.917 +    snappy::RawCompress(reinterpret_cast<const char*>(uncompressed),
   1.918 +                        uncompressedLength, compressed, &compressedLength);
   1.919 +
   1.920 +    std::pair<uint8_t *, int> data((uint8_t*)compressed,
   1.921 +                                   int(compressedLength));
   1.922 +    // The variant takes ownership of | compressed |.
   1.923 +    nsCOMPtr<nsIVariant> result = new mozilla::storage::AdoptedBlobVariant(data);
   1.924 +
   1.925 +    result.forget(aResult);
   1.926 +    return NS_OK;
   1.927 +  }
   1.928 +};
   1.929 +
   1.930 +NS_IMPL_ISUPPORTS(CompressDataBlobsFunction, mozIStorageFunction)
   1.931 +
   1.932 +nsresult
   1.933 +UpgradeSchemaFrom8To9_0(mozIStorageConnection* aConnection)
   1.934 +{
   1.935 +  AssertIsOnIOThread();
   1.936 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   1.937 +
   1.938 +  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom8To9_0");
   1.939 +
   1.940 +  // We no longer use the dataVersion column.
   1.941 +  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.942 +    "UPDATE database SET dataVersion = 0;"
   1.943 +  ));
   1.944 +  NS_ENSURE_SUCCESS(rv, rv);
   1.945 +
   1.946 +  nsCOMPtr<mozIStorageFunction> compressor = new CompressDataBlobsFunction();
   1.947 +
   1.948 +  NS_NAMED_LITERAL_CSTRING(compressorName, "compress");
   1.949 +
   1.950 +  rv = aConnection->CreateFunction(compressorName, 1, compressor);
   1.951 +  NS_ENSURE_SUCCESS(rv, rv);
   1.952 +
   1.953 +  // Turn off foreign key constraints before we do anything here.
   1.954 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.955 +    "UPDATE object_data SET data = compress(data);"
   1.956 +  ));
   1.957 +  NS_ENSURE_SUCCESS(rv, rv);
   1.958 +
   1.959 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.960 +    "UPDATE ai_object_data SET data = compress(data);"
   1.961 +  ));
   1.962 +  NS_ENSURE_SUCCESS(rv, rv);
   1.963 +
   1.964 +  rv = aConnection->RemoveFunction(compressorName);
   1.965 +  NS_ENSURE_SUCCESS(rv, rv);
   1.966 +
   1.967 +  rv = aConnection->SetSchemaVersion(MakeSchemaVersion(9, 0));
   1.968 +  NS_ENSURE_SUCCESS(rv, rv);
   1.969 +
   1.970 +  return NS_OK;
   1.971 +}
   1.972 +
   1.973 +nsresult
   1.974 +UpgradeSchemaFrom9_0To10_0(mozIStorageConnection* aConnection)
   1.975 +{
   1.976 +  AssertIsOnIOThread();
   1.977 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   1.978 +
   1.979 +  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom9_0To10_0");
   1.980 +
   1.981 +  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.982 +    "ALTER TABLE object_data ADD COLUMN file_ids TEXT;"
   1.983 +  ));
   1.984 +  NS_ENSURE_SUCCESS(rv, rv);
   1.985 +
   1.986 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   1.987 +    "ALTER TABLE ai_object_data ADD COLUMN file_ids TEXT;"
   1.988 +  ));
   1.989 +  NS_ENSURE_SUCCESS(rv, rv);
   1.990 +
   1.991 +  rv = CreateFileTables(aConnection);
   1.992 +  NS_ENSURE_SUCCESS(rv, rv);
   1.993 +
   1.994 +  rv = aConnection->SetSchemaVersion(MakeSchemaVersion(10, 0));
   1.995 +  NS_ENSURE_SUCCESS(rv, rv);
   1.996 +
   1.997 +  return NS_OK;
   1.998 +}
   1.999 +
  1.1000 +nsresult
  1.1001 +UpgradeSchemaFrom10_0To11_0(mozIStorageConnection* aConnection)
  1.1002 +{
  1.1003 +  AssertIsOnIOThread();
  1.1004 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1.1005 +
  1.1006 +  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom10_0To11_0");
  1.1007 +
  1.1008 +  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1009 +    "CREATE TEMPORARY TABLE temp_upgrade ("
  1.1010 +      "id, "
  1.1011 +      "object_store_id, "
  1.1012 +      "name, "
  1.1013 +      "key_path, "
  1.1014 +      "unique_index, "
  1.1015 +      "multientry"
  1.1016 +    ");"
  1.1017 +  ));
  1.1018 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1019 +
  1.1020 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1021 +    "INSERT INTO temp_upgrade "
  1.1022 +      "SELECT id, object_store_id, name, key_path, "
  1.1023 +      "unique_index, multientry "
  1.1024 +      "FROM object_store_index;"
  1.1025 +  ));
  1.1026 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1027 +
  1.1028 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1029 +    "DROP TABLE object_store_index;"
  1.1030 +  ));
  1.1031 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1032 +
  1.1033 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1034 +    "CREATE TABLE object_store_index ("
  1.1035 +      "id INTEGER PRIMARY KEY, "
  1.1036 +      "object_store_id INTEGER NOT NULL, "
  1.1037 +      "name TEXT NOT NULL, "
  1.1038 +      "key_path TEXT NOT NULL, "
  1.1039 +      "unique_index INTEGER NOT NULL, "
  1.1040 +      "multientry INTEGER NOT NULL, "
  1.1041 +      "UNIQUE (object_store_id, name), "
  1.1042 +      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
  1.1043 +        "CASCADE"
  1.1044 +    ");"
  1.1045 +  ));
  1.1046 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1047 +
  1.1048 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1049 +    "INSERT INTO object_store_index "
  1.1050 +      "SELECT id, object_store_id, name, key_path, "
  1.1051 +      "unique_index, multientry "
  1.1052 +      "FROM temp_upgrade;"
  1.1053 +  ));
  1.1054 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1055 +
  1.1056 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1057 +    "DROP TABLE temp_upgrade;"
  1.1058 +  ));
  1.1059 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1060 +
  1.1061 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1062 +    "DROP TRIGGER object_data_insert_trigger;"
  1.1063 +  ));
  1.1064 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1065 +
  1.1066 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1067 +    "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
  1.1068 +      "SELECT object_store_id, id, data, file_ids "
  1.1069 +      "FROM ai_object_data;"
  1.1070 +  ));
  1.1071 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1072 +
  1.1073 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1074 +    "CREATE TRIGGER object_data_insert_trigger "
  1.1075 +    "AFTER INSERT ON object_data "
  1.1076 +    "FOR EACH ROW "
  1.1077 +    "WHEN NEW.file_ids IS NOT NULL "
  1.1078 +    "BEGIN "
  1.1079 +      "SELECT update_refcount(NULL, NEW.file_ids); "
  1.1080 +    "END;"
  1.1081 +  ));
  1.1082 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1083 +
  1.1084 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1085 +    "INSERT INTO index_data (index_id, value, object_data_key, object_data_id) "
  1.1086 +      "SELECT ai_index_data.index_id, ai_index_data.value, ai_index_data.ai_object_data_id, object_data.id "
  1.1087 +      "FROM ai_index_data "
  1.1088 +      "INNER JOIN object_store_index ON "
  1.1089 +        "object_store_index.id = ai_index_data.index_id "
  1.1090 +      "INNER JOIN object_data ON "
  1.1091 +        "object_data.object_store_id = object_store_index.object_store_id AND "
  1.1092 +        "object_data.key_value = ai_index_data.ai_object_data_id;"
  1.1093 +  ));
  1.1094 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1095 +
  1.1096 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1097 +    "INSERT INTO unique_index_data (index_id, value, object_data_key, object_data_id) "
  1.1098 +      "SELECT ai_unique_index_data.index_id, ai_unique_index_data.value, ai_unique_index_data.ai_object_data_id, object_data.id "
  1.1099 +      "FROM ai_unique_index_data "
  1.1100 +      "INNER JOIN object_store_index ON "
  1.1101 +        "object_store_index.id = ai_unique_index_data.index_id "
  1.1102 +      "INNER JOIN object_data ON "
  1.1103 +        "object_data.object_store_id = object_store_index.object_store_id AND "
  1.1104 +        "object_data.key_value = ai_unique_index_data.ai_object_data_id;"
  1.1105 +  ));
  1.1106 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1107 +
  1.1108 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1109 +    "UPDATE object_store "
  1.1110 +      "SET auto_increment = (SELECT max(id) FROM ai_object_data) + 1 "
  1.1111 +      "WHERE auto_increment;"
  1.1112 +  ));
  1.1113 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1114 +
  1.1115 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1116 +    "DROP TABLE ai_unique_index_data;"
  1.1117 +  ));
  1.1118 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1119 +
  1.1120 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1121 +    "DROP TABLE ai_index_data;"
  1.1122 +  ));
  1.1123 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1124 +
  1.1125 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1126 +    "DROP TABLE ai_object_data;"
  1.1127 +  ));
  1.1128 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1129 +
  1.1130 +  rv = aConnection->SetSchemaVersion(MakeSchemaVersion(11, 0));
  1.1131 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1132 +
  1.1133 +  return NS_OK;
  1.1134 +}
  1.1135 +
  1.1136 +class EncodeKeysFunction MOZ_FINAL : public mozIStorageFunction
  1.1137 +{
  1.1138 +public:
  1.1139 +  NS_DECL_ISUPPORTS
  1.1140 +
  1.1141 +  NS_IMETHOD
  1.1142 +  OnFunctionCall(mozIStorageValueArray* aArguments,
  1.1143 +                 nsIVariant** aResult)
  1.1144 +  {
  1.1145 +    PROFILER_LABEL("IndexedDB", "EncodeKeysFunction::OnFunctionCall");
  1.1146 +
  1.1147 +    uint32_t argc;
  1.1148 +    nsresult rv = aArguments->GetNumEntries(&argc);
  1.1149 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1150 +
  1.1151 +    if (argc != 1) {
  1.1152 +      NS_WARNING("Don't call me with the wrong number of arguments!");
  1.1153 +      return NS_ERROR_UNEXPECTED;
  1.1154 +    }
  1.1155 +
  1.1156 +    int32_t type;
  1.1157 +    rv = aArguments->GetTypeOfIndex(0, &type);
  1.1158 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1159 +
  1.1160 +    Key key;
  1.1161 +    if (type == mozIStorageStatement::VALUE_TYPE_INTEGER) {
  1.1162 +      int64_t intKey;
  1.1163 +      aArguments->GetInt64(0, &intKey);
  1.1164 +      key.SetFromInteger(intKey);
  1.1165 +    }
  1.1166 +    else if (type == mozIStorageStatement::VALUE_TYPE_TEXT) {
  1.1167 +      nsString stringKey;
  1.1168 +      aArguments->GetString(0, stringKey);
  1.1169 +      key.SetFromString(stringKey);
  1.1170 +    }
  1.1171 +    else {
  1.1172 +      NS_WARNING("Don't call me with the wrong type of arguments!");
  1.1173 +      return NS_ERROR_UNEXPECTED;
  1.1174 +    }
  1.1175 +
  1.1176 +    const nsCString& buffer = key.GetBuffer();
  1.1177 +
  1.1178 +    std::pair<const void *, int> data(static_cast<const void*>(buffer.get()),
  1.1179 +                                      int(buffer.Length()));
  1.1180 +
  1.1181 +    nsCOMPtr<nsIVariant> result = new mozilla::storage::BlobVariant(data);
  1.1182 +
  1.1183 +    result.forget(aResult);
  1.1184 +    return NS_OK;
  1.1185 +  }
  1.1186 +};
  1.1187 +
  1.1188 +NS_IMPL_ISUPPORTS(EncodeKeysFunction, mozIStorageFunction)
  1.1189 +
  1.1190 +nsresult
  1.1191 +UpgradeSchemaFrom11_0To12_0(mozIStorageConnection* aConnection)
  1.1192 +{
  1.1193 +  AssertIsOnIOThread();
  1.1194 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1.1195 +
  1.1196 +  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom11_0To12_0");
  1.1197 +
  1.1198 +  NS_NAMED_LITERAL_CSTRING(encoderName, "encode");
  1.1199 +
  1.1200 +  nsCOMPtr<mozIStorageFunction> encoder = new EncodeKeysFunction();
  1.1201 +
  1.1202 +  nsresult rv = aConnection->CreateFunction(encoderName, 1, encoder);
  1.1203 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1204 +
  1.1205 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1206 +    "CREATE TEMPORARY TABLE temp_upgrade ("
  1.1207 +      "id INTEGER PRIMARY KEY, "
  1.1208 +      "object_store_id, "
  1.1209 +      "key_value, "
  1.1210 +      "data, "
  1.1211 +      "file_ids "
  1.1212 +    ");"
  1.1213 +  ));
  1.1214 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1215 +
  1.1216 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1217 +    "INSERT INTO temp_upgrade "
  1.1218 +      "SELECT id, object_store_id, encode(key_value), data, file_ids "
  1.1219 +      "FROM object_data;"
  1.1220 +  ));
  1.1221 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1222 +
  1.1223 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1224 +    "DROP TABLE object_data;"
  1.1225 +  ));
  1.1226 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1227 +
  1.1228 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1229 +    "CREATE TABLE object_data ("
  1.1230 +      "id INTEGER PRIMARY KEY, "
  1.1231 +      "object_store_id INTEGER NOT NULL, "
  1.1232 +      "key_value BLOB DEFAULT NULL, "
  1.1233 +      "file_ids TEXT, "
  1.1234 +      "data BLOB NOT NULL, "
  1.1235 +      "UNIQUE (object_store_id, key_value), "
  1.1236 +      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
  1.1237 +        "CASCADE"
  1.1238 +    ");"
  1.1239 +  ));
  1.1240 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1241 +
  1.1242 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1243 +    "INSERT INTO object_data "
  1.1244 +      "SELECT id, object_store_id, key_value, file_ids, data "
  1.1245 +      "FROM temp_upgrade;"
  1.1246 +  ));
  1.1247 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1248 +
  1.1249 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1250 +    "DROP TABLE temp_upgrade;"
  1.1251 +  ));
  1.1252 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1253 +
  1.1254 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1255 +    "CREATE TRIGGER object_data_insert_trigger "
  1.1256 +    "AFTER INSERT ON object_data "
  1.1257 +    "FOR EACH ROW "
  1.1258 +    "WHEN NEW.file_ids IS NOT NULL "
  1.1259 +    "BEGIN "
  1.1260 +      "SELECT update_refcount(NULL, NEW.file_ids); "
  1.1261 +    "END;"
  1.1262 +  ));
  1.1263 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1264 +
  1.1265 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1266 +    "CREATE TRIGGER object_data_update_trigger "
  1.1267 +    "AFTER UPDATE OF file_ids ON object_data "
  1.1268 +    "FOR EACH ROW "
  1.1269 +    "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
  1.1270 +    "BEGIN "
  1.1271 +      "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
  1.1272 +    "END;"
  1.1273 +  ));
  1.1274 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1275 +
  1.1276 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1277 +    "CREATE TRIGGER object_data_delete_trigger "
  1.1278 +    "AFTER DELETE ON object_data "
  1.1279 +    "FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
  1.1280 +    "BEGIN "
  1.1281 +      "SELECT update_refcount(OLD.file_ids, NULL); "
  1.1282 +    "END;"
  1.1283 +  ));
  1.1284 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1285 +
  1.1286 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1287 +    "CREATE TEMPORARY TABLE temp_upgrade ("
  1.1288 +      "index_id, "
  1.1289 +      "value, "
  1.1290 +      "object_data_key, "
  1.1291 +      "object_data_id "
  1.1292 +    ");"
  1.1293 +  ));
  1.1294 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1295 +
  1.1296 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1297 +    "INSERT INTO temp_upgrade "
  1.1298 +      "SELECT index_id, encode(value), encode(object_data_key), object_data_id "
  1.1299 +      "FROM index_data;"
  1.1300 +  ));
  1.1301 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1302 +
  1.1303 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1304 +    "DROP TABLE index_data;"
  1.1305 +  ));
  1.1306 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1307 +
  1.1308 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1309 +    "CREATE TABLE index_data ("
  1.1310 +      "index_id INTEGER NOT NULL, "
  1.1311 +      "value BLOB NOT NULL, "
  1.1312 +      "object_data_key BLOB NOT NULL, "
  1.1313 +      "object_data_id INTEGER NOT NULL, "
  1.1314 +      "PRIMARY KEY (index_id, value, object_data_key), "
  1.1315 +      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
  1.1316 +        "CASCADE, "
  1.1317 +      "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
  1.1318 +        "CASCADE"
  1.1319 +    ");"
  1.1320 +  ));
  1.1321 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1322 +
  1.1323 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1324 +    "INSERT INTO index_data "
  1.1325 +      "SELECT index_id, value, object_data_key, object_data_id "
  1.1326 +      "FROM temp_upgrade;"
  1.1327 +  ));
  1.1328 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1329 +
  1.1330 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1331 +    "DROP TABLE temp_upgrade;"
  1.1332 +  ));
  1.1333 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1334 +
  1.1335 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1336 +    "CREATE INDEX index_data_object_data_id_index "
  1.1337 +    "ON index_data (object_data_id);"
  1.1338 +  ));
  1.1339 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1340 +
  1.1341 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1342 +    "CREATE TEMPORARY TABLE temp_upgrade ("
  1.1343 +      "index_id, "
  1.1344 +      "value, "
  1.1345 +      "object_data_key, "
  1.1346 +      "object_data_id "
  1.1347 +    ");"
  1.1348 +  ));
  1.1349 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1350 +
  1.1351 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1352 +    "INSERT INTO temp_upgrade "
  1.1353 +      "SELECT index_id, encode(value), encode(object_data_key), object_data_id "
  1.1354 +      "FROM unique_index_data;"
  1.1355 +  ));
  1.1356 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1357 +
  1.1358 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1359 +    "DROP TABLE unique_index_data;"
  1.1360 +  ));
  1.1361 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1362 +
  1.1363 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1364 +    "CREATE TABLE unique_index_data ("
  1.1365 +      "index_id INTEGER NOT NULL, "
  1.1366 +      "value BLOB NOT NULL, "
  1.1367 +      "object_data_key BLOB NOT NULL, "
  1.1368 +      "object_data_id INTEGER NOT NULL, "
  1.1369 +      "PRIMARY KEY (index_id, value, object_data_key), "
  1.1370 +      "UNIQUE (index_id, value), "
  1.1371 +      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
  1.1372 +        "CASCADE "
  1.1373 +      "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
  1.1374 +        "CASCADE"
  1.1375 +    ");"
  1.1376 +  ));
  1.1377 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1378 +
  1.1379 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1380 +    "INSERT INTO unique_index_data "
  1.1381 +      "SELECT index_id, value, object_data_key, object_data_id "
  1.1382 +      "FROM temp_upgrade;"
  1.1383 +  ));
  1.1384 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1385 +
  1.1386 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1387 +    "DROP TABLE temp_upgrade;"
  1.1388 +  ));
  1.1389 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1390 +
  1.1391 +  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.1392 +    "CREATE INDEX unique_index_data_object_data_id_index "
  1.1393 +    "ON unique_index_data (object_data_id);"
  1.1394 +  ));
  1.1395 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1396 +
  1.1397 +  rv = aConnection->RemoveFunction(encoderName);
  1.1398 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1399 +
  1.1400 +  rv = aConnection->SetSchemaVersion(MakeSchemaVersion(12, 0));
  1.1401 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1402 +
  1.1403 +  return NS_OK;
  1.1404 +}
  1.1405 +
  1.1406 +nsresult
  1.1407 +UpgradeSchemaFrom12_0To13_0(mozIStorageConnection* aConnection,
  1.1408 +                            bool* aVacuumNeeded)
  1.1409 +{
  1.1410 +  AssertIsOnIOThread();
  1.1411 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1.1412 +
  1.1413 +  PROFILER_LABEL("IndexedDB", "UpgradeSchemaFrom12_0To13_0");
  1.1414 +
  1.1415 +  nsresult rv;
  1.1416 +
  1.1417 +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
  1.1418 +  int32_t defaultPageSize;
  1.1419 +  rv = aConnection->GetDefaultPageSize(&defaultPageSize);
  1.1420 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1421 +
  1.1422 +  // Enable auto_vacuum mode and update the page size to the platform default.
  1.1423 +  nsAutoCString upgradeQuery("PRAGMA auto_vacuum = FULL; PRAGMA page_size = ");
  1.1424 +  upgradeQuery.AppendInt(defaultPageSize);
  1.1425 +
  1.1426 +  rv = aConnection->ExecuteSimpleSQL(upgradeQuery);
  1.1427 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1428 +
  1.1429 +  *aVacuumNeeded = true;
  1.1430 +#endif
  1.1431 +
  1.1432 +  rv = aConnection->SetSchemaVersion(MakeSchemaVersion(13, 0));
  1.1433 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1434 +
  1.1435 +  return NS_OK;
  1.1436 +}
  1.1437 +
  1.1438 +nsresult
  1.1439 +UpgradeSchemaFrom13_0To14_0(mozIStorageConnection* aConnection)
  1.1440 +{
  1.1441 +  // The only change between 13 and 14 was a different structured
  1.1442 +  // clone format, but it's backwards-compatible.
  1.1443 +  nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(14, 0));
  1.1444 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1445 +
  1.1446 +  return NS_OK;
  1.1447 +}
  1.1448 +
  1.1449 +class VersionChangeEventsRunnable;
  1.1450 +
  1.1451 +class SetVersionHelper : public AsyncConnectionHelper,
  1.1452 +                         public IDBTransactionListener,
  1.1453 +                         public AcquireListener
  1.1454 +{
  1.1455 +  friend class VersionChangeEventsRunnable;
  1.1456 +
  1.1457 +public:
  1.1458 +  SetVersionHelper(IDBTransaction* aTransaction,
  1.1459 +                   IDBOpenDBRequest* aRequest,
  1.1460 +                   OpenDatabaseHelper* aHelper,
  1.1461 +                   uint64_t aRequestedVersion,
  1.1462 +                   uint64_t aCurrentVersion)
  1.1463 +  : AsyncConnectionHelper(aTransaction, aRequest),
  1.1464 +    mOpenRequest(aRequest), mOpenHelper(aHelper),
  1.1465 +    mRequestedVersion(aRequestedVersion),
  1.1466 +    mCurrentVersion(aCurrentVersion)
  1.1467 +  {
  1.1468 +    mTransaction->SetTransactionListener(this);
  1.1469 +  }
  1.1470 +
  1.1471 +  NS_DECL_ISUPPORTS_INHERITED
  1.1472 +
  1.1473 +  virtual nsresult GetSuccessResult(JSContext* aCx,
  1.1474 +                                    JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
  1.1475 +
  1.1476 +  virtual nsresult
  1.1477 +  OnExclusiveAccessAcquired() MOZ_OVERRIDE;
  1.1478 +
  1.1479 +protected:
  1.1480 +  virtual nsresult Init() MOZ_OVERRIDE;
  1.1481 +
  1.1482 +  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
  1.1483 +                                  MOZ_OVERRIDE;
  1.1484 +
  1.1485 +  // SetVersionHelper never fires an error event at the request.  It hands that
  1.1486 +  // responsibility back to the OpenDatabaseHelper
  1.1487 +  virtual void OnError() MOZ_OVERRIDE
  1.1488 +  { }
  1.1489 +
  1.1490 +  // Need an upgradeneeded event here.
  1.1491 +  virtual already_AddRefed<nsIDOMEvent> CreateSuccessEvent(
  1.1492 +    mozilla::dom::EventTarget* aOwner) MOZ_OVERRIDE;
  1.1493 +
  1.1494 +  virtual nsresult NotifyTransactionPreComplete(IDBTransaction* aTransaction)
  1.1495 +                                                MOZ_OVERRIDE;
  1.1496 +  virtual nsresult NotifyTransactionPostComplete(IDBTransaction* aTransaction)
  1.1497 +                                                 MOZ_OVERRIDE;
  1.1498 +
  1.1499 +  virtual ChildProcessSendResult
  1.1500 +  SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE
  1.1501 +  {
  1.1502 +    return Success_NotSent;
  1.1503 +  }
  1.1504 +
  1.1505 +  virtual nsresult UnpackResponseFromParentProcess(
  1.1506 +                                            const ResponseValue& aResponseValue)
  1.1507 +                                            MOZ_OVERRIDE
  1.1508 +  {
  1.1509 +    MOZ_CRASH("Should never get here!");
  1.1510 +  }
  1.1511 +
  1.1512 +  uint64_t RequestedVersion() const
  1.1513 +  {
  1.1514 +    return mRequestedVersion;
  1.1515 +  }
  1.1516 +
  1.1517 +private:
  1.1518 +  // In-params
  1.1519 +  nsRefPtr<IDBOpenDBRequest> mOpenRequest;
  1.1520 +  nsRefPtr<OpenDatabaseHelper> mOpenHelper;
  1.1521 +  uint64_t mRequestedVersion;
  1.1522 +  uint64_t mCurrentVersion;
  1.1523 +};
  1.1524 +
  1.1525 +class DeleteDatabaseHelper : public AsyncConnectionHelper,
  1.1526 +                             public AcquireListener
  1.1527 +{
  1.1528 +  friend class VersionChangeEventsRunnable;
  1.1529 +public:
  1.1530 +  DeleteDatabaseHelper(IDBOpenDBRequest* aRequest,
  1.1531 +                       OpenDatabaseHelper* aHelper,
  1.1532 +                       uint64_t aCurrentVersion,
  1.1533 +                       const nsAString& aName,
  1.1534 +                       const nsACString& aGroup,
  1.1535 +                       const nsACString& aASCIIOrigin,
  1.1536 +                       PersistenceType aPersistenceType)
  1.1537 +  : AsyncConnectionHelper(static_cast<IDBDatabase*>(nullptr), aRequest),
  1.1538 +    mOpenHelper(aHelper), mOpenRequest(aRequest),
  1.1539 +    mCurrentVersion(aCurrentVersion), mName(aName),
  1.1540 +    mGroup(aGroup), mASCIIOrigin(aASCIIOrigin),
  1.1541 +    mPersistenceType(aPersistenceType)
  1.1542 +  { }
  1.1543 +
  1.1544 +  NS_DECL_ISUPPORTS_INHERITED
  1.1545 +
  1.1546 +  nsresult GetSuccessResult(JSContext* aCx,
  1.1547 +                            JS::MutableHandle<JS::Value> aVal);
  1.1548 +
  1.1549 +  void ReleaseMainThreadObjects()
  1.1550 +  {
  1.1551 +    mOpenHelper = nullptr;
  1.1552 +    mOpenRequest = nullptr;
  1.1553 +
  1.1554 +    AsyncConnectionHelper::ReleaseMainThreadObjects();
  1.1555 +  }
  1.1556 +
  1.1557 +  virtual nsresult
  1.1558 +  OnExclusiveAccessAcquired() MOZ_OVERRIDE;
  1.1559 +
  1.1560 +protected:
  1.1561 +  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
  1.1562 +  nsresult Init();
  1.1563 +
  1.1564 +  // DeleteDatabaseHelper never fires events at the request.  It hands that
  1.1565 +  // responsibility back to the OpenDatabaseHelper
  1.1566 +  void OnError()
  1.1567 +  {
  1.1568 +    mOpenHelper->NotifyDeleteFinished();
  1.1569 +  }
  1.1570 +
  1.1571 +  nsresult OnSuccess()
  1.1572 +  {
  1.1573 +    return mOpenHelper->NotifyDeleteFinished();
  1.1574 +  }
  1.1575 +
  1.1576 +  uint64_t RequestedVersion() const
  1.1577 +  {
  1.1578 +    return 0;
  1.1579 +  }
  1.1580 +
  1.1581 +  virtual ChildProcessSendResult
  1.1582 +  SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE
  1.1583 +  {
  1.1584 +    return Success_NotSent;
  1.1585 +  }
  1.1586 +
  1.1587 +  virtual nsresult UnpackResponseFromParentProcess(
  1.1588 +                                            const ResponseValue& aResponseValue)
  1.1589 +                                            MOZ_OVERRIDE
  1.1590 +  {
  1.1591 +    MOZ_CRASH("Should never get here!");
  1.1592 +  }
  1.1593 +
  1.1594 +private:
  1.1595 +  // In-params
  1.1596 +  nsRefPtr<OpenDatabaseHelper> mOpenHelper;
  1.1597 +  nsRefPtr<IDBOpenDBRequest> mOpenRequest;
  1.1598 +  uint64_t mCurrentVersion;
  1.1599 +  nsString mName;
  1.1600 +  nsCString mGroup;
  1.1601 +  nsCString mASCIIOrigin;
  1.1602 +  PersistenceType mPersistenceType;
  1.1603 +};
  1.1604 +
  1.1605 +// Responsible for firing "versionchange" events at all live and non-closed
  1.1606 +// databases, and for firing a "blocked" event at the requesting database if any
  1.1607 +// databases fail to close.
  1.1608 +class VersionChangeEventsRunnable : public nsRunnable
  1.1609 +{
  1.1610 +public:
  1.1611 +  VersionChangeEventsRunnable(
  1.1612 +                      IDBDatabase* aRequestingDatabase,
  1.1613 +                      IDBOpenDBRequest* aRequest,
  1.1614 +                      nsTArray<nsCOMPtr<nsIOfflineStorage> >& aWaitingDatabases,
  1.1615 +                      int64_t aOldVersion,
  1.1616 +                      int64_t aNewVersion)
  1.1617 +  : mRequestingDatabase(aRequestingDatabase),
  1.1618 +    mRequest(aRequest),
  1.1619 +    mOldVersion(aOldVersion),
  1.1620 +    mNewVersion(aNewVersion)
  1.1621 +  {
  1.1622 +    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.1623 +    NS_ASSERTION(aRequestingDatabase, "Null pointer!");
  1.1624 +    NS_ASSERTION(aRequest, "Null pointer!");
  1.1625 +
  1.1626 +    mWaitingDatabases.SwapElements(aWaitingDatabases);
  1.1627 +  }
  1.1628 +
  1.1629 +  NS_IMETHOD Run()
  1.1630 +  {
  1.1631 +    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.1632 +
  1.1633 +    PROFILER_MAIN_THREAD_LABEL("IndexedDB", "VersionChangeEventsRunnable::Run");
  1.1634 +
  1.1635 +    // Fire version change events at all of the databases that are not already
  1.1636 +    // closed. Also kick bfcached documents out of bfcache.
  1.1637 +    uint32_t count = mWaitingDatabases.Length();
  1.1638 +    for (uint32_t index = 0; index < count; index++) {
  1.1639 +      IDBDatabase* database =
  1.1640 +        IDBDatabase::FromStorage(mWaitingDatabases[index]);
  1.1641 +      NS_ASSERTION(database, "This shouldn't be null!");
  1.1642 +
  1.1643 +      if (database->IsClosed()) {
  1.1644 +        continue;
  1.1645 +      }
  1.1646 +
  1.1647 +      // First check if the document the IDBDatabase is part of is bfcached.
  1.1648 +      nsCOMPtr<nsIDocument> ownerDoc = database->GetOwnerDocument();
  1.1649 +      nsIBFCacheEntry* bfCacheEntry;
  1.1650 +      if (ownerDoc && (bfCacheEntry = ownerDoc->GetBFCacheEntry())) {
  1.1651 +        bfCacheEntry->RemoveFromBFCacheSync();
  1.1652 +        NS_ASSERTION(database->IsClosed(),
  1.1653 +                     "Kicking doc out of bfcache should have closed database");
  1.1654 +        continue;
  1.1655 +      }
  1.1656 +
  1.1657 +      // Next check if it's in the process of being bfcached.
  1.1658 +      nsPIDOMWindow* owner = database->GetOwner();
  1.1659 +      if (owner && owner->IsFrozen()) {
  1.1660 +        // We can't kick the document out of the bfcache because it's not yet
  1.1661 +        // fully in the bfcache.  Instead we'll abort everything for the window
  1.1662 +        // and mark it as not-bfcacheable.
  1.1663 +        QuotaManager* quotaManager = QuotaManager::Get();
  1.1664 +        NS_ASSERTION(quotaManager, "Huh?");
  1.1665 +        quotaManager->AbortCloseStoragesForWindow(owner);
  1.1666 +
  1.1667 +        NS_ASSERTION(database->IsClosed(),
  1.1668 +                   "AbortCloseStoragesForWindow should have closed database");
  1.1669 +        ownerDoc->DisallowBFCaching();
  1.1670 +        continue;
  1.1671 +      }
  1.1672 +
  1.1673 +      // Otherwise fire a versionchange event.
  1.1674 +      nsRefPtr<Event> event = 
  1.1675 +        IDBVersionChangeEvent::Create(database, mOldVersion, mNewVersion);
  1.1676 +      NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
  1.1677 +
  1.1678 +      bool dummy;
  1.1679 +      database->DispatchEvent(event, &dummy);
  1.1680 +    }
  1.1681 +
  1.1682 +    // Now check to see if any didn't close. If there are some running still
  1.1683 +    // then fire the blocked event.
  1.1684 +    for (uint32_t index = 0; index < count; index++) {
  1.1685 +      if (!mWaitingDatabases[index]->IsClosed()) {
  1.1686 +        nsRefPtr<Event> event =
  1.1687 +          IDBVersionChangeEvent::CreateBlocked(mRequest,
  1.1688 +                                               mOldVersion, mNewVersion);
  1.1689 +        NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
  1.1690 +
  1.1691 +        bool dummy;
  1.1692 +        mRequest->DispatchEvent(event, &dummy);
  1.1693 +
  1.1694 +        break;
  1.1695 +      }
  1.1696 +    }
  1.1697 +
  1.1698 +    return NS_OK;
  1.1699 +  }
  1.1700 +
  1.1701 +  template <class T>
  1.1702 +  static
  1.1703 +  void QueueVersionChange(nsTArray<nsCOMPtr<nsIOfflineStorage> >& aDatabases,
  1.1704 +                          void* aClosure);
  1.1705 +private:
  1.1706 +  nsRefPtr<IDBDatabase> mRequestingDatabase;
  1.1707 +  nsRefPtr<IDBOpenDBRequest> mRequest;
  1.1708 +  nsTArray<nsCOMPtr<nsIOfflineStorage> > mWaitingDatabases;
  1.1709 +  int64_t mOldVersion;
  1.1710 +  int64_t mNewVersion;
  1.1711 +};
  1.1712 +
  1.1713 +} // anonymous namespace
  1.1714 +
  1.1715 +NS_IMPL_ISUPPORTS(OpenDatabaseHelper, nsIRunnable)
  1.1716 +
  1.1717 +nsresult
  1.1718 +OpenDatabaseHelper::Init()
  1.1719 +{
  1.1720 +  QuotaManager::GetStorageId(mPersistenceType, mASCIIOrigin, Client::IDB,
  1.1721 +                             mName, mDatabaseId);
  1.1722 +  MOZ_ASSERT(!mDatabaseId.IsEmpty());
  1.1723 +
  1.1724 +  return NS_OK;
  1.1725 +}
  1.1726 +
  1.1727 +nsresult
  1.1728 +OpenDatabaseHelper::WaitForOpenAllowed()
  1.1729 +{
  1.1730 +  NS_ASSERTION(mState == eCreated, "We've already been dispatched?");
  1.1731 +  NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!");
  1.1732 +
  1.1733 +  mState = eOpenPending;
  1.1734 +
  1.1735 +  QuotaManager* quotaManager = QuotaManager::Get();
  1.1736 +  NS_ASSERTION(quotaManager, "This should never be null!");
  1.1737 +
  1.1738 +  return quotaManager->
  1.1739 +    WaitForOpenAllowed(OriginOrPatternString::FromOrigin(mASCIIOrigin),
  1.1740 +                       Nullable<PersistenceType>(mPersistenceType), mDatabaseId,
  1.1741 +                       this);
  1.1742 +}
  1.1743 +
  1.1744 +nsresult
  1.1745 +OpenDatabaseHelper::Dispatch(nsIEventTarget* aTarget)
  1.1746 +{
  1.1747 +  NS_ASSERTION(mState == eCreated || mState == eOpenPending,
  1.1748 +               "We've already been dispatched?");
  1.1749 +
  1.1750 +  mState = eDBWork;
  1.1751 +
  1.1752 +  return aTarget->Dispatch(this, NS_DISPATCH_NORMAL);
  1.1753 +}
  1.1754 +
  1.1755 +nsresult
  1.1756 +OpenDatabaseHelper::DispatchToIOThread()
  1.1757 +{
  1.1758 +  QuotaManager* quotaManager = QuotaManager::Get();
  1.1759 +  NS_ASSERTION(quotaManager, "This should never be null!");
  1.1760 +
  1.1761 +  return Dispatch(quotaManager->IOThread());
  1.1762 +}
  1.1763 +
  1.1764 +nsresult
  1.1765 +OpenDatabaseHelper::RunImmediately()
  1.1766 +{
  1.1767 +  NS_ASSERTION(mState == eCreated || mState == eOpenPending,
  1.1768 +               "We've already been dispatched?");
  1.1769 +  NS_ASSERTION(NS_FAILED(mResultCode),
  1.1770 +               "Should only be short-circuiting if we failed!");
  1.1771 +  NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!");
  1.1772 +
  1.1773 +  mState = eFiringEvents;
  1.1774 +
  1.1775 +  return this->Run();
  1.1776 +}
  1.1777 +
  1.1778 +nsresult
  1.1779 +OpenDatabaseHelper::DoDatabaseWork()
  1.1780 +{
  1.1781 +  AssertIsOnIOThread();
  1.1782 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1.1783 +
  1.1784 +  PROFILER_LABEL("IndexedDB", "OpenDatabaseHelper::DoDatabaseWork");
  1.1785 +
  1.1786 +  mState = eFiringEvents; // In case we fail somewhere along the line.
  1.1787 +
  1.1788 +  if (QuotaManager::IsShuttingDown()) {
  1.1789 +    IDB_REPORT_INTERNAL_ERR();
  1.1790 +    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1.1791 +  }
  1.1792 +
  1.1793 +  NS_ASSERTION(mOpenDBRequest, "This should never be null!");
  1.1794 +
  1.1795 +  // This will be null for non-window contexts.
  1.1796 +  nsPIDOMWindow* window = mOpenDBRequest->GetOwner();
  1.1797 +
  1.1798 +  AutoEnterWindow autoWindow(window);
  1.1799 +
  1.1800 +  nsCOMPtr<nsIFile> dbDirectory;
  1.1801 +
  1.1802 +  QuotaManager* quotaManager = QuotaManager::Get();
  1.1803 +  NS_ASSERTION(quotaManager, "This should never be null!");
  1.1804 +
  1.1805 +  nsresult rv =
  1.1806 +    quotaManager->EnsureOriginIsInitialized(mPersistenceType, mGroup,
  1.1807 +                                            mASCIIOrigin, mTrackingQuota,
  1.1808 +                                            getter_AddRefs(dbDirectory));
  1.1809 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1810 +
  1.1811 +  rv = dbDirectory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
  1.1812 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1813 +
  1.1814 +  bool exists;
  1.1815 +  rv = dbDirectory->Exists(&exists);
  1.1816 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1817 +
  1.1818 +  if (!exists) {
  1.1819 +    rv = dbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
  1.1820 +    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1821 +  }
  1.1822 +#ifdef DEBUG
  1.1823 +  else {
  1.1824 +    bool isDirectory;
  1.1825 +    NS_ASSERTION(NS_SUCCEEDED(dbDirectory->IsDirectory(&isDirectory)) &&
  1.1826 +                isDirectory, "Should have caught this earlier!");
  1.1827 +  }
  1.1828 +#endif
  1.1829 +
  1.1830 +  nsAutoString filename;
  1.1831 +  rv = GetDatabaseFilename(mName, filename);
  1.1832 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1833 +
  1.1834 +  nsCOMPtr<nsIFile> dbFile;
  1.1835 +  rv = dbDirectory->Clone(getter_AddRefs(dbFile));
  1.1836 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1837 +
  1.1838 +  rv = dbFile->Append(filename + NS_LITERAL_STRING(".sqlite"));
  1.1839 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1840 +
  1.1841 +  rv = dbFile->GetPath(mDatabaseFilePath);
  1.1842 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1843 +
  1.1844 +  nsCOMPtr<nsIFile> fmDirectory;
  1.1845 +  rv = dbDirectory->Clone(getter_AddRefs(fmDirectory));
  1.1846 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1847 +
  1.1848 +  rv = fmDirectory->Append(filename);
  1.1849 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1850 +
  1.1851 +  nsCOMPtr<mozIStorageConnection> connection;
  1.1852 +  rv = CreateDatabaseConnection(dbFile, fmDirectory, mName, mPersistenceType,
  1.1853 +                                mGroup, mASCIIOrigin,
  1.1854 +                                getter_AddRefs(connection));
  1.1855 +  if (NS_FAILED(rv) &&
  1.1856 +      NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) {
  1.1857 +    IDB_REPORT_INTERNAL_ERR();
  1.1858 +    rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1.1859 +  }
  1.1860 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1861 +
  1.1862 +  rv = IDBFactory::LoadDatabaseInformation(connection, mDatabaseId,
  1.1863 +                                           &mCurrentVersion, mObjectStores);
  1.1864 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1865 +
  1.1866 +  if (mForDeletion) {
  1.1867 +    mState = eDeletePending;
  1.1868 +    return NS_OK;
  1.1869 +  }
  1.1870 +
  1.1871 +  for (uint32_t i = 0; i < mObjectStores.Length(); i++) {
  1.1872 +    nsRefPtr<ObjectStoreInfo>& objectStoreInfo = mObjectStores[i];
  1.1873 +    for (uint32_t j = 0; j < objectStoreInfo->indexes.Length(); j++) {
  1.1874 +      IndexInfo& indexInfo = objectStoreInfo->indexes[j];
  1.1875 +      mLastIndexId = std::max(indexInfo.id, mLastIndexId);
  1.1876 +    }
  1.1877 +    mLastObjectStoreId = std::max(objectStoreInfo->id, mLastObjectStoreId);
  1.1878 +  }
  1.1879 +
  1.1880 +  // See if we need to do a VERSION_CHANGE transaction
  1.1881 +
  1.1882 +  // Optional version semantics.
  1.1883 +  if (!mRequestedVersion) {
  1.1884 +    // If the requested version was not specified and the database was created,
  1.1885 +    // treat it as if version 1 were requested.
  1.1886 +    if (mCurrentVersion == 0) {
  1.1887 +      mRequestedVersion = 1;
  1.1888 +    }
  1.1889 +    else {
  1.1890 +      // Otherwise, treat it as if the current version were requested.
  1.1891 +      mRequestedVersion = mCurrentVersion;
  1.1892 +    }
  1.1893 +  }
  1.1894 +
  1.1895 +  if (mCurrentVersion > mRequestedVersion) {
  1.1896 +    return NS_ERROR_DOM_INDEXEDDB_VERSION_ERR;
  1.1897 +  }
  1.1898 +
  1.1899 +  if (mCurrentVersion != mRequestedVersion) {
  1.1900 +    mState = eSetVersionPending;
  1.1901 +  }
  1.1902 +
  1.1903 +  IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
  1.1904 +  NS_ASSERTION(mgr, "This should never be null!");
  1.1905 +
  1.1906 +  nsRefPtr<FileManager> fileManager =
  1.1907 +    mgr->GetFileManager(mPersistenceType, mASCIIOrigin, mName);
  1.1908 +  if (!fileManager) {
  1.1909 +    fileManager = new FileManager(mPersistenceType, mGroup, mASCIIOrigin,
  1.1910 +                                  mPrivilege, mName);
  1.1911 +
  1.1912 +    rv = fileManager->Init(fmDirectory, connection);
  1.1913 +    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1914 +
  1.1915 +    mgr->AddFileManager(fileManager);
  1.1916 +  }
  1.1917 +
  1.1918 +  mFileManager = fileManager.forget();
  1.1919 +
  1.1920 +  return NS_OK;
  1.1921 +}
  1.1922 +
  1.1923 +// static
  1.1924 +nsresult
  1.1925 +OpenDatabaseHelper::CreateDatabaseConnection(
  1.1926 +                                        nsIFile* aDBFile,
  1.1927 +                                        nsIFile* aFMDirectory,
  1.1928 +                                        const nsAString& aName,
  1.1929 +                                        PersistenceType aPersistenceType,
  1.1930 +                                        const nsACString& aGroup,
  1.1931 +                                        const nsACString& aOrigin,
  1.1932 +                                        mozIStorageConnection** aConnection)
  1.1933 +{
  1.1934 +  AssertIsOnIOThread();
  1.1935 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1.1936 +
  1.1937 +  PROFILER_LABEL("IndexedDB", "OpenDatabaseHelper::CreateDatabaseConnection");
  1.1938 +
  1.1939 +  nsresult rv;
  1.1940 +  bool exists;
  1.1941 +
  1.1942 +  if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
  1.1943 +    rv = aDBFile->Exists(&exists);
  1.1944 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1945 +
  1.1946 +    if (!exists) {
  1.1947 +      NS_WARNING("Refusing to create database because disk space is low!");
  1.1948 +      return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
  1.1949 +    }
  1.1950 +  }
  1.1951 +
  1.1952 +  nsCOMPtr<nsIFileURL> dbFileUrl =
  1.1953 +    IDBFactory::GetDatabaseFileURL(aDBFile, aPersistenceType, aGroup, aOrigin);
  1.1954 +  NS_ENSURE_TRUE(dbFileUrl, NS_ERROR_FAILURE);
  1.1955 +
  1.1956 +  nsCOMPtr<mozIStorageService> ss =
  1.1957 +    do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
  1.1958 +  NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
  1.1959 +
  1.1960 +  nsCOMPtr<mozIStorageConnection> connection;
  1.1961 +  rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection));
  1.1962 +  if (rv == NS_ERROR_FILE_CORRUPTED) {
  1.1963 +    // If we're just opening the database during origin initialization, then
  1.1964 +    // we don't want to erase any files. The failure here will fail origin
  1.1965 +    // initialization too.
  1.1966 +    if (aName.IsVoid()) {
  1.1967 +      return rv;
  1.1968 +    }
  1.1969 +
  1.1970 +    // Nuke the database file.  The web services can recreate their data.
  1.1971 +    rv = aDBFile->Remove(false);
  1.1972 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1973 +
  1.1974 +    rv = aFMDirectory->Exists(&exists);
  1.1975 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1976 +
  1.1977 +    if (exists) {
  1.1978 +      bool isDirectory;
  1.1979 +      rv = aFMDirectory->IsDirectory(&isDirectory);
  1.1980 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1981 +      IDB_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1982 +
  1.1983 +      rv = aFMDirectory->Remove(true);
  1.1984 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1985 +    }
  1.1986 +
  1.1987 +    rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection));
  1.1988 +  }
  1.1989 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1990 +
  1.1991 +  rv = IDBFactory::SetDefaultPragmas(connection);
  1.1992 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1993 +
  1.1994 +  rv = connection->EnableModule(NS_LITERAL_CSTRING("filesystem"));
  1.1995 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1996 +
  1.1997 +  // Check to make sure that the database schema is correct.
  1.1998 +  int32_t schemaVersion;
  1.1999 +  rv = connection->GetSchemaVersion(&schemaVersion);
  1.2000 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2001 +
  1.2002 +  // Unknown schema will fail origin initialization too
  1.2003 +  if (!schemaVersion && aName.IsVoid()) {
  1.2004 +    IDB_WARNING("Unable to open IndexedDB database, schema is not set!");
  1.2005 +    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1.2006 +  }
  1.2007 +
  1.2008 +  if (schemaVersion > kSQLiteSchemaVersion) {
  1.2009 +    IDB_WARNING("Unable to open IndexedDB database, schema is too high!");
  1.2010 +    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1.2011 +  }
  1.2012 +
  1.2013 +  bool vacuumNeeded = false;
  1.2014 +
  1.2015 +  if (schemaVersion != kSQLiteSchemaVersion) {
  1.2016 +#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
  1.2017 +    if (!schemaVersion) {
  1.2018 +      // Have to do this before opening a transaction.
  1.2019 +      rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  1.2020 +        // Turn on auto_vacuum mode to reclaim disk space on mobile devices.
  1.2021 +        "PRAGMA auto_vacuum = FULL; "
  1.2022 +      ));
  1.2023 +      if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) {
  1.2024 +        // mozstorage translates SQLITE_FULL to NS_ERROR_FILE_NO_DEVICE_SPACE,
  1.2025 +        // which we know better as NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR.
  1.2026 +        rv = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
  1.2027 +      }
  1.2028 +      NS_ENSURE_SUCCESS(rv, rv);
  1.2029 +    }
  1.2030 +#endif
  1.2031 +
  1.2032 +    mozStorageTransaction transaction(connection, false,
  1.2033 +                                  mozIStorageConnection::TRANSACTION_IMMEDIATE);
  1.2034 +
  1.2035 +    if (!schemaVersion) {
  1.2036 +      // Brand new file, initialize our tables.
  1.2037 +      rv = CreateTables(connection);
  1.2038 +      NS_ENSURE_SUCCESS(rv, rv);
  1.2039 +
  1.2040 +      NS_ASSERTION(NS_SUCCEEDED(connection->GetSchemaVersion(&schemaVersion)) &&
  1.2041 +                   schemaVersion == kSQLiteSchemaVersion,
  1.2042 +                   "CreateTables set a bad schema version!");
  1.2043 +
  1.2044 +      nsCOMPtr<mozIStorageStatement> stmt;
  1.2045 +      nsresult rv = connection->CreateStatement(NS_LITERAL_CSTRING(
  1.2046 +        "INSERT INTO database (name) "
  1.2047 +        "VALUES (:name)"
  1.2048 +      ), getter_AddRefs(stmt));
  1.2049 +      IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2050 +
  1.2051 +      rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), aName);
  1.2052 +      IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2053 +
  1.2054 +      rv = stmt->Execute();
  1.2055 +      IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2056 +    }
  1.2057 +    else  {
  1.2058 +      // This logic needs to change next time we change the schema!
  1.2059 +      static_assert(kSQLiteSchemaVersion == int32_t((14 << 4) + 0),
  1.2060 +                    "Need upgrade code from schema version increase.");
  1.2061 +
  1.2062 +      while (schemaVersion != kSQLiteSchemaVersion) {
  1.2063 +        if (schemaVersion == 4) {
  1.2064 +          rv = UpgradeSchemaFrom4To5(connection);
  1.2065 +        }
  1.2066 +        else if (schemaVersion == 5) {
  1.2067 +          rv = UpgradeSchemaFrom5To6(connection);
  1.2068 +        }
  1.2069 +        else if (schemaVersion == 6) {
  1.2070 +          rv = UpgradeSchemaFrom6To7(connection);
  1.2071 +        }
  1.2072 +        else if (schemaVersion == 7) {
  1.2073 +          rv = UpgradeSchemaFrom7To8(connection);
  1.2074 +        }
  1.2075 +        else if (schemaVersion == 8) {
  1.2076 +          rv = UpgradeSchemaFrom8To9_0(connection);
  1.2077 +          vacuumNeeded = true;
  1.2078 +        }
  1.2079 +        else if (schemaVersion == MakeSchemaVersion(9, 0)) {
  1.2080 +          rv = UpgradeSchemaFrom9_0To10_0(connection);
  1.2081 +        }
  1.2082 +        else if (schemaVersion == MakeSchemaVersion(10, 0)) {
  1.2083 +          rv = UpgradeSchemaFrom10_0To11_0(connection);
  1.2084 +        }
  1.2085 +        else if (schemaVersion == MakeSchemaVersion(11, 0)) {
  1.2086 +          rv = UpgradeSchemaFrom11_0To12_0(connection);
  1.2087 +        }
  1.2088 +        else if (schemaVersion == MakeSchemaVersion(12, 0)) {
  1.2089 +          rv = UpgradeSchemaFrom12_0To13_0(connection, &vacuumNeeded);
  1.2090 +        }
  1.2091 +        else if (schemaVersion == MakeSchemaVersion(13, 0)) {
  1.2092 +          rv = UpgradeSchemaFrom13_0To14_0(connection);
  1.2093 +        }
  1.2094 +        else {
  1.2095 +          NS_WARNING("Unable to open IndexedDB database, no upgrade path is "
  1.2096 +                     "available!");
  1.2097 +          IDB_REPORT_INTERNAL_ERR();
  1.2098 +          return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1.2099 +        }
  1.2100 +        NS_ENSURE_SUCCESS(rv, rv);
  1.2101 +
  1.2102 +        rv = connection->GetSchemaVersion(&schemaVersion);
  1.2103 +        NS_ENSURE_SUCCESS(rv, rv);
  1.2104 +      }
  1.2105 +
  1.2106 +      NS_ASSERTION(schemaVersion == kSQLiteSchemaVersion, "Huh?!");
  1.2107 +    }
  1.2108 +
  1.2109 +    rv = transaction.Commit();
  1.2110 +    if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) {
  1.2111 +      // mozstorage translates SQLITE_FULL to NS_ERROR_FILE_NO_DEVICE_SPACE,
  1.2112 +      // which we know better as NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR.
  1.2113 +      rv = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
  1.2114 +    }
  1.2115 +    NS_ENSURE_SUCCESS(rv, rv);
  1.2116 +  }
  1.2117 +
  1.2118 +  if (vacuumNeeded) {
  1.2119 +    rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING("VACUUM;"));
  1.2120 +    NS_ENSURE_SUCCESS(rv, rv);
  1.2121 +  }
  1.2122 +
  1.2123 +  connection.forget(aConnection);
  1.2124 +  return NS_OK;
  1.2125 +}
  1.2126 +
  1.2127 +nsresult
  1.2128 +OpenDatabaseHelper::StartSetVersion()
  1.2129 +{
  1.2130 +  NS_ASSERTION(mState == eSetVersionPending, "Why are we here?");
  1.2131 +
  1.2132 +  // In case we fail, fire error events
  1.2133 +  mState = eFiringEvents;
  1.2134 +
  1.2135 +  nsresult rv = EnsureSuccessResult();
  1.2136 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2137 +
  1.2138 +  Sequence<nsString> storesToOpen;
  1.2139 +  nsRefPtr<IDBTransaction> transaction =
  1.2140 +    IDBTransaction::Create(mDatabase, storesToOpen,
  1.2141 +                           IDBTransaction::VERSION_CHANGE, true);
  1.2142 +  IDB_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2143 +
  1.2144 +  nsRefPtr<SetVersionHelper> helper =
  1.2145 +    new SetVersionHelper(transaction, mOpenDBRequest, this, mRequestedVersion,
  1.2146 +                         mCurrentVersion);
  1.2147 +
  1.2148 +  QuotaManager* quotaManager = QuotaManager::Get();
  1.2149 +  NS_ASSERTION(quotaManager, "This should never be null!");
  1.2150 +
  1.2151 +  rv = quotaManager->AcquireExclusiveAccess(
  1.2152 +             mDatabase, mDatabase->Origin(),
  1.2153 +             Nullable<PersistenceType>(mDatabase->Type()), helper,
  1.2154 +             &VersionChangeEventsRunnable::QueueVersionChange<SetVersionHelper>,
  1.2155 +             helper);
  1.2156 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2157 +
  1.2158 +  // The SetVersionHelper is responsible for dispatching us back to the
  1.2159 +  // main thread again and changing the state to eSetVersionCompleted.
  1.2160 +  mState = eSetVersionPending;
  1.2161 +  return NS_OK;
  1.2162 +}
  1.2163 +
  1.2164 +nsresult
  1.2165 +OpenDatabaseHelper::StartDelete()
  1.2166 +{
  1.2167 +  NS_ASSERTION(mState == eDeletePending, "Why are we here?");
  1.2168 +
  1.2169 +  // In case we fail, fire error events
  1.2170 +  mState = eFiringEvents;
  1.2171 +
  1.2172 +  nsresult rv = EnsureSuccessResult();
  1.2173 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2174 +
  1.2175 +  nsRefPtr<DeleteDatabaseHelper> helper =
  1.2176 +    new DeleteDatabaseHelper(mOpenDBRequest, this, mCurrentVersion, mName,
  1.2177 +                             mGroup, mASCIIOrigin, mPersistenceType);
  1.2178 +
  1.2179 +  QuotaManager* quotaManager = QuotaManager::Get();
  1.2180 +  NS_ASSERTION(quotaManager, "This should never be null!");
  1.2181 +
  1.2182 +  rv = quotaManager->AcquireExclusiveAccess(
  1.2183 +         mDatabase, mDatabase->Origin(),
  1.2184 +         Nullable<PersistenceType>(mDatabase->Type()), helper,
  1.2185 +         &VersionChangeEventsRunnable::QueueVersionChange<DeleteDatabaseHelper>,
  1.2186 +         helper);
  1.2187 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2188 +
  1.2189 +  // The DeleteDatabaseHelper is responsible for dispatching us back to the
  1.2190 +  // main thread again and changing the state to eDeleteCompleted.
  1.2191 +  mState = eDeletePending;
  1.2192 +  return NS_OK;
  1.2193 +}
  1.2194 +
  1.2195 +NS_IMETHODIMP
  1.2196 +OpenDatabaseHelper::Run()
  1.2197 +{
  1.2198 +  NS_ASSERTION(mState != eCreated, "Dispatch was not called?!?");
  1.2199 +
  1.2200 +  if (NS_IsMainThread()) {
  1.2201 +    PROFILER_MAIN_THREAD_LABEL("IndexedDB", "OpenDatabaseHelper::Run");
  1.2202 +
  1.2203 +    if (mState == eOpenPending) {
  1.2204 +      if (NS_FAILED(mResultCode)) {
  1.2205 +        return RunImmediately();
  1.2206 +      }
  1.2207 +
  1.2208 +      return DispatchToIOThread();
  1.2209 +    }
  1.2210 +
  1.2211 +    // If we need to queue up a SetVersionHelper, do that here.
  1.2212 +    if (mState == eSetVersionPending) {
  1.2213 +      nsresult rv = StartSetVersion();
  1.2214 +
  1.2215 +      if (NS_SUCCEEDED(rv)) {
  1.2216 +        return rv;
  1.2217 +      }
  1.2218 +
  1.2219 +      SetError(rv);
  1.2220 +      // fall through and run the default error processing
  1.2221 +    }
  1.2222 +    else if (mState == eDeletePending) {
  1.2223 +      nsresult rv = StartDelete();
  1.2224 +
  1.2225 +      if (NS_SUCCEEDED(rv)) {
  1.2226 +        return rv;
  1.2227 +      }
  1.2228 +
  1.2229 +      SetError(rv);
  1.2230 +      // fall through and run the default error processing
  1.2231 +    }
  1.2232 +
  1.2233 +    // We've done whatever work we need to do on the DB thread, and any
  1.2234 +    // SetVersion/DeleteDatabase stuff is done by now.
  1.2235 +    NS_ASSERTION(mState == eFiringEvents ||
  1.2236 +                 mState == eSetVersionCompleted ||
  1.2237 +                 mState == eDeleteCompleted, "Why are we here?");
  1.2238 +
  1.2239 +    switch (mState) {
  1.2240 +      case eSetVersionCompleted: {
  1.2241 +        mState = eFiringEvents;
  1.2242 +        break;
  1.2243 +      }
  1.2244 +
  1.2245 +      case eDeleteCompleted: {
  1.2246 +        // Destroy the database now (we should have the only ref).
  1.2247 +        mDatabase = nullptr;
  1.2248 +
  1.2249 +        DatabaseInfo::Remove(mDatabaseId);
  1.2250 +
  1.2251 +        mState = eFiringEvents;
  1.2252 +        break;
  1.2253 +      }
  1.2254 +
  1.2255 +      case eFiringEvents: {
  1.2256 +        // Notify the request that we're done, but only if we didn't just
  1.2257 +        // finish a [SetVersion/DeleteDatabase]Helper.  In that case, the
  1.2258 +        // helper tells the request that it is done, and we avoid calling
  1.2259 +        // NotifyHelperCompleted twice.
  1.2260 +
  1.2261 +        nsresult rv = mOpenDBRequest->NotifyHelperCompleted(this);
  1.2262 +        if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
  1.2263 +          mResultCode = rv;
  1.2264 +        }
  1.2265 +        break;
  1.2266 +      }
  1.2267 +
  1.2268 +      default:
  1.2269 +        NS_NOTREACHED("Shouldn't get here!");
  1.2270 +    }
  1.2271 +
  1.2272 +    NS_ASSERTION(mState == eFiringEvents, "Why are we here?");
  1.2273 +
  1.2274 +    IDB_PROFILER_MARK("IndexedDB Request %llu: Running main thread "
  1.2275 +                      "response (rv = %lu)",
  1.2276 +                      "IDBRequest[%llu] MT Done",
  1.2277 +                      mRequest->GetSerialNumber(), mResultCode);
  1.2278 +
  1.2279 +    if (NS_FAILED(mResultCode)) {
  1.2280 +      DispatchErrorEvent();
  1.2281 +    } else {
  1.2282 +      DispatchSuccessEvent();
  1.2283 +    }
  1.2284 +
  1.2285 +    QuotaManager* quotaManager = QuotaManager::Get();
  1.2286 +    NS_ASSERTION(quotaManager, "This should never be null!");
  1.2287 +
  1.2288 +    quotaManager->
  1.2289 +      AllowNextSynchronizedOp(OriginOrPatternString::FromOrigin(mASCIIOrigin),
  1.2290 +                              Nullable<PersistenceType>(mPersistenceType),
  1.2291 +                              mDatabaseId);
  1.2292 +
  1.2293 +    ReleaseMainThreadObjects();
  1.2294 +
  1.2295 +    return NS_OK;
  1.2296 +  }
  1.2297 +
  1.2298 +  PROFILER_LABEL("IndexedDB", "OpenDatabaseHelper::Run");
  1.2299 +
  1.2300 +  // We're on the DB thread.
  1.2301 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1.2302 +
  1.2303 +  IDB_PROFILER_MARK("IndexedDB Request %llu: Beginning database work",
  1.2304 +                    "IDBRequest[%llu] DT Start", mRequest->GetSerialNumber());
  1.2305 +
  1.2306 +  NS_ASSERTION(mState == eDBWork, "Why are we here?");
  1.2307 +  mResultCode = DoDatabaseWork();
  1.2308 +  NS_ASSERTION(mState != eDBWork, "We should be doing something else now.");
  1.2309 +
  1.2310 +  IDB_PROFILER_MARK("IndexedDB Request %llu: Finished database work (rv = %lu)",
  1.2311 +                    "IDBRequest[%llu] DT Done", mRequest->GetSerialNumber(),
  1.2312 +                    mResultCode);
  1.2313 +
  1.2314 +  return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
  1.2315 +}
  1.2316 +
  1.2317 +nsresult
  1.2318 +OpenDatabaseHelper::EnsureSuccessResult()
  1.2319 +{
  1.2320 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.2321 +
  1.2322 +  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  1.2323 +                             "OpenDatabaseHelper::EnsureSuccessResult");
  1.2324 +
  1.2325 +  nsRefPtr<DatabaseInfo> dbInfo;
  1.2326 +  if (DatabaseInfo::Get(mDatabaseId, getter_AddRefs(dbInfo))) {
  1.2327 +
  1.2328 +#ifdef DEBUG
  1.2329 +    {
  1.2330 +      NS_ASSERTION(dbInfo->name == mName &&
  1.2331 +                   dbInfo->version == mCurrentVersion &&
  1.2332 +                   dbInfo->persistenceType == mPersistenceType &&
  1.2333 +                   dbInfo->id == mDatabaseId &&
  1.2334 +                   dbInfo->filePath == mDatabaseFilePath,
  1.2335 +                   "Metadata mismatch!");
  1.2336 +
  1.2337 +      uint32_t objectStoreCount = mObjectStores.Length();
  1.2338 +      for (uint32_t index = 0; index < objectStoreCount; index++) {
  1.2339 +        nsRefPtr<ObjectStoreInfo>& info = mObjectStores[index];
  1.2340 +
  1.2341 +        ObjectStoreInfo* otherInfo = dbInfo->GetObjectStore(info->name);
  1.2342 +        NS_ASSERTION(otherInfo, "ObjectStore not known!");
  1.2343 +
  1.2344 +        NS_ASSERTION(info->name == otherInfo->name &&
  1.2345 +                     info->id == otherInfo->id &&
  1.2346 +                     info->keyPath == otherInfo->keyPath,
  1.2347 +                     "Metadata mismatch!");
  1.2348 +        NS_ASSERTION(dbInfo->ContainsStoreName(info->name),
  1.2349 +                     "Object store names out of date!");
  1.2350 +        NS_ASSERTION(info->indexes.Length() == otherInfo->indexes.Length(),
  1.2351 +                     "Bad index length!");
  1.2352 +
  1.2353 +        uint32_t indexCount = info->indexes.Length();
  1.2354 +        for (uint32_t indexIndex = 0; indexIndex < indexCount; indexIndex++) {
  1.2355 +          const IndexInfo& indexInfo = info->indexes[indexIndex];
  1.2356 +          const IndexInfo& otherIndexInfo = otherInfo->indexes[indexIndex];
  1.2357 +          NS_ASSERTION(indexInfo.id == otherIndexInfo.id,
  1.2358 +                       "Bad index id!");
  1.2359 +          NS_ASSERTION(indexInfo.name == otherIndexInfo.name,
  1.2360 +                       "Bad index name!");
  1.2361 +          NS_ASSERTION(indexInfo.keyPath == otherIndexInfo.keyPath,
  1.2362 +                       "Bad index keyPath!");
  1.2363 +          NS_ASSERTION(indexInfo.unique == otherIndexInfo.unique,
  1.2364 +                       "Bad index unique value!");
  1.2365 +        }
  1.2366 +      }
  1.2367 +    }
  1.2368 +#endif
  1.2369 +
  1.2370 +  }
  1.2371 +  else {
  1.2372 +    nsRefPtr<DatabaseInfo> newInfo(new DatabaseInfo());
  1.2373 +
  1.2374 +    newInfo->name = mName;
  1.2375 +    newInfo->group = mGroup;
  1.2376 +    newInfo->origin = mASCIIOrigin;
  1.2377 +    newInfo->persistenceType = mPersistenceType;
  1.2378 +    newInfo->id = mDatabaseId;
  1.2379 +    newInfo->filePath = mDatabaseFilePath;
  1.2380 +
  1.2381 +    if (!DatabaseInfo::Put(newInfo)) {
  1.2382 +      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1.2383 +    }
  1.2384 +
  1.2385 +    newInfo.swap(dbInfo);
  1.2386 +
  1.2387 +    nsresult rv = IDBFactory::SetDatabaseMetadata(dbInfo, mCurrentVersion,
  1.2388 +                                                  mObjectStores);
  1.2389 +    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2390 +
  1.2391 +    NS_ASSERTION(mObjectStores.IsEmpty(), "Should have swapped!");
  1.2392 +  }
  1.2393 +
  1.2394 +  dbInfo->nextObjectStoreId = mLastObjectStoreId + 1;
  1.2395 +  dbInfo->nextIndexId = mLastIndexId + 1;
  1.2396 +
  1.2397 +  nsRefPtr<IDBDatabase> database =
  1.2398 +    IDBDatabase::Create(mOpenDBRequest, mOpenDBRequest->Factory(),
  1.2399 +                        dbInfo.forget(), mASCIIOrigin, mFileManager,
  1.2400 +                        mContentParent);
  1.2401 +  if (!database) {
  1.2402 +    IDB_REPORT_INTERNAL_ERR();
  1.2403 +    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1.2404 +  }
  1.2405 +
  1.2406 +  NS_ASSERTION(!mDatabase, "Shouldn't have a database yet!");
  1.2407 +  mDatabase.swap(database);
  1.2408 +
  1.2409 +  return NS_OK;
  1.2410 +}
  1.2411 +
  1.2412 +nsresult
  1.2413 +OpenDatabaseHelper::GetSuccessResult(JSContext* aCx,
  1.2414 +                                     JS::MutableHandle<JS::Value> aVal)
  1.2415 +{
  1.2416 +  // Be careful not to load the database twice.
  1.2417 +  if (!mDatabase) {
  1.2418 +    nsresult rv = EnsureSuccessResult();
  1.2419 +    NS_ENSURE_SUCCESS(rv, rv);
  1.2420 +  }
  1.2421 +
  1.2422 +  return WrapNative(aCx, NS_ISUPPORTS_CAST(EventTarget*, mDatabase),
  1.2423 +                    aVal);
  1.2424 +}
  1.2425 +
  1.2426 +nsresult
  1.2427 +OpenDatabaseHelper::NotifySetVersionFinished()
  1.2428 +{
  1.2429 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread");
  1.2430 +  NS_ASSERTION(mState = eSetVersionPending, "How did we get here?");
  1.2431 +
  1.2432 +  // Allow transaction creation to proceed.
  1.2433 +  mDatabase->ExitSetVersionTransaction();
  1.2434 +
  1.2435 +  mState = eSetVersionCompleted;
  1.2436 +
  1.2437 +  // Dispatch ourself back to the main thread
  1.2438 +  return NS_DispatchToCurrentThread(this);
  1.2439 +}
  1.2440 +
  1.2441 +nsresult
  1.2442 +OpenDatabaseHelper::NotifyDeleteFinished()
  1.2443 +{
  1.2444 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread");
  1.2445 +  NS_ASSERTION(mState == eDeletePending, "How did we get here?");
  1.2446 +
  1.2447 +  mState = eDeleteCompleted;
  1.2448 +  
  1.2449 +  // Dispatch ourself back to the main thread
  1.2450 +  return NS_DispatchToCurrentThread(this);
  1.2451 +}
  1.2452 +
  1.2453 +void
  1.2454 +OpenDatabaseHelper::BlockDatabase()
  1.2455 +{
  1.2456 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.2457 +  NS_ASSERTION(mDatabase, "This is going bad fast.");
  1.2458 +
  1.2459 +  mDatabase->EnterSetVersionTransaction();
  1.2460 +}
  1.2461 +
  1.2462 +void
  1.2463 +OpenDatabaseHelper::DispatchSuccessEvent()
  1.2464 +{
  1.2465 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.2466 +
  1.2467 +  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  1.2468 +                              "OpenDatabaseHelper::DispatchSuccessEvent");
  1.2469 +
  1.2470 +  nsRefPtr<nsIDOMEvent> event =
  1.2471 +    CreateGenericEvent(mOpenDBRequest, NS_LITERAL_STRING(SUCCESS_EVT_STR),
  1.2472 +                       eDoesNotBubble, eNotCancelable);
  1.2473 +  if (!event) {
  1.2474 +    NS_ERROR("Failed to create event!");
  1.2475 +    return;
  1.2476 +  }
  1.2477 +
  1.2478 +  bool dummy;
  1.2479 +  mOpenDBRequest->DispatchEvent(event, &dummy);
  1.2480 +}
  1.2481 +
  1.2482 +void
  1.2483 +OpenDatabaseHelper::DispatchErrorEvent()
  1.2484 +{
  1.2485 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.2486 +
  1.2487 +  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  1.2488 +                              "OpenDatabaseHelper::DispatchErrorEvent");
  1.2489 +
  1.2490 +  nsRefPtr<nsIDOMEvent> event =
  1.2491 +    CreateGenericEvent(mOpenDBRequest, NS_LITERAL_STRING(ERROR_EVT_STR),
  1.2492 +                       eDoesBubble, eCancelable);
  1.2493 +  if (!event) {
  1.2494 +    NS_ERROR("Failed to create event!");
  1.2495 +    return;
  1.2496 +  }
  1.2497 +
  1.2498 +  ErrorResult rv;
  1.2499 +  nsRefPtr<DOMError> error = mOpenDBRequest->GetError(rv);
  1.2500 +
  1.2501 +  NS_ASSERTION(!rv.Failed(), "This shouldn't be failing at this point!");
  1.2502 +  if (!error) {
  1.2503 +    mOpenDBRequest->SetError(mResultCode);
  1.2504 +  }
  1.2505 +
  1.2506 +  bool dummy;
  1.2507 +  mOpenDBRequest->DispatchEvent(event, &dummy);
  1.2508 +}
  1.2509 +
  1.2510 +void
  1.2511 +OpenDatabaseHelper::ReleaseMainThreadObjects()
  1.2512 +{
  1.2513 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.2514 +
  1.2515 +  mOpenDBRequest = nullptr;
  1.2516 +  mDatabase = nullptr;
  1.2517 +
  1.2518 +  HelperBase::ReleaseMainThreadObjects();
  1.2519 +}
  1.2520 +
  1.2521 +NS_IMPL_ISUPPORTS_INHERITED0(SetVersionHelper, AsyncConnectionHelper)
  1.2522 +
  1.2523 +nsresult
  1.2524 +SetVersionHelper::Init()
  1.2525 +{
  1.2526 +  // Block transaction creation until we are done.
  1.2527 +  mOpenHelper->BlockDatabase();
  1.2528 +
  1.2529 +  return NS_OK;
  1.2530 +}
  1.2531 +
  1.2532 +nsresult
  1.2533 +SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
  1.2534 +{
  1.2535 +  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  1.2536 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1.2537 +  NS_ASSERTION(aConnection, "Passing a null connection!");
  1.2538 +
  1.2539 +  PROFILER_LABEL("IndexedDB", "SetVersionHelper::DoDatabaseWork");
  1.2540 +
  1.2541 +  nsCOMPtr<mozIStorageStatement> stmt;
  1.2542 +  nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
  1.2543 +    "UPDATE database "
  1.2544 +    "SET version = :version"
  1.2545 +  ), getter_AddRefs(stmt));
  1.2546 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2547 +
  1.2548 +  rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("version"),
  1.2549 +                             mRequestedVersion);
  1.2550 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2551 +
  1.2552 +  if (NS_FAILED(stmt->Execute())) {
  1.2553 +    return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
  1.2554 +  }
  1.2555 +
  1.2556 +  return NS_OK;
  1.2557 +}
  1.2558 +
  1.2559 +nsresult
  1.2560 +SetVersionHelper::GetSuccessResult(JSContext* aCx,
  1.2561 +                                   JS::MutableHandle<JS::Value> aVal)
  1.2562 +{
  1.2563 +  DatabaseInfo* info = mDatabase->Info();
  1.2564 +  info->version = mRequestedVersion;
  1.2565 +
  1.2566 +  NS_ASSERTION(mTransaction, "Better have a transaction!");
  1.2567 +
  1.2568 +  mOpenRequest->SetTransaction(mTransaction);
  1.2569 +
  1.2570 +  return WrapNative(aCx, NS_ISUPPORTS_CAST(EventTarget*, mDatabase),
  1.2571 +                    aVal);
  1.2572 +}
  1.2573 +
  1.2574 +nsresult
  1.2575 +SetVersionHelper::OnExclusiveAccessAcquired()
  1.2576 +{
  1.2577 +  nsresult rv = DispatchToTransactionPool();
  1.2578 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2579 +
  1.2580 +  return NS_OK;
  1.2581 +}
  1.2582 +
  1.2583 +// static
  1.2584 +template <class T>
  1.2585 +void
  1.2586 +VersionChangeEventsRunnable::QueueVersionChange(
  1.2587 +                             nsTArray<nsCOMPtr<nsIOfflineStorage> >& aDatabases,
  1.2588 +                             void* aClosure)
  1.2589 +{
  1.2590 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.2591 +  NS_ASSERTION(!aDatabases.IsEmpty(), "Why are we here?");
  1.2592 +
  1.2593 +  T* closure = static_cast<T*>(aClosure);
  1.2594 +
  1.2595 +  nsRefPtr<VersionChangeEventsRunnable> eventsRunnable =
  1.2596 +    new VersionChangeEventsRunnable(closure->mOpenHelper->Database(),
  1.2597 +                                    closure->mOpenRequest,
  1.2598 +                                    aDatabases,
  1.2599 +                                    closure->mCurrentVersion,
  1.2600 +                                    closure->RequestedVersion());
  1.2601 +
  1.2602 +  NS_DispatchToCurrentThread(eventsRunnable);
  1.2603 +}
  1.2604 +
  1.2605 +already_AddRefed<nsIDOMEvent>
  1.2606 +SetVersionHelper::CreateSuccessEvent(mozilla::dom::EventTarget* aOwner)
  1.2607 +{
  1.2608 +  NS_ASSERTION(mCurrentVersion < mRequestedVersion, "Huh?");
  1.2609 +
  1.2610 +  return IDBVersionChangeEvent::CreateUpgradeNeeded(aOwner,
  1.2611 +                                                    mCurrentVersion,
  1.2612 +                                                    mRequestedVersion);
  1.2613 +}
  1.2614 +
  1.2615 +nsresult
  1.2616 +SetVersionHelper::NotifyTransactionPreComplete(IDBTransaction* aTransaction)
  1.2617 +{
  1.2618 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.2619 +  NS_ASSERTION(aTransaction, "This is unexpected.");
  1.2620 +  NS_ASSERTION(mOpenRequest, "Why don't we have a request?");
  1.2621 +
  1.2622 +  return mOpenHelper->NotifySetVersionFinished();
  1.2623 +}
  1.2624 +
  1.2625 +nsresult
  1.2626 +SetVersionHelper::NotifyTransactionPostComplete(IDBTransaction* aTransaction)
  1.2627 +{
  1.2628 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.2629 +  NS_ASSERTION(aTransaction, "This is unexpected.");
  1.2630 +  NS_ASSERTION(mOpenRequest, "Why don't we have a request?");
  1.2631 +
  1.2632 +  // If we hit an error, the OpenDatabaseHelper needs to get that error too.
  1.2633 +  nsresult rv = GetResultCode();
  1.2634 +  if (NS_FAILED(rv)) {
  1.2635 +    mOpenHelper->SetError(rv);
  1.2636 +  }
  1.2637 +
  1.2638 +  // If the transaction was aborted, we should throw an error message.
  1.2639 +  if (aTransaction->IsAborted()) {
  1.2640 +    mOpenHelper->SetError(aTransaction->GetAbortCode());
  1.2641 +  }
  1.2642 +
  1.2643 +  mOpenRequest->SetTransaction(nullptr);
  1.2644 +  mOpenRequest = nullptr;
  1.2645 +
  1.2646 +  mOpenHelper = nullptr;
  1.2647 +
  1.2648 +  return rv;
  1.2649 +}
  1.2650 +
  1.2651 +NS_IMPL_ISUPPORTS_INHERITED0(DeleteDatabaseHelper, AsyncConnectionHelper);
  1.2652 +
  1.2653 +nsresult
  1.2654 +DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
  1.2655 +{
  1.2656 +  AssertIsOnIOThread();
  1.2657 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1.2658 +  NS_ASSERTION(!aConnection, "How did we get a connection here?");
  1.2659 +
  1.2660 +  PROFILER_LABEL("IndexedDB", "DeleteDatabaseHelper::DoDatabaseWork");
  1.2661 +
  1.2662 +  const StoragePrivilege& privilege = mOpenHelper->Privilege();
  1.2663 +
  1.2664 +  QuotaManager* quotaManager = QuotaManager::Get();
  1.2665 +  NS_ASSERTION(quotaManager, "This should never fail!");
  1.2666 +
  1.2667 +  nsCOMPtr<nsIFile> directory;
  1.2668 +  nsresult rv = quotaManager->GetDirectoryForOrigin(mPersistenceType,
  1.2669 +                                                    mASCIIOrigin,
  1.2670 +                                                    getter_AddRefs(directory));
  1.2671 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2672 +
  1.2673 +  NS_ASSERTION(directory, "What?");
  1.2674 +
  1.2675 +  rv = directory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
  1.2676 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2677 +
  1.2678 +  nsAutoString filename;
  1.2679 +  rv = GetDatabaseFilename(mName, filename);
  1.2680 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2681 +
  1.2682 +  nsCOMPtr<nsIFile> dbFile;
  1.2683 +  rv = directory->Clone(getter_AddRefs(dbFile));
  1.2684 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2685 +
  1.2686 +  rv = dbFile->Append(filename + NS_LITERAL_STRING(".sqlite"));
  1.2687 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2688 +
  1.2689 +  bool exists = false;
  1.2690 +  rv = dbFile->Exists(&exists);
  1.2691 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2692 +
  1.2693 +  if (exists) {
  1.2694 +    int64_t fileSize;
  1.2695 +
  1.2696 +    if (privilege != Chrome) {
  1.2697 +      rv = dbFile->GetFileSize(&fileSize);
  1.2698 +      IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2699 +    }
  1.2700 +
  1.2701 +    rv = dbFile->Remove(false);
  1.2702 +    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2703 +
  1.2704 +    if (privilege != Chrome) {
  1.2705 +      QuotaManager* quotaManager = QuotaManager::Get();
  1.2706 +      NS_ASSERTION(quotaManager, "Shouldn't be null!");
  1.2707 +
  1.2708 +      quotaManager->DecreaseUsageForOrigin(mPersistenceType, mGroup,
  1.2709 +                                           mASCIIOrigin, fileSize);
  1.2710 +    }
  1.2711 +  }
  1.2712 +
  1.2713 +  nsCOMPtr<nsIFile> dbJournalFile;
  1.2714 +  rv = directory->Clone(getter_AddRefs(dbJournalFile));
  1.2715 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2716 +
  1.2717 +  rv = dbJournalFile->Append(filename + NS_LITERAL_STRING(".sqlite-journal"));
  1.2718 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2719 +
  1.2720 +  rv = dbJournalFile->Exists(&exists);
  1.2721 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2722 +
  1.2723 +  if (exists) {
  1.2724 +    rv = dbJournalFile->Remove(false);
  1.2725 +    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2726 +  }
  1.2727 +
  1.2728 +  nsCOMPtr<nsIFile> fmDirectory;
  1.2729 +  rv = directory->Clone(getter_AddRefs(fmDirectory));
  1.2730 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2731 +
  1.2732 +  rv = fmDirectory->Append(filename);
  1.2733 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2734 +
  1.2735 +  rv = fmDirectory->Exists(&exists);
  1.2736 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2737 +
  1.2738 +  if (exists) {
  1.2739 +    bool isDirectory;
  1.2740 +    rv = fmDirectory->IsDirectory(&isDirectory);
  1.2741 +    NS_ENSURE_SUCCESS(rv, rv);
  1.2742 +    IDB_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2743 +
  1.2744 +    uint64_t usage = 0;
  1.2745 +
  1.2746 +    if (privilege != Chrome) {
  1.2747 +      rv = FileManager::GetUsage(fmDirectory, &usage);
  1.2748 +      IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2749 +    }
  1.2750 +
  1.2751 +    rv = fmDirectory->Remove(true);
  1.2752 +    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.2753 +
  1.2754 +    if (privilege != Chrome) {
  1.2755 +      QuotaManager* quotaManager = QuotaManager::Get();
  1.2756 +      NS_ASSERTION(quotaManager, "Shouldn't be null!");
  1.2757 +
  1.2758 +      quotaManager->DecreaseUsageForOrigin(mPersistenceType, mGroup,
  1.2759 +                                           mASCIIOrigin, usage);
  1.2760 +    }
  1.2761 +  }
  1.2762 +
  1.2763 +  IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
  1.2764 +  NS_ASSERTION(mgr, "This should never fail!");
  1.2765 +
  1.2766 +  mgr->InvalidateFileManager(mPersistenceType, mASCIIOrigin, mName);
  1.2767 +
  1.2768 +  return NS_OK;
  1.2769 +}
  1.2770 +
  1.2771 +nsresult
  1.2772 +DeleteDatabaseHelper::GetSuccessResult(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
  1.2773 +{
  1.2774 +  return NS_OK;
  1.2775 +}
  1.2776 +
  1.2777 +nsresult
  1.2778 +DeleteDatabaseHelper::OnExclusiveAccessAcquired()
  1.2779 +{
  1.2780 +  QuotaManager* quotaManager = QuotaManager::Get();
  1.2781 +  NS_ASSERTION(quotaManager, "We should definitely have a manager here");
  1.2782 +
  1.2783 +  nsresult rv = Dispatch(quotaManager->IOThread());
  1.2784 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2785 +
  1.2786 +  return NS_OK;
  1.2787 +}
  1.2788 +
  1.2789 +nsresult
  1.2790 +DeleteDatabaseHelper::Init()
  1.2791 +{
  1.2792 +  // Note that there's no need to block the database here, since the page
  1.2793 +  // never gets to touch it, and all other databases must be closed.
  1.2794 +
  1.2795 +  return NS_OK;
  1.2796 +}

mercurial