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/. */
5 #include "mozilla/DebugOnly.h"
7 #include "OpenDatabaseHelper.h"
9 #include "nsIBFCacheEntry.h"
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"
18 #include "nsNetUtil.h"
19 #include "nsThreadUtils.h"
20 #include "snappy/snappy.h"
23 #include "IDBEvents.h"
24 #include "IDBFactory.h"
25 #include "IndexedDatabaseManager.h"
26 #include "ProfilerHelpers.h"
27 #include "ReportInternalError.h"
29 using namespace mozilla
;
30 using namespace mozilla::dom
;
31 USING_INDEXEDDB_NAMESPACE
36 // If JS_STRUCTURED_CLONE_VERSION changes then we need to update our major
38 static_assert(JS_STRUCTURED_CLONE_VERSION
== 4,
39 "Need to update the major schema version.");
41 // Major schema version. Bump for almost everything.
42 const uint32_t kMajorSchemaVersion
= 16;
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;
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.");
58 MakeSchemaVersion(uint32_t aMajorSchemaVersion
,
59 uint32_t aMinorSchemaVersion
)
61 return int32_t((aMajorSchemaVersion
<< 4) + aMinorSchemaVersion
);
64 const int32_t kSQLiteSchemaVersion
= int32_t((kMajorSchemaVersion
<< 4) +
67 const uint32_t kGoldenRatioU32
= 0x9E3779B9U
;
71 RotateBitsLeft32(uint32_t value
, uint8_t bits
)
73 MOZ_ASSERT(bits
< 32);
74 return (value
<< bits
) | (value
>> (32 - bits
));
79 HashName(const nsAString
& aName
)
81 const char16_t
* str
= aName
.BeginReading();
82 size_t length
= aName
.Length();
85 for (size_t i
= 0; i
< length
; i
++) {
86 hash
= kGoldenRatioU32
* (RotateBitsLeft32(hash
, 5) ^ str
[i
]);
93 GetDatabaseFilename(const nsAString
& aName
,
94 nsAString
& aDatabaseFilename
)
96 aDatabaseFilename
.AppendInt(HashName(aName
));
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
;
104 const char* forwardIter
= escapedName
.BeginReading();
105 const char* backwardIter
= escapedName
.EndReading() - 1;
108 while (forwardIter
<= backwardIter
&& substring
.Length() < 21) {
109 if (substring
.Length() % 2) {
110 substring
.Append(*backwardIter
--);
113 substring
.Append(*forwardIter
++);
117 aDatabaseFilename
.Append(NS_ConvertASCIItoUTF16(substring
));
123 CreateFileTables(mozIStorageConnection
* aDBConn
)
125 AssertIsOnIOThread();
126 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
128 PROFILER_LABEL("OpenDatabaseHelper", "CreateFileTables",
129 js::ProfileEntry::Category::STORAGE
);
132 nsresult rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
133 "CREATE TABLE file ("
134 "id INTEGER PRIMARY KEY, "
135 "refcount INTEGER NOT NULL"
138 NS_ENSURE_SUCCESS(rv
, rv
);
140 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
141 "CREATE TRIGGER object_data_insert_trigger "
142 "AFTER INSERT ON object_data "
144 "WHEN NEW.file_ids IS NOT NULL "
146 "SELECT update_refcount(NULL, NEW.file_ids); "
149 NS_ENSURE_SUCCESS(rv
, rv
);
151 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
152 "CREATE TRIGGER object_data_update_trigger "
153 "AFTER UPDATE OF file_ids ON object_data "
155 "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
157 "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
160 NS_ENSURE_SUCCESS(rv
, rv
);
162 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
163 "CREATE TRIGGER object_data_delete_trigger "
164 "AFTER DELETE ON object_data "
165 "FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
167 "SELECT update_refcount(OLD.file_ids, NULL); "
170 NS_ENSURE_SUCCESS(rv
, rv
);
172 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
173 "CREATE TRIGGER file_update_trigger "
174 "AFTER UPDATE ON file "
175 "FOR EACH ROW WHEN NEW.refcount = 0 "
177 "DELETE FROM file WHERE id = OLD.id; "
180 NS_ENSURE_SUCCESS(rv
, rv
);
186 CreateTables(mozIStorageConnection
* aDBConn
)
188 AssertIsOnIOThread();
189 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
190 NS_ASSERTION(aDBConn
, "Passing a null database connection!");
192 PROFILER_LABEL("OpenDatabaseHelper", "CreateTables",
193 js::ProfileEntry::Category::STORAGE
);
196 nsresult rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
197 "CREATE TABLE database ("
198 "name TEXT NOT NULL, "
199 "version INTEGER NOT NULL DEFAULT 0"
202 NS_ENSURE_SUCCESS(rv
, rv
);
204 // Table `object_store`
205 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
206 "CREATE TABLE object_store ("
207 "id INTEGER PRIMARY KEY, "
208 "auto_increment INTEGER NOT NULL DEFAULT 0, "
209 "name TEXT NOT NULL, "
214 NS_ENSURE_SUCCESS(rv
, rv
);
216 // Table `object_data`
217 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
218 "CREATE TABLE object_data ("
219 "id INTEGER PRIMARY KEY, "
220 "object_store_id INTEGER NOT NULL, "
221 "key_value BLOB DEFAULT NULL, "
223 "data BLOB NOT NULL, "
224 "UNIQUE (object_store_id, key_value), "
225 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
229 NS_ENSURE_SUCCESS(rv
, rv
);
232 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
233 "CREATE TABLE object_store_index ("
234 "id INTEGER PRIMARY KEY, "
235 "object_store_id INTEGER NOT NULL, "
236 "name TEXT NOT NULL, "
237 "key_path TEXT NOT NULL, "
238 "unique_index INTEGER NOT NULL, "
239 "multientry INTEGER NOT NULL, "
240 "UNIQUE (object_store_id, name), "
241 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
245 NS_ENSURE_SUCCESS(rv
, rv
);
247 // Table `index_data`
248 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
249 "CREATE TABLE index_data ("
250 "index_id INTEGER NOT NULL, "
251 "value BLOB NOT NULL, "
252 "object_data_key BLOB NOT NULL, "
253 "object_data_id INTEGER NOT NULL, "
254 "PRIMARY KEY (index_id, value, object_data_key), "
255 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
257 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
261 NS_ENSURE_SUCCESS(rv
, rv
);
263 // Need this to make cascading deletes from object_data and object_store fast.
264 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
265 "CREATE INDEX index_data_object_data_id_index "
266 "ON index_data (object_data_id);"
268 NS_ENSURE_SUCCESS(rv
, rv
);
270 // Table `unique_index_data`
271 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
272 "CREATE TABLE unique_index_data ("
273 "index_id INTEGER NOT NULL, "
274 "value BLOB NOT NULL, "
275 "object_data_key BLOB NOT NULL, "
276 "object_data_id INTEGER NOT NULL, "
277 "PRIMARY KEY (index_id, value, object_data_key), "
278 "UNIQUE (index_id, value), "
279 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
281 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
285 NS_ENSURE_SUCCESS(rv
, rv
);
287 // Need this to make cascading deletes from object_data and object_store fast.
288 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
289 "CREATE INDEX unique_index_data_object_data_id_index "
290 "ON unique_index_data (object_data_id);"
292 NS_ENSURE_SUCCESS(rv
, rv
);
294 rv
= CreateFileTables(aDBConn
);
295 NS_ENSURE_SUCCESS(rv
, rv
);
297 rv
= aDBConn
->SetSchemaVersion(kSQLiteSchemaVersion
);
298 NS_ENSURE_SUCCESS(rv
, rv
);
304 UpgradeSchemaFrom4To5(mozIStorageConnection
* aConnection
)
306 AssertIsOnIOThread();
307 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
309 PROFILER_LABEL("OpenDatabaseHelper", "UpgradeSchemaFrom4To5",
310 js::ProfileEntry::Category::STORAGE
);
314 // All we changed is the type of the version column, so lets try to
315 // convert that to an integer, and if we fail, set it to 0.
316 nsCOMPtr
<mozIStorageStatement
> stmt
;
317 rv
= aConnection
->CreateStatement(NS_LITERAL_CSTRING(
318 "SELECT name, version, dataVersion "
320 ), getter_AddRefs(stmt
));
321 NS_ENSURE_SUCCESS(rv
, rv
);
328 mozStorageStatementScoper
scoper(stmt
);
331 rv
= stmt
->ExecuteStep(&hasResults
);
332 NS_ENSURE_SUCCESS(rv
, rv
);
333 NS_ENSURE_TRUE(hasResults
, NS_ERROR_FAILURE
);
336 rv
= stmt
->GetString(1, version
);
337 NS_ENSURE_SUCCESS(rv
, rv
);
339 intVersion
= version
.ToInteger(&rv
);
344 rv
= stmt
->GetString(0, name
);
345 NS_ENSURE_SUCCESS(rv
, rv
);
347 rv
= stmt
->GetInt64(2, &dataVersion
);
348 NS_ENSURE_SUCCESS(rv
, rv
);
351 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
352 "DROP TABLE database"
354 NS_ENSURE_SUCCESS(rv
, rv
);
356 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
357 "CREATE TABLE database ("
358 "name TEXT NOT NULL, "
359 "version INTEGER NOT NULL DEFAULT 0, "
360 "dataVersion INTEGER NOT NULL"
363 NS_ENSURE_SUCCESS(rv
, rv
);
365 rv
= aConnection
->CreateStatement(NS_LITERAL_CSTRING(
366 "INSERT INTO database (name, version, dataVersion) "
367 "VALUES (:name, :version, :dataVersion)"
368 ), getter_AddRefs(stmt
));
369 NS_ENSURE_SUCCESS(rv
, rv
);
372 mozStorageStatementScoper
scoper(stmt
);
374 rv
= stmt
->BindStringByName(NS_LITERAL_CSTRING("name"), name
);
375 NS_ENSURE_SUCCESS(rv
, rv
);
377 rv
= stmt
->BindInt32ByName(NS_LITERAL_CSTRING("version"), intVersion
);
378 NS_ENSURE_SUCCESS(rv
, rv
);
380 rv
= stmt
->BindInt64ByName(NS_LITERAL_CSTRING("dataVersion"), dataVersion
);
381 NS_ENSURE_SUCCESS(rv
, rv
);
383 rv
= stmt
->Execute();
384 NS_ENSURE_SUCCESS(rv
, rv
);
387 rv
= aConnection
->SetSchemaVersion(5);
388 NS_ENSURE_SUCCESS(rv
, rv
);
394 UpgradeSchemaFrom5To6(mozIStorageConnection
* aConnection
)
396 AssertIsOnIOThread();
397 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
399 PROFILER_LABEL("OpenDatabaseHelper", "UpgradeSchemaFrom5To6",
400 js::ProfileEntry::Category::STORAGE
);
402 // First, drop all the indexes we're no longer going to use.
403 nsresult rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
404 "DROP INDEX key_index;"
406 NS_ENSURE_SUCCESS(rv
, rv
);
408 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
409 "DROP INDEX ai_key_index;"
411 NS_ENSURE_SUCCESS(rv
, rv
);
413 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
414 "DROP INDEX value_index;"
416 NS_ENSURE_SUCCESS(rv
, rv
);
418 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
419 "DROP INDEX ai_value_index;"
421 NS_ENSURE_SUCCESS(rv
, rv
);
423 // Now, reorder the columns of object_data to put the blob data last. We do
424 // this by copying into a temporary table, dropping the original, then copying
425 // back into a newly created table.
426 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
427 "CREATE TEMPORARY TABLE temp_upgrade ("
428 "id INTEGER PRIMARY KEY, "
434 NS_ENSURE_SUCCESS(rv
, rv
);
436 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
437 "INSERT INTO temp_upgrade "
438 "SELECT id, object_store_id, key_value, data "
441 NS_ENSURE_SUCCESS(rv
, rv
);
443 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
444 "DROP TABLE object_data;"
446 NS_ENSURE_SUCCESS(rv
, rv
);
448 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
449 "CREATE TABLE object_data ("
450 "id INTEGER PRIMARY KEY, "
451 "object_store_id INTEGER NOT NULL, "
452 "key_value DEFAULT NULL, "
453 "data BLOB NOT NULL, "
454 "UNIQUE (object_store_id, key_value), "
455 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
459 NS_ENSURE_SUCCESS(rv
, rv
);
461 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
462 "INSERT INTO object_data "
463 "SELECT id, object_store_id, key_value, data "
466 NS_ENSURE_SUCCESS(rv
, rv
);
468 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
469 "DROP TABLE temp_upgrade;"
471 NS_ENSURE_SUCCESS(rv
, rv
);
473 // We need to add a unique constraint to our ai_object_data table. Copy all
474 // the data out of it using a temporary table as before.
475 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
476 "CREATE TEMPORARY TABLE temp_upgrade ("
477 "id INTEGER PRIMARY KEY, "
482 NS_ENSURE_SUCCESS(rv
, rv
);
484 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
485 "INSERT INTO temp_upgrade "
486 "SELECT id, object_store_id, data "
487 "FROM ai_object_data;"
489 NS_ENSURE_SUCCESS(rv
, rv
);
491 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
492 "DROP TABLE ai_object_data;"
494 NS_ENSURE_SUCCESS(rv
, rv
);
496 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
497 "CREATE TABLE ai_object_data ("
498 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
499 "object_store_id INTEGER NOT NULL, "
500 "data BLOB NOT NULL, "
501 "UNIQUE (object_store_id, id), "
502 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
506 NS_ENSURE_SUCCESS(rv
, rv
);
508 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
509 "INSERT INTO ai_object_data "
510 "SELECT id, object_store_id, data "
513 NS_ENSURE_SUCCESS(rv
, rv
);
515 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
516 "DROP TABLE temp_upgrade;"
518 NS_ENSURE_SUCCESS(rv
, rv
);
520 // Fix up the index_data table. We're reordering the columns as well as
521 // changing the primary key from being a simple id to being a composite.
522 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
523 "CREATE TEMPORARY TABLE temp_upgrade ("
530 NS_ENSURE_SUCCESS(rv
, rv
);
532 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
533 "INSERT INTO temp_upgrade "
534 "SELECT index_id, value, object_data_key, object_data_id "
537 NS_ENSURE_SUCCESS(rv
, rv
);
539 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
540 "DROP TABLE index_data;"
542 NS_ENSURE_SUCCESS(rv
, rv
);
544 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
545 "CREATE TABLE index_data ("
546 "index_id INTEGER NOT NULL, "
548 "object_data_key NOT NULL, "
549 "object_data_id INTEGER NOT NULL, "
550 "PRIMARY KEY (index_id, value, object_data_key), "
551 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
553 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
557 NS_ENSURE_SUCCESS(rv
, rv
);
559 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
560 "INSERT OR IGNORE INTO index_data "
561 "SELECT index_id, value, object_data_key, object_data_id "
564 NS_ENSURE_SUCCESS(rv
, rv
);
566 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
567 "DROP TABLE temp_upgrade;"
569 NS_ENSURE_SUCCESS(rv
, rv
);
571 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
572 "CREATE INDEX index_data_object_data_id_index "
573 "ON index_data (object_data_id);"
575 NS_ENSURE_SUCCESS(rv
, rv
);
577 // Fix up the unique_index_data table. We're reordering the columns as well as
578 // changing the primary key from being a simple id to being a composite.
579 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
580 "CREATE TEMPORARY TABLE temp_upgrade ("
587 NS_ENSURE_SUCCESS(rv
, rv
);
589 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
590 "INSERT INTO temp_upgrade "
591 "SELECT index_id, value, object_data_key, object_data_id "
592 "FROM unique_index_data;"
594 NS_ENSURE_SUCCESS(rv
, rv
);
596 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
597 "DROP TABLE unique_index_data;"
599 NS_ENSURE_SUCCESS(rv
, rv
);
601 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
602 "CREATE TABLE unique_index_data ("
603 "index_id INTEGER NOT NULL, "
605 "object_data_key NOT NULL, "
606 "object_data_id INTEGER NOT NULL, "
607 "PRIMARY KEY (index_id, value, object_data_key), "
608 "UNIQUE (index_id, value), "
609 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
611 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
615 NS_ENSURE_SUCCESS(rv
, rv
);
617 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
618 "INSERT INTO unique_index_data "
619 "SELECT index_id, value, object_data_key, object_data_id "
622 NS_ENSURE_SUCCESS(rv
, rv
);
624 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
625 "DROP TABLE temp_upgrade;"
627 NS_ENSURE_SUCCESS(rv
, rv
);
629 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
630 "CREATE INDEX unique_index_data_object_data_id_index "
631 "ON unique_index_data (object_data_id);"
633 NS_ENSURE_SUCCESS(rv
, rv
);
635 // Fix up the ai_index_data table. We're reordering the columns as well as
636 // changing the primary key from being a simple id to being a composite.
637 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
638 "CREATE TEMPORARY TABLE temp_upgrade ("
644 NS_ENSURE_SUCCESS(rv
, rv
);
646 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
647 "INSERT INTO temp_upgrade "
648 "SELECT index_id, value, ai_object_data_id "
649 "FROM ai_index_data;"
651 NS_ENSURE_SUCCESS(rv
, rv
);
653 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
654 "DROP TABLE ai_index_data;"
656 NS_ENSURE_SUCCESS(rv
, rv
);
658 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
659 "CREATE TABLE ai_index_data ("
660 "index_id INTEGER NOT NULL, "
662 "ai_object_data_id INTEGER NOT NULL, "
663 "PRIMARY KEY (index_id, value, ai_object_data_id), "
664 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
666 "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
670 NS_ENSURE_SUCCESS(rv
, rv
);
672 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
673 "INSERT OR IGNORE INTO ai_index_data "
674 "SELECT index_id, value, ai_object_data_id "
677 NS_ENSURE_SUCCESS(rv
, rv
);
679 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
680 "DROP TABLE temp_upgrade;"
682 NS_ENSURE_SUCCESS(rv
, rv
);
684 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
685 "CREATE INDEX ai_index_data_ai_object_data_id_index "
686 "ON ai_index_data (ai_object_data_id);"
688 NS_ENSURE_SUCCESS(rv
, rv
);
690 // Fix up the ai_unique_index_data table. We're reordering the columns as well
691 // as changing the primary key from being a simple id to being a composite.
692 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
693 "CREATE TEMPORARY TABLE temp_upgrade ("
699 NS_ENSURE_SUCCESS(rv
, rv
);
701 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
702 "INSERT INTO temp_upgrade "
703 "SELECT index_id, value, ai_object_data_id "
704 "FROM ai_unique_index_data;"
706 NS_ENSURE_SUCCESS(rv
, rv
);
708 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
709 "DROP TABLE ai_unique_index_data;"
711 NS_ENSURE_SUCCESS(rv
, rv
);
713 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
714 "CREATE TABLE ai_unique_index_data ("
715 "index_id INTEGER NOT NULL, "
717 "ai_object_data_id INTEGER NOT NULL, "
718 "UNIQUE (index_id, value), "
719 "PRIMARY KEY (index_id, value, ai_object_data_id), "
720 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
722 "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
726 NS_ENSURE_SUCCESS(rv
, rv
);
728 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
729 "INSERT INTO ai_unique_index_data "
730 "SELECT index_id, value, ai_object_data_id "
733 NS_ENSURE_SUCCESS(rv
, rv
);
735 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
736 "DROP TABLE temp_upgrade;"
738 NS_ENSURE_SUCCESS(rv
, rv
);
740 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
741 "CREATE INDEX ai_unique_index_data_ai_object_data_id_index "
742 "ON ai_unique_index_data (ai_object_data_id);"
744 NS_ENSURE_SUCCESS(rv
, rv
);
746 rv
= aConnection
->SetSchemaVersion(6);
747 NS_ENSURE_SUCCESS(rv
, rv
);
753 UpgradeSchemaFrom6To7(mozIStorageConnection
* aConnection
)
755 AssertIsOnIOThread();
756 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
758 PROFILER_LABEL("OpenDatabaseHelper", "UpgradeSchemaFrom6To7",
759 js::ProfileEntry::Category::STORAGE
);
761 nsresult rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
762 "CREATE TEMPORARY TABLE temp_upgrade ("
769 NS_ENSURE_SUCCESS(rv
, rv
);
771 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
772 "INSERT INTO temp_upgrade "
773 "SELECT id, name, key_path, auto_increment "
776 NS_ENSURE_SUCCESS(rv
, rv
);
778 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
779 "DROP TABLE object_store;"
781 NS_ENSURE_SUCCESS(rv
, rv
);
783 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
784 "CREATE TABLE object_store ("
785 "id INTEGER PRIMARY KEY, "
786 "auto_increment INTEGER NOT NULL DEFAULT 0, "
787 "name TEXT NOT NULL, "
792 NS_ENSURE_SUCCESS(rv
, rv
);
794 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
795 "INSERT INTO object_store "
796 "SELECT id, auto_increment, name, nullif(key_path, '') "
799 NS_ENSURE_SUCCESS(rv
, rv
);
801 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
802 "DROP TABLE temp_upgrade;"
804 NS_ENSURE_SUCCESS(rv
, rv
);
806 rv
= aConnection
->SetSchemaVersion(7);
807 NS_ENSURE_SUCCESS(rv
, rv
);
813 UpgradeSchemaFrom7To8(mozIStorageConnection
* aConnection
)
815 AssertIsOnIOThread();
816 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
818 PROFILER_LABEL("OpenDatabaseHelper", "UpgradeSchemaFrom7To8",
819 js::ProfileEntry::Category::STORAGE
);
821 nsresult rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
822 "CREATE TEMPORARY TABLE temp_upgrade ("
828 "object_store_autoincrement"
831 NS_ENSURE_SUCCESS(rv
, rv
);
833 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
834 "INSERT INTO temp_upgrade "
835 "SELECT id, object_store_id, name, key_path, "
836 "unique_index, object_store_autoincrement "
837 "FROM object_store_index;"
839 NS_ENSURE_SUCCESS(rv
, rv
);
841 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
842 "DROP TABLE object_store_index;"
844 NS_ENSURE_SUCCESS(rv
, rv
);
846 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
847 "CREATE TABLE object_store_index ("
849 "object_store_id INTEGER NOT NULL, "
850 "name TEXT NOT NULL, "
851 "key_path TEXT NOT NULL, "
852 "unique_index INTEGER NOT NULL, "
853 "multientry INTEGER NOT NULL, "
854 "object_store_autoincrement INTERGER NOT NULL, "
856 "UNIQUE (object_store_id, name), "
857 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
861 NS_ENSURE_SUCCESS(rv
, rv
);
863 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
864 "INSERT INTO object_store_index "
865 "SELECT id, object_store_id, name, key_path, "
866 "unique_index, 0, object_store_autoincrement "
869 NS_ENSURE_SUCCESS(rv
, rv
);
871 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
872 "DROP TABLE temp_upgrade;"
874 NS_ENSURE_SUCCESS(rv
, rv
);
876 rv
= aConnection
->SetSchemaVersion(8);
877 NS_ENSURE_SUCCESS(rv
, rv
);
882 class CompressDataBlobsFunction MOZ_FINAL
: public mozIStorageFunction
884 ~CompressDataBlobsFunction() {}
890 OnFunctionCall(mozIStorageValueArray
* aArguments
,
891 nsIVariant
** aResult
)
893 PROFILER_LABEL("CompressDataBlobsFunction", "OnFunctionCall",
894 js::ProfileEntry::Category::STORAGE
);
897 nsresult rv
= aArguments
->GetNumEntries(&argc
);
898 NS_ENSURE_SUCCESS(rv
, rv
);
901 NS_WARNING("Don't call me with the wrong number of arguments!");
902 return NS_ERROR_UNEXPECTED
;
906 rv
= aArguments
->GetTypeOfIndex(0, &type
);
907 NS_ENSURE_SUCCESS(rv
, rv
);
909 if (type
!= mozIStorageStatement::VALUE_TYPE_BLOB
) {
910 NS_WARNING("Don't call me with the wrong type of arguments!");
911 return NS_ERROR_UNEXPECTED
;
914 const uint8_t* uncompressed
;
915 uint32_t uncompressedLength
;
916 rv
= aArguments
->GetSharedBlob(0, &uncompressedLength
, &uncompressed
);
917 NS_ENSURE_SUCCESS(rv
, rv
);
919 size_t compressedLength
= snappy::MaxCompressedLength(uncompressedLength
);
920 char* compressed
= (char*)moz_malloc(compressedLength
);
921 NS_ENSURE_TRUE(compressed
, NS_ERROR_OUT_OF_MEMORY
);
923 snappy::RawCompress(reinterpret_cast<const char*>(uncompressed
),
924 uncompressedLength
, compressed
, &compressedLength
);
926 std::pair
<uint8_t *, int> data((uint8_t*)compressed
,
927 int(compressedLength
));
928 // The variant takes ownership of | compressed |.
929 nsCOMPtr
<nsIVariant
> result
= new mozilla::storage::AdoptedBlobVariant(data
);
931 result
.forget(aResult
);
936 NS_IMPL_ISUPPORTS(CompressDataBlobsFunction
, mozIStorageFunction
)
939 UpgradeSchemaFrom8To9_0(mozIStorageConnection
* aConnection
)
941 AssertIsOnIOThread();
942 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
944 PROFILER_LABEL("OpenDatabaseHelper", "UpgradeSchemaFrom8To9_0",
945 js::ProfileEntry::Category::STORAGE
);
947 // We no longer use the dataVersion column.
948 nsresult rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
949 "UPDATE database SET dataVersion = 0;"
951 NS_ENSURE_SUCCESS(rv
, rv
);
953 nsCOMPtr
<mozIStorageFunction
> compressor
= new CompressDataBlobsFunction();
955 NS_NAMED_LITERAL_CSTRING(compressorName
, "compress");
957 rv
= aConnection
->CreateFunction(compressorName
, 1, compressor
);
958 NS_ENSURE_SUCCESS(rv
, rv
);
960 // Turn off foreign key constraints before we do anything here.
961 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
962 "UPDATE object_data SET data = compress(data);"
964 NS_ENSURE_SUCCESS(rv
, rv
);
966 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
967 "UPDATE ai_object_data SET data = compress(data);"
969 NS_ENSURE_SUCCESS(rv
, rv
);
971 rv
= aConnection
->RemoveFunction(compressorName
);
972 NS_ENSURE_SUCCESS(rv
, rv
);
974 rv
= aConnection
->SetSchemaVersion(MakeSchemaVersion(9, 0));
975 NS_ENSURE_SUCCESS(rv
, rv
);
981 UpgradeSchemaFrom9_0To10_0(mozIStorageConnection
* aConnection
)
983 AssertIsOnIOThread();
984 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
986 PROFILER_LABEL("OpenDatabaseHelper", "UpgradeSchemaFrom9_0To10_0",
987 js::ProfileEntry::Category::STORAGE
);
989 nsresult rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
990 "ALTER TABLE object_data ADD COLUMN file_ids TEXT;"
992 NS_ENSURE_SUCCESS(rv
, rv
);
994 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
995 "ALTER TABLE ai_object_data ADD COLUMN file_ids TEXT;"
997 NS_ENSURE_SUCCESS(rv
, rv
);
999 rv
= CreateFileTables(aConnection
);
1000 NS_ENSURE_SUCCESS(rv
, rv
);
1002 rv
= aConnection
->SetSchemaVersion(MakeSchemaVersion(10, 0));
1003 NS_ENSURE_SUCCESS(rv
, rv
);
1009 UpgradeSchemaFrom10_0To11_0(mozIStorageConnection
* aConnection
)
1011 AssertIsOnIOThread();
1012 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1014 PROFILER_LABEL("OpenDatabaseHelper", "UpgradeSchemaFrom10_0To11_0",
1015 js::ProfileEntry::Category::STORAGE
);
1017 nsresult rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1018 "CREATE TEMPORARY TABLE temp_upgrade ("
1027 NS_ENSURE_SUCCESS(rv
, rv
);
1029 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1030 "INSERT INTO temp_upgrade "
1031 "SELECT id, object_store_id, name, key_path, "
1032 "unique_index, multientry "
1033 "FROM object_store_index;"
1035 NS_ENSURE_SUCCESS(rv
, rv
);
1037 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1038 "DROP TABLE object_store_index;"
1040 NS_ENSURE_SUCCESS(rv
, rv
);
1042 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1043 "CREATE TABLE object_store_index ("
1044 "id INTEGER PRIMARY KEY, "
1045 "object_store_id INTEGER NOT NULL, "
1046 "name TEXT NOT NULL, "
1047 "key_path TEXT NOT NULL, "
1048 "unique_index INTEGER NOT NULL, "
1049 "multientry INTEGER NOT NULL, "
1050 "UNIQUE (object_store_id, name), "
1051 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
1055 NS_ENSURE_SUCCESS(rv
, rv
);
1057 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1058 "INSERT INTO object_store_index "
1059 "SELECT id, object_store_id, name, key_path, "
1060 "unique_index, multientry "
1061 "FROM temp_upgrade;"
1063 NS_ENSURE_SUCCESS(rv
, rv
);
1065 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1066 "DROP TABLE temp_upgrade;"
1068 NS_ENSURE_SUCCESS(rv
, rv
);
1070 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1071 "DROP TRIGGER object_data_insert_trigger;"
1073 NS_ENSURE_SUCCESS(rv
, rv
);
1075 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1076 "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
1077 "SELECT object_store_id, id, data, file_ids "
1078 "FROM ai_object_data;"
1080 NS_ENSURE_SUCCESS(rv
, rv
);
1082 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1083 "CREATE TRIGGER object_data_insert_trigger "
1084 "AFTER INSERT ON object_data "
1086 "WHEN NEW.file_ids IS NOT NULL "
1088 "SELECT update_refcount(NULL, NEW.file_ids); "
1091 NS_ENSURE_SUCCESS(rv
, rv
);
1093 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1094 "INSERT INTO index_data (index_id, value, object_data_key, object_data_id) "
1095 "SELECT ai_index_data.index_id, ai_index_data.value, ai_index_data.ai_object_data_id, object_data.id "
1096 "FROM ai_index_data "
1097 "INNER JOIN object_store_index ON "
1098 "object_store_index.id = ai_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_index_data.ai_object_data_id;"
1103 NS_ENSURE_SUCCESS(rv
, rv
);
1105 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1106 "INSERT INTO unique_index_data (index_id, value, object_data_key, object_data_id) "
1107 "SELECT ai_unique_index_data.index_id, ai_unique_index_data.value, ai_unique_index_data.ai_object_data_id, object_data.id "
1108 "FROM ai_unique_index_data "
1109 "INNER JOIN object_store_index ON "
1110 "object_store_index.id = ai_unique_index_data.index_id "
1111 "INNER JOIN object_data ON "
1112 "object_data.object_store_id = object_store_index.object_store_id AND "
1113 "object_data.key_value = ai_unique_index_data.ai_object_data_id;"
1115 NS_ENSURE_SUCCESS(rv
, rv
);
1117 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1118 "UPDATE object_store "
1119 "SET auto_increment = (SELECT max(id) FROM ai_object_data) + 1 "
1120 "WHERE auto_increment;"
1122 NS_ENSURE_SUCCESS(rv
, rv
);
1124 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1125 "DROP TABLE ai_unique_index_data;"
1127 NS_ENSURE_SUCCESS(rv
, rv
);
1129 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1130 "DROP TABLE ai_index_data;"
1132 NS_ENSURE_SUCCESS(rv
, rv
);
1134 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1135 "DROP TABLE ai_object_data;"
1137 NS_ENSURE_SUCCESS(rv
, rv
);
1139 rv
= aConnection
->SetSchemaVersion(MakeSchemaVersion(11, 0));
1140 NS_ENSURE_SUCCESS(rv
, rv
);
1145 class EncodeKeysFunction MOZ_FINAL
: public mozIStorageFunction
1147 ~EncodeKeysFunction() {}
1153 OnFunctionCall(mozIStorageValueArray
* aArguments
,
1154 nsIVariant
** aResult
)
1156 PROFILER_LABEL("EncodeKeysFunction", "OnFunctionCall",
1157 js::ProfileEntry::Category::STORAGE
);
1160 nsresult rv
= aArguments
->GetNumEntries(&argc
);
1161 NS_ENSURE_SUCCESS(rv
, rv
);
1164 NS_WARNING("Don't call me with the wrong number of arguments!");
1165 return NS_ERROR_UNEXPECTED
;
1169 rv
= aArguments
->GetTypeOfIndex(0, &type
);
1170 NS_ENSURE_SUCCESS(rv
, rv
);
1173 if (type
== mozIStorageStatement::VALUE_TYPE_INTEGER
) {
1175 aArguments
->GetInt64(0, &intKey
);
1176 key
.SetFromInteger(intKey
);
1178 else if (type
== mozIStorageStatement::VALUE_TYPE_TEXT
) {
1180 aArguments
->GetString(0, stringKey
);
1181 key
.SetFromString(stringKey
);
1184 NS_WARNING("Don't call me with the wrong type of arguments!");
1185 return NS_ERROR_UNEXPECTED
;
1188 const nsCString
& buffer
= key
.GetBuffer();
1190 std::pair
<const void *, int> data(static_cast<const void*>(buffer
.get()),
1191 int(buffer
.Length()));
1193 nsCOMPtr
<nsIVariant
> result
= new mozilla::storage::BlobVariant(data
);
1195 result
.forget(aResult
);
1200 NS_IMPL_ISUPPORTS(EncodeKeysFunction
, mozIStorageFunction
)
1203 UpgradeSchemaFrom11_0To12_0(mozIStorageConnection
* aConnection
)
1205 AssertIsOnIOThread();
1206 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1208 PROFILER_LABEL("OpenDatabaseHelper", "UpgradeSchemaFrom11_0To12_0",
1209 js::ProfileEntry::Category::STORAGE
);
1211 NS_NAMED_LITERAL_CSTRING(encoderName
, "encode");
1213 nsCOMPtr
<mozIStorageFunction
> encoder
= new EncodeKeysFunction();
1215 nsresult rv
= aConnection
->CreateFunction(encoderName
, 1, encoder
);
1216 NS_ENSURE_SUCCESS(rv
, rv
);
1218 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1219 "CREATE TEMPORARY TABLE temp_upgrade ("
1220 "id INTEGER PRIMARY KEY, "
1227 NS_ENSURE_SUCCESS(rv
, rv
);
1229 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1230 "INSERT INTO temp_upgrade "
1231 "SELECT id, object_store_id, encode(key_value), data, file_ids "
1234 NS_ENSURE_SUCCESS(rv
, rv
);
1236 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1237 "DROP TABLE object_data;"
1239 NS_ENSURE_SUCCESS(rv
, rv
);
1241 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1242 "CREATE TABLE object_data ("
1243 "id INTEGER PRIMARY KEY, "
1244 "object_store_id INTEGER NOT NULL, "
1245 "key_value BLOB DEFAULT NULL, "
1247 "data BLOB NOT NULL, "
1248 "UNIQUE (object_store_id, key_value), "
1249 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
1253 NS_ENSURE_SUCCESS(rv
, rv
);
1255 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1256 "INSERT INTO object_data "
1257 "SELECT id, object_store_id, key_value, file_ids, data "
1258 "FROM temp_upgrade;"
1260 NS_ENSURE_SUCCESS(rv
, rv
);
1262 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1263 "DROP TABLE temp_upgrade;"
1265 NS_ENSURE_SUCCESS(rv
, rv
);
1267 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1268 "CREATE TRIGGER object_data_insert_trigger "
1269 "AFTER INSERT ON object_data "
1271 "WHEN NEW.file_ids IS NOT NULL "
1273 "SELECT update_refcount(NULL, NEW.file_ids); "
1276 NS_ENSURE_SUCCESS(rv
, rv
);
1278 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1279 "CREATE TRIGGER object_data_update_trigger "
1280 "AFTER UPDATE OF file_ids ON object_data "
1282 "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
1284 "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
1287 NS_ENSURE_SUCCESS(rv
, rv
);
1289 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1290 "CREATE TRIGGER object_data_delete_trigger "
1291 "AFTER DELETE ON object_data "
1292 "FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
1294 "SELECT update_refcount(OLD.file_ids, NULL); "
1297 NS_ENSURE_SUCCESS(rv
, rv
);
1299 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1300 "CREATE TEMPORARY TABLE temp_upgrade ("
1307 NS_ENSURE_SUCCESS(rv
, rv
);
1309 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1310 "INSERT INTO temp_upgrade "
1311 "SELECT index_id, encode(value), encode(object_data_key), object_data_id "
1314 NS_ENSURE_SUCCESS(rv
, rv
);
1316 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1317 "DROP TABLE index_data;"
1319 NS_ENSURE_SUCCESS(rv
, rv
);
1321 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1322 "CREATE TABLE index_data ("
1323 "index_id INTEGER NOT NULL, "
1324 "value BLOB NOT NULL, "
1325 "object_data_key BLOB NOT NULL, "
1326 "object_data_id INTEGER NOT NULL, "
1327 "PRIMARY KEY (index_id, value, object_data_key), "
1328 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
1330 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
1334 NS_ENSURE_SUCCESS(rv
, rv
);
1336 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1337 "INSERT INTO index_data "
1338 "SELECT index_id, value, object_data_key, object_data_id "
1339 "FROM temp_upgrade;"
1341 NS_ENSURE_SUCCESS(rv
, rv
);
1343 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1344 "DROP TABLE temp_upgrade;"
1346 NS_ENSURE_SUCCESS(rv
, rv
);
1348 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1349 "CREATE INDEX index_data_object_data_id_index "
1350 "ON index_data (object_data_id);"
1352 NS_ENSURE_SUCCESS(rv
, rv
);
1354 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1355 "CREATE TEMPORARY TABLE temp_upgrade ("
1362 NS_ENSURE_SUCCESS(rv
, rv
);
1364 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1365 "INSERT INTO temp_upgrade "
1366 "SELECT index_id, encode(value), encode(object_data_key), object_data_id "
1367 "FROM unique_index_data;"
1369 NS_ENSURE_SUCCESS(rv
, rv
);
1371 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1372 "DROP TABLE unique_index_data;"
1374 NS_ENSURE_SUCCESS(rv
, rv
);
1376 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1377 "CREATE TABLE unique_index_data ("
1378 "index_id INTEGER NOT NULL, "
1379 "value BLOB NOT NULL, "
1380 "object_data_key BLOB NOT NULL, "
1381 "object_data_id INTEGER NOT NULL, "
1382 "PRIMARY KEY (index_id, value, object_data_key), "
1383 "UNIQUE (index_id, value), "
1384 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
1386 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
1390 NS_ENSURE_SUCCESS(rv
, rv
);
1392 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1393 "INSERT INTO unique_index_data "
1394 "SELECT index_id, value, object_data_key, object_data_id "
1395 "FROM temp_upgrade;"
1397 NS_ENSURE_SUCCESS(rv
, rv
);
1399 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1400 "DROP TABLE temp_upgrade;"
1402 NS_ENSURE_SUCCESS(rv
, rv
);
1404 rv
= aConnection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
1405 "CREATE INDEX unique_index_data_object_data_id_index "
1406 "ON unique_index_data (object_data_id);"
1408 NS_ENSURE_SUCCESS(rv
, rv
);
1410 rv
= aConnection
->RemoveFunction(encoderName
);
1411 NS_ENSURE_SUCCESS(rv
, rv
);
1413 rv
= aConnection
->SetSchemaVersion(MakeSchemaVersion(12, 0));
1414 NS_ENSURE_SUCCESS(rv
, rv
);
1420 UpgradeSchemaFrom12_0To13_0(mozIStorageConnection
* aConnection
,
1421 bool* aVacuumNeeded
)
1423 AssertIsOnIOThread();
1424 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1426 PROFILER_LABEL("OpenDatabaseHelper", "UpgradeSchemaFrom12_0To13_0",
1427 js::ProfileEntry::Category::STORAGE
);
1431 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
1432 int32_t defaultPageSize
;
1433 rv
= aConnection
->GetDefaultPageSize(&defaultPageSize
);
1434 NS_ENSURE_SUCCESS(rv
, rv
);
1436 // Enable auto_vacuum mode and update the page size to the platform default.
1437 nsAutoCString
upgradeQuery("PRAGMA auto_vacuum = FULL; PRAGMA page_size = ");
1438 upgradeQuery
.AppendInt(defaultPageSize
);
1440 rv
= aConnection
->ExecuteSimpleSQL(upgradeQuery
);
1441 NS_ENSURE_SUCCESS(rv
, rv
);
1443 *aVacuumNeeded
= true;
1446 rv
= aConnection
->SetSchemaVersion(MakeSchemaVersion(13, 0));
1447 NS_ENSURE_SUCCESS(rv
, rv
);
1453 UpgradeSchemaFrom13_0To14_0(mozIStorageConnection
* aConnection
)
1455 // The only change between 13 and 14 was a different structured
1456 // clone format, but it's backwards-compatible.
1457 nsresult rv
= aConnection
->SetSchemaVersion(MakeSchemaVersion(14, 0));
1458 NS_ENSURE_SUCCESS(rv
, rv
);
1464 UpgradeSchemaFrom14_0To15_0(mozIStorageConnection
* aConnection
)
1466 // The only change between 14 and 15 was a different structured
1467 // clone format, but it's backwards-compatible.
1468 nsresult rv
= aConnection
->SetSchemaVersion(MakeSchemaVersion(15, 0));
1469 NS_ENSURE_SUCCESS(rv
, rv
);
1475 UpgradeSchemaFrom15_0To16_0(mozIStorageConnection
* aConnection
)
1477 // The only change between 15 and 16 was a different structured
1478 // clone format, but it's backwards-compatible.
1479 nsresult rv
= aConnection
->SetSchemaVersion(MakeSchemaVersion(16, 0));
1480 NS_ENSURE_SUCCESS(rv
, rv
);
1485 class VersionChangeEventsRunnable
;
1487 class SetVersionHelper
: public AsyncConnectionHelper
,
1488 public IDBTransactionListener
,
1489 public AcquireListener
1491 friend class VersionChangeEventsRunnable
;
1494 SetVersionHelper(IDBTransaction
* aTransaction
,
1495 IDBOpenDBRequest
* aRequest
,
1496 OpenDatabaseHelper
* aHelper
,
1497 uint64_t aRequestedVersion
,
1498 uint64_t aCurrentVersion
)
1499 : AsyncConnectionHelper(aTransaction
, aRequest
),
1500 mOpenRequest(aRequest
), mOpenHelper(aHelper
),
1501 mRequestedVersion(aRequestedVersion
),
1502 mCurrentVersion(aCurrentVersion
)
1504 mTransaction
->SetTransactionListener(this);
1507 NS_DECL_ISUPPORTS_INHERITED
1509 virtual nsresult
GetSuccessResult(JSContext
* aCx
,
1510 JS::MutableHandle
<JS::Value
> aVal
) MOZ_OVERRIDE
;
1513 OnExclusiveAccessAcquired() MOZ_OVERRIDE
;
1516 virtual ~SetVersionHelper() {}
1518 virtual nsresult
Init() MOZ_OVERRIDE
;
1520 virtual nsresult
DoDatabaseWork(mozIStorageConnection
* aConnection
)
1523 // SetVersionHelper never fires an error event at the request. It hands that
1524 // responsibility back to the OpenDatabaseHelper
1525 virtual void OnError() MOZ_OVERRIDE
1528 // Need an upgradeneeded event here.
1529 virtual already_AddRefed
<nsIDOMEvent
> CreateSuccessEvent(
1530 mozilla::dom::EventTarget
* aOwner
) MOZ_OVERRIDE
;
1532 virtual nsresult
NotifyTransactionPreComplete(IDBTransaction
* aTransaction
)
1534 virtual nsresult
NotifyTransactionPostComplete(IDBTransaction
* aTransaction
)
1537 virtual ChildProcessSendResult
1538 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
1540 return Success_NotSent
;
1543 virtual nsresult
UnpackResponseFromParentProcess(
1544 const ResponseValue
& aResponseValue
)
1547 MOZ_CRASH("Should never get here!");
1550 uint64_t RequestedVersion() const
1552 return mRequestedVersion
;
1557 nsRefPtr
<IDBOpenDBRequest
> mOpenRequest
;
1558 nsRefPtr
<OpenDatabaseHelper
> mOpenHelper
;
1559 uint64_t mRequestedVersion
;
1560 uint64_t mCurrentVersion
;
1563 class DeleteDatabaseHelper
: public AsyncConnectionHelper
,
1564 public AcquireListener
1566 friend class VersionChangeEventsRunnable
;
1568 DeleteDatabaseHelper(IDBOpenDBRequest
* aRequest
,
1569 OpenDatabaseHelper
* aHelper
,
1570 uint64_t aCurrentVersion
,
1571 const nsAString
& aName
,
1572 const nsACString
& aGroup
,
1573 const nsACString
& aASCIIOrigin
,
1574 PersistenceType aPersistenceType
)
1575 : AsyncConnectionHelper(static_cast<IDBDatabase
*>(nullptr), aRequest
),
1576 mOpenHelper(aHelper
), mOpenRequest(aRequest
),
1577 mCurrentVersion(aCurrentVersion
), mName(aName
),
1578 mGroup(aGroup
), mASCIIOrigin(aASCIIOrigin
),
1579 mPersistenceType(aPersistenceType
)
1582 NS_DECL_ISUPPORTS_INHERITED
1584 nsresult
GetSuccessResult(JSContext
* aCx
,
1585 JS::MutableHandle
<JS::Value
> aVal
);
1587 void ReleaseMainThreadObjects()
1589 mOpenHelper
= nullptr;
1590 mOpenRequest
= nullptr;
1592 AsyncConnectionHelper::ReleaseMainThreadObjects();
1596 OnExclusiveAccessAcquired() MOZ_OVERRIDE
;
1599 virtual ~DeleteDatabaseHelper() {}
1601 nsresult
DoDatabaseWork(mozIStorageConnection
* aConnection
);
1604 // DeleteDatabaseHelper never fires events at the request. It hands that
1605 // responsibility back to the OpenDatabaseHelper
1608 mOpenHelper
->NotifyDeleteFinished();
1611 nsresult
OnSuccess()
1613 return mOpenHelper
->NotifyDeleteFinished();
1616 uint64_t RequestedVersion() const
1621 virtual ChildProcessSendResult
1622 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
1624 return Success_NotSent
;
1627 virtual nsresult
UnpackResponseFromParentProcess(
1628 const ResponseValue
& aResponseValue
)
1631 MOZ_CRASH("Should never get here!");
1636 nsRefPtr
<OpenDatabaseHelper
> mOpenHelper
;
1637 nsRefPtr
<IDBOpenDBRequest
> mOpenRequest
;
1638 uint64_t mCurrentVersion
;
1641 nsCString mASCIIOrigin
;
1642 PersistenceType mPersistenceType
;
1645 // Responsible for firing "versionchange" events at all live and non-closed
1646 // databases, and for firing a "blocked" event at the requesting database if any
1647 // databases fail to close.
1648 class VersionChangeEventsRunnable
: public nsRunnable
1651 VersionChangeEventsRunnable(
1652 IDBDatabase
* aRequestingDatabase
,
1653 IDBOpenDBRequest
* aRequest
,
1654 nsTArray
<nsCOMPtr
<nsIOfflineStorage
> >& aWaitingDatabases
,
1655 int64_t aOldVersion
,
1656 int64_t aNewVersion
)
1657 : mRequestingDatabase(aRequestingDatabase
),
1659 mOldVersion(aOldVersion
),
1660 mNewVersion(aNewVersion
)
1662 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1663 NS_ASSERTION(aRequestingDatabase
, "Null pointer!");
1664 NS_ASSERTION(aRequest
, "Null pointer!");
1666 mWaitingDatabases
.SwapElements(aWaitingDatabases
);
1671 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1673 PROFILER_MAIN_THREAD_LABEL("OpenDatabaseHelper", "VersionChangeEventsRunnable::Run",
1674 js::ProfileEntry::Category::STORAGE
);
1676 // Fire version change events at all of the databases that are not already
1677 // closed. Also kick bfcached documents out of bfcache.
1678 uint32_t count
= mWaitingDatabases
.Length();
1679 for (uint32_t index
= 0; index
< count
; index
++) {
1680 IDBDatabase
* database
=
1681 IDBDatabase::FromStorage(mWaitingDatabases
[index
]);
1682 NS_ASSERTION(database
, "This shouldn't be null!");
1684 if (database
->IsClosed()) {
1688 // First check if the document the IDBDatabase is part of is bfcached.
1689 nsCOMPtr
<nsIDocument
> ownerDoc
= database
->GetOwnerDocument();
1690 nsIBFCacheEntry
* bfCacheEntry
;
1691 if (ownerDoc
&& (bfCacheEntry
= ownerDoc
->GetBFCacheEntry())) {
1692 bfCacheEntry
->RemoveFromBFCacheSync();
1693 NS_ASSERTION(database
->IsClosed(),
1694 "Kicking doc out of bfcache should have closed database");
1698 // Next check if it's in the process of being bfcached.
1699 nsPIDOMWindow
* owner
= database
->GetOwner();
1700 if (owner
&& owner
->IsFrozen()) {
1701 // We can't kick the document out of the bfcache because it's not yet
1702 // fully in the bfcache. Instead we'll abort everything for the window
1703 // and mark it as not-bfcacheable.
1704 QuotaManager
* quotaManager
= QuotaManager::Get();
1705 NS_ASSERTION(quotaManager
, "Huh?");
1706 quotaManager
->AbortCloseStoragesForWindow(owner
);
1708 NS_ASSERTION(database
->IsClosed(),
1709 "AbortCloseStoragesForWindow should have closed database");
1711 ownerDoc
->DisallowBFCaching();
1716 // Otherwise fire a versionchange event.
1717 nsRefPtr
<Event
> event
=
1718 IDBVersionChangeEvent::Create(database
, mOldVersion
, mNewVersion
);
1719 NS_ENSURE_TRUE(event
, NS_ERROR_FAILURE
);
1722 database
->DispatchEvent(event
, &dummy
);
1725 // Now check to see if any didn't close. If there are some running still
1726 // then fire the blocked event.
1727 for (uint32_t index
= 0; index
< count
; index
++) {
1728 if (!mWaitingDatabases
[index
]->IsClosed()) {
1729 nsRefPtr
<Event
> event
=
1730 IDBVersionChangeEvent::CreateBlocked(mRequest
,
1731 mOldVersion
, mNewVersion
);
1732 NS_ENSURE_TRUE(event
, NS_ERROR_FAILURE
);
1735 mRequest
->DispatchEvent(event
, &dummy
);
1746 void QueueVersionChange(nsTArray
<nsCOMPtr
<nsIOfflineStorage
> >& aDatabases
,
1749 nsRefPtr
<IDBDatabase
> mRequestingDatabase
;
1750 nsRefPtr
<IDBOpenDBRequest
> mRequest
;
1751 nsTArray
<nsCOMPtr
<nsIOfflineStorage
> > mWaitingDatabases
;
1752 int64_t mOldVersion
;
1753 int64_t mNewVersion
;
1756 } // anonymous namespace
1758 NS_IMPL_ISUPPORTS(OpenDatabaseHelper
, nsIRunnable
)
1761 OpenDatabaseHelper::Init()
1763 QuotaManager::GetStorageId(mPersistenceType
, mASCIIOrigin
, Client::IDB
,
1764 mName
, mDatabaseId
);
1765 MOZ_ASSERT(!mDatabaseId
.IsEmpty());
1771 OpenDatabaseHelper::WaitForOpenAllowed()
1773 NS_ASSERTION(mState
== eCreated
, "We've already been dispatched?");
1774 NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!");
1776 mState
= eOpenPending
;
1778 QuotaManager
* quotaManager
= QuotaManager::Get();
1779 NS_ASSERTION(quotaManager
, "This should never be null!");
1781 return quotaManager
->
1782 WaitForOpenAllowed(OriginOrPatternString::FromOrigin(mASCIIOrigin
),
1783 Nullable
<PersistenceType
>(mPersistenceType
), mDatabaseId
,
1788 OpenDatabaseHelper::Dispatch(nsIEventTarget
* aTarget
)
1790 NS_ASSERTION(mState
== eCreated
|| mState
== eOpenPending
,
1791 "We've already been dispatched?");
1795 return aTarget
->Dispatch(this, NS_DISPATCH_NORMAL
);
1799 OpenDatabaseHelper::DispatchToIOThread()
1801 QuotaManager
* quotaManager
= QuotaManager::Get();
1802 NS_ASSERTION(quotaManager
, "This should never be null!");
1804 return Dispatch(quotaManager
->IOThread());
1808 OpenDatabaseHelper::RunImmediately()
1810 NS_ASSERTION(mState
== eCreated
|| mState
== eOpenPending
,
1811 "We've already been dispatched?");
1812 NS_ASSERTION(NS_FAILED(mResultCode
),
1813 "Should only be short-circuiting if we failed!");
1814 NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!");
1816 mState
= eFiringEvents
;
1822 OpenDatabaseHelper::DoDatabaseWork()
1824 AssertIsOnIOThread();
1825 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1827 PROFILER_LABEL("OpenDatabaseHelper", "DoDatabaseWork",
1828 js::ProfileEntry::Category::STORAGE
);
1830 mState
= eFiringEvents
; // In case we fail somewhere along the line.
1832 if (QuotaManager::IsShuttingDown()) {
1833 IDB_REPORT_INTERNAL_ERR();
1834 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
1837 NS_ASSERTION(mOpenDBRequest
, "This should never be null!");
1839 // This will be null for non-window contexts.
1840 nsPIDOMWindow
* window
= mOpenDBRequest
->GetOwner();
1842 AutoEnterWindow
autoWindow(window
);
1844 nsCOMPtr
<nsIFile
> dbDirectory
;
1846 QuotaManager
* quotaManager
= QuotaManager::Get();
1847 NS_ASSERTION(quotaManager
, "This should never be null!");
1850 quotaManager
->EnsureOriginIsInitialized(mPersistenceType
, mGroup
,
1851 mASCIIOrigin
, mTrackingQuota
,
1852 getter_AddRefs(dbDirectory
));
1853 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1855 rv
= dbDirectory
->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME
));
1856 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1859 rv
= dbDirectory
->Exists(&exists
);
1860 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1863 rv
= dbDirectory
->Create(nsIFile::DIRECTORY_TYPE
, 0755);
1864 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1869 NS_ASSERTION(NS_SUCCEEDED(dbDirectory
->IsDirectory(&isDirectory
)) &&
1870 isDirectory
, "Should have caught this earlier!");
1874 nsAutoString filename
;
1875 rv
= GetDatabaseFilename(mName
, filename
);
1876 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1878 nsCOMPtr
<nsIFile
> dbFile
;
1879 rv
= dbDirectory
->Clone(getter_AddRefs(dbFile
));
1880 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1882 rv
= dbFile
->Append(filename
+ NS_LITERAL_STRING(".sqlite"));
1883 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1885 rv
= dbFile
->GetPath(mDatabaseFilePath
);
1886 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1888 nsCOMPtr
<nsIFile
> fmDirectory
;
1889 rv
= dbDirectory
->Clone(getter_AddRefs(fmDirectory
));
1890 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1892 rv
= fmDirectory
->Append(filename
);
1893 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1895 nsCOMPtr
<mozIStorageConnection
> connection
;
1896 rv
= CreateDatabaseConnection(dbFile
, fmDirectory
, mName
, mPersistenceType
,
1897 mGroup
, mASCIIOrigin
,
1898 getter_AddRefs(connection
));
1899 if (NS_FAILED(rv
) &&
1900 NS_ERROR_GET_MODULE(rv
) != NS_ERROR_MODULE_DOM_INDEXEDDB
) {
1901 IDB_REPORT_INTERNAL_ERR();
1902 rv
= NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
1904 NS_ENSURE_SUCCESS(rv
, rv
);
1906 rv
= IDBFactory::LoadDatabaseInformation(connection
, mDatabaseId
,
1907 &mCurrentVersion
, mObjectStores
);
1908 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1911 mState
= eDeletePending
;
1915 for (uint32_t i
= 0; i
< mObjectStores
.Length(); i
++) {
1916 nsRefPtr
<ObjectStoreInfo
>& objectStoreInfo
= mObjectStores
[i
];
1917 for (uint32_t j
= 0; j
< objectStoreInfo
->indexes
.Length(); j
++) {
1918 IndexInfo
& indexInfo
= objectStoreInfo
->indexes
[j
];
1919 mLastIndexId
= std::max(indexInfo
.id
, mLastIndexId
);
1921 mLastObjectStoreId
= std::max(objectStoreInfo
->id
, mLastObjectStoreId
);
1924 // See if we need to do a VERSION_CHANGE transaction
1926 // Optional version semantics.
1927 if (!mRequestedVersion
) {
1928 // If the requested version was not specified and the database was created,
1929 // treat it as if version 1 were requested.
1930 if (mCurrentVersion
== 0) {
1931 mRequestedVersion
= 1;
1934 // Otherwise, treat it as if the current version were requested.
1935 mRequestedVersion
= mCurrentVersion
;
1939 if (mCurrentVersion
> mRequestedVersion
) {
1940 return NS_ERROR_DOM_INDEXEDDB_VERSION_ERR
;
1943 if (mCurrentVersion
!= mRequestedVersion
) {
1944 mState
= eSetVersionPending
;
1947 IndexedDatabaseManager
* mgr
= IndexedDatabaseManager::Get();
1948 NS_ASSERTION(mgr
, "This should never be null!");
1950 nsRefPtr
<FileManager
> fileManager
=
1951 mgr
->GetFileManager(mPersistenceType
, mASCIIOrigin
, mName
);
1953 fileManager
= new FileManager(mPersistenceType
, mGroup
, mASCIIOrigin
,
1956 rv
= fileManager
->Init(fmDirectory
, connection
);
1957 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1959 mgr
->AddFileManager(fileManager
);
1962 mFileManager
= fileManager
.forget();
1969 OpenDatabaseHelper::CreateDatabaseConnection(
1971 nsIFile
* aFMDirectory
,
1972 const nsAString
& aName
,
1973 PersistenceType aPersistenceType
,
1974 const nsACString
& aGroup
,
1975 const nsACString
& aOrigin
,
1976 mozIStorageConnection
** aConnection
)
1978 AssertIsOnIOThread();
1979 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1981 PROFILER_LABEL("OpenDatabaseHelper", "CreateDatabaseConnection",
1982 js::ProfileEntry::Category::STORAGE
);
1987 if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
1988 rv
= aDBFile
->Exists(&exists
);
1989 NS_ENSURE_SUCCESS(rv
, rv
);
1992 NS_WARNING("Refusing to create database because disk space is low!");
1993 return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR
;
1997 nsCOMPtr
<nsIFileURL
> dbFileUrl
=
1998 IDBFactory::GetDatabaseFileURL(aDBFile
, aPersistenceType
, aGroup
, aOrigin
);
1999 NS_ENSURE_TRUE(dbFileUrl
, NS_ERROR_FAILURE
);
2001 nsCOMPtr
<mozIStorageService
> ss
=
2002 do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID
);
2003 NS_ENSURE_TRUE(ss
, NS_ERROR_FAILURE
);
2005 nsCOMPtr
<mozIStorageConnection
> connection
;
2006 rv
= ss
->OpenDatabaseWithFileURL(dbFileUrl
, getter_AddRefs(connection
));
2007 if (rv
== NS_ERROR_FILE_CORRUPTED
) {
2008 // If we're just opening the database during origin initialization, then
2009 // we don't want to erase any files. The failure here will fail origin
2010 // initialization too.
2011 if (aName
.IsVoid()) {
2015 // Nuke the database file. The web services can recreate their data.
2016 rv
= aDBFile
->Remove(false);
2017 NS_ENSURE_SUCCESS(rv
, rv
);
2019 rv
= aFMDirectory
->Exists(&exists
);
2020 NS_ENSURE_SUCCESS(rv
, rv
);
2024 rv
= aFMDirectory
->IsDirectory(&isDirectory
);
2025 NS_ENSURE_SUCCESS(rv
, rv
);
2026 IDB_ENSURE_TRUE(isDirectory
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2028 rv
= aFMDirectory
->Remove(true);
2029 NS_ENSURE_SUCCESS(rv
, rv
);
2032 rv
= ss
->OpenDatabaseWithFileURL(dbFileUrl
, getter_AddRefs(connection
));
2034 NS_ENSURE_SUCCESS(rv
, rv
);
2036 rv
= IDBFactory::SetDefaultPragmas(connection
);
2037 NS_ENSURE_SUCCESS(rv
, rv
);
2039 rv
= connection
->EnableModule(NS_LITERAL_CSTRING("filesystem"));
2040 NS_ENSURE_SUCCESS(rv
, rv
);
2042 // Check to make sure that the database schema is correct.
2043 int32_t schemaVersion
;
2044 rv
= connection
->GetSchemaVersion(&schemaVersion
);
2045 NS_ENSURE_SUCCESS(rv
, rv
);
2047 // Unknown schema will fail origin initialization too
2048 if (!schemaVersion
&& aName
.IsVoid()) {
2049 IDB_WARNING("Unable to open IndexedDB database, schema is not set!");
2050 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
2053 if (schemaVersion
> kSQLiteSchemaVersion
) {
2054 IDB_WARNING("Unable to open IndexedDB database, schema is too high!");
2055 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
2058 bool vacuumNeeded
= false;
2060 if (schemaVersion
!= kSQLiteSchemaVersion
) {
2061 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
2062 if (!schemaVersion
) {
2063 // Have to do this before opening a transaction.
2064 rv
= connection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
2065 // Turn on auto_vacuum mode to reclaim disk space on mobile devices.
2066 "PRAGMA auto_vacuum = FULL; "
2068 if (rv
== NS_ERROR_FILE_NO_DEVICE_SPACE
) {
2069 // mozstorage translates SQLITE_FULL to NS_ERROR_FILE_NO_DEVICE_SPACE,
2070 // which we know better as NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR.
2071 rv
= NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR
;
2073 NS_ENSURE_SUCCESS(rv
, rv
);
2077 mozStorageTransaction
transaction(connection
, false,
2078 mozIStorageConnection::TRANSACTION_IMMEDIATE
);
2080 if (!schemaVersion
) {
2081 // Brand new file, initialize our tables.
2082 rv
= CreateTables(connection
);
2083 NS_ENSURE_SUCCESS(rv
, rv
);
2085 NS_ASSERTION(NS_SUCCEEDED(connection
->GetSchemaVersion(&schemaVersion
)) &&
2086 schemaVersion
== kSQLiteSchemaVersion
,
2087 "CreateTables set a bad schema version!");
2089 nsCOMPtr
<mozIStorageStatement
> stmt
;
2090 nsresult rv
= connection
->CreateStatement(NS_LITERAL_CSTRING(
2091 "INSERT INTO database (name) "
2093 ), getter_AddRefs(stmt
));
2094 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2096 rv
= stmt
->BindStringByName(NS_LITERAL_CSTRING("name"), aName
);
2097 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2099 rv
= stmt
->Execute();
2100 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2103 // This logic needs to change next time we change the schema!
2104 static_assert(kSQLiteSchemaVersion
== int32_t((16 << 4) + 0),
2105 "Need upgrade code from schema version increase.");
2107 while (schemaVersion
!= kSQLiteSchemaVersion
) {
2108 if (schemaVersion
== 4) {
2109 rv
= UpgradeSchemaFrom4To5(connection
);
2111 else if (schemaVersion
== 5) {
2112 rv
= UpgradeSchemaFrom5To6(connection
);
2114 else if (schemaVersion
== 6) {
2115 rv
= UpgradeSchemaFrom6To7(connection
);
2117 else if (schemaVersion
== 7) {
2118 rv
= UpgradeSchemaFrom7To8(connection
);
2120 else if (schemaVersion
== 8) {
2121 rv
= UpgradeSchemaFrom8To9_0(connection
);
2122 vacuumNeeded
= true;
2124 else if (schemaVersion
== MakeSchemaVersion(9, 0)) {
2125 rv
= UpgradeSchemaFrom9_0To10_0(connection
);
2127 else if (schemaVersion
== MakeSchemaVersion(10, 0)) {
2128 rv
= UpgradeSchemaFrom10_0To11_0(connection
);
2130 else if (schemaVersion
== MakeSchemaVersion(11, 0)) {
2131 rv
= UpgradeSchemaFrom11_0To12_0(connection
);
2133 else if (schemaVersion
== MakeSchemaVersion(12, 0)) {
2134 rv
= UpgradeSchemaFrom12_0To13_0(connection
, &vacuumNeeded
);
2136 else if (schemaVersion
== MakeSchemaVersion(13, 0)) {
2137 rv
= UpgradeSchemaFrom13_0To14_0(connection
);
2139 else if (schemaVersion
== MakeSchemaVersion(14, 0)) {
2140 rv
= UpgradeSchemaFrom14_0To15_0(connection
);
2142 else if (schemaVersion
== MakeSchemaVersion(15, 0)) {
2143 rv
= UpgradeSchemaFrom15_0To16_0(connection
);
2146 NS_WARNING("Unable to open IndexedDB database, no upgrade path is "
2148 IDB_REPORT_INTERNAL_ERR();
2149 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
2151 NS_ENSURE_SUCCESS(rv
, rv
);
2153 rv
= connection
->GetSchemaVersion(&schemaVersion
);
2154 NS_ENSURE_SUCCESS(rv
, rv
);
2157 NS_ASSERTION(schemaVersion
== kSQLiteSchemaVersion
, "Huh?!");
2160 rv
= transaction
.Commit();
2161 if (rv
== NS_ERROR_FILE_NO_DEVICE_SPACE
) {
2162 // mozstorage translates SQLITE_FULL to NS_ERROR_FILE_NO_DEVICE_SPACE,
2163 // which we know better as NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR.
2164 rv
= NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR
;
2166 NS_ENSURE_SUCCESS(rv
, rv
);
2170 rv
= connection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING("VACUUM;"));
2171 NS_ENSURE_SUCCESS(rv
, rv
);
2174 connection
.forget(aConnection
);
2179 OpenDatabaseHelper::StartSetVersion()
2181 NS_ASSERTION(mState
== eSetVersionPending
, "Why are we here?");
2183 // In case we fail, fire error events
2184 mState
= eFiringEvents
;
2186 nsresult rv
= EnsureSuccessResult();
2187 NS_ENSURE_SUCCESS(rv
, rv
);
2189 Sequence
<nsString
> storesToOpen
;
2190 nsRefPtr
<IDBTransaction
> transaction
=
2191 IDBTransaction::Create(mDatabase
, storesToOpen
,
2192 IDBTransaction::VERSION_CHANGE
, true);
2193 IDB_ENSURE_TRUE(transaction
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2195 nsRefPtr
<SetVersionHelper
> helper
=
2196 new SetVersionHelper(transaction
, mOpenDBRequest
, this, mRequestedVersion
,
2199 QuotaManager
* quotaManager
= QuotaManager::Get();
2200 NS_ASSERTION(quotaManager
, "This should never be null!");
2202 rv
= quotaManager
->AcquireExclusiveAccess(
2203 mDatabase
, mDatabase
->Origin(),
2204 Nullable
<PersistenceType
>(mDatabase
->Type()), helper
,
2205 &VersionChangeEventsRunnable::QueueVersionChange
<SetVersionHelper
>,
2207 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2209 // The SetVersionHelper is responsible for dispatching us back to the
2210 // main thread again and changing the state to eSetVersionCompleted.
2211 mState
= eSetVersionPending
;
2216 OpenDatabaseHelper::StartDelete()
2218 NS_ASSERTION(mState
== eDeletePending
, "Why are we here?");
2220 // In case we fail, fire error events
2221 mState
= eFiringEvents
;
2223 nsresult rv
= EnsureSuccessResult();
2224 NS_ENSURE_SUCCESS(rv
, rv
);
2226 nsRefPtr
<DeleteDatabaseHelper
> helper
=
2227 new DeleteDatabaseHelper(mOpenDBRequest
, this, mCurrentVersion
, mName
,
2228 mGroup
, mASCIIOrigin
, mPersistenceType
);
2230 QuotaManager
* quotaManager
= QuotaManager::Get();
2231 NS_ASSERTION(quotaManager
, "This should never be null!");
2233 rv
= quotaManager
->AcquireExclusiveAccess(
2234 mDatabase
, mDatabase
->Origin(),
2235 Nullable
<PersistenceType
>(mDatabase
->Type()), helper
,
2236 &VersionChangeEventsRunnable::QueueVersionChange
<DeleteDatabaseHelper
>,
2238 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2240 // The DeleteDatabaseHelper is responsible for dispatching us back to the
2241 // main thread again and changing the state to eDeleteCompleted.
2242 mState
= eDeletePending
;
2247 OpenDatabaseHelper::Run()
2249 NS_ASSERTION(mState
!= eCreated
, "Dispatch was not called?!?");
2251 if (NS_IsMainThread()) {
2252 PROFILER_MAIN_THREAD_LABEL("OpenDatabaseHelper", "Run",
2253 js::ProfileEntry::Category::STORAGE
);
2255 if (mState
== eOpenPending
) {
2256 if (NS_FAILED(mResultCode
)) {
2257 return RunImmediately();
2260 return DispatchToIOThread();
2263 // If we need to queue up a SetVersionHelper, do that here.
2264 if (mState
== eSetVersionPending
) {
2265 nsresult rv
= StartSetVersion();
2267 if (NS_SUCCEEDED(rv
)) {
2272 // fall through and run the default error processing
2274 else if (mState
== eDeletePending
) {
2275 nsresult rv
= StartDelete();
2277 if (NS_SUCCEEDED(rv
)) {
2282 // fall through and run the default error processing
2285 // We've done whatever work we need to do on the DB thread, and any
2286 // SetVersion/DeleteDatabase stuff is done by now.
2287 NS_ASSERTION(mState
== eFiringEvents
||
2288 mState
== eSetVersionCompleted
||
2289 mState
== eDeleteCompleted
, "Why are we here?");
2292 case eSetVersionCompleted
: {
2293 mState
= eFiringEvents
;
2297 case eDeleteCompleted
: {
2298 // Destroy the database now (we should have the only ref).
2299 mDatabase
= nullptr;
2301 DatabaseInfo::Remove(mDatabaseId
);
2303 mState
= eFiringEvents
;
2307 case eFiringEvents
: {
2308 // Notify the request that we're done, but only if we didn't just
2309 // finish a [SetVersion/DeleteDatabase]Helper. In that case, the
2310 // helper tells the request that it is done, and we avoid calling
2311 // NotifyHelperCompleted twice.
2313 nsresult rv
= mOpenDBRequest
->NotifyHelperCompleted(this);
2314 if (NS_SUCCEEDED(mResultCode
) && NS_FAILED(rv
)) {
2321 NS_NOTREACHED("Shouldn't get here!");
2324 NS_ASSERTION(mState
== eFiringEvents
, "Why are we here?");
2326 IDB_PROFILER_MARK("IndexedDB Request %llu: Running main thread "
2327 "response (rv = %lu)",
2328 "IDBRequest[%llu] MT Done",
2329 mRequest
->GetSerialNumber(), mResultCode
);
2331 if (NS_FAILED(mResultCode
)) {
2332 DispatchErrorEvent();
2334 DispatchSuccessEvent();
2337 QuotaManager
* quotaManager
= QuotaManager::Get();
2338 NS_ASSERTION(quotaManager
, "This should never be null!");
2341 AllowNextSynchronizedOp(OriginOrPatternString::FromOrigin(mASCIIOrigin
),
2342 Nullable
<PersistenceType
>(mPersistenceType
),
2345 ReleaseMainThreadObjects();
2350 PROFILER_LABEL("OpenDatabaseHelper", "Run",
2351 js::ProfileEntry::Category::STORAGE
);
2353 // We're on the DB thread.
2354 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
2356 IDB_PROFILER_MARK("IndexedDB Request %llu: Beginning database work",
2357 "IDBRequest[%llu] DT Start", mRequest
->GetSerialNumber());
2359 NS_ASSERTION(mState
== eDBWork
, "Why are we here?");
2360 mResultCode
= DoDatabaseWork();
2361 NS_ASSERTION(mState
!= eDBWork
, "We should be doing something else now.");
2363 IDB_PROFILER_MARK("IndexedDB Request %llu: Finished database work (rv = %lu)",
2364 "IDBRequest[%llu] DT Done", mRequest
->GetSerialNumber(),
2367 return NS_DispatchToMainThread(this);
2371 OpenDatabaseHelper::EnsureSuccessResult()
2373 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2375 PROFILER_MAIN_THREAD_LABEL("OpenDatabaseHelper", "EnsureSuccessResult",
2376 js::ProfileEntry::Category::STORAGE
);
2378 nsRefPtr
<DatabaseInfo
> dbInfo
;
2379 if (DatabaseInfo::Get(mDatabaseId
, getter_AddRefs(dbInfo
))) {
2383 NS_ASSERTION(dbInfo
->name
== mName
&&
2384 dbInfo
->version
== mCurrentVersion
&&
2385 dbInfo
->persistenceType
== mPersistenceType
&&
2386 dbInfo
->id
== mDatabaseId
&&
2387 dbInfo
->filePath
== mDatabaseFilePath
,
2388 "Metadata mismatch!");
2390 uint32_t objectStoreCount
= mObjectStores
.Length();
2391 for (uint32_t index
= 0; index
< objectStoreCount
; index
++) {
2392 nsRefPtr
<ObjectStoreInfo
>& info
= mObjectStores
[index
];
2394 ObjectStoreInfo
* otherInfo
= dbInfo
->GetObjectStore(info
->name
);
2395 NS_ASSERTION(otherInfo
, "ObjectStore not known!");
2397 NS_ASSERTION(info
->name
== otherInfo
->name
&&
2398 info
->id
== otherInfo
->id
&&
2399 info
->keyPath
== otherInfo
->keyPath
,
2400 "Metadata mismatch!");
2401 NS_ASSERTION(dbInfo
->ContainsStoreName(info
->name
),
2402 "Object store names out of date!");
2403 NS_ASSERTION(info
->indexes
.Length() == otherInfo
->indexes
.Length(),
2404 "Bad index length!");
2406 uint32_t indexCount
= info
->indexes
.Length();
2407 for (uint32_t indexIndex
= 0; indexIndex
< indexCount
; indexIndex
++) {
2408 const IndexInfo
& indexInfo
= info
->indexes
[indexIndex
];
2409 const IndexInfo
& otherIndexInfo
= otherInfo
->indexes
[indexIndex
];
2410 NS_ASSERTION(indexInfo
.id
== otherIndexInfo
.id
,
2412 NS_ASSERTION(indexInfo
.name
== otherIndexInfo
.name
,
2414 NS_ASSERTION(indexInfo
.keyPath
== otherIndexInfo
.keyPath
,
2415 "Bad index keyPath!");
2416 NS_ASSERTION(indexInfo
.unique
== otherIndexInfo
.unique
,
2417 "Bad index unique value!");
2425 nsRefPtr
<DatabaseInfo
> newInfo(new DatabaseInfo());
2427 newInfo
->name
= mName
;
2428 newInfo
->group
= mGroup
;
2429 newInfo
->origin
= mASCIIOrigin
;
2430 newInfo
->persistenceType
= mPersistenceType
;
2431 newInfo
->id
= mDatabaseId
;
2432 newInfo
->filePath
= mDatabaseFilePath
;
2434 if (!DatabaseInfo::Put(newInfo
)) {
2435 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
2438 newInfo
.swap(dbInfo
);
2440 nsresult rv
= IDBFactory::SetDatabaseMetadata(dbInfo
, mCurrentVersion
,
2442 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2444 NS_ASSERTION(mObjectStores
.IsEmpty(), "Should have swapped!");
2447 dbInfo
->nextObjectStoreId
= mLastObjectStoreId
+ 1;
2448 dbInfo
->nextIndexId
= mLastIndexId
+ 1;
2450 nsRefPtr
<IDBDatabase
> database
=
2451 IDBDatabase::Create(mOpenDBRequest
, mOpenDBRequest
->Factory(),
2452 dbInfo
.forget(), mASCIIOrigin
, mFileManager
,
2455 IDB_REPORT_INTERNAL_ERR();
2456 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
2459 NS_ASSERTION(!mDatabase
, "Shouldn't have a database yet!");
2460 mDatabase
.swap(database
);
2466 OpenDatabaseHelper::GetSuccessResult(JSContext
* aCx
,
2467 JS::MutableHandle
<JS::Value
> aVal
)
2469 // Be careful not to load the database twice.
2471 nsresult rv
= EnsureSuccessResult();
2472 NS_ENSURE_SUCCESS(rv
, rv
);
2475 return WrapNative(aCx
, NS_ISUPPORTS_CAST(EventTarget
*, mDatabase
),
2480 OpenDatabaseHelper::NotifySetVersionFinished()
2482 NS_ASSERTION(NS_IsMainThread(), "Wrong thread");
2483 NS_ASSERTION(mState
= eSetVersionPending
, "How did we get here?");
2485 // Allow transaction creation to proceed.
2486 mDatabase
->ExitSetVersionTransaction();
2488 mState
= eSetVersionCompleted
;
2490 // Dispatch ourself back to the main thread
2491 return NS_DispatchToCurrentThread(this);
2495 OpenDatabaseHelper::NotifyDeleteFinished()
2497 NS_ASSERTION(NS_IsMainThread(), "Wrong thread");
2498 NS_ASSERTION(mState
== eDeletePending
, "How did we get here?");
2500 mState
= eDeleteCompleted
;
2502 // Dispatch ourself back to the main thread
2503 return NS_DispatchToCurrentThread(this);
2507 OpenDatabaseHelper::BlockDatabase()
2509 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2510 NS_ASSERTION(mDatabase
, "This is going bad fast.");
2512 mDatabase
->EnterSetVersionTransaction();
2516 OpenDatabaseHelper::DispatchSuccessEvent()
2518 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2520 PROFILER_MAIN_THREAD_LABEL("OpenDatabaseHelper", "DispatchSuccessEvent",
2521 js::ProfileEntry::Category::STORAGE
);
2523 nsRefPtr
<nsIDOMEvent
> event
=
2524 CreateGenericEvent(mOpenDBRequest
, NS_LITERAL_STRING(SUCCESS_EVT_STR
),
2525 eDoesNotBubble
, eNotCancelable
);
2527 NS_ERROR("Failed to create event!");
2532 mOpenDBRequest
->DispatchEvent(event
, &dummy
);
2536 OpenDatabaseHelper::DispatchErrorEvent()
2538 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2540 PROFILER_MAIN_THREAD_LABEL("OpenDatabaseHelper", "DispatchErrorEvent",
2541 js::ProfileEntry::Category::STORAGE
);
2543 nsRefPtr
<nsIDOMEvent
> event
=
2544 CreateGenericEvent(mOpenDBRequest
, NS_LITERAL_STRING(ERROR_EVT_STR
),
2545 eDoesBubble
, eCancelable
);
2547 NS_ERROR("Failed to create event!");
2552 nsRefPtr
<DOMError
> error
= mOpenDBRequest
->GetError(rv
);
2554 NS_ASSERTION(!rv
.Failed(), "This shouldn't be failing at this point!");
2556 mOpenDBRequest
->SetError(mResultCode
);
2560 mOpenDBRequest
->DispatchEvent(event
, &dummy
);
2564 OpenDatabaseHelper::ReleaseMainThreadObjects()
2566 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2568 mOpenDBRequest
= nullptr;
2569 mDatabase
= nullptr;
2571 HelperBase::ReleaseMainThreadObjects();
2574 NS_IMPL_ISUPPORTS_INHERITED0(SetVersionHelper
, AsyncConnectionHelper
)
2577 SetVersionHelper::Init()
2579 // Block transaction creation until we are done.
2580 mOpenHelper
->BlockDatabase();
2586 SetVersionHelper::DoDatabaseWork(mozIStorageConnection
* aConnection
)
2588 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
2589 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
2590 NS_ASSERTION(aConnection
, "Passing a null connection!");
2592 PROFILER_LABEL("SetVersionHelper", "DoDatabaseWork",
2593 js::ProfileEntry::Category::STORAGE
);
2595 nsCOMPtr
<mozIStorageStatement
> stmt
;
2596 nsresult rv
= aConnection
->CreateStatement(NS_LITERAL_CSTRING(
2598 "SET version = :version"
2599 ), getter_AddRefs(stmt
));
2600 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2602 rv
= stmt
->BindInt64ByName(NS_LITERAL_CSTRING("version"),
2604 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2606 if (NS_FAILED(stmt
->Execute())) {
2607 return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR
;
2614 SetVersionHelper::GetSuccessResult(JSContext
* aCx
,
2615 JS::MutableHandle
<JS::Value
> aVal
)
2617 DatabaseInfo
* info
= mDatabase
->Info();
2618 info
->version
= mRequestedVersion
;
2620 NS_ASSERTION(mTransaction
, "Better have a transaction!");
2622 mOpenRequest
->SetTransaction(mTransaction
);
2624 return WrapNative(aCx
, NS_ISUPPORTS_CAST(EventTarget
*, mDatabase
),
2629 SetVersionHelper::OnExclusiveAccessAcquired()
2631 nsresult rv
= DispatchToTransactionPool();
2632 NS_ENSURE_SUCCESS(rv
, rv
);
2640 VersionChangeEventsRunnable::QueueVersionChange(
2641 nsTArray
<nsCOMPtr
<nsIOfflineStorage
> >& aDatabases
,
2644 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2645 NS_ASSERTION(!aDatabases
.IsEmpty(), "Why are we here?");
2647 T
* closure
= static_cast<T
*>(aClosure
);
2649 nsRefPtr
<VersionChangeEventsRunnable
> eventsRunnable
=
2650 new VersionChangeEventsRunnable(closure
->mOpenHelper
->Database(),
2651 closure
->mOpenRequest
,
2653 closure
->mCurrentVersion
,
2654 closure
->RequestedVersion());
2656 NS_DispatchToCurrentThread(eventsRunnable
);
2659 already_AddRefed
<nsIDOMEvent
>
2660 SetVersionHelper::CreateSuccessEvent(mozilla::dom::EventTarget
* aOwner
)
2662 NS_ASSERTION(mCurrentVersion
< mRequestedVersion
, "Huh?");
2664 return IDBVersionChangeEvent::CreateUpgradeNeeded(aOwner
,
2670 SetVersionHelper::NotifyTransactionPreComplete(IDBTransaction
* aTransaction
)
2672 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2673 NS_ASSERTION(aTransaction
, "This is unexpected.");
2674 NS_ASSERTION(mOpenRequest
, "Why don't we have a request?");
2676 return mOpenHelper
->NotifySetVersionFinished();
2680 SetVersionHelper::NotifyTransactionPostComplete(IDBTransaction
* aTransaction
)
2682 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2683 NS_ASSERTION(aTransaction
, "This is unexpected.");
2684 NS_ASSERTION(mOpenRequest
, "Why don't we have a request?");
2686 // If we hit an error, the OpenDatabaseHelper needs to get that error too.
2687 nsresult rv
= GetResultCode();
2688 if (NS_FAILED(rv
)) {
2689 mOpenHelper
->SetError(rv
);
2692 // If the transaction was aborted, we should throw an error message.
2693 if (aTransaction
->IsAborted()) {
2694 mOpenHelper
->SetError(aTransaction
->GetAbortCode());
2697 mOpenRequest
->SetTransaction(nullptr);
2698 mOpenRequest
= nullptr;
2700 mOpenHelper
= nullptr;
2705 NS_IMPL_ISUPPORTS_INHERITED0(DeleteDatabaseHelper
, AsyncConnectionHelper
);
2708 DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection
* aConnection
)
2710 AssertIsOnIOThread();
2711 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
2712 NS_ASSERTION(!aConnection
, "How did we get a connection here?");
2714 PROFILER_LABEL("DeleteDatabaseHelper", "DoDatabaseWork",
2715 js::ProfileEntry::Category::STORAGE
);
2717 const StoragePrivilege
& privilege
= mOpenHelper
->Privilege();
2719 QuotaManager
* quotaManager
= QuotaManager::Get();
2720 NS_ASSERTION(quotaManager
, "This should never fail!");
2722 nsCOMPtr
<nsIFile
> directory
;
2723 nsresult rv
= quotaManager
->GetDirectoryForOrigin(mPersistenceType
,
2725 getter_AddRefs(directory
));
2726 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2728 NS_ASSERTION(directory
, "What?");
2730 rv
= directory
->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME
));
2731 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2733 nsAutoString filename
;
2734 rv
= GetDatabaseFilename(mName
, filename
);
2735 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2737 nsCOMPtr
<nsIFile
> dbFile
;
2738 rv
= directory
->Clone(getter_AddRefs(dbFile
));
2739 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2741 rv
= dbFile
->Append(filename
+ NS_LITERAL_STRING(".sqlite"));
2742 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2744 bool exists
= false;
2745 rv
= dbFile
->Exists(&exists
);
2746 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2751 if (privilege
!= Chrome
) {
2752 rv
= dbFile
->GetFileSize(&fileSize
);
2753 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2756 rv
= dbFile
->Remove(false);
2757 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2759 if (privilege
!= Chrome
) {
2760 QuotaManager
* quotaManager
= QuotaManager::Get();
2761 NS_ASSERTION(quotaManager
, "Shouldn't be null!");
2763 quotaManager
->DecreaseUsageForOrigin(mPersistenceType
, mGroup
,
2764 mASCIIOrigin
, fileSize
);
2768 nsCOMPtr
<nsIFile
> dbJournalFile
;
2769 rv
= directory
->Clone(getter_AddRefs(dbJournalFile
));
2770 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2772 rv
= dbJournalFile
->Append(filename
+ NS_LITERAL_STRING(".sqlite-journal"));
2773 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2775 rv
= dbJournalFile
->Exists(&exists
);
2776 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2779 rv
= dbJournalFile
->Remove(false);
2780 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2783 nsCOMPtr
<nsIFile
> fmDirectory
;
2784 rv
= directory
->Clone(getter_AddRefs(fmDirectory
));
2785 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2787 rv
= fmDirectory
->Append(filename
);
2788 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2790 rv
= fmDirectory
->Exists(&exists
);
2791 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2795 rv
= fmDirectory
->IsDirectory(&isDirectory
);
2796 NS_ENSURE_SUCCESS(rv
, rv
);
2797 IDB_ENSURE_TRUE(isDirectory
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2801 if (privilege
!= Chrome
) {
2802 rv
= FileManager::GetUsage(fmDirectory
, &usage
);
2803 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2806 rv
= fmDirectory
->Remove(true);
2807 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2809 if (privilege
!= Chrome
) {
2810 QuotaManager
* quotaManager
= QuotaManager::Get();
2811 NS_ASSERTION(quotaManager
, "Shouldn't be null!");
2813 quotaManager
->DecreaseUsageForOrigin(mPersistenceType
, mGroup
,
2814 mASCIIOrigin
, usage
);
2818 IndexedDatabaseManager
* mgr
= IndexedDatabaseManager::Get();
2819 NS_ASSERTION(mgr
, "This should never fail!");
2821 mgr
->InvalidateFileManager(mPersistenceType
, mASCIIOrigin
, mName
);
2827 DeleteDatabaseHelper::GetSuccessResult(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aVal
)
2833 DeleteDatabaseHelper::OnExclusiveAccessAcquired()
2835 QuotaManager
* quotaManager
= QuotaManager::Get();
2836 NS_ASSERTION(quotaManager
, "We should definitely have a manager here");
2838 nsresult rv
= Dispatch(quotaManager
->IOThread());
2839 NS_ENSURE_SUCCESS(rv
, rv
);
2845 DeleteDatabaseHelper::Init()
2847 // Note that there's no need to block the database here, since the page
2848 // never gets to touch it, and all other databases must be closed.