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