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