1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "SchemaUpgrades.h"
10 #include "ActorsParentCommon.h"
11 #include "DatabaseFileInfo.h"
12 #include "DatabaseFileManager.h"
14 #include "IndexedDatabase.h"
15 #include "IndexedDatabaseInlines.h"
16 #include "IndexedDBCommon.h"
17 #include "ReportInternalError.h"
23 #include <type_traits>
25 #include "ErrorList.h"
26 #include "MainThreadUtils.h"
27 #include "SafeRefPtr.h"
28 #include "js/RootingAPI.h"
29 #include "js/StructuredClone.h"
32 #include "mozIStorageConnection.h"
33 #include "mozIStorageFunction.h"
34 #include "mozIStorageStatement.h"
35 #include "mozIStorageValueArray.h"
36 #include "mozStorageHelper.h"
37 #include "mozilla/Assertions.h"
38 #include "mozilla/ErrorResult.h"
39 #include "mozilla/MacroForEach.h"
40 #include "mozilla/Monitor.h"
41 #include "mozilla/OriginAttributes.h"
42 #include "mozilla/RefPtr.h"
43 #include "mozilla/SchedulerGroup.h"
44 #include "mozilla/Span.h"
45 #include "mozilla/TaskCategory.h"
46 #include "mozilla/UniquePtr.h"
47 #include "mozilla/dom/ScriptSettings.h"
48 #include "mozilla/dom/indexedDB/IDBResult.h"
49 #include "mozilla/dom/indexedDB/Key.h"
50 #include "mozilla/dom/quota/PersistenceType.h"
51 #include "mozilla/dom/quota/QuotaCommon.h"
52 #include "mozilla/fallible.h"
53 #include "mozilla/ipc/BackgroundParent.h"
54 #include "mozilla/mozalloc.h"
55 #include "mozilla/ProfilerLabels.h"
56 #include "mozilla/storage/Variant.h"
60 #include "nsISupports.h"
61 #include "nsIVariant.h"
62 #include "nsLiteralString.h"
65 #include "nsTLiteralString.h"
66 #include "nsTStringRepr.h"
67 #include "nsThreadUtils.h"
69 #include "snappy/snappy.h"
74 #if defined(MOZ_WIDGET_ANDROID)
78 namespace mozilla::dom::indexedDB
{
80 using mozilla::ipc::IsOnBackgroundThread
;
81 using quota::AssertIsOnIOThread
;
82 using quota::PERSISTENCE_TYPE_INVALID
;
86 nsresult
UpgradeSchemaFrom4To5(mozIStorageConnection
& aConnection
) {
89 AUTO_PROFILER_LABEL("UpgradeSchemaFrom4To5", DOM
);
93 // All we changed is the type of the version column, so lets try to
94 // convert that to an integer, and if we fail, set it to 0.
95 nsCOMPtr
<mozIStorageStatement
> stmt
;
96 rv
= aConnection
.CreateStatement(
97 "SELECT name, version, dataVersion "
99 getter_AddRefs(stmt
));
100 if (NS_WARN_IF(NS_FAILED(rv
))) {
109 mozStorageStatementScoper
scoper(stmt
);
111 QM_TRY_INSPECT(const bool& hasResults
,
112 MOZ_TO_RESULT_INVOKE(stmt
, ExecuteStep
));
114 if (NS_WARN_IF(!hasResults
)) {
115 return NS_ERROR_FAILURE
;
119 rv
= stmt
->GetString(1, version
);
120 if (NS_WARN_IF(NS_FAILED(rv
))) {
124 intVersion
= version
.ToInteger(&rv
);
129 rv
= stmt
->GetString(0, name
);
130 if (NS_WARN_IF(NS_FAILED(rv
))) {
134 rv
= stmt
->GetInt64(2, &dataVersion
);
135 if (NS_WARN_IF(NS_FAILED(rv
))) {
140 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE database"_ns
);
141 if (NS_WARN_IF(NS_FAILED(rv
))) {
145 rv
= aConnection
.ExecuteSimpleSQL(
146 "CREATE TABLE database ("
147 "name TEXT NOT NULL, "
148 "version INTEGER NOT NULL DEFAULT 0, "
149 "dataVersion INTEGER NOT NULL"
151 if (NS_WARN_IF(NS_FAILED(rv
))) {
155 // The parameter names are not used, parameters are bound by index only
156 // locally in the same function.
157 rv
= aConnection
.CreateStatement(
158 "INSERT INTO database (name, version, dataVersion) "
159 "VALUES (:name, :version, :dataVersion)"_ns
,
160 getter_AddRefs(stmt
));
161 if (NS_WARN_IF(NS_FAILED(rv
))) {
166 mozStorageStatementScoper
scoper(stmt
);
168 rv
= stmt
->BindStringByIndex(0, name
);
169 if (NS_WARN_IF(NS_FAILED(rv
))) {
173 rv
= stmt
->BindInt32ByIndex(1, intVersion
);
174 if (NS_WARN_IF(NS_FAILED(rv
))) {
178 rv
= stmt
->BindInt64ByIndex(2, dataVersion
);
179 if (NS_WARN_IF(NS_FAILED(rv
))) {
183 rv
= stmt
->Execute();
184 if (NS_WARN_IF(NS_FAILED(rv
))) {
189 rv
= aConnection
.SetSchemaVersion(5);
190 if (NS_WARN_IF(NS_FAILED(rv
))) {
197 nsresult
UpgradeSchemaFrom5To6(mozIStorageConnection
& aConnection
) {
198 AssertIsOnIOThread();
200 AUTO_PROFILER_LABEL("UpgradeSchemaFrom5To6", DOM
);
202 // First, drop all the indexes we're no longer going to use.
203 nsresult rv
= aConnection
.ExecuteSimpleSQL("DROP INDEX key_index;"_ns
);
204 if (NS_WARN_IF(NS_FAILED(rv
))) {
208 rv
= aConnection
.ExecuteSimpleSQL("DROP INDEX ai_key_index;"_ns
);
209 if (NS_WARN_IF(NS_FAILED(rv
))) {
213 rv
= aConnection
.ExecuteSimpleSQL("DROP INDEX value_index;"_ns
);
214 if (NS_WARN_IF(NS_FAILED(rv
))) {
218 rv
= aConnection
.ExecuteSimpleSQL("DROP INDEX ai_value_index;"_ns
);
219 if (NS_WARN_IF(NS_FAILED(rv
))) {
223 // Now, reorder the columns of object_data to put the blob data last. We do
224 // this by copying into a temporary table, dropping the original, then copying
225 // back into a newly created table.
226 rv
= aConnection
.ExecuteSimpleSQL(
227 "CREATE TEMPORARY TABLE temp_upgrade ("
228 "id INTEGER PRIMARY KEY, "
233 if (NS_WARN_IF(NS_FAILED(rv
))) {
237 rv
= aConnection
.ExecuteSimpleSQL(
238 "INSERT INTO temp_upgrade "
239 "SELECT id, object_store_id, key_value, data "
240 "FROM object_data;"_ns
);
241 if (NS_WARN_IF(NS_FAILED(rv
))) {
245 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_data;"_ns
);
246 if (NS_WARN_IF(NS_FAILED(rv
))) {
250 rv
= aConnection
.ExecuteSimpleSQL(
251 "CREATE TABLE object_data ("
252 "id INTEGER PRIMARY KEY, "
253 "object_store_id INTEGER NOT NULL, "
254 "key_value DEFAULT NULL, "
255 "data BLOB NOT NULL, "
256 "UNIQUE (object_store_id, key_value), "
257 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
260 if (NS_WARN_IF(NS_FAILED(rv
))) {
264 rv
= aConnection
.ExecuteSimpleSQL(
265 "INSERT INTO object_data "
266 "SELECT id, object_store_id, key_value, data "
267 "FROM temp_upgrade;"_ns
);
268 if (NS_WARN_IF(NS_FAILED(rv
))) {
272 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
273 if (NS_WARN_IF(NS_FAILED(rv
))) {
277 // We need to add a unique constraint to our ai_object_data table. Copy all
278 // the data out of it using a temporary table as before.
279 rv
= aConnection
.ExecuteSimpleSQL(
280 "CREATE TEMPORARY TABLE temp_upgrade ("
281 "id INTEGER PRIMARY KEY, "
285 if (NS_WARN_IF(NS_FAILED(rv
))) {
289 rv
= aConnection
.ExecuteSimpleSQL(
290 "INSERT INTO temp_upgrade "
291 "SELECT id, object_store_id, data "
292 "FROM ai_object_data;"_ns
);
293 if (NS_WARN_IF(NS_FAILED(rv
))) {
297 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE ai_object_data;"_ns
);
298 if (NS_WARN_IF(NS_FAILED(rv
))) {
302 rv
= aConnection
.ExecuteSimpleSQL(
303 "CREATE TABLE ai_object_data ("
304 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
305 "object_store_id INTEGER NOT NULL, "
306 "data BLOB NOT NULL, "
307 "UNIQUE (object_store_id, id), "
308 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
311 if (NS_WARN_IF(NS_FAILED(rv
))) {
315 rv
= aConnection
.ExecuteSimpleSQL(
316 "INSERT INTO ai_object_data "
317 "SELECT id, object_store_id, data "
318 "FROM temp_upgrade;"_ns
);
319 if (NS_WARN_IF(NS_FAILED(rv
))) {
323 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
324 if (NS_WARN_IF(NS_FAILED(rv
))) {
328 // Fix up the index_data table. We're reordering the columns as well as
329 // changing the primary key from being a simple id to being a composite.
330 rv
= aConnection
.ExecuteSimpleSQL(
331 "CREATE TEMPORARY TABLE temp_upgrade ("
337 if (NS_WARN_IF(NS_FAILED(rv
))) {
341 rv
= aConnection
.ExecuteSimpleSQL(
342 "INSERT INTO temp_upgrade "
343 "SELECT index_id, value, object_data_key, object_data_id "
344 "FROM index_data;"_ns
);
345 if (NS_WARN_IF(NS_FAILED(rv
))) {
349 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE index_data;"_ns
);
350 if (NS_WARN_IF(NS_FAILED(rv
))) {
354 rv
= aConnection
.ExecuteSimpleSQL(
355 "CREATE TABLE index_data ("
356 "index_id INTEGER NOT NULL, "
358 "object_data_key NOT NULL, "
359 "object_data_id INTEGER NOT NULL, "
360 "PRIMARY KEY (index_id, value, object_data_key), "
361 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
363 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
366 if (NS_WARN_IF(NS_FAILED(rv
))) {
370 rv
= aConnection
.ExecuteSimpleSQL(
371 "INSERT OR IGNORE INTO index_data "
372 "SELECT index_id, value, object_data_key, object_data_id "
373 "FROM temp_upgrade;"_ns
);
374 if (NS_WARN_IF(NS_FAILED(rv
))) {
378 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
379 if (NS_WARN_IF(NS_FAILED(rv
))) {
383 rv
= aConnection
.ExecuteSimpleSQL(
384 "CREATE INDEX index_data_object_data_id_index "
385 "ON index_data (object_data_id);"_ns
);
386 if (NS_WARN_IF(NS_FAILED(rv
))) {
390 // Fix up the unique_index_data table. We're reordering the columns as well as
391 // changing the primary key from being a simple id to being a composite.
392 rv
= aConnection
.ExecuteSimpleSQL(
393 "CREATE TEMPORARY TABLE temp_upgrade ("
399 if (NS_WARN_IF(NS_FAILED(rv
))) {
403 rv
= aConnection
.ExecuteSimpleSQL(
404 "INSERT INTO temp_upgrade "
405 "SELECT index_id, value, object_data_key, object_data_id "
406 "FROM unique_index_data;"_ns
);
407 if (NS_WARN_IF(NS_FAILED(rv
))) {
411 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE unique_index_data;"_ns
);
412 if (NS_WARN_IF(NS_FAILED(rv
))) {
416 rv
= aConnection
.ExecuteSimpleSQL(
417 "CREATE TABLE unique_index_data ("
418 "index_id INTEGER NOT NULL, "
420 "object_data_key NOT NULL, "
421 "object_data_id INTEGER NOT NULL, "
422 "PRIMARY KEY (index_id, value, object_data_key), "
423 "UNIQUE (index_id, value), "
424 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
426 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
429 if (NS_WARN_IF(NS_FAILED(rv
))) {
433 rv
= aConnection
.ExecuteSimpleSQL(
434 "INSERT INTO unique_index_data "
435 "SELECT index_id, value, object_data_key, object_data_id "
436 "FROM temp_upgrade;"_ns
);
437 if (NS_WARN_IF(NS_FAILED(rv
))) {
441 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
442 if (NS_WARN_IF(NS_FAILED(rv
))) {
446 rv
= aConnection
.ExecuteSimpleSQL(
447 "CREATE INDEX unique_index_data_object_data_id_index "
448 "ON unique_index_data (object_data_id);"_ns
);
449 if (NS_WARN_IF(NS_FAILED(rv
))) {
453 // Fix up the ai_index_data table. We're reordering the columns as well as
454 // changing the primary key from being a simple id to being a composite.
455 rv
= aConnection
.ExecuteSimpleSQL(
456 "CREATE TEMPORARY TABLE temp_upgrade ("
461 if (NS_WARN_IF(NS_FAILED(rv
))) {
465 rv
= aConnection
.ExecuteSimpleSQL(
466 "INSERT INTO temp_upgrade "
467 "SELECT index_id, value, ai_object_data_id "
468 "FROM ai_index_data;"_ns
);
469 if (NS_WARN_IF(NS_FAILED(rv
))) {
473 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE ai_index_data;"_ns
);
474 if (NS_WARN_IF(NS_FAILED(rv
))) {
478 rv
= aConnection
.ExecuteSimpleSQL(
479 "CREATE TABLE ai_index_data ("
480 "index_id INTEGER NOT NULL, "
482 "ai_object_data_id INTEGER NOT NULL, "
483 "PRIMARY KEY (index_id, value, ai_object_data_id), "
484 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
486 "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
489 if (NS_WARN_IF(NS_FAILED(rv
))) {
493 rv
= aConnection
.ExecuteSimpleSQL(
494 "INSERT OR IGNORE INTO ai_index_data "
495 "SELECT index_id, value, ai_object_data_id "
496 "FROM temp_upgrade;"_ns
);
497 if (NS_WARN_IF(NS_FAILED(rv
))) {
501 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
502 if (NS_WARN_IF(NS_FAILED(rv
))) {
506 rv
= aConnection
.ExecuteSimpleSQL(
507 "CREATE INDEX ai_index_data_ai_object_data_id_index "
508 "ON ai_index_data (ai_object_data_id);"_ns
);
509 if (NS_WARN_IF(NS_FAILED(rv
))) {
513 // Fix up the ai_unique_index_data table. We're reordering the columns as well
514 // as changing the primary key from being a simple id to being a composite.
515 rv
= aConnection
.ExecuteSimpleSQL(
516 "CREATE TEMPORARY TABLE temp_upgrade ("
521 if (NS_WARN_IF(NS_FAILED(rv
))) {
525 rv
= aConnection
.ExecuteSimpleSQL(
526 "INSERT INTO temp_upgrade "
527 "SELECT index_id, value, ai_object_data_id "
528 "FROM ai_unique_index_data;"_ns
);
529 if (NS_WARN_IF(NS_FAILED(rv
))) {
533 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE ai_unique_index_data;"_ns
);
534 if (NS_WARN_IF(NS_FAILED(rv
))) {
538 rv
= aConnection
.ExecuteSimpleSQL(
539 "CREATE TABLE ai_unique_index_data ("
540 "index_id INTEGER NOT NULL, "
542 "ai_object_data_id INTEGER NOT NULL, "
543 "UNIQUE (index_id, value), "
544 "PRIMARY KEY (index_id, value, ai_object_data_id), "
545 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
547 "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
550 if (NS_WARN_IF(NS_FAILED(rv
))) {
554 rv
= aConnection
.ExecuteSimpleSQL(
555 "INSERT INTO ai_unique_index_data "
556 "SELECT index_id, value, ai_object_data_id "
557 "FROM temp_upgrade;"_ns
);
558 if (NS_WARN_IF(NS_FAILED(rv
))) {
562 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
563 if (NS_WARN_IF(NS_FAILED(rv
))) {
567 rv
= aConnection
.ExecuteSimpleSQL(
568 "CREATE INDEX ai_unique_index_data_ai_object_data_id_index "
569 "ON ai_unique_index_data (ai_object_data_id);"_ns
);
570 if (NS_WARN_IF(NS_FAILED(rv
))) {
574 rv
= aConnection
.SetSchemaVersion(6);
575 if (NS_WARN_IF(NS_FAILED(rv
))) {
582 nsresult
UpgradeSchemaFrom6To7(mozIStorageConnection
& aConnection
) {
583 AssertIsOnIOThread();
585 AUTO_PROFILER_LABEL("UpgradeSchemaFrom6To7", DOM
);
587 nsresult rv
= aConnection
.ExecuteSimpleSQL(
588 "CREATE TEMPORARY TABLE temp_upgrade ("
594 if (NS_WARN_IF(NS_FAILED(rv
))) {
598 rv
= aConnection
.ExecuteSimpleSQL(
599 "INSERT INTO temp_upgrade "
600 "SELECT id, name, key_path, auto_increment "
601 "FROM object_store;"_ns
);
602 if (NS_WARN_IF(NS_FAILED(rv
))) {
606 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_store;"_ns
);
607 if (NS_WARN_IF(NS_FAILED(rv
))) {
611 rv
= aConnection
.ExecuteSimpleSQL(
612 "CREATE TABLE object_store ("
613 "id INTEGER PRIMARY KEY, "
614 "auto_increment INTEGER NOT NULL DEFAULT 0, "
615 "name TEXT NOT NULL, "
619 if (NS_WARN_IF(NS_FAILED(rv
))) {
623 rv
= aConnection
.ExecuteSimpleSQL(
624 "INSERT INTO object_store "
625 "SELECT id, auto_increment, name, nullif(key_path, '') "
626 "FROM temp_upgrade;"_ns
);
627 if (NS_WARN_IF(NS_FAILED(rv
))) {
631 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
632 if (NS_WARN_IF(NS_FAILED(rv
))) {
636 rv
= aConnection
.SetSchemaVersion(7);
637 if (NS_WARN_IF(NS_FAILED(rv
))) {
644 nsresult
UpgradeSchemaFrom7To8(mozIStorageConnection
& aConnection
) {
645 AssertIsOnIOThread();
647 AUTO_PROFILER_LABEL("UpgradeSchemaFrom7To8", DOM
);
649 nsresult rv
= aConnection
.ExecuteSimpleSQL(
650 "CREATE TEMPORARY TABLE temp_upgrade ("
656 "object_store_autoincrement"
658 if (NS_WARN_IF(NS_FAILED(rv
))) {
662 rv
= aConnection
.ExecuteSimpleSQL(
663 "INSERT INTO temp_upgrade "
664 "SELECT id, object_store_id, name, key_path, "
665 "unique_index, object_store_autoincrement "
666 "FROM object_store_index;"_ns
);
667 if (NS_WARN_IF(NS_FAILED(rv
))) {
671 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_store_index;"_ns
);
672 if (NS_WARN_IF(NS_FAILED(rv
))) {
676 rv
= aConnection
.ExecuteSimpleSQL(
677 "CREATE TABLE object_store_index ("
679 "object_store_id INTEGER NOT NULL, "
680 "name TEXT NOT NULL, "
681 "key_path TEXT NOT NULL, "
682 "unique_index INTEGER NOT NULL, "
683 "multientry INTEGER NOT NULL, "
684 "object_store_autoincrement INTERGER NOT NULL, "
686 "UNIQUE (object_store_id, name), "
687 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
690 if (NS_WARN_IF(NS_FAILED(rv
))) {
694 rv
= aConnection
.ExecuteSimpleSQL(
695 "INSERT INTO object_store_index "
696 "SELECT id, object_store_id, name, key_path, "
697 "unique_index, 0, object_store_autoincrement "
698 "FROM temp_upgrade;"_ns
);
699 if (NS_WARN_IF(NS_FAILED(rv
))) {
703 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
704 if (NS_WARN_IF(NS_FAILED(rv
))) {
708 rv
= aConnection
.SetSchemaVersion(8);
709 if (NS_WARN_IF(NS_FAILED(rv
))) {
716 class CompressDataBlobsFunction final
: public mozIStorageFunction
{
721 ~CompressDataBlobsFunction() = default;
724 OnFunctionCall(mozIStorageValueArray
* aArguments
,
725 nsIVariant
** aResult
) override
{
726 MOZ_ASSERT(aArguments
);
729 AUTO_PROFILER_LABEL("CompressDataBlobsFunction::OnFunctionCall", DOM
);
732 nsresult rv
= aArguments
->GetNumEntries(&argc
);
733 if (NS_WARN_IF(NS_FAILED(rv
))) {
738 NS_WARNING("Don't call me with the wrong number of arguments!");
739 return NS_ERROR_UNEXPECTED
;
743 rv
= aArguments
->GetTypeOfIndex(0, &type
);
744 if (NS_WARN_IF(NS_FAILED(rv
))) {
748 if (type
!= mozIStorageStatement::VALUE_TYPE_BLOB
) {
749 NS_WARNING("Don't call me with the wrong type of arguments!");
750 return NS_ERROR_UNEXPECTED
;
753 const uint8_t* uncompressed
;
754 uint32_t uncompressedLength
;
755 rv
= aArguments
->GetSharedBlob(0, &uncompressedLength
, &uncompressed
);
756 if (NS_WARN_IF(NS_FAILED(rv
))) {
760 size_t compressedLength
= snappy::MaxCompressedLength(uncompressedLength
);
761 UniqueFreePtr
<uint8_t> compressed(
762 static_cast<uint8_t*>(malloc(compressedLength
)));
763 if (NS_WARN_IF(!compressed
)) {
764 return NS_ERROR_OUT_OF_MEMORY
;
768 reinterpret_cast<const char*>(uncompressed
), uncompressedLength
,
769 reinterpret_cast<char*>(compressed
.get()), &compressedLength
);
771 std::pair
<uint8_t*, int> data(compressed
.release(), int(compressedLength
));
773 nsCOMPtr
<nsIVariant
> result
=
774 new mozilla::storage::AdoptedBlobVariant(data
);
776 result
.forget(aResult
);
781 nsresult
UpgradeSchemaFrom8To9_0(mozIStorageConnection
& aConnection
) {
782 AssertIsOnIOThread();
784 AUTO_PROFILER_LABEL("UpgradeSchemaFrom8To9_0", DOM
);
786 // We no longer use the dataVersion column.
788 aConnection
.ExecuteSimpleSQL("UPDATE database SET dataVersion = 0;"_ns
);
789 if (NS_WARN_IF(NS_FAILED(rv
))) {
793 nsCOMPtr
<mozIStorageFunction
> compressor
= new CompressDataBlobsFunction();
795 constexpr auto compressorName
= "compress"_ns
;
797 rv
= aConnection
.CreateFunction(compressorName
, 1, compressor
);
798 if (NS_WARN_IF(NS_FAILED(rv
))) {
802 // Turn off foreign key constraints before we do anything here.
803 rv
= aConnection
.ExecuteSimpleSQL(
804 "UPDATE object_data SET data = compress(data);"_ns
);
805 if (NS_WARN_IF(NS_FAILED(rv
))) {
809 rv
= aConnection
.ExecuteSimpleSQL(
810 "UPDATE ai_object_data SET data = compress(data);"_ns
);
811 if (NS_WARN_IF(NS_FAILED(rv
))) {
815 rv
= aConnection
.RemoveFunction(compressorName
);
816 if (NS_WARN_IF(NS_FAILED(rv
))) {
820 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(9, 0));
821 if (NS_WARN_IF(NS_FAILED(rv
))) {
828 nsresult
UpgradeSchemaFrom9_0To10_0(mozIStorageConnection
& aConnection
) {
829 AssertIsOnIOThread();
831 AUTO_PROFILER_LABEL("UpgradeSchemaFrom9_0To10_0", DOM
);
833 nsresult rv
= aConnection
.ExecuteSimpleSQL(
834 "ALTER TABLE object_data ADD COLUMN file_ids TEXT;"_ns
);
835 if (NS_WARN_IF(NS_FAILED(rv
))) {
839 rv
= aConnection
.ExecuteSimpleSQL(
840 "ALTER TABLE ai_object_data ADD COLUMN file_ids TEXT;"_ns
);
841 if (NS_WARN_IF(NS_FAILED(rv
))) {
845 rv
= CreateFileTables(aConnection
);
846 if (NS_WARN_IF(NS_FAILED(rv
))) {
850 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(10, 0));
851 if (NS_WARN_IF(NS_FAILED(rv
))) {
858 nsresult
UpgradeSchemaFrom10_0To11_0(mozIStorageConnection
& aConnection
) {
859 AssertIsOnIOThread();
861 AUTO_PROFILER_LABEL("UpgradeSchemaFrom10_0To11_0", DOM
);
863 nsresult rv
= aConnection
.ExecuteSimpleSQL(
864 "CREATE TEMPORARY TABLE temp_upgrade ("
872 if (NS_WARN_IF(NS_FAILED(rv
))) {
876 rv
= aConnection
.ExecuteSimpleSQL(
877 "INSERT INTO temp_upgrade "
878 "SELECT id, object_store_id, name, key_path, "
879 "unique_index, multientry "
880 "FROM object_store_index;"_ns
);
881 if (NS_WARN_IF(NS_FAILED(rv
))) {
885 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_store_index;"_ns
);
886 if (NS_WARN_IF(NS_FAILED(rv
))) {
890 rv
= aConnection
.ExecuteSimpleSQL(
891 "CREATE TABLE object_store_index ("
892 "id INTEGER PRIMARY KEY, "
893 "object_store_id INTEGER NOT NULL, "
894 "name TEXT NOT NULL, "
895 "key_path TEXT NOT NULL, "
896 "unique_index INTEGER NOT NULL, "
897 "multientry INTEGER NOT NULL, "
898 "UNIQUE (object_store_id, name), "
899 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
902 if (NS_WARN_IF(NS_FAILED(rv
))) {
906 rv
= aConnection
.ExecuteSimpleSQL(
907 "INSERT INTO object_store_index "
908 "SELECT id, object_store_id, name, key_path, "
909 "unique_index, multientry "
910 "FROM temp_upgrade;"_ns
);
911 if (NS_WARN_IF(NS_FAILED(rv
))) {
915 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
916 if (NS_WARN_IF(NS_FAILED(rv
))) {
920 rv
= aConnection
.ExecuteSimpleSQL(
921 "DROP TRIGGER object_data_insert_trigger;"_ns
);
922 if (NS_WARN_IF(NS_FAILED(rv
))) {
926 rv
= aConnection
.ExecuteSimpleSQL(
927 "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
928 "SELECT object_store_id, id, data, file_ids "
929 "FROM ai_object_data;"_ns
);
930 if (NS_WARN_IF(NS_FAILED(rv
))) {
934 rv
= aConnection
.ExecuteSimpleSQL(
935 "CREATE TRIGGER object_data_insert_trigger "
936 "AFTER INSERT ON object_data "
938 "WHEN NEW.file_ids IS NOT NULL "
940 "SELECT update_refcount(NULL, NEW.file_ids); "
942 if (NS_WARN_IF(NS_FAILED(rv
))) {
946 rv
= aConnection
.ExecuteSimpleSQL(
947 "INSERT INTO index_data (index_id, value, object_data_key, "
949 "SELECT ai_index_data.index_id, ai_index_data.value, "
950 "ai_index_data.ai_object_data_id, object_data.id "
951 "FROM ai_index_data "
952 "INNER JOIN object_store_index ON "
953 "object_store_index.id = ai_index_data.index_id "
954 "INNER JOIN object_data ON "
955 "object_data.object_store_id = object_store_index.object_store_id AND "
956 "object_data.key_value = ai_index_data.ai_object_data_id;"_ns
);
957 if (NS_WARN_IF(NS_FAILED(rv
))) {
961 rv
= aConnection
.ExecuteSimpleSQL(
962 "INSERT INTO unique_index_data (index_id, value, object_data_key, "
964 "SELECT ai_unique_index_data.index_id, ai_unique_index_data.value, "
965 "ai_unique_index_data.ai_object_data_id, object_data.id "
966 "FROM ai_unique_index_data "
967 "INNER JOIN object_store_index ON "
968 "object_store_index.id = ai_unique_index_data.index_id "
969 "INNER JOIN object_data ON "
970 "object_data.object_store_id = object_store_index.object_store_id AND "
971 "object_data.key_value = ai_unique_index_data.ai_object_data_id;"_ns
);
972 if (NS_WARN_IF(NS_FAILED(rv
))) {
976 rv
= aConnection
.ExecuteSimpleSQL(
977 "UPDATE object_store "
978 "SET auto_increment = (SELECT max(id) FROM ai_object_data) + 1 "
979 "WHERE auto_increment;"_ns
);
980 if (NS_WARN_IF(NS_FAILED(rv
))) {
984 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE ai_unique_index_data;"_ns
);
985 if (NS_WARN_IF(NS_FAILED(rv
))) {
989 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE ai_index_data;"_ns
);
990 if (NS_WARN_IF(NS_FAILED(rv
))) {
994 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE ai_object_data;"_ns
);
995 if (NS_WARN_IF(NS_FAILED(rv
))) {
999 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(11, 0));
1000 if (NS_WARN_IF(NS_FAILED(rv
))) {
1007 class EncodeKeysFunction final
: public mozIStorageFunction
{
1012 ~EncodeKeysFunction() = default;
1015 OnFunctionCall(mozIStorageValueArray
* aArguments
,
1016 nsIVariant
** aResult
) override
{
1017 MOZ_ASSERT(aArguments
);
1018 MOZ_ASSERT(aResult
);
1020 AUTO_PROFILER_LABEL("EncodeKeysFunction::OnFunctionCall", DOM
);
1023 nsresult rv
= aArguments
->GetNumEntries(&argc
);
1024 if (NS_WARN_IF(NS_FAILED(rv
))) {
1029 NS_WARNING("Don't call me with the wrong number of arguments!");
1030 return NS_ERROR_UNEXPECTED
;
1034 rv
= aArguments
->GetTypeOfIndex(0, &type
);
1035 if (NS_WARN_IF(NS_FAILED(rv
))) {
1040 const auto& key
, ([type
, aArguments
]() -> Result
<Key
, nsresult
> {
1042 case mozIStorageStatement::VALUE_TYPE_INTEGER
: {
1044 aArguments
->GetInt64(0, &intKey
);
1047 key
.SetFromInteger(intKey
);
1051 case mozIStorageStatement::VALUE_TYPE_TEXT
: {
1053 aArguments
->GetString(0, stringKey
);
1056 QM_TRY(key
.SetFromString(stringKey
));
1061 NS_WARNING("Don't call me with the wrong type of arguments!");
1062 return Err(NS_ERROR_UNEXPECTED
);
1066 const nsCString
& buffer
= key
.GetBuffer();
1068 std::pair
<const void*, int> data(static_cast<const void*>(buffer
.get()),
1069 int(buffer
.Length()));
1071 nsCOMPtr
<nsIVariant
> result
= new mozilla::storage::BlobVariant(data
);
1073 result
.forget(aResult
);
1078 nsresult
UpgradeSchemaFrom11_0To12_0(mozIStorageConnection
& aConnection
) {
1079 AssertIsOnIOThread();
1081 AUTO_PROFILER_LABEL("UpgradeSchemaFrom11_0To12_0", DOM
);
1083 constexpr auto encoderName
= "encode"_ns
;
1085 nsCOMPtr
<mozIStorageFunction
> encoder
= new EncodeKeysFunction();
1087 nsresult rv
= aConnection
.CreateFunction(encoderName
, 1, encoder
);
1088 if (NS_WARN_IF(NS_FAILED(rv
))) {
1092 rv
= aConnection
.ExecuteSimpleSQL(
1093 "CREATE TEMPORARY TABLE temp_upgrade ("
1094 "id INTEGER PRIMARY KEY, "
1100 if (NS_WARN_IF(NS_FAILED(rv
))) {
1104 rv
= aConnection
.ExecuteSimpleSQL(
1105 "INSERT INTO temp_upgrade "
1106 "SELECT id, object_store_id, encode(key_value), data, file_ids "
1107 "FROM object_data;"_ns
);
1108 if (NS_WARN_IF(NS_FAILED(rv
))) {
1112 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_data;"_ns
);
1113 if (NS_WARN_IF(NS_FAILED(rv
))) {
1117 rv
= aConnection
.ExecuteSimpleSQL(
1118 "CREATE TABLE object_data ("
1119 "id INTEGER PRIMARY KEY, "
1120 "object_store_id INTEGER NOT NULL, "
1121 "key_value BLOB DEFAULT NULL, "
1123 "data BLOB NOT NULL, "
1124 "UNIQUE (object_store_id, key_value), "
1125 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
1128 if (NS_WARN_IF(NS_FAILED(rv
))) {
1132 rv
= aConnection
.ExecuteSimpleSQL(
1133 "INSERT INTO object_data "
1134 "SELECT id, object_store_id, key_value, file_ids, data "
1135 "FROM temp_upgrade;"_ns
);
1136 if (NS_WARN_IF(NS_FAILED(rv
))) {
1140 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
1141 if (NS_WARN_IF(NS_FAILED(rv
))) {
1145 rv
= aConnection
.ExecuteSimpleSQL(
1146 "CREATE TRIGGER object_data_insert_trigger "
1147 "AFTER INSERT ON object_data "
1149 "WHEN NEW.file_ids IS NOT NULL "
1151 "SELECT update_refcount(NULL, NEW.file_ids); "
1153 if (NS_WARN_IF(NS_FAILED(rv
))) {
1157 rv
= aConnection
.ExecuteSimpleSQL(
1158 "CREATE TRIGGER object_data_update_trigger "
1159 "AFTER UPDATE OF file_ids ON object_data "
1161 "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
1163 "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
1165 if (NS_WARN_IF(NS_FAILED(rv
))) {
1169 rv
= aConnection
.ExecuteSimpleSQL(
1170 "CREATE TRIGGER object_data_delete_trigger "
1171 "AFTER DELETE ON object_data "
1172 "FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
1174 "SELECT update_refcount(OLD.file_ids, NULL); "
1176 if (NS_WARN_IF(NS_FAILED(rv
))) {
1180 rv
= aConnection
.ExecuteSimpleSQL(
1181 "CREATE TEMPORARY TABLE temp_upgrade ("
1187 if (NS_WARN_IF(NS_FAILED(rv
))) {
1191 rv
= aConnection
.ExecuteSimpleSQL(
1192 "INSERT INTO temp_upgrade "
1193 "SELECT index_id, encode(value), encode(object_data_key), object_data_id "
1194 "FROM index_data;"_ns
);
1195 if (NS_WARN_IF(NS_FAILED(rv
))) {
1199 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE index_data;"_ns
);
1200 if (NS_WARN_IF(NS_FAILED(rv
))) {
1204 rv
= aConnection
.ExecuteSimpleSQL(
1205 "CREATE TABLE index_data ("
1206 "index_id INTEGER NOT NULL, "
1207 "value BLOB NOT NULL, "
1208 "object_data_key BLOB NOT NULL, "
1209 "object_data_id INTEGER NOT NULL, "
1210 "PRIMARY KEY (index_id, value, object_data_key), "
1211 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
1213 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
1216 if (NS_WARN_IF(NS_FAILED(rv
))) {
1220 rv
= aConnection
.ExecuteSimpleSQL(
1221 "INSERT INTO index_data "
1222 "SELECT index_id, value, object_data_key, object_data_id "
1223 "FROM temp_upgrade;"_ns
);
1224 if (NS_WARN_IF(NS_FAILED(rv
))) {
1228 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
1229 if (NS_WARN_IF(NS_FAILED(rv
))) {
1233 rv
= aConnection
.ExecuteSimpleSQL(
1234 "CREATE INDEX index_data_object_data_id_index "
1235 "ON index_data (object_data_id);"_ns
);
1236 if (NS_WARN_IF(NS_FAILED(rv
))) {
1240 rv
= aConnection
.ExecuteSimpleSQL(
1241 "CREATE TEMPORARY TABLE temp_upgrade ("
1247 if (NS_WARN_IF(NS_FAILED(rv
))) {
1251 rv
= aConnection
.ExecuteSimpleSQL(
1252 "INSERT INTO temp_upgrade "
1253 "SELECT index_id, encode(value), encode(object_data_key), object_data_id "
1254 "FROM unique_index_data;"_ns
);
1255 if (NS_WARN_IF(NS_FAILED(rv
))) {
1259 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE unique_index_data;"_ns
);
1260 if (NS_WARN_IF(NS_FAILED(rv
))) {
1264 rv
= aConnection
.ExecuteSimpleSQL(
1265 "CREATE TABLE unique_index_data ("
1266 "index_id INTEGER NOT NULL, "
1267 "value BLOB NOT NULL, "
1268 "object_data_key BLOB NOT NULL, "
1269 "object_data_id INTEGER NOT NULL, "
1270 "PRIMARY KEY (index_id, value, object_data_key), "
1271 "UNIQUE (index_id, value), "
1272 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
1274 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
1277 if (NS_WARN_IF(NS_FAILED(rv
))) {
1281 rv
= aConnection
.ExecuteSimpleSQL(
1282 "INSERT INTO unique_index_data "
1283 "SELECT index_id, value, object_data_key, object_data_id "
1284 "FROM temp_upgrade;"_ns
);
1285 if (NS_WARN_IF(NS_FAILED(rv
))) {
1289 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
1290 if (NS_WARN_IF(NS_FAILED(rv
))) {
1294 rv
= aConnection
.ExecuteSimpleSQL(
1295 "CREATE INDEX unique_index_data_object_data_id_index "
1296 "ON unique_index_data (object_data_id);"_ns
);
1297 if (NS_WARN_IF(NS_FAILED(rv
))) {
1301 rv
= aConnection
.RemoveFunction(encoderName
);
1302 if (NS_WARN_IF(NS_FAILED(rv
))) {
1306 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(12, 0));
1307 if (NS_WARN_IF(NS_FAILED(rv
))) {
1314 nsresult
UpgradeSchemaFrom12_0To13_0(mozIStorageConnection
& aConnection
,
1315 bool* aVacuumNeeded
) {
1316 AssertIsOnIOThread();
1318 AUTO_PROFILER_LABEL("UpgradeSchemaFrom12_0To13_0", DOM
);
1323 int32_t defaultPageSize
;
1324 rv
= aConnection
.GetDefaultPageSize(&defaultPageSize
);
1325 if (NS_WARN_IF(NS_FAILED(rv
))) {
1329 // Enable auto_vacuum mode and update the page size to the platform default.
1330 nsAutoCString
upgradeQuery("PRAGMA auto_vacuum = FULL; PRAGMA page_size = ");
1331 upgradeQuery
.AppendInt(defaultPageSize
);
1333 rv
= aConnection
.ExecuteSimpleSQL(upgradeQuery
);
1334 if (NS_WARN_IF(NS_FAILED(rv
))) {
1338 *aVacuumNeeded
= true;
1341 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(13, 0));
1342 if (NS_WARN_IF(NS_FAILED(rv
))) {
1349 nsresult
UpgradeSchemaFrom13_0To14_0(mozIStorageConnection
& aConnection
) {
1350 AssertIsOnIOThread();
1352 // The only change between 13 and 14 was a different structured
1353 // clone format, but it's backwards-compatible.
1354 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(14, 0));
1355 if (NS_WARN_IF(NS_FAILED(rv
))) {
1362 nsresult
UpgradeSchemaFrom14_0To15_0(mozIStorageConnection
& aConnection
) {
1363 // The only change between 14 and 15 was a different structured
1364 // clone format, but it's backwards-compatible.
1365 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(15, 0));
1366 if (NS_WARN_IF(NS_FAILED(rv
))) {
1373 nsresult
UpgradeSchemaFrom15_0To16_0(mozIStorageConnection
& aConnection
) {
1374 // The only change between 15 and 16 was a different structured
1375 // clone format, but it's backwards-compatible.
1376 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(16, 0));
1377 if (NS_WARN_IF(NS_FAILED(rv
))) {
1384 nsresult
UpgradeSchemaFrom16_0To17_0(mozIStorageConnection
& aConnection
) {
1385 // The only change between 16 and 17 was a different structured
1386 // clone format, but it's backwards-compatible.
1387 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(17, 0));
1388 if (NS_WARN_IF(NS_FAILED(rv
))) {
1395 class UpgradeSchemaFrom17_0To18_0Helper final
{
1396 class InsertIndexDataValuesFunction
;
1397 class UpgradeKeyFunction
;
1400 static nsresult
DoUpgrade(mozIStorageConnection
& aConnection
,
1401 const nsACString
& aOrigin
);
1404 static nsresult
DoUpgradeInternal(mozIStorageConnection
& aConnection
,
1405 const nsACString
& aOrigin
);
1407 UpgradeSchemaFrom17_0To18_0Helper() = delete;
1408 ~UpgradeSchemaFrom17_0To18_0Helper() = delete;
1411 class UpgradeSchemaFrom17_0To18_0Helper::InsertIndexDataValuesFunction final
1412 : public mozIStorageFunction
{
1414 InsertIndexDataValuesFunction() = default;
1419 ~InsertIndexDataValuesFunction() = default;
1421 NS_DECL_MOZISTORAGEFUNCTION
1425 UpgradeSchemaFrom17_0To18_0Helper::InsertIndexDataValuesFunction
,
1426 mozIStorageFunction
);
1429 UpgradeSchemaFrom17_0To18_0Helper::InsertIndexDataValuesFunction::
1430 OnFunctionCall(mozIStorageValueArray
* aValues
, nsIVariant
** _retval
) {
1431 MOZ_ASSERT(!NS_IsMainThread());
1432 MOZ_ASSERT(!IsOnBackgroundThread());
1433 MOZ_ASSERT(aValues
);
1434 MOZ_ASSERT(_retval
);
1439 MOZ_ALWAYS_SUCCEEDS(aValues
->GetNumEntries(&argCount
));
1440 MOZ_ASSERT(argCount
== 4);
1443 MOZ_ALWAYS_SUCCEEDS(aValues
->GetTypeOfIndex(0, &valueType
));
1444 MOZ_ASSERT(valueType
== mozIStorageValueArray::VALUE_TYPE_NULL
||
1445 valueType
== mozIStorageValueArray::VALUE_TYPE_BLOB
);
1447 MOZ_ALWAYS_SUCCEEDS(aValues
->GetTypeOfIndex(1, &valueType
));
1448 MOZ_ASSERT(valueType
== mozIStorageValueArray::VALUE_TYPE_INTEGER
);
1450 MOZ_ALWAYS_SUCCEEDS(aValues
->GetTypeOfIndex(2, &valueType
));
1451 MOZ_ASSERT(valueType
== mozIStorageValueArray::VALUE_TYPE_INTEGER
);
1453 MOZ_ALWAYS_SUCCEEDS(aValues
->GetTypeOfIndex(3, &valueType
));
1454 MOZ_ASSERT(valueType
== mozIStorageValueArray::VALUE_TYPE_BLOB
);
1458 // Read out the previous value. It may be NULL, in which case we'll just end
1459 // up with an empty array.
1460 QM_TRY_UNWRAP(auto indexValues
, ReadCompressedIndexDataValues(*aValues
, 0));
1462 IndexOrObjectStoreId indexId
;
1463 nsresult rv
= aValues
->GetInt64(1, &indexId
);
1464 if (NS_WARN_IF(NS_FAILED(rv
))) {
1469 rv
= aValues
->GetInt32(2, &unique
);
1470 if (NS_WARN_IF(NS_FAILED(rv
))) {
1475 rv
= value
.SetFromValueArray(aValues
, 3);
1476 if (NS_WARN_IF(NS_FAILED(rv
))) {
1480 // Update the array with the new addition.
1481 if (NS_WARN_IF(!indexValues
.InsertElementSorted(
1482 IndexDataValue(indexId
, !!unique
, value
), fallible
))) {
1483 IDB_REPORT_INTERNAL_ERR();
1484 return NS_ERROR_OUT_OF_MEMORY
;
1487 // Compress the array.
1488 QM_TRY_UNWRAP((auto [indexValuesBlob
, indexValuesBlobLength
]),
1489 MakeCompressedIndexDataValues(indexValues
));
1491 // The compressed blob is the result of this function.
1492 nsCOMPtr
<nsIVariant
> result
= new storage::AdoptedBlobVariant(
1493 std::pair(indexValuesBlob
.release(), indexValuesBlobLength
));
1495 result
.forget(_retval
);
1499 class UpgradeSchemaFrom17_0To18_0Helper::UpgradeKeyFunction final
1500 : public mozIStorageFunction
{
1502 UpgradeKeyFunction() = default;
1504 static nsresult
CopyAndUpgradeKeyBuffer(const uint8_t* aSource
,
1505 const uint8_t* aSourceEnd
,
1506 uint8_t* aDestination
) {
1507 return CopyAndUpgradeKeyBufferInternal(aSource
, aSourceEnd
, aDestination
,
1509 0 /* aRecursionDepth */);
1515 ~UpgradeKeyFunction() = default;
1517 static nsresult
CopyAndUpgradeKeyBufferInternal(const uint8_t*& aSource
,
1518 const uint8_t* aSourceEnd
,
1519 uint8_t*& aDestination
,
1521 uint8_t aRecursionDepth
);
1523 static uint32_t AdjustedSize(uint32_t aMaxSize
, const uint8_t* aSource
,
1524 const uint8_t* aSourceEnd
) {
1525 MOZ_ASSERT(aMaxSize
);
1526 MOZ_ASSERT(aSource
);
1527 MOZ_ASSERT(aSourceEnd
);
1528 MOZ_ASSERT(aSource
<= aSourceEnd
);
1530 return std::min(aMaxSize
, uint32_t(aSourceEnd
- aSource
));
1533 NS_DECL_MOZISTORAGEFUNCTION
1537 nsresult
UpgradeSchemaFrom17_0To18_0Helper::UpgradeKeyFunction::
1538 CopyAndUpgradeKeyBufferInternal(const uint8_t*& aSource
,
1539 const uint8_t* aSourceEnd
,
1540 uint8_t*& aDestination
, uint8_t aTagOffset
,
1541 uint8_t aRecursionDepth
) {
1542 MOZ_ASSERT(!NS_IsMainThread());
1543 MOZ_ASSERT(!IsOnBackgroundThread());
1544 MOZ_ASSERT(aSource
);
1545 MOZ_ASSERT(*aSource
);
1546 MOZ_ASSERT(aSourceEnd
);
1547 MOZ_ASSERT(aSource
< aSourceEnd
);
1548 MOZ_ASSERT(aDestination
);
1549 MOZ_ASSERT(aTagOffset
<= Key::kMaxArrayCollapse
);
1551 static constexpr uint8_t kOldNumberTag
= 0x1;
1552 static constexpr uint8_t kOldDateTag
= 0x2;
1553 static constexpr uint8_t kOldStringTag
= 0x3;
1554 static constexpr uint8_t kOldArrayTag
= 0x4;
1555 static constexpr uint8_t kOldMaxType
= kOldArrayTag
;
1557 if (NS_WARN_IF(aRecursionDepth
> Key::kMaxRecursionDepth
)) {
1558 IDB_REPORT_INTERNAL_ERR();
1559 return NS_ERROR_FILE_CORRUPTED
;
1562 const uint8_t sourceTag
= *aSource
- (aTagOffset
* kOldMaxType
);
1563 MOZ_ASSERT(sourceTag
);
1565 if (NS_WARN_IF(sourceTag
> kOldMaxType
* Key::kMaxArrayCollapse
)) {
1566 IDB_REPORT_INTERNAL_ERR();
1567 return NS_ERROR_FILE_CORRUPTED
;
1570 if (sourceTag
== kOldNumberTag
|| sourceTag
== kOldDateTag
) {
1571 // Write the new tag.
1572 *aDestination
++ = (sourceTag
== kOldNumberTag
? Key::eFloat
: Key::eDate
) +
1573 (aTagOffset
* Key::eMaxType
);
1576 // Numbers and Dates are encoded as 64-bit integers, but trailing 0
1577 // bytes have been removed.
1578 const uint32_t byteCount
=
1579 AdjustedSize(sizeof(uint64_t), aSource
, aSourceEnd
);
1581 aDestination
= std::copy(aSource
, aSource
+ byteCount
, aDestination
);
1582 aSource
+= byteCount
;
1587 if (sourceTag
== kOldStringTag
) {
1588 // Write the new tag.
1589 *aDestination
++ = Key::eString
+ (aTagOffset
* Key::eMaxType
);
1592 while (aSource
< aSourceEnd
) {
1593 const uint8_t byte
= *aSource
++;
1594 *aDestination
++ = byte
;
1597 // Just copied the terminator.
1601 // Maybe copy one or two extra bytes if the byte is tagged and we have
1602 // enough source space.
1604 const uint32_t byteCount
=
1605 AdjustedSize((byte
& 0x40) ? 2 : 1, aSource
, aSourceEnd
);
1607 aDestination
= std::copy(aSource
, aSource
+ byteCount
, aDestination
);
1608 aSource
+= byteCount
;
1615 if (NS_WARN_IF(sourceTag
< kOldArrayTag
)) {
1616 IDB_REPORT_INTERNAL_ERR();
1617 return NS_ERROR_FILE_CORRUPTED
;
1622 if (aTagOffset
== Key::kMaxArrayCollapse
) {
1623 MOZ_ASSERT(sourceTag
== kOldArrayTag
);
1625 *aDestination
++ = (aTagOffset
* Key::eMaxType
);
1631 while (aSource
< aSourceEnd
&&
1632 (*aSource
- (aTagOffset
* kOldMaxType
)) != Key::eTerminator
) {
1633 nsresult rv
= CopyAndUpgradeKeyBufferInternal(
1634 aSource
, aSourceEnd
, aDestination
, aTagOffset
, aRecursionDepth
+ 1);
1635 if (NS_WARN_IF(NS_FAILED(rv
))) {
1642 if (aSource
< aSourceEnd
) {
1643 MOZ_ASSERT((*aSource
- (aTagOffset
* kOldMaxType
)) == Key::eTerminator
);
1644 *aDestination
++ = Key::eTerminator
+ (aTagOffset
* Key::eMaxType
);
1651 NS_IMPL_ISUPPORTS(UpgradeSchemaFrom17_0To18_0Helper::UpgradeKeyFunction
,
1652 mozIStorageFunction
);
1655 UpgradeSchemaFrom17_0To18_0Helper::UpgradeKeyFunction::OnFunctionCall(
1656 mozIStorageValueArray
* aValues
, nsIVariant
** _retval
) {
1657 MOZ_ASSERT(!NS_IsMainThread());
1658 MOZ_ASSERT(!IsOnBackgroundThread());
1659 MOZ_ASSERT(aValues
);
1660 MOZ_ASSERT(_retval
);
1665 MOZ_ALWAYS_SUCCEEDS(aValues
->GetNumEntries(&argCount
));
1666 MOZ_ASSERT(argCount
== 1);
1669 MOZ_ALWAYS_SUCCEEDS(aValues
->GetTypeOfIndex(0, &valueType
));
1670 MOZ_ASSERT(valueType
== mozIStorageValueArray::VALUE_TYPE_BLOB
);
1674 // Dig the old key out of the values.
1675 const uint8_t* blobData
;
1676 uint32_t blobDataLength
;
1677 nsresult rv
= aValues
->GetSharedBlob(0, &blobDataLength
, &blobData
);
1678 if (NS_WARN_IF(NS_FAILED(rv
))) {
1682 // Upgrading the key doesn't change the amount of space needed to hold it.
1683 UniqueFreePtr
<uint8_t> upgradedBlobData(
1684 static_cast<uint8_t*>(malloc(blobDataLength
)));
1685 if (NS_WARN_IF(!upgradedBlobData
)) {
1686 IDB_REPORT_INTERNAL_ERR();
1687 return NS_ERROR_OUT_OF_MEMORY
;
1690 rv
= CopyAndUpgradeKeyBuffer(blobData
, blobData
+ blobDataLength
,
1691 upgradedBlobData
.get());
1692 if (NS_WARN_IF(NS_FAILED(rv
))) {
1696 // The upgraded key is the result of this function.
1697 std::pair
<uint8_t*, int> data(upgradedBlobData
.release(),
1698 int(blobDataLength
));
1700 nsCOMPtr
<nsIVariant
> result
= new mozilla::storage::AdoptedBlobVariant(data
);
1702 result
.forget(_retval
);
1707 nsresult
UpgradeSchemaFrom17_0To18_0Helper::DoUpgrade(
1708 mozIStorageConnection
& aConnection
, const nsACString
& aOrigin
) {
1709 MOZ_ASSERT(!aOrigin
.IsEmpty());
1711 // Register the |upgrade_key| function.
1712 RefPtr
<UpgradeKeyFunction
> updateFunction
= new UpgradeKeyFunction();
1714 constexpr auto upgradeKeyFunctionName
= "upgrade_key"_ns
;
1717 aConnection
.CreateFunction(upgradeKeyFunctionName
, 1, updateFunction
);
1718 if (NS_WARN_IF(NS_FAILED(rv
))) {
1722 // Register the |insert_idv| function.
1723 RefPtr
<InsertIndexDataValuesFunction
> insertIDVFunction
=
1724 new InsertIndexDataValuesFunction();
1726 constexpr auto insertIDVFunctionName
= "insert_idv"_ns
;
1728 rv
= aConnection
.CreateFunction(insertIDVFunctionName
, 4, insertIDVFunction
);
1729 if (NS_WARN_IF(NS_FAILED(rv
))) {
1730 MOZ_ALWAYS_SUCCEEDS(aConnection
.RemoveFunction(upgradeKeyFunctionName
));
1734 rv
= DoUpgradeInternal(aConnection
, aOrigin
);
1736 MOZ_ALWAYS_SUCCEEDS(aConnection
.RemoveFunction(upgradeKeyFunctionName
));
1737 MOZ_ALWAYS_SUCCEEDS(aConnection
.RemoveFunction(insertIDVFunctionName
));
1739 if (NS_WARN_IF(NS_FAILED(rv
))) {
1747 nsresult
UpgradeSchemaFrom17_0To18_0Helper::DoUpgradeInternal(
1748 mozIStorageConnection
& aConnection
, const nsACString
& aOrigin
) {
1749 MOZ_ASSERT(!aOrigin
.IsEmpty());
1751 nsresult rv
= aConnection
.ExecuteSimpleSQL(
1752 // Drop these triggers to avoid unnecessary work during the upgrade
1754 "DROP TRIGGER object_data_insert_trigger;"
1755 "DROP TRIGGER object_data_update_trigger;"
1756 "DROP TRIGGER object_data_delete_trigger;"_ns
);
1757 if (NS_WARN_IF(NS_FAILED(rv
))) {
1761 rv
= aConnection
.ExecuteSimpleSQL(
1762 // Drop these indexes before we do anything else to free disk space.
1763 "DROP INDEX index_data_object_data_id_index;"
1764 "DROP INDEX unique_index_data_object_data_id_index;"_ns
);
1765 if (NS_WARN_IF(NS_FAILED(rv
))) {
1769 // Create the new tables and triggers first.
1771 rv
= aConnection
.ExecuteSimpleSQL(
1772 // This will eventually become the |database| table.
1773 "CREATE TABLE database_upgrade "
1774 "( name TEXT PRIMARY KEY"
1775 ", origin TEXT NOT NULL"
1776 ", version INTEGER NOT NULL DEFAULT 0"
1777 ", last_vacuum_time INTEGER NOT NULL DEFAULT 0"
1778 ", last_analyze_time INTEGER NOT NULL DEFAULT 0"
1779 ", last_vacuum_size INTEGER NOT NULL DEFAULT 0"
1780 ") WITHOUT ROWID;"_ns
);
1781 if (NS_WARN_IF(NS_FAILED(rv
))) {
1785 rv
= aConnection
.ExecuteSimpleSQL(
1786 // This will eventually become the |object_store| table.
1787 "CREATE TABLE object_store_upgrade"
1788 "( id INTEGER PRIMARY KEY"
1789 ", auto_increment INTEGER NOT NULL DEFAULT 0"
1790 ", name TEXT NOT NULL"
1793 if (NS_WARN_IF(NS_FAILED(rv
))) {
1797 rv
= aConnection
.ExecuteSimpleSQL(
1798 // This will eventually become the |object_store_index| table.
1799 "CREATE TABLE object_store_index_upgrade"
1800 "( id INTEGER PRIMARY KEY"
1801 ", object_store_id INTEGER NOT NULL"
1802 ", name TEXT NOT NULL"
1803 ", key_path TEXT NOT NULL"
1804 ", unique_index INTEGER NOT NULL"
1805 ", multientry INTEGER NOT NULL"
1806 ", FOREIGN KEY (object_store_id) "
1807 "REFERENCES object_store(id) "
1809 if (NS_WARN_IF(NS_FAILED(rv
))) {
1813 rv
= aConnection
.ExecuteSimpleSQL(
1814 // This will eventually become the |object_data| table.
1815 "CREATE TABLE object_data_upgrade"
1816 "( object_store_id INTEGER NOT NULL"
1817 ", key BLOB NOT NULL"
1818 ", index_data_values BLOB DEFAULT NULL"
1820 ", data BLOB NOT NULL"
1821 ", PRIMARY KEY (object_store_id, key)"
1822 ", FOREIGN KEY (object_store_id) "
1823 "REFERENCES object_store(id) "
1824 ") WITHOUT ROWID;"_ns
);
1825 if (NS_WARN_IF(NS_FAILED(rv
))) {
1829 rv
= aConnection
.ExecuteSimpleSQL(
1830 // This will eventually become the |index_data| table.
1831 "CREATE TABLE index_data_upgrade"
1832 "( index_id INTEGER NOT NULL"
1833 ", value BLOB NOT NULL"
1834 ", object_data_key BLOB NOT NULL"
1835 ", object_store_id INTEGER NOT NULL"
1836 ", PRIMARY KEY (index_id, value, object_data_key)"
1837 ", FOREIGN KEY (index_id) "
1838 "REFERENCES object_store_index(id) "
1839 ", FOREIGN KEY (object_store_id, object_data_key) "
1840 "REFERENCES object_data(object_store_id, key) "
1841 ") WITHOUT ROWID;"_ns
);
1842 if (NS_WARN_IF(NS_FAILED(rv
))) {
1846 rv
= aConnection
.ExecuteSimpleSQL(
1847 // This will eventually become the |unique_index_data| table.
1848 "CREATE TABLE unique_index_data_upgrade"
1849 "( index_id INTEGER NOT NULL"
1850 ", value BLOB NOT NULL"
1851 ", object_store_id INTEGER NOT NULL"
1852 ", object_data_key BLOB NOT NULL"
1853 ", PRIMARY KEY (index_id, value)"
1854 ", FOREIGN KEY (index_id) "
1855 "REFERENCES object_store_index(id) "
1856 ", FOREIGN KEY (object_store_id, object_data_key) "
1857 "REFERENCES object_data(object_store_id, key) "
1858 ") WITHOUT ROWID;"_ns
);
1859 if (NS_WARN_IF(NS_FAILED(rv
))) {
1863 rv
= aConnection
.ExecuteSimpleSQL(
1864 // Temporarily store |index_data_values| that we build during the upgrade
1865 // of the index tables. We will later move this to the |object_data|
1867 "CREATE TEMPORARY TABLE temp_index_data_values "
1868 "( object_store_id INTEGER NOT NULL"
1869 ", key BLOB NOT NULL"
1870 ", index_data_values BLOB DEFAULT NULL"
1871 ", PRIMARY KEY (object_store_id, key)"
1872 ") WITHOUT ROWID;"_ns
);
1873 if (NS_WARN_IF(NS_FAILED(rv
))) {
1877 rv
= aConnection
.ExecuteSimpleSQL(
1878 // These two triggers help build the |index_data_values| blobs. The nested
1879 // SELECT statements help us achieve an "INSERT OR UPDATE"-like behavior.
1880 "CREATE TEMPORARY TRIGGER unique_index_data_upgrade_insert_trigger "
1881 "AFTER INSERT ON unique_index_data_upgrade "
1883 "INSERT OR REPLACE INTO temp_index_data_values "
1885 "( NEW.object_store_id"
1886 ", NEW.object_data_key"
1888 "( SELECT index_data_values "
1889 "FROM temp_index_data_values "
1890 "WHERE object_store_id = NEW.object_store_id "
1891 "AND key = NEW.object_data_key "
1898 if (NS_WARN_IF(NS_FAILED(rv
))) {
1902 rv
= aConnection
.ExecuteSimpleSQL(
1903 "CREATE TEMPORARY TRIGGER index_data_upgrade_insert_trigger "
1904 "AFTER INSERT ON index_data_upgrade "
1906 "INSERT OR REPLACE INTO temp_index_data_values "
1908 "( NEW.object_store_id"
1909 ", NEW.object_data_key"
1912 "SELECT index_data_values "
1913 "FROM temp_index_data_values "
1914 "WHERE object_store_id = NEW.object_store_id "
1915 "AND key = NEW.object_data_key "
1917 ", 0" /* not unique */
1922 if (NS_WARN_IF(NS_FAILED(rv
))) {
1926 // Update the |unique_index_data| table to change the column order, remove the
1927 // ON DELETE CASCADE clauses, and to apply the WITHOUT ROWID optimization.
1928 rv
= aConnection
.ExecuteSimpleSQL(
1929 // Insert all the data.
1930 "INSERT INTO unique_index_data_upgrade "
1932 "unique_index_data.index_id, "
1933 "upgrade_key(unique_index_data.value), "
1934 "object_data.object_store_id, "
1935 "upgrade_key(unique_index_data.object_data_key) "
1936 "FROM unique_index_data "
1938 "ON unique_index_data.object_data_id = object_data.id;"_ns
);
1939 if (NS_WARN_IF(NS_FAILED(rv
))) {
1943 rv
= aConnection
.ExecuteSimpleSQL(
1944 // The trigger is no longer needed.
1945 "DROP TRIGGER unique_index_data_upgrade_insert_trigger;"_ns
);
1946 if (NS_WARN_IF(NS_FAILED(rv
))) {
1950 rv
= aConnection
.ExecuteSimpleSQL(
1951 // The old table is no longer needed.
1952 "DROP TABLE unique_index_data;"_ns
);
1953 if (NS_WARN_IF(NS_FAILED(rv
))) {
1957 rv
= aConnection
.ExecuteSimpleSQL(
1958 // Rename the table.
1959 "ALTER TABLE unique_index_data_upgrade "
1960 "RENAME TO unique_index_data;"_ns
);
1961 if (NS_WARN_IF(NS_FAILED(rv
))) {
1965 // Update the |index_data| table to change the column order, remove the ON
1966 // DELETE CASCADE clauses, and to apply the WITHOUT ROWID optimization.
1967 rv
= aConnection
.ExecuteSimpleSQL(
1968 // Insert all the data.
1969 "INSERT INTO index_data_upgrade "
1971 "index_data.index_id, "
1972 "upgrade_key(index_data.value), "
1973 "upgrade_key(index_data.object_data_key), "
1974 "object_data.object_store_id "
1977 "ON index_data.object_data_id = object_data.id;"_ns
);
1978 if (NS_WARN_IF(NS_FAILED(rv
))) {
1982 rv
= aConnection
.ExecuteSimpleSQL(
1983 // The trigger is no longer needed.
1984 "DROP TRIGGER index_data_upgrade_insert_trigger;"_ns
);
1985 if (NS_WARN_IF(NS_FAILED(rv
))) {
1989 rv
= aConnection
.ExecuteSimpleSQL(
1990 // The old table is no longer needed.
1991 "DROP TABLE index_data;"_ns
);
1992 if (NS_WARN_IF(NS_FAILED(rv
))) {
1996 rv
= aConnection
.ExecuteSimpleSQL(
1997 // Rename the table.
1998 "ALTER TABLE index_data_upgrade "
1999 "RENAME TO index_data;"_ns
);
2000 if (NS_WARN_IF(NS_FAILED(rv
))) {
2004 // Update the |object_data| table to add the |index_data_values| column,
2005 // remove the ON DELETE CASCADE clause, and apply the WITHOUT ROWID
2007 rv
= aConnection
.ExecuteSimpleSQL(
2008 // Insert all the data.
2009 "INSERT INTO object_data_upgrade "
2011 "object_data.object_store_id, "
2012 "upgrade_key(object_data.key_value), "
2013 "temp_index_data_values.index_data_values, "
2014 "object_data.file_ids, "
2017 "LEFT JOIN temp_index_data_values "
2018 "ON object_data.object_store_id = "
2019 "temp_index_data_values.object_store_id "
2020 "AND upgrade_key(object_data.key_value) = "
2021 "temp_index_data_values.key;"_ns
);
2022 if (NS_WARN_IF(NS_FAILED(rv
))) {
2026 rv
= aConnection
.ExecuteSimpleSQL(
2027 // The temporary table is no longer needed.
2028 "DROP TABLE temp_index_data_values;"_ns
);
2029 if (NS_WARN_IF(NS_FAILED(rv
))) {
2033 rv
= aConnection
.ExecuteSimpleSQL(
2034 // The old table is no longer needed.
2035 "DROP TABLE object_data;"_ns
);
2036 if (NS_WARN_IF(NS_FAILED(rv
))) {
2040 rv
= aConnection
.ExecuteSimpleSQL(
2041 // Rename the table.
2042 "ALTER TABLE object_data_upgrade "
2043 "RENAME TO object_data;"_ns
);
2044 if (NS_WARN_IF(NS_FAILED(rv
))) {
2048 // Update the |object_store_index| table to remove the UNIQUE constraint and
2049 // the ON DELETE CASCADE clause.
2050 rv
= aConnection
.ExecuteSimpleSQL(
2051 "INSERT INTO object_store_index_upgrade "
2053 "FROM object_store_index;"_ns
);
2054 if (NS_WARN_IF(NS_FAILED(rv
))) {
2058 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_store_index;"_ns
);
2059 if (NS_WARN_IF(NS_FAILED(rv
))) {
2063 rv
= aConnection
.ExecuteSimpleSQL(
2064 "ALTER TABLE object_store_index_upgrade "
2065 "RENAME TO object_store_index;"_ns
);
2066 if (NS_WARN_IF(NS_FAILED(rv
))) {
2070 // Update the |object_store| table to remove the UNIQUE constraint.
2071 rv
= aConnection
.ExecuteSimpleSQL(
2072 "INSERT INTO object_store_upgrade "
2074 "FROM object_store;"_ns
);
2075 if (NS_WARN_IF(NS_FAILED(rv
))) {
2079 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_store;"_ns
);
2080 if (NS_WARN_IF(NS_FAILED(rv
))) {
2084 rv
= aConnection
.ExecuteSimpleSQL(
2085 "ALTER TABLE object_store_upgrade "
2086 "RENAME TO object_store;"_ns
);
2087 if (NS_WARN_IF(NS_FAILED(rv
))) {
2091 // Update the |database| table to include the origin, vacuum information, and
2092 // apply the WITHOUT ROWID optimization.
2093 nsCOMPtr
<mozIStorageStatement
> stmt
;
2095 // The parameter names are not used, parameters are bound by index only
2096 // locally in the same function.
2097 rv
= aConnection
.CreateStatement(
2098 "INSERT INTO database_upgrade "
2099 "SELECT name, :origin, version, 0, 0, 0 "
2100 "FROM database;"_ns
,
2101 getter_AddRefs(stmt
));
2102 if (NS_WARN_IF(NS_FAILED(rv
))) {
2106 rv
= stmt
->BindUTF8StringByIndex(0, aOrigin
);
2107 if (NS_WARN_IF(NS_FAILED(rv
))) {
2111 rv
= stmt
->Execute();
2112 if (NS_WARN_IF(NS_FAILED(rv
))) {
2116 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE database;"_ns
);
2117 if (NS_WARN_IF(NS_FAILED(rv
))) {
2121 rv
= aConnection
.ExecuteSimpleSQL(
2122 "ALTER TABLE database_upgrade "
2123 "RENAME TO database;"_ns
);
2124 if (NS_WARN_IF(NS_FAILED(rv
))) {
2130 // Make sure there's only one entry in the |database| table.
2131 QM_TRY_INSPECT(const auto& stmt
,
2132 quota::CreateAndExecuteSingleStepStatement(
2133 aConnection
, "SELECT COUNT(*) FROM database;"_ns
),
2134 QM_ASSERT_UNREACHABLE
);
2137 MOZ_ASSERT(NS_SUCCEEDED(stmt
->GetInt64(0, &count
)));
2139 MOZ_ASSERT(count
== 1);
2143 // Recreate file table triggers.
2144 rv
= aConnection
.ExecuteSimpleSQL(
2145 "CREATE TRIGGER object_data_insert_trigger "
2146 "AFTER INSERT ON object_data "
2147 "WHEN NEW.file_ids IS NOT NULL "
2149 "SELECT update_refcount(NULL, NEW.file_ids);"
2151 if (NS_WARN_IF(NS_FAILED(rv
))) {
2155 rv
= aConnection
.ExecuteSimpleSQL(
2156 "CREATE TRIGGER object_data_update_trigger "
2157 "AFTER UPDATE OF file_ids ON object_data "
2158 "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
2160 "SELECT update_refcount(OLD.file_ids, NEW.file_ids);"
2162 if (NS_WARN_IF(NS_FAILED(rv
))) {
2166 rv
= aConnection
.ExecuteSimpleSQL(
2167 "CREATE TRIGGER object_data_delete_trigger "
2168 "AFTER DELETE ON object_data "
2169 "WHEN OLD.file_ids IS NOT NULL "
2171 "SELECT update_refcount(OLD.file_ids, NULL);"
2173 if (NS_WARN_IF(NS_FAILED(rv
))) {
2177 // Finally, turn on auto_vacuum mode. We use full auto_vacuum mode to reclaim
2178 // disk space on mobile devices (at the cost of some COMMIT speed), and
2179 // incremental auto_vacuum mode on desktop builds.
2180 rv
= aConnection
.ExecuteSimpleSQL(
2182 "PRAGMA auto_vacuum = FULL;"_ns
2184 "PRAGMA auto_vacuum = INCREMENTAL;"_ns
2187 if (NS_WARN_IF(NS_FAILED(rv
))) {
2191 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(18, 0));
2192 if (NS_WARN_IF(NS_FAILED(rv
))) {
2199 nsresult
UpgradeSchemaFrom17_0To18_0(mozIStorageConnection
& aConnection
,
2200 const nsACString
& aOrigin
) {
2201 MOZ_ASSERT(!aOrigin
.IsEmpty());
2203 AUTO_PROFILER_LABEL("UpgradeSchemaFrom17_0To18_0", DOM
);
2205 return UpgradeSchemaFrom17_0To18_0Helper::DoUpgrade(aConnection
, aOrigin
);
2208 nsresult
UpgradeSchemaFrom18_0To19_0(mozIStorageConnection
& aConnection
) {
2209 AssertIsOnIOThread();
2212 AUTO_PROFILER_LABEL("UpgradeSchemaFrom18_0To19_0", DOM
);
2214 rv
= aConnection
.ExecuteSimpleSQL(
2215 "ALTER TABLE object_store_index "
2216 "ADD COLUMN locale TEXT;"_ns
);
2217 if (NS_WARN_IF(NS_FAILED(rv
))) {
2221 rv
= aConnection
.ExecuteSimpleSQL(
2222 "ALTER TABLE object_store_index "
2223 "ADD COLUMN is_auto_locale BOOLEAN;"_ns
);
2224 if (NS_WARN_IF(NS_FAILED(rv
))) {
2228 rv
= aConnection
.ExecuteSimpleSQL(
2229 "ALTER TABLE index_data "
2230 "ADD COLUMN value_locale BLOB;"_ns
);
2231 if (NS_WARN_IF(NS_FAILED(rv
))) {
2235 rv
= aConnection
.ExecuteSimpleSQL(
2236 "ALTER TABLE unique_index_data "
2237 "ADD COLUMN value_locale BLOB;"_ns
);
2238 if (NS_WARN_IF(NS_FAILED(rv
))) {
2242 rv
= aConnection
.ExecuteSimpleSQL(
2243 "CREATE INDEX index_data_value_locale_index "
2244 "ON index_data (index_id, value_locale, object_data_key, value) "
2245 "WHERE value_locale IS NOT NULL;"_ns
);
2246 if (NS_WARN_IF(NS_FAILED(rv
))) {
2250 rv
= aConnection
.ExecuteSimpleSQL(
2251 "CREATE INDEX unique_index_data_value_locale_index "
2252 "ON unique_index_data (index_id, value_locale, object_data_key, value) "
2253 "WHERE value_locale IS NOT NULL;"_ns
);
2254 if (NS_WARN_IF(NS_FAILED(rv
))) {
2258 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(19, 0));
2259 if (NS_WARN_IF(NS_FAILED(rv
))) {
2266 class UpgradeFileIdsFunction final
: public mozIStorageFunction
{
2267 SafeRefPtr
<DatabaseFileManager
> mFileManager
;
2270 UpgradeFileIdsFunction() { AssertIsOnIOThread(); }
2272 nsresult
Init(nsIFile
* aFMDirectory
, mozIStorageConnection
& aConnection
);
2277 ~UpgradeFileIdsFunction() {
2278 AssertIsOnIOThread();
2281 mFileManager
->Invalidate();
2286 OnFunctionCall(mozIStorageValueArray
* aArguments
,
2287 nsIVariant
** aResult
) override
;
2290 nsresult
UpgradeSchemaFrom19_0To20_0(nsIFile
* aFMDirectory
,
2291 mozIStorageConnection
& aConnection
) {
2292 AssertIsOnIOThread();
2294 AUTO_PROFILER_LABEL("UpgradeSchemaFrom19_0To20_0", DOM
);
2296 nsCOMPtr
<mozIStorageStatement
> stmt
;
2297 nsresult rv
= aConnection
.CreateStatement(
2300 "WHERE file_ids IS NOT NULL"_ns
,
2301 getter_AddRefs(stmt
));
2302 if (NS_WARN_IF(NS_FAILED(rv
))) {
2309 mozStorageStatementScoper
scoper(stmt
);
2311 QM_TRY_INSPECT(const bool& hasResult
,
2312 MOZ_TO_RESULT_INVOKE(stmt
, ExecuteStep
));
2314 if (NS_WARN_IF(!hasResult
)) {
2315 MOZ_ASSERT(false, "This should never be possible!");
2316 return NS_ERROR_FAILURE
;
2319 count
= stmt
->AsInt64(0);
2320 if (NS_WARN_IF(count
< 0)) {
2321 MOZ_ASSERT(false, "This should never be possible!");
2322 return NS_ERROR_FAILURE
;
2327 // Nothing to upgrade.
2328 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(20, 0));
2329 if (NS_WARN_IF(NS_FAILED(rv
))) {
2336 RefPtr
<UpgradeFileIdsFunction
> function
= new UpgradeFileIdsFunction();
2338 rv
= function
->Init(aFMDirectory
, aConnection
);
2339 if (NS_WARN_IF(NS_FAILED(rv
))) {
2343 constexpr auto functionName
= "upgrade"_ns
;
2345 rv
= aConnection
.CreateFunction(functionName
, 2, function
);
2346 if (NS_WARN_IF(NS_FAILED(rv
))) {
2350 // Disable update trigger.
2351 rv
= aConnection
.ExecuteSimpleSQL(
2352 "DROP TRIGGER object_data_update_trigger;"_ns
);
2353 if (NS_WARN_IF(NS_FAILED(rv
))) {
2357 rv
= aConnection
.ExecuteSimpleSQL(
2358 "UPDATE object_data "
2359 "SET file_ids = upgrade(file_ids, data) "
2360 "WHERE file_ids IS NOT NULL;"_ns
);
2361 if (NS_WARN_IF(NS_FAILED(rv
))) {
2365 // Enable update trigger.
2366 rv
= aConnection
.ExecuteSimpleSQL(
2367 "CREATE TRIGGER object_data_update_trigger "
2368 "AFTER UPDATE OF file_ids ON object_data "
2370 "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
2372 "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
2374 if (NS_WARN_IF(NS_FAILED(rv
))) {
2378 rv
= aConnection
.RemoveFunction(functionName
);
2379 if (NS_WARN_IF(NS_FAILED(rv
))) {
2383 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(20, 0));
2384 if (NS_WARN_IF(NS_FAILED(rv
))) {
2391 class UpgradeIndexDataValuesFunction final
: public mozIStorageFunction
{
2393 UpgradeIndexDataValuesFunction() { AssertIsOnIOThread(); }
2398 ~UpgradeIndexDataValuesFunction() { AssertIsOnIOThread(); }
2400 using IndexDataValuesArray
= IndexDataValuesAutoArray
;
2401 Result
<IndexDataValuesArray
, nsresult
> ReadOldCompressedIDVFromBlob(
2402 Span
<const uint8_t> aBlobData
);
2405 OnFunctionCall(mozIStorageValueArray
* aArguments
,
2406 nsIVariant
** aResult
) override
;
2409 NS_IMPL_ISUPPORTS(UpgradeIndexDataValuesFunction
, mozIStorageFunction
)
2411 Result
<UpgradeIndexDataValuesFunction::IndexDataValuesArray
, nsresult
>
2412 UpgradeIndexDataValuesFunction::ReadOldCompressedIDVFromBlob(
2413 const Span
<const uint8_t> aBlobData
) {
2414 MOZ_ASSERT(!NS_IsMainThread());
2415 MOZ_ASSERT(!IsOnBackgroundThread());
2417 IndexOrObjectStoreId indexId
;
2419 bool nextIndexIdAlreadyRead
= false;
2421 IndexDataValuesArray result
;
2422 for (auto remainder
= aBlobData
; !remainder
.IsEmpty();) {
2423 if (!nextIndexIdAlreadyRead
) {
2424 QM_TRY_UNWRAP((std::tie(indexId
, unique
, remainder
)),
2425 ReadCompressedIndexId(remainder
));
2427 nextIndexIdAlreadyRead
= false;
2429 if (NS_WARN_IF(remainder
.IsEmpty())) {
2430 IDB_REPORT_INTERNAL_ERR();
2431 return Err(NS_ERROR_FILE_CORRUPTED
);
2434 // Read key buffer length.
2436 (const auto& [keyBufferLength
, remainderAfterKeyBufferLength
]),
2437 ReadCompressedNumber(remainder
));
2439 if (NS_WARN_IF(remainderAfterKeyBufferLength
.IsEmpty()) ||
2440 NS_WARN_IF(keyBufferLength
> uint64_t(UINT32_MAX
)) ||
2441 NS_WARN_IF(keyBufferLength
> remainderAfterKeyBufferLength
.Length())) {
2442 IDB_REPORT_INTERNAL_ERR();
2443 return Err(NS_ERROR_FILE_CORRUPTED
);
2446 const auto [keyBuffer
, remainderAfterKeyBuffer
] =
2447 remainderAfterKeyBufferLength
.SplitAt(keyBufferLength
);
2448 if (NS_WARN_IF(!result
.EmplaceBack(fallible
, indexId
, unique
,
2449 Key
{nsCString
{AsChars(keyBuffer
)}}))) {
2450 IDB_REPORT_INTERNAL_ERR();
2451 return Err(NS_ERROR_OUT_OF_MEMORY
);
2454 remainder
= remainderAfterKeyBuffer
;
2455 if (!remainder
.IsEmpty()) {
2456 // Read either a sort key buffer length or an index id.
2457 QM_TRY_INSPECT((const auto& [maybeIndexId
, remainderAfterIndexId
]),
2458 ReadCompressedNumber(remainder
));
2460 // Locale-aware indexes haven't been around long enough to have any users,
2461 // we can safely assume all sort key buffer lengths will be zero.
2462 // XXX This duplicates logic from ReadCompressedIndexId.
2463 if (maybeIndexId
!= 0) {
2464 unique
= maybeIndexId
% 2 == 1;
2465 indexId
= maybeIndexId
/ 2;
2466 nextIndexIdAlreadyRead
= true;
2469 remainder
= remainderAfterIndexId
;
2478 UpgradeIndexDataValuesFunction::OnFunctionCall(
2479 mozIStorageValueArray
* aArguments
, nsIVariant
** aResult
) {
2480 MOZ_ASSERT(aArguments
);
2481 MOZ_ASSERT(aResult
);
2483 AUTO_PROFILER_LABEL("UpgradeIndexDataValuesFunction::OnFunctionCall", DOM
);
2486 nsresult rv
= aArguments
->GetNumEntries(&argc
);
2487 if (NS_WARN_IF(NS_FAILED(rv
))) {
2492 NS_WARNING("Don't call me with the wrong number of arguments!");
2493 return NS_ERROR_UNEXPECTED
;
2497 rv
= aArguments
->GetTypeOfIndex(0, &type
);
2498 if (NS_WARN_IF(NS_FAILED(rv
))) {
2502 if (type
!= mozIStorageStatement::VALUE_TYPE_BLOB
) {
2503 NS_WARNING("Don't call me with the wrong type of arguments!");
2504 return NS_ERROR_UNEXPECTED
;
2507 const uint8_t* oldBlob
;
2508 uint32_t oldBlobLength
;
2509 rv
= aArguments
->GetSharedBlob(0, &oldBlobLength
, &oldBlob
);
2510 if (NS_WARN_IF(NS_FAILED(rv
))) {
2514 QM_TRY_INSPECT(const auto& oldIdv
,
2515 ReadOldCompressedIDVFromBlob(Span(oldBlob
, oldBlobLength
)));
2517 QM_TRY_UNWRAP((auto [newIdv
, newIdvLength
]),
2518 MakeCompressedIndexDataValues(oldIdv
));
2520 nsCOMPtr
<nsIVariant
> result
= new storage::AdoptedBlobVariant(
2521 std::pair(newIdv
.release(), newIdvLength
));
2523 result
.forget(aResult
);
2527 nsresult
UpgradeSchemaFrom20_0To21_0(mozIStorageConnection
& aConnection
) {
2528 // This should have been part of the 18 to 19 upgrade, where we changed the
2529 // layout of the index_data_values blobs but didn't upgrade the existing data.
2532 AssertIsOnIOThread();
2534 AUTO_PROFILER_LABEL("UpgradeSchemaFrom20_0To21_0", DOM
);
2536 RefPtr
<UpgradeIndexDataValuesFunction
> function
=
2537 new UpgradeIndexDataValuesFunction();
2539 constexpr auto functionName
= "upgrade_idv"_ns
;
2541 nsresult rv
= aConnection
.CreateFunction(functionName
, 1, function
);
2542 if (NS_WARN_IF(NS_FAILED(rv
))) {
2546 rv
= aConnection
.ExecuteSimpleSQL(
2547 "UPDATE object_data "
2548 "SET index_data_values = upgrade_idv(index_data_values) "
2549 "WHERE index_data_values IS NOT NULL;"_ns
);
2550 if (NS_WARN_IF(NS_FAILED(rv
))) {
2554 rv
= aConnection
.RemoveFunction(functionName
);
2555 if (NS_WARN_IF(NS_FAILED(rv
))) {
2559 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(21, 0));
2560 if (NS_WARN_IF(NS_FAILED(rv
))) {
2567 nsresult
UpgradeSchemaFrom21_0To22_0(mozIStorageConnection
& aConnection
) {
2568 // The only change between 21 and 22 was a different structured clone format,
2569 // but it's backwards-compatible.
2570 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(22, 0));
2571 if (NS_WARN_IF(NS_FAILED(rv
))) {
2578 nsresult
UpgradeSchemaFrom22_0To23_0(mozIStorageConnection
& aConnection
,
2579 const nsACString
& aOrigin
) {
2580 AssertIsOnIOThread();
2582 MOZ_ASSERT(!aOrigin
.IsEmpty());
2584 AUTO_PROFILER_LABEL("UpgradeSchemaFrom22_0To23_0", DOM
);
2586 nsCOMPtr
<mozIStorageStatement
> stmt
;
2587 // The parameter names are not used, parameters are bound by index only
2588 // locally in the same function.
2589 nsresult rv
= aConnection
.CreateStatement(
2590 "UPDATE database SET origin = :origin;"_ns
, getter_AddRefs(stmt
));
2591 if (NS_WARN_IF(NS_FAILED(rv
))) {
2595 rv
= stmt
->BindUTF8StringByIndex(0, aOrigin
);
2596 if (NS_WARN_IF(NS_FAILED(rv
))) {
2600 rv
= stmt
->Execute();
2601 if (NS_WARN_IF(NS_FAILED(rv
))) {
2605 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(23, 0));
2606 if (NS_WARN_IF(NS_FAILED(rv
))) {
2613 nsresult
UpgradeSchemaFrom23_0To24_0(mozIStorageConnection
& aConnection
) {
2614 // The only change between 23 and 24 was a different structured clone format,
2615 // but it's backwards-compatible.
2616 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(24, 0));
2617 if (NS_WARN_IF(NS_FAILED(rv
))) {
2624 nsresult
UpgradeSchemaFrom24_0To25_0(mozIStorageConnection
& aConnection
) {
2625 // The changes between 24 and 25 were an upgraded snappy library, a different
2626 // structured clone format and a different file_ds format. But everything is
2627 // backwards-compatible.
2628 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(25, 0));
2629 if (NS_WARN_IF(NS_FAILED(rv
))) {
2636 class StripObsoleteOriginAttributesFunction final
: public mozIStorageFunction
{
2641 ~StripObsoleteOriginAttributesFunction() = default;
2644 OnFunctionCall(mozIStorageValueArray
* aArguments
,
2645 nsIVariant
** aResult
) override
{
2646 MOZ_ASSERT(aArguments
);
2647 MOZ_ASSERT(aResult
);
2649 AUTO_PROFILER_LABEL("StripObsoleteOriginAttributesFunction::OnFunctionCall",
2655 MOZ_ALWAYS_SUCCEEDS(aArguments
->GetNumEntries(&argCount
));
2656 MOZ_ASSERT(argCount
== 1);
2659 MOZ_ALWAYS_SUCCEEDS(aArguments
->GetTypeOfIndex(0, &type
));
2660 MOZ_ASSERT(type
== mozIStorageValueArray::VALUE_TYPE_TEXT
);
2665 nsresult rv
= aArguments
->GetUTF8String(0, origin
);
2666 if (NS_WARN_IF(NS_FAILED(rv
))) {
2670 // Deserialize and re-serialize to automatically drop any obsolete origin
2672 OriginAttributes oa
;
2674 nsCString originNoSuffix
;
2675 bool ok
= oa
.PopulateFromOrigin(origin
, originNoSuffix
);
2676 if (NS_WARN_IF(!ok
)) {
2677 return NS_ERROR_FAILURE
;
2681 oa
.CreateSuffix(suffix
);
2683 nsCOMPtr
<nsIVariant
> result
=
2684 new mozilla::storage::UTF8TextVariant(originNoSuffix
+ suffix
);
2686 result
.forget(aResult
);
2691 nsresult
UpgradeSchemaFrom25_0To26_0(mozIStorageConnection
& aConnection
) {
2692 AssertIsOnIOThread();
2694 AUTO_PROFILER_LABEL("UpgradeSchemaFrom25_0To26_0", DOM
);
2696 constexpr auto functionName
= "strip_obsolete_attributes"_ns
;
2698 nsCOMPtr
<mozIStorageFunction
> stripObsoleteAttributes
=
2699 new StripObsoleteOriginAttributesFunction();
2701 nsresult rv
= aConnection
.CreateFunction(functionName
,
2702 /* aNumArguments */ 1,
2703 stripObsoleteAttributes
);
2704 if (NS_WARN_IF(NS_FAILED(rv
))) {
2708 rv
= aConnection
.ExecuteSimpleSQL(
2710 "SET origin = strip_obsolete_attributes(origin) "
2711 "WHERE origin LIKE '%^%';"_ns
);
2712 if (NS_WARN_IF(NS_FAILED(rv
))) {
2716 rv
= aConnection
.RemoveFunction(functionName
);
2717 if (NS_WARN_IF(NS_FAILED(rv
))) {
2721 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(26, 0));
2722 if (NS_WARN_IF(NS_FAILED(rv
))) {
2729 NS_IMPL_ISUPPORTS(CompressDataBlobsFunction
, mozIStorageFunction
)
2730 NS_IMPL_ISUPPORTS(EncodeKeysFunction
, mozIStorageFunction
)
2731 NS_IMPL_ISUPPORTS(StripObsoleteOriginAttributesFunction
, mozIStorageFunction
);
2733 class DeserializeUpgradeValueHelper final
: public Runnable
{
2735 explicit DeserializeUpgradeValueHelper(
2736 StructuredCloneReadInfoParent
& aCloneReadInfo
)
2737 : Runnable("DeserializeUpgradeValueHelper"),
2738 mMonitor("DeserializeUpgradeValueHelper::mMonitor"),
2739 mCloneReadInfo(aCloneReadInfo
),
2740 mStatus(NS_ERROR_FAILURE
) {}
2742 nsresult
DispatchAndWait(nsAString
& aFileIds
) {
2743 // We don't need to go to the main-thread and use the sandbox.
2744 if (!mCloneReadInfo
.Data().Size()) {
2745 PopulateFileIds(aFileIds
);
2749 // The operation will continue on the main-thread.
2751 MOZ_ASSERT(!(mCloneReadInfo
.Data().Size() % sizeof(uint64_t)));
2753 MonitorAutoLock
lock(mMonitor
);
2755 RefPtr
<Runnable
> self
= this;
2757 SchedulerGroup::Dispatch(TaskCategory::Other
, self
.forget());
2758 if (NS_WARN_IF(NS_FAILED(rv
))) {
2764 if (NS_FAILED(mStatus
)) {
2768 PopulateFileIds(aFileIds
);
2774 MOZ_ASSERT(NS_IsMainThread());
2778 JSContext
* cx
= jsapi
.cx();
2780 JS::Rooted
<JSObject
*> global(cx
, GetSandbox(cx
));
2781 if (NS_WARN_IF(!global
)) {
2782 OperationCompleted(NS_ERROR_FAILURE
);
2786 const JSAutoRealm
ar(cx
, global
);
2788 JS::Rooted
<JS::Value
> value(cx
);
2789 const nsresult rv
= DeserializeUpgradeValue(cx
, &value
);
2790 if (NS_WARN_IF(NS_FAILED(rv
))) {
2791 OperationCompleted(rv
);
2795 OperationCompleted(NS_OK
);
2800 nsresult
DeserializeUpgradeValue(JSContext
* aCx
,
2801 JS::MutableHandle
<JS::Value
> aValue
) {
2802 static const JSStructuredCloneCallbacks callbacks
= {
2803 StructuredCloneReadCallback
<StructuredCloneReadInfoParent
>,
2812 if (!JS_ReadStructuredClone(
2813 aCx
, mCloneReadInfo
.Data(), JS_STRUCTURED_CLONE_VERSION
,
2814 JS::StructuredCloneScope::DifferentProcessForIndexedDB
, aValue
,
2815 JS::CloneDataPolicy(), &callbacks
, &mCloneReadInfo
)) {
2816 return NS_ERROR_DOM_DATA_CLONE_ERR
;
2822 void PopulateFileIds(nsAString
& aFileIds
) {
2823 for (uint32_t count
= mCloneReadInfo
.Files().Length(), index
= 0;
2824 index
< count
; index
++) {
2825 const StructuredCloneFileParent
& file
= mCloneReadInfo
.Files()[index
];
2827 const int64_t id
= file
.FileInfo().Id();
2830 aFileIds
.Append(' ');
2832 aFileIds
.AppendInt(file
.Type() == StructuredCloneFileBase::eBlob
? id
2837 void OperationCompleted(nsresult aStatus
) {
2840 MonitorAutoLock
lock(mMonitor
);
2845 StructuredCloneReadInfoParent
& mCloneReadInfo
;
2849 nsresult
DeserializeUpgradeValueToFileIds(
2850 StructuredCloneReadInfoParent
& aCloneReadInfo
, nsAString
& aFileIds
) {
2851 MOZ_ASSERT(!NS_IsMainThread());
2853 const RefPtr
<DeserializeUpgradeValueHelper
> helper
=
2854 new DeserializeUpgradeValueHelper(aCloneReadInfo
);
2855 return helper
->DispatchAndWait(aFileIds
);
2858 nsresult
UpgradeFileIdsFunction::Init(nsIFile
* aFMDirectory
,
2859 mozIStorageConnection
& aConnection
) {
2860 // This DatabaseFileManager doesn't need real origin info, etc. The only
2861 // purpose is to store file ids without adding more complexity or code
2863 auto fileManager
= MakeSafeRefPtr
<DatabaseFileManager
>(
2864 PERSISTENCE_TYPE_INVALID
, quota::OriginMetadata
{}, u
""_ns
, false);
2866 nsresult rv
= fileManager
->Init(aFMDirectory
, aConnection
);
2867 if (NS_WARN_IF(NS_FAILED(rv
))) {
2871 mFileManager
= std::move(fileManager
);
2875 NS_IMPL_ISUPPORTS(UpgradeFileIdsFunction
, mozIStorageFunction
)
2878 UpgradeFileIdsFunction::OnFunctionCall(mozIStorageValueArray
* aArguments
,
2879 nsIVariant
** aResult
) {
2880 MOZ_ASSERT(aArguments
);
2881 MOZ_ASSERT(aResult
);
2882 MOZ_ASSERT(mFileManager
);
2884 AUTO_PROFILER_LABEL("UpgradeFileIdsFunction::OnFunctionCall", DOM
);
2887 nsresult rv
= aArguments
->GetNumEntries(&argc
);
2888 if (NS_WARN_IF(NS_FAILED(rv
))) {
2893 NS_WARNING("Don't call me with the wrong number of arguments!");
2894 return NS_ERROR_UNEXPECTED
;
2897 QM_TRY_UNWRAP(auto cloneInfo
,
2898 GetStructuredCloneReadInfoFromValueArray(
2899 aArguments
, 1, 0, *mFileManager
, Nothing
{}));
2901 nsAutoString fileIds
;
2902 // XXX does this really need non-const cloneInfo?
2903 rv
= DeserializeUpgradeValueToFileIds(cloneInfo
, fileIds
);
2904 if (NS_WARN_IF(NS_FAILED(rv
))) {
2905 return NS_ERROR_DOM_DATA_CLONE_ERR
;
2908 nsCOMPtr
<nsIVariant
> result
= new mozilla::storage::TextVariant(fileIds
);
2910 result
.forget(aResult
);
2916 Result
<bool, nsresult
> MaybeUpgradeSchema(mozIStorageConnection
& aConnection
,
2917 const int32_t aSchemaVersion
,
2918 nsIFile
& aFMDirectory
,
2919 const nsACString
& aOrigin
) {
2920 bool vacuumNeeded
= false;
2921 int32_t schemaVersion
= aSchemaVersion
;
2923 // This logic needs to change next time we change the schema!
2924 static_assert(kSQLiteSchemaVersion
== int32_t((26 << 4) + 0),
2925 "Upgrade function needed due to schema version increase.");
2927 while (schemaVersion
!= kSQLiteSchemaVersion
) {
2928 switch (schemaVersion
) {
2930 QM_TRY(UpgradeSchemaFrom4To5(aConnection
));
2933 QM_TRY(UpgradeSchemaFrom5To6(aConnection
));
2936 QM_TRY(UpgradeSchemaFrom6To7(aConnection
));
2939 QM_TRY(UpgradeSchemaFrom7To8(aConnection
));
2942 QM_TRY(UpgradeSchemaFrom8To9_0(aConnection
));
2943 vacuumNeeded
= true;
2945 case MakeSchemaVersion(9, 0):
2946 QM_TRY(UpgradeSchemaFrom9_0To10_0(aConnection
));
2948 case MakeSchemaVersion(10, 0):
2949 QM_TRY(UpgradeSchemaFrom10_0To11_0(aConnection
));
2951 case MakeSchemaVersion(11, 0):
2952 QM_TRY(UpgradeSchemaFrom11_0To12_0(aConnection
));
2954 case MakeSchemaVersion(12, 0):
2955 QM_TRY(UpgradeSchemaFrom12_0To13_0(aConnection
, &vacuumNeeded
));
2957 case MakeSchemaVersion(13, 0):
2958 QM_TRY(UpgradeSchemaFrom13_0To14_0(aConnection
));
2960 case MakeSchemaVersion(14, 0):
2961 QM_TRY(UpgradeSchemaFrom14_0To15_0(aConnection
));
2963 case MakeSchemaVersion(15, 0):
2964 QM_TRY(UpgradeSchemaFrom15_0To16_0(aConnection
));
2966 case MakeSchemaVersion(16, 0):
2967 QM_TRY(UpgradeSchemaFrom16_0To17_0(aConnection
));
2969 case MakeSchemaVersion(17, 0):
2970 QM_TRY(UpgradeSchemaFrom17_0To18_0(aConnection
, aOrigin
));
2971 vacuumNeeded
= true;
2973 case MakeSchemaVersion(18, 0):
2974 QM_TRY(UpgradeSchemaFrom18_0To19_0(aConnection
));
2976 case MakeSchemaVersion(19, 0):
2977 QM_TRY(UpgradeSchemaFrom19_0To20_0(&aFMDirectory
, aConnection
));
2979 case MakeSchemaVersion(20, 0):
2980 QM_TRY(UpgradeSchemaFrom20_0To21_0(aConnection
));
2982 case MakeSchemaVersion(21, 0):
2983 QM_TRY(UpgradeSchemaFrom21_0To22_0(aConnection
));
2985 case MakeSchemaVersion(22, 0):
2986 QM_TRY(UpgradeSchemaFrom22_0To23_0(aConnection
, aOrigin
));
2988 case MakeSchemaVersion(23, 0):
2989 QM_TRY(UpgradeSchemaFrom23_0To24_0(aConnection
));
2991 case MakeSchemaVersion(24, 0):
2992 QM_TRY(UpgradeSchemaFrom24_0To25_0(aConnection
));
2994 case MakeSchemaVersion(25, 0):
2995 QM_TRY(UpgradeSchemaFrom25_0To26_0(aConnection
));
2998 QM_FAIL(Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
), []() {
3000 "Unable to open IndexedDB database, no upgrade path is "
3005 QM_TRY_UNWRAP(schemaVersion
,
3006 MOZ_TO_RESULT_INVOKE(aConnection
, GetSchemaVersion
));
3009 MOZ_ASSERT(schemaVersion
== kSQLiteSchemaVersion
);
3011 return vacuumNeeded
;
3014 } // namespace mozilla::dom::indexedDB