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