dom/indexedDB/OpenDatabaseHelper.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial