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/UniquePtr.h"
46 #include "mozilla/dom/ScriptSettings.h"
47 #include "mozilla/dom/indexedDB/IDBResult.h"
48 #include "mozilla/dom/indexedDB/Key.h"
49 #include "mozilla/dom/quota/Assertions.h"
50 #include "mozilla/dom/quota/PersistenceType.h"
51 #include "mozilla/dom/quota/QuotaCommon.h"
52 #include "mozilla/dom/quota/ResultExtensions.h"
53 #include "mozilla/fallible.h"
54 #include "mozilla/ipc/BackgroundParent.h"
55 #include "mozilla/mozalloc.h"
56 #include "mozilla/ProfilerLabels.h"
57 #include "mozilla/storage/Variant.h"
61 #include "nsISupports.h"
62 #include "nsIVariant.h"
63 #include "nsLiteralString.h"
66 #include "nsTLiteralString.h"
67 #include "nsTStringRepr.h"
68 #include "nsThreadUtils.h"
70 #include "snappy/snappy.h"
75 #if defined(MOZ_WIDGET_ANDROID)
79 namespace mozilla::dom::indexedDB
{
81 using mozilla::ipc::IsOnBackgroundThread
;
82 using quota::AssertIsOnIOThread
;
83 using quota::PERSISTENCE_TYPE_INVALID
;
87 nsresult
UpgradeSchemaFrom4To5(mozIStorageConnection
& aConnection
) {
90 AUTO_PROFILER_LABEL("UpgradeSchemaFrom4To5", DOM
);
94 // All we changed is the type of the version column, so lets try to
95 // convert that to an integer, and if we fail, set it to 0.
96 nsCOMPtr
<mozIStorageStatement
> stmt
;
97 rv
= aConnection
.CreateStatement(
98 "SELECT name, version, dataVersion "
100 getter_AddRefs(stmt
));
101 if (NS_WARN_IF(NS_FAILED(rv
))) {
110 mozStorageStatementScoper
scoper(stmt
);
112 QM_TRY_INSPECT(const bool& hasResults
,
113 MOZ_TO_RESULT_INVOKE_MEMBER(stmt
, ExecuteStep
));
115 if (NS_WARN_IF(!hasResults
)) {
116 return NS_ERROR_FAILURE
;
120 rv
= stmt
->GetString(1, version
);
121 if (NS_WARN_IF(NS_FAILED(rv
))) {
125 intVersion
= version
.ToInteger(&rv
);
130 rv
= stmt
->GetString(0, name
);
131 if (NS_WARN_IF(NS_FAILED(rv
))) {
135 rv
= stmt
->GetInt64(2, &dataVersion
);
136 if (NS_WARN_IF(NS_FAILED(rv
))) {
141 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE database"_ns
);
142 if (NS_WARN_IF(NS_FAILED(rv
))) {
146 rv
= aConnection
.ExecuteSimpleSQL(
147 "CREATE TABLE database ("
148 "name TEXT NOT NULL, "
149 "version INTEGER NOT NULL DEFAULT 0, "
150 "dataVersion INTEGER NOT NULL"
152 if (NS_WARN_IF(NS_FAILED(rv
))) {
156 // The parameter names are not used, parameters are bound by index only
157 // locally in the same function.
158 rv
= aConnection
.CreateStatement(
159 "INSERT INTO database (name, version, dataVersion) "
160 "VALUES (:name, :version, :dataVersion)"_ns
,
161 getter_AddRefs(stmt
));
162 if (NS_WARN_IF(NS_FAILED(rv
))) {
167 mozStorageStatementScoper
scoper(stmt
);
169 rv
= stmt
->BindStringByIndex(0, name
);
170 if (NS_WARN_IF(NS_FAILED(rv
))) {
174 rv
= stmt
->BindInt32ByIndex(1, intVersion
);
175 if (NS_WARN_IF(NS_FAILED(rv
))) {
179 rv
= stmt
->BindInt64ByIndex(2, dataVersion
);
180 if (NS_WARN_IF(NS_FAILED(rv
))) {
184 rv
= stmt
->Execute();
185 if (NS_WARN_IF(NS_FAILED(rv
))) {
190 rv
= aConnection
.SetSchemaVersion(5);
191 if (NS_WARN_IF(NS_FAILED(rv
))) {
198 nsresult
UpgradeSchemaFrom5To6(mozIStorageConnection
& aConnection
) {
199 AssertIsOnIOThread();
201 AUTO_PROFILER_LABEL("UpgradeSchemaFrom5To6", DOM
);
203 // First, drop all the indexes we're no longer going to use.
204 nsresult rv
= aConnection
.ExecuteSimpleSQL("DROP INDEX key_index;"_ns
);
205 if (NS_WARN_IF(NS_FAILED(rv
))) {
209 rv
= aConnection
.ExecuteSimpleSQL("DROP INDEX ai_key_index;"_ns
);
210 if (NS_WARN_IF(NS_FAILED(rv
))) {
214 rv
= aConnection
.ExecuteSimpleSQL("DROP INDEX value_index;"_ns
);
215 if (NS_WARN_IF(NS_FAILED(rv
))) {
219 rv
= aConnection
.ExecuteSimpleSQL("DROP INDEX ai_value_index;"_ns
);
220 if (NS_WARN_IF(NS_FAILED(rv
))) {
224 // Now, reorder the columns of object_data to put the blob data last. We do
225 // this by copying into a temporary table, dropping the original, then copying
226 // back into a newly created table.
227 rv
= aConnection
.ExecuteSimpleSQL(
228 "CREATE TEMPORARY TABLE temp_upgrade ("
229 "id INTEGER PRIMARY KEY, "
234 if (NS_WARN_IF(NS_FAILED(rv
))) {
238 rv
= aConnection
.ExecuteSimpleSQL(
239 "INSERT INTO temp_upgrade "
240 "SELECT id, object_store_id, key_value, data "
241 "FROM object_data;"_ns
);
242 if (NS_WARN_IF(NS_FAILED(rv
))) {
246 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_data;"_ns
);
247 if (NS_WARN_IF(NS_FAILED(rv
))) {
251 rv
= aConnection
.ExecuteSimpleSQL(
252 "CREATE TABLE object_data ("
253 "id INTEGER PRIMARY KEY, "
254 "object_store_id INTEGER NOT NULL, "
255 "key_value DEFAULT NULL, "
256 "data BLOB NOT NULL, "
257 "UNIQUE (object_store_id, key_value), "
258 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
261 if (NS_WARN_IF(NS_FAILED(rv
))) {
265 rv
= aConnection
.ExecuteSimpleSQL(
266 "INSERT INTO object_data "
267 "SELECT id, object_store_id, key_value, data "
268 "FROM temp_upgrade;"_ns
);
269 if (NS_WARN_IF(NS_FAILED(rv
))) {
273 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
274 if (NS_WARN_IF(NS_FAILED(rv
))) {
278 // We need to add a unique constraint to our ai_object_data table. Copy all
279 // the data out of it using a temporary table as before.
280 rv
= aConnection
.ExecuteSimpleSQL(
281 "CREATE TEMPORARY TABLE temp_upgrade ("
282 "id INTEGER PRIMARY KEY, "
286 if (NS_WARN_IF(NS_FAILED(rv
))) {
290 rv
= aConnection
.ExecuteSimpleSQL(
291 "INSERT INTO temp_upgrade "
292 "SELECT id, object_store_id, data "
293 "FROM ai_object_data;"_ns
);
294 if (NS_WARN_IF(NS_FAILED(rv
))) {
298 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE ai_object_data;"_ns
);
299 if (NS_WARN_IF(NS_FAILED(rv
))) {
303 rv
= aConnection
.ExecuteSimpleSQL(
304 "CREATE TABLE ai_object_data ("
305 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
306 "object_store_id INTEGER NOT NULL, "
307 "data BLOB NOT NULL, "
308 "UNIQUE (object_store_id, id), "
309 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
312 if (NS_WARN_IF(NS_FAILED(rv
))) {
316 rv
= aConnection
.ExecuteSimpleSQL(
317 "INSERT INTO ai_object_data "
318 "SELECT id, object_store_id, data "
319 "FROM temp_upgrade;"_ns
);
320 if (NS_WARN_IF(NS_FAILED(rv
))) {
324 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
325 if (NS_WARN_IF(NS_FAILED(rv
))) {
329 // Fix up the index_data table. We're reordering the columns as well as
330 // changing the primary key from being a simple id to being a composite.
331 rv
= aConnection
.ExecuteSimpleSQL(
332 "CREATE TEMPORARY TABLE temp_upgrade ("
338 if (NS_WARN_IF(NS_FAILED(rv
))) {
342 rv
= aConnection
.ExecuteSimpleSQL(
343 "INSERT INTO temp_upgrade "
344 "SELECT index_id, value, object_data_key, object_data_id "
345 "FROM index_data;"_ns
);
346 if (NS_WARN_IF(NS_FAILED(rv
))) {
350 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE index_data;"_ns
);
351 if (NS_WARN_IF(NS_FAILED(rv
))) {
355 rv
= aConnection
.ExecuteSimpleSQL(
356 "CREATE TABLE index_data ("
357 "index_id INTEGER NOT NULL, "
359 "object_data_key NOT NULL, "
360 "object_data_id INTEGER NOT NULL, "
361 "PRIMARY KEY (index_id, value, object_data_key), "
362 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
364 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
367 if (NS_WARN_IF(NS_FAILED(rv
))) {
371 rv
= aConnection
.ExecuteSimpleSQL(
372 "INSERT OR IGNORE INTO index_data "
373 "SELECT index_id, value, object_data_key, object_data_id "
374 "FROM temp_upgrade;"_ns
);
375 if (NS_WARN_IF(NS_FAILED(rv
))) {
379 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
380 if (NS_WARN_IF(NS_FAILED(rv
))) {
384 rv
= aConnection
.ExecuteSimpleSQL(
385 "CREATE INDEX index_data_object_data_id_index "
386 "ON index_data (object_data_id);"_ns
);
387 if (NS_WARN_IF(NS_FAILED(rv
))) {
391 // Fix up the unique_index_data table. We're reordering the columns as well as
392 // changing the primary key from being a simple id to being a composite.
393 rv
= aConnection
.ExecuteSimpleSQL(
394 "CREATE TEMPORARY TABLE temp_upgrade ("
400 if (NS_WARN_IF(NS_FAILED(rv
))) {
404 rv
= aConnection
.ExecuteSimpleSQL(
405 "INSERT INTO temp_upgrade "
406 "SELECT index_id, value, object_data_key, object_data_id "
407 "FROM unique_index_data;"_ns
);
408 if (NS_WARN_IF(NS_FAILED(rv
))) {
412 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE unique_index_data;"_ns
);
413 if (NS_WARN_IF(NS_FAILED(rv
))) {
417 rv
= aConnection
.ExecuteSimpleSQL(
418 "CREATE TABLE unique_index_data ("
419 "index_id INTEGER NOT NULL, "
421 "object_data_key NOT NULL, "
422 "object_data_id INTEGER NOT NULL, "
423 "PRIMARY KEY (index_id, value, object_data_key), "
424 "UNIQUE (index_id, value), "
425 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
427 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
430 if (NS_WARN_IF(NS_FAILED(rv
))) {
434 rv
= aConnection
.ExecuteSimpleSQL(
435 "INSERT INTO unique_index_data "
436 "SELECT index_id, value, object_data_key, object_data_id "
437 "FROM temp_upgrade;"_ns
);
438 if (NS_WARN_IF(NS_FAILED(rv
))) {
442 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
443 if (NS_WARN_IF(NS_FAILED(rv
))) {
447 rv
= aConnection
.ExecuteSimpleSQL(
448 "CREATE INDEX unique_index_data_object_data_id_index "
449 "ON unique_index_data (object_data_id);"_ns
);
450 if (NS_WARN_IF(NS_FAILED(rv
))) {
454 // Fix up the ai_index_data table. We're reordering the columns as well as
455 // changing the primary key from being a simple id to being a composite.
456 rv
= aConnection
.ExecuteSimpleSQL(
457 "CREATE TEMPORARY TABLE temp_upgrade ("
462 if (NS_WARN_IF(NS_FAILED(rv
))) {
466 rv
= aConnection
.ExecuteSimpleSQL(
467 "INSERT INTO temp_upgrade "
468 "SELECT index_id, value, ai_object_data_id "
469 "FROM ai_index_data;"_ns
);
470 if (NS_WARN_IF(NS_FAILED(rv
))) {
474 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE ai_index_data;"_ns
);
475 if (NS_WARN_IF(NS_FAILED(rv
))) {
479 rv
= aConnection
.ExecuteSimpleSQL(
480 "CREATE TABLE ai_index_data ("
481 "index_id INTEGER NOT NULL, "
483 "ai_object_data_id INTEGER NOT NULL, "
484 "PRIMARY KEY (index_id, value, ai_object_data_id), "
485 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
487 "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
490 if (NS_WARN_IF(NS_FAILED(rv
))) {
494 rv
= aConnection
.ExecuteSimpleSQL(
495 "INSERT OR IGNORE INTO ai_index_data "
496 "SELECT index_id, value, ai_object_data_id "
497 "FROM temp_upgrade;"_ns
);
498 if (NS_WARN_IF(NS_FAILED(rv
))) {
502 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
503 if (NS_WARN_IF(NS_FAILED(rv
))) {
507 rv
= aConnection
.ExecuteSimpleSQL(
508 "CREATE INDEX ai_index_data_ai_object_data_id_index "
509 "ON ai_index_data (ai_object_data_id);"_ns
);
510 if (NS_WARN_IF(NS_FAILED(rv
))) {
514 // Fix up the ai_unique_index_data table. We're reordering the columns as well
515 // as changing the primary key from being a simple id to being a composite.
516 rv
= aConnection
.ExecuteSimpleSQL(
517 "CREATE TEMPORARY TABLE temp_upgrade ("
522 if (NS_WARN_IF(NS_FAILED(rv
))) {
526 rv
= aConnection
.ExecuteSimpleSQL(
527 "INSERT INTO temp_upgrade "
528 "SELECT index_id, value, ai_object_data_id "
529 "FROM ai_unique_index_data;"_ns
);
530 if (NS_WARN_IF(NS_FAILED(rv
))) {
534 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE ai_unique_index_data;"_ns
);
535 if (NS_WARN_IF(NS_FAILED(rv
))) {
539 rv
= aConnection
.ExecuteSimpleSQL(
540 "CREATE TABLE ai_unique_index_data ("
541 "index_id INTEGER NOT NULL, "
543 "ai_object_data_id INTEGER NOT NULL, "
544 "UNIQUE (index_id, value), "
545 "PRIMARY KEY (index_id, value, ai_object_data_id), "
546 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
548 "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
551 if (NS_WARN_IF(NS_FAILED(rv
))) {
555 rv
= aConnection
.ExecuteSimpleSQL(
556 "INSERT INTO ai_unique_index_data "
557 "SELECT index_id, value, ai_object_data_id "
558 "FROM temp_upgrade;"_ns
);
559 if (NS_WARN_IF(NS_FAILED(rv
))) {
563 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
564 if (NS_WARN_IF(NS_FAILED(rv
))) {
568 rv
= aConnection
.ExecuteSimpleSQL(
569 "CREATE INDEX ai_unique_index_data_ai_object_data_id_index "
570 "ON ai_unique_index_data (ai_object_data_id);"_ns
);
571 if (NS_WARN_IF(NS_FAILED(rv
))) {
575 rv
= aConnection
.SetSchemaVersion(6);
576 if (NS_WARN_IF(NS_FAILED(rv
))) {
583 nsresult
UpgradeSchemaFrom6To7(mozIStorageConnection
& aConnection
) {
584 AssertIsOnIOThread();
586 AUTO_PROFILER_LABEL("UpgradeSchemaFrom6To7", DOM
);
588 nsresult rv
= aConnection
.ExecuteSimpleSQL(
589 "CREATE TEMPORARY TABLE temp_upgrade ("
595 if (NS_WARN_IF(NS_FAILED(rv
))) {
599 rv
= aConnection
.ExecuteSimpleSQL(
600 "INSERT INTO temp_upgrade "
601 "SELECT id, name, key_path, auto_increment "
602 "FROM object_store;"_ns
);
603 if (NS_WARN_IF(NS_FAILED(rv
))) {
607 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_store;"_ns
);
608 if (NS_WARN_IF(NS_FAILED(rv
))) {
612 rv
= aConnection
.ExecuteSimpleSQL(
613 "CREATE TABLE object_store ("
614 "id INTEGER PRIMARY KEY, "
615 "auto_increment INTEGER NOT NULL DEFAULT 0, "
616 "name TEXT NOT NULL, "
620 if (NS_WARN_IF(NS_FAILED(rv
))) {
624 rv
= aConnection
.ExecuteSimpleSQL(
625 "INSERT INTO object_store "
626 "SELECT id, auto_increment, name, nullif(key_path, '') "
627 "FROM temp_upgrade;"_ns
);
628 if (NS_WARN_IF(NS_FAILED(rv
))) {
632 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
633 if (NS_WARN_IF(NS_FAILED(rv
))) {
637 rv
= aConnection
.SetSchemaVersion(7);
638 if (NS_WARN_IF(NS_FAILED(rv
))) {
645 nsresult
UpgradeSchemaFrom7To8(mozIStorageConnection
& aConnection
) {
646 AssertIsOnIOThread();
648 AUTO_PROFILER_LABEL("UpgradeSchemaFrom7To8", DOM
);
650 nsresult rv
= aConnection
.ExecuteSimpleSQL(
651 "CREATE TEMPORARY TABLE temp_upgrade ("
657 "object_store_autoincrement"
659 if (NS_WARN_IF(NS_FAILED(rv
))) {
663 rv
= aConnection
.ExecuteSimpleSQL(
664 "INSERT INTO temp_upgrade "
665 "SELECT id, object_store_id, name, key_path, "
666 "unique_index, object_store_autoincrement "
667 "FROM object_store_index;"_ns
);
668 if (NS_WARN_IF(NS_FAILED(rv
))) {
672 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_store_index;"_ns
);
673 if (NS_WARN_IF(NS_FAILED(rv
))) {
677 rv
= aConnection
.ExecuteSimpleSQL(
678 "CREATE TABLE object_store_index ("
680 "object_store_id INTEGER NOT NULL, "
681 "name TEXT NOT NULL, "
682 "key_path TEXT NOT NULL, "
683 "unique_index INTEGER NOT NULL, "
684 "multientry INTEGER NOT NULL, "
685 "object_store_autoincrement INTERGER NOT NULL, "
687 "UNIQUE (object_store_id, name), "
688 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
691 if (NS_WARN_IF(NS_FAILED(rv
))) {
695 rv
= aConnection
.ExecuteSimpleSQL(
696 "INSERT INTO object_store_index "
697 "SELECT id, object_store_id, name, key_path, "
698 "unique_index, 0, object_store_autoincrement "
699 "FROM temp_upgrade;"_ns
);
700 if (NS_WARN_IF(NS_FAILED(rv
))) {
704 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
705 if (NS_WARN_IF(NS_FAILED(rv
))) {
709 rv
= aConnection
.SetSchemaVersion(8);
710 if (NS_WARN_IF(NS_FAILED(rv
))) {
717 class CompressDataBlobsFunction final
: public mozIStorageFunction
{
722 ~CompressDataBlobsFunction() = default;
725 OnFunctionCall(mozIStorageValueArray
* aArguments
,
726 nsIVariant
** aResult
) override
{
727 MOZ_ASSERT(aArguments
);
730 AUTO_PROFILER_LABEL("CompressDataBlobsFunction::OnFunctionCall", DOM
);
733 nsresult rv
= aArguments
->GetNumEntries(&argc
);
734 if (NS_WARN_IF(NS_FAILED(rv
))) {
739 NS_WARNING("Don't call me with the wrong number of arguments!");
740 return NS_ERROR_UNEXPECTED
;
744 rv
= aArguments
->GetTypeOfIndex(0, &type
);
745 if (NS_WARN_IF(NS_FAILED(rv
))) {
749 if (type
!= mozIStorageStatement::VALUE_TYPE_BLOB
) {
750 NS_WARNING("Don't call me with the wrong type of arguments!");
751 return NS_ERROR_UNEXPECTED
;
754 const uint8_t* uncompressed
;
755 uint32_t uncompressedLength
;
756 rv
= aArguments
->GetSharedBlob(0, &uncompressedLength
, &uncompressed
);
757 if (NS_WARN_IF(NS_FAILED(rv
))) {
761 size_t compressedLength
= snappy::MaxCompressedLength(uncompressedLength
);
762 UniqueFreePtr
<uint8_t> compressed(
763 static_cast<uint8_t*>(malloc(compressedLength
)));
764 if (NS_WARN_IF(!compressed
)) {
765 return NS_ERROR_OUT_OF_MEMORY
;
769 reinterpret_cast<const char*>(uncompressed
), uncompressedLength
,
770 reinterpret_cast<char*>(compressed
.get()), &compressedLength
);
772 std::pair
<uint8_t*, int> data(compressed
.release(), int(compressedLength
));
774 nsCOMPtr
<nsIVariant
> result
=
775 new mozilla::storage::AdoptedBlobVariant(data
);
777 result
.forget(aResult
);
782 nsresult
UpgradeSchemaFrom8To9_0(mozIStorageConnection
& aConnection
) {
783 AssertIsOnIOThread();
785 AUTO_PROFILER_LABEL("UpgradeSchemaFrom8To9_0", DOM
);
787 // We no longer use the dataVersion column.
789 aConnection
.ExecuteSimpleSQL("UPDATE database SET dataVersion = 0;"_ns
);
790 if (NS_WARN_IF(NS_FAILED(rv
))) {
794 nsCOMPtr
<mozIStorageFunction
> compressor
= new CompressDataBlobsFunction();
796 constexpr auto compressorName
= "compress"_ns
;
798 rv
= aConnection
.CreateFunction(compressorName
, 1, compressor
);
799 if (NS_WARN_IF(NS_FAILED(rv
))) {
803 // Turn off foreign key constraints before we do anything here.
804 rv
= aConnection
.ExecuteSimpleSQL(
805 "UPDATE object_data SET data = compress(data);"_ns
);
806 if (NS_WARN_IF(NS_FAILED(rv
))) {
810 rv
= aConnection
.ExecuteSimpleSQL(
811 "UPDATE ai_object_data SET data = compress(data);"_ns
);
812 if (NS_WARN_IF(NS_FAILED(rv
))) {
816 rv
= aConnection
.RemoveFunction(compressorName
);
817 if (NS_WARN_IF(NS_FAILED(rv
))) {
821 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(9, 0));
822 if (NS_WARN_IF(NS_FAILED(rv
))) {
829 nsresult
UpgradeSchemaFrom9_0To10_0(mozIStorageConnection
& aConnection
) {
830 AssertIsOnIOThread();
832 AUTO_PROFILER_LABEL("UpgradeSchemaFrom9_0To10_0", DOM
);
834 nsresult rv
= aConnection
.ExecuteSimpleSQL(
835 "ALTER TABLE object_data ADD COLUMN file_ids TEXT;"_ns
);
836 if (NS_WARN_IF(NS_FAILED(rv
))) {
840 rv
= aConnection
.ExecuteSimpleSQL(
841 "ALTER TABLE ai_object_data ADD COLUMN file_ids TEXT;"_ns
);
842 if (NS_WARN_IF(NS_FAILED(rv
))) {
846 rv
= CreateFileTables(aConnection
);
847 if (NS_WARN_IF(NS_FAILED(rv
))) {
851 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(10, 0));
852 if (NS_WARN_IF(NS_FAILED(rv
))) {
859 nsresult
UpgradeSchemaFrom10_0To11_0(mozIStorageConnection
& aConnection
) {
860 AssertIsOnIOThread();
862 AUTO_PROFILER_LABEL("UpgradeSchemaFrom10_0To11_0", DOM
);
864 nsresult rv
= aConnection
.ExecuteSimpleSQL(
865 "CREATE TEMPORARY TABLE temp_upgrade ("
873 if (NS_WARN_IF(NS_FAILED(rv
))) {
877 rv
= aConnection
.ExecuteSimpleSQL(
878 "INSERT INTO temp_upgrade "
879 "SELECT id, object_store_id, name, key_path, "
880 "unique_index, multientry "
881 "FROM object_store_index;"_ns
);
882 if (NS_WARN_IF(NS_FAILED(rv
))) {
886 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_store_index;"_ns
);
887 if (NS_WARN_IF(NS_FAILED(rv
))) {
891 rv
= aConnection
.ExecuteSimpleSQL(
892 "CREATE TABLE object_store_index ("
893 "id INTEGER PRIMARY KEY, "
894 "object_store_id INTEGER NOT NULL, "
895 "name TEXT NOT NULL, "
896 "key_path TEXT NOT NULL, "
897 "unique_index INTEGER NOT NULL, "
898 "multientry INTEGER NOT NULL, "
899 "UNIQUE (object_store_id, name), "
900 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
903 if (NS_WARN_IF(NS_FAILED(rv
))) {
907 rv
= aConnection
.ExecuteSimpleSQL(
908 "INSERT INTO object_store_index "
909 "SELECT id, object_store_id, name, key_path, "
910 "unique_index, multientry "
911 "FROM temp_upgrade;"_ns
);
912 if (NS_WARN_IF(NS_FAILED(rv
))) {
916 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
917 if (NS_WARN_IF(NS_FAILED(rv
))) {
921 rv
= aConnection
.ExecuteSimpleSQL(
922 "DROP TRIGGER object_data_insert_trigger;"_ns
);
923 if (NS_WARN_IF(NS_FAILED(rv
))) {
927 rv
= aConnection
.ExecuteSimpleSQL(
928 "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
929 "SELECT object_store_id, id, data, file_ids "
930 "FROM ai_object_data;"_ns
);
931 if (NS_WARN_IF(NS_FAILED(rv
))) {
935 rv
= aConnection
.ExecuteSimpleSQL(
936 "CREATE TRIGGER object_data_insert_trigger "
937 "AFTER INSERT ON object_data "
939 "WHEN NEW.file_ids IS NOT NULL "
941 "SELECT update_refcount(NULL, NEW.file_ids); "
943 if (NS_WARN_IF(NS_FAILED(rv
))) {
947 rv
= aConnection
.ExecuteSimpleSQL(
948 "INSERT INTO index_data (index_id, value, object_data_key, "
950 "SELECT ai_index_data.index_id, ai_index_data.value, "
951 "ai_index_data.ai_object_data_id, object_data.id "
952 "FROM ai_index_data "
953 "INNER JOIN object_store_index ON "
954 "object_store_index.id = ai_index_data.index_id "
955 "INNER JOIN object_data ON "
956 "object_data.object_store_id = object_store_index.object_store_id AND "
957 "object_data.key_value = ai_index_data.ai_object_data_id;"_ns
);
958 if (NS_WARN_IF(NS_FAILED(rv
))) {
962 rv
= aConnection
.ExecuteSimpleSQL(
963 "INSERT INTO unique_index_data (index_id, value, object_data_key, "
965 "SELECT ai_unique_index_data.index_id, ai_unique_index_data.value, "
966 "ai_unique_index_data.ai_object_data_id, object_data.id "
967 "FROM ai_unique_index_data "
968 "INNER JOIN object_store_index ON "
969 "object_store_index.id = ai_unique_index_data.index_id "
970 "INNER JOIN object_data ON "
971 "object_data.object_store_id = object_store_index.object_store_id AND "
972 "object_data.key_value = ai_unique_index_data.ai_object_data_id;"_ns
);
973 if (NS_WARN_IF(NS_FAILED(rv
))) {
977 rv
= aConnection
.ExecuteSimpleSQL(
978 "UPDATE object_store "
979 "SET auto_increment = (SELECT max(id) FROM ai_object_data) + 1 "
980 "WHERE auto_increment;"_ns
);
981 if (NS_WARN_IF(NS_FAILED(rv
))) {
985 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE ai_unique_index_data;"_ns
);
986 if (NS_WARN_IF(NS_FAILED(rv
))) {
990 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE ai_index_data;"_ns
);
991 if (NS_WARN_IF(NS_FAILED(rv
))) {
995 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE ai_object_data;"_ns
);
996 if (NS_WARN_IF(NS_FAILED(rv
))) {
1000 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(11, 0));
1001 if (NS_WARN_IF(NS_FAILED(rv
))) {
1008 class EncodeKeysFunction final
: public mozIStorageFunction
{
1013 ~EncodeKeysFunction() = default;
1016 OnFunctionCall(mozIStorageValueArray
* aArguments
,
1017 nsIVariant
** aResult
) override
{
1018 MOZ_ASSERT(aArguments
);
1019 MOZ_ASSERT(aResult
);
1021 AUTO_PROFILER_LABEL("EncodeKeysFunction::OnFunctionCall", DOM
);
1024 nsresult rv
= aArguments
->GetNumEntries(&argc
);
1025 if (NS_WARN_IF(NS_FAILED(rv
))) {
1030 NS_WARNING("Don't call me with the wrong number of arguments!");
1031 return NS_ERROR_UNEXPECTED
;
1035 rv
= aArguments
->GetTypeOfIndex(0, &type
);
1036 if (NS_WARN_IF(NS_FAILED(rv
))) {
1041 const auto& key
, ([type
, aArguments
]() -> Result
<Key
, nsresult
> {
1043 case mozIStorageStatement::VALUE_TYPE_INTEGER
: {
1045 aArguments
->GetInt64(0, &intKey
);
1048 QM_TRY(key
.SetFromInteger(intKey
));
1052 case mozIStorageStatement::VALUE_TYPE_TEXT
: {
1054 aArguments
->GetString(0, stringKey
);
1057 QM_TRY(key
.SetFromString(stringKey
));
1062 NS_WARNING("Don't call me with the wrong type of arguments!");
1063 return Err(NS_ERROR_UNEXPECTED
);
1067 const nsCString
& buffer
= key
.GetBuffer();
1069 std::pair
<const void*, int> data(static_cast<const void*>(buffer
.get()),
1070 int(buffer
.Length()));
1072 nsCOMPtr
<nsIVariant
> result
= new mozilla::storage::BlobVariant(data
);
1074 result
.forget(aResult
);
1079 nsresult
UpgradeSchemaFrom11_0To12_0(mozIStorageConnection
& aConnection
) {
1080 AssertIsOnIOThread();
1082 AUTO_PROFILER_LABEL("UpgradeSchemaFrom11_0To12_0", DOM
);
1084 constexpr auto encoderName
= "encode"_ns
;
1086 nsCOMPtr
<mozIStorageFunction
> encoder
= new EncodeKeysFunction();
1088 nsresult rv
= aConnection
.CreateFunction(encoderName
, 1, encoder
);
1089 if (NS_WARN_IF(NS_FAILED(rv
))) {
1093 rv
= aConnection
.ExecuteSimpleSQL(
1094 "CREATE TEMPORARY TABLE temp_upgrade ("
1095 "id INTEGER PRIMARY KEY, "
1101 if (NS_WARN_IF(NS_FAILED(rv
))) {
1105 rv
= aConnection
.ExecuteSimpleSQL(
1106 "INSERT INTO temp_upgrade "
1107 "SELECT id, object_store_id, encode(key_value), data, file_ids "
1108 "FROM object_data;"_ns
);
1109 if (NS_WARN_IF(NS_FAILED(rv
))) {
1113 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_data;"_ns
);
1114 if (NS_WARN_IF(NS_FAILED(rv
))) {
1118 rv
= aConnection
.ExecuteSimpleSQL(
1119 "CREATE TABLE object_data ("
1120 "id INTEGER PRIMARY KEY, "
1121 "object_store_id INTEGER NOT NULL, "
1122 "key_value BLOB DEFAULT NULL, "
1124 "data BLOB NOT NULL, "
1125 "UNIQUE (object_store_id, key_value), "
1126 "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
1129 if (NS_WARN_IF(NS_FAILED(rv
))) {
1133 rv
= aConnection
.ExecuteSimpleSQL(
1134 "INSERT INTO object_data "
1135 "SELECT id, object_store_id, key_value, file_ids, data "
1136 "FROM temp_upgrade;"_ns
);
1137 if (NS_WARN_IF(NS_FAILED(rv
))) {
1141 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
1142 if (NS_WARN_IF(NS_FAILED(rv
))) {
1146 rv
= aConnection
.ExecuteSimpleSQL(
1147 "CREATE TRIGGER object_data_insert_trigger "
1148 "AFTER INSERT ON object_data "
1150 "WHEN NEW.file_ids IS NOT NULL "
1152 "SELECT update_refcount(NULL, NEW.file_ids); "
1154 if (NS_WARN_IF(NS_FAILED(rv
))) {
1158 rv
= aConnection
.ExecuteSimpleSQL(
1159 "CREATE TRIGGER object_data_update_trigger "
1160 "AFTER UPDATE OF file_ids ON object_data "
1162 "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
1164 "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
1166 if (NS_WARN_IF(NS_FAILED(rv
))) {
1170 rv
= aConnection
.ExecuteSimpleSQL(
1171 "CREATE TRIGGER object_data_delete_trigger "
1172 "AFTER DELETE ON object_data "
1173 "FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
1175 "SELECT update_refcount(OLD.file_ids, NULL); "
1177 if (NS_WARN_IF(NS_FAILED(rv
))) {
1181 rv
= aConnection
.ExecuteSimpleSQL(
1182 "CREATE TEMPORARY TABLE temp_upgrade ("
1188 if (NS_WARN_IF(NS_FAILED(rv
))) {
1192 rv
= aConnection
.ExecuteSimpleSQL(
1193 "INSERT INTO temp_upgrade "
1194 "SELECT index_id, encode(value), encode(object_data_key), object_data_id "
1195 "FROM index_data;"_ns
);
1196 if (NS_WARN_IF(NS_FAILED(rv
))) {
1200 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE index_data;"_ns
);
1201 if (NS_WARN_IF(NS_FAILED(rv
))) {
1205 rv
= aConnection
.ExecuteSimpleSQL(
1206 "CREATE TABLE index_data ("
1207 "index_id INTEGER NOT NULL, "
1208 "value BLOB NOT NULL, "
1209 "object_data_key BLOB NOT NULL, "
1210 "object_data_id INTEGER NOT NULL, "
1211 "PRIMARY KEY (index_id, value, object_data_key), "
1212 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
1214 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
1217 if (NS_WARN_IF(NS_FAILED(rv
))) {
1221 rv
= aConnection
.ExecuteSimpleSQL(
1222 "INSERT INTO index_data "
1223 "SELECT index_id, value, object_data_key, object_data_id "
1224 "FROM temp_upgrade;"_ns
);
1225 if (NS_WARN_IF(NS_FAILED(rv
))) {
1229 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
1230 if (NS_WARN_IF(NS_FAILED(rv
))) {
1234 rv
= aConnection
.ExecuteSimpleSQL(
1235 "CREATE INDEX index_data_object_data_id_index "
1236 "ON index_data (object_data_id);"_ns
);
1237 if (NS_WARN_IF(NS_FAILED(rv
))) {
1241 rv
= aConnection
.ExecuteSimpleSQL(
1242 "CREATE TEMPORARY TABLE temp_upgrade ("
1248 if (NS_WARN_IF(NS_FAILED(rv
))) {
1252 rv
= aConnection
.ExecuteSimpleSQL(
1253 "INSERT INTO temp_upgrade "
1254 "SELECT index_id, encode(value), encode(object_data_key), object_data_id "
1255 "FROM unique_index_data;"_ns
);
1256 if (NS_WARN_IF(NS_FAILED(rv
))) {
1260 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE unique_index_data;"_ns
);
1261 if (NS_WARN_IF(NS_FAILED(rv
))) {
1265 rv
= aConnection
.ExecuteSimpleSQL(
1266 "CREATE TABLE unique_index_data ("
1267 "index_id INTEGER NOT NULL, "
1268 "value BLOB NOT NULL, "
1269 "object_data_key BLOB NOT NULL, "
1270 "object_data_id INTEGER NOT NULL, "
1271 "PRIMARY KEY (index_id, value, object_data_key), "
1272 "UNIQUE (index_id, value), "
1273 "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
1275 "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
1278 if (NS_WARN_IF(NS_FAILED(rv
))) {
1282 rv
= aConnection
.ExecuteSimpleSQL(
1283 "INSERT INTO unique_index_data "
1284 "SELECT index_id, value, object_data_key, object_data_id "
1285 "FROM temp_upgrade;"_ns
);
1286 if (NS_WARN_IF(NS_FAILED(rv
))) {
1290 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE temp_upgrade;"_ns
);
1291 if (NS_WARN_IF(NS_FAILED(rv
))) {
1295 rv
= aConnection
.ExecuteSimpleSQL(
1296 "CREATE INDEX unique_index_data_object_data_id_index "
1297 "ON unique_index_data (object_data_id);"_ns
);
1298 if (NS_WARN_IF(NS_FAILED(rv
))) {
1302 rv
= aConnection
.RemoveFunction(encoderName
);
1303 if (NS_WARN_IF(NS_FAILED(rv
))) {
1307 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(12, 0));
1308 if (NS_WARN_IF(NS_FAILED(rv
))) {
1315 nsresult
UpgradeSchemaFrom12_0To13_0(mozIStorageConnection
& aConnection
,
1316 bool* aVacuumNeeded
) {
1317 AssertIsOnIOThread();
1319 AUTO_PROFILER_LABEL("UpgradeSchemaFrom12_0To13_0", DOM
);
1324 int32_t defaultPageSize
;
1325 rv
= aConnection
.GetDefaultPageSize(&defaultPageSize
);
1326 if (NS_WARN_IF(NS_FAILED(rv
))) {
1330 // Enable auto_vacuum mode and update the page size to the platform default.
1331 nsAutoCString
upgradeQuery("PRAGMA auto_vacuum = FULL; PRAGMA page_size = ");
1332 upgradeQuery
.AppendInt(defaultPageSize
);
1334 rv
= aConnection
.ExecuteSimpleSQL(upgradeQuery
);
1335 if (NS_WARN_IF(NS_FAILED(rv
))) {
1339 *aVacuumNeeded
= true;
1342 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(13, 0));
1343 if (NS_WARN_IF(NS_FAILED(rv
))) {
1350 nsresult
UpgradeSchemaFrom13_0To14_0(mozIStorageConnection
& aConnection
) {
1351 AssertIsOnIOThread();
1353 // The only change between 13 and 14 was a different structured
1354 // clone format, but it's backwards-compatible.
1355 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(14, 0));
1356 if (NS_WARN_IF(NS_FAILED(rv
))) {
1363 nsresult
UpgradeSchemaFrom14_0To15_0(mozIStorageConnection
& aConnection
) {
1364 // The only change between 14 and 15 was a different structured
1365 // clone format, but it's backwards-compatible.
1366 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(15, 0));
1367 if (NS_WARN_IF(NS_FAILED(rv
))) {
1374 nsresult
UpgradeSchemaFrom15_0To16_0(mozIStorageConnection
& aConnection
) {
1375 // The only change between 15 and 16 was a different structured
1376 // clone format, but it's backwards-compatible.
1377 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(16, 0));
1378 if (NS_WARN_IF(NS_FAILED(rv
))) {
1385 nsresult
UpgradeSchemaFrom16_0To17_0(mozIStorageConnection
& aConnection
) {
1386 // The only change between 16 and 17 was a different structured
1387 // clone format, but it's backwards-compatible.
1388 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(17, 0));
1389 if (NS_WARN_IF(NS_FAILED(rv
))) {
1396 class UpgradeSchemaFrom17_0To18_0Helper final
{
1397 class InsertIndexDataValuesFunction
;
1398 class UpgradeKeyFunction
;
1401 static nsresult
DoUpgrade(mozIStorageConnection
& aConnection
,
1402 const nsACString
& aOrigin
);
1405 static nsresult
DoUpgradeInternal(mozIStorageConnection
& aConnection
,
1406 const nsACString
& aOrigin
);
1408 UpgradeSchemaFrom17_0To18_0Helper() = delete;
1409 ~UpgradeSchemaFrom17_0To18_0Helper() = delete;
1412 class UpgradeSchemaFrom17_0To18_0Helper::InsertIndexDataValuesFunction final
1413 : public mozIStorageFunction
{
1415 InsertIndexDataValuesFunction() = default;
1420 ~InsertIndexDataValuesFunction() = default;
1422 NS_DECL_MOZISTORAGEFUNCTION
1426 UpgradeSchemaFrom17_0To18_0Helper::InsertIndexDataValuesFunction
,
1427 mozIStorageFunction
);
1430 UpgradeSchemaFrom17_0To18_0Helper::InsertIndexDataValuesFunction::
1431 OnFunctionCall(mozIStorageValueArray
* aValues
, nsIVariant
** _retval
) {
1432 MOZ_ASSERT(!NS_IsMainThread());
1433 MOZ_ASSERT(!IsOnBackgroundThread());
1434 MOZ_ASSERT(aValues
);
1435 MOZ_ASSERT(_retval
);
1440 MOZ_ALWAYS_SUCCEEDS(aValues
->GetNumEntries(&argCount
));
1441 MOZ_ASSERT(argCount
== 4);
1444 MOZ_ALWAYS_SUCCEEDS(aValues
->GetTypeOfIndex(0, &valueType
));
1445 MOZ_ASSERT(valueType
== mozIStorageValueArray::VALUE_TYPE_NULL
||
1446 valueType
== mozIStorageValueArray::VALUE_TYPE_BLOB
);
1448 MOZ_ALWAYS_SUCCEEDS(aValues
->GetTypeOfIndex(1, &valueType
));
1449 MOZ_ASSERT(valueType
== mozIStorageValueArray::VALUE_TYPE_INTEGER
);
1451 MOZ_ALWAYS_SUCCEEDS(aValues
->GetTypeOfIndex(2, &valueType
));
1452 MOZ_ASSERT(valueType
== mozIStorageValueArray::VALUE_TYPE_INTEGER
);
1454 MOZ_ALWAYS_SUCCEEDS(aValues
->GetTypeOfIndex(3, &valueType
));
1455 MOZ_ASSERT(valueType
== mozIStorageValueArray::VALUE_TYPE_BLOB
);
1459 // Read out the previous value. It may be NULL, in which case we'll just end
1460 // up with an empty array.
1461 QM_TRY_UNWRAP(auto indexValues
, ReadCompressedIndexDataValues(*aValues
, 0));
1463 IndexOrObjectStoreId indexId
;
1464 nsresult rv
= aValues
->GetInt64(1, &indexId
);
1465 if (NS_WARN_IF(NS_FAILED(rv
))) {
1470 rv
= aValues
->GetInt32(2, &unique
);
1471 if (NS_WARN_IF(NS_FAILED(rv
))) {
1476 rv
= value
.SetFromValueArray(aValues
, 3);
1477 if (NS_WARN_IF(NS_FAILED(rv
))) {
1481 // Update the array with the new addition.
1482 if (NS_WARN_IF(!indexValues
.InsertElementSorted(
1483 IndexDataValue(indexId
, !!unique
, value
), fallible
))) {
1484 IDB_REPORT_INTERNAL_ERR();
1485 return NS_ERROR_OUT_OF_MEMORY
;
1488 // Compress the array.
1489 QM_TRY_UNWRAP((auto [indexValuesBlob
, indexValuesBlobLength
]),
1490 MakeCompressedIndexDataValues(indexValues
));
1492 // The compressed blob is the result of this function.
1493 nsCOMPtr
<nsIVariant
> result
= new storage::AdoptedBlobVariant(
1494 std::pair(indexValuesBlob
.release(), indexValuesBlobLength
));
1496 result
.forget(_retval
);
1500 class UpgradeSchemaFrom17_0To18_0Helper::UpgradeKeyFunction final
1501 : public mozIStorageFunction
{
1503 UpgradeKeyFunction() = default;
1505 static nsresult
CopyAndUpgradeKeyBuffer(const uint8_t* aSource
,
1506 const uint8_t* aSourceEnd
,
1507 uint8_t* aDestination
) {
1508 return CopyAndUpgradeKeyBufferInternal(aSource
, aSourceEnd
, aDestination
,
1510 0 /* aRecursionDepth */);
1516 ~UpgradeKeyFunction() = default;
1518 static nsresult
CopyAndUpgradeKeyBufferInternal(const uint8_t*& aSource
,
1519 const uint8_t* aSourceEnd
,
1520 uint8_t*& aDestination
,
1522 uint8_t aRecursionDepth
);
1524 static uint32_t AdjustedSize(uint32_t aMaxSize
, const uint8_t* aSource
,
1525 const uint8_t* aSourceEnd
) {
1526 MOZ_ASSERT(aMaxSize
);
1527 MOZ_ASSERT(aSource
);
1528 MOZ_ASSERT(aSourceEnd
);
1529 MOZ_ASSERT(aSource
<= aSourceEnd
);
1531 return std::min(aMaxSize
, uint32_t(aSourceEnd
- aSource
));
1534 NS_DECL_MOZISTORAGEFUNCTION
1538 nsresult
UpgradeSchemaFrom17_0To18_0Helper::UpgradeKeyFunction::
1539 CopyAndUpgradeKeyBufferInternal(const uint8_t*& aSource
,
1540 const uint8_t* aSourceEnd
,
1541 uint8_t*& aDestination
, uint8_t aTagOffset
,
1542 uint8_t aRecursionDepth
) {
1543 MOZ_ASSERT(!NS_IsMainThread());
1544 MOZ_ASSERT(!IsOnBackgroundThread());
1545 MOZ_ASSERT(aSource
);
1546 MOZ_ASSERT(*aSource
);
1547 MOZ_ASSERT(aSourceEnd
);
1548 MOZ_ASSERT(aSource
< aSourceEnd
);
1549 MOZ_ASSERT(aDestination
);
1550 MOZ_ASSERT(aTagOffset
<= Key::kMaxArrayCollapse
);
1552 static constexpr uint8_t kOldNumberTag
= 0x1;
1553 static constexpr uint8_t kOldDateTag
= 0x2;
1554 static constexpr uint8_t kOldStringTag
= 0x3;
1555 static constexpr uint8_t kOldArrayTag
= 0x4;
1556 static constexpr uint8_t kOldMaxType
= kOldArrayTag
;
1558 if (NS_WARN_IF(aRecursionDepth
> Key::kMaxRecursionDepth
)) {
1559 IDB_REPORT_INTERNAL_ERR();
1560 return NS_ERROR_FILE_CORRUPTED
;
1563 const uint8_t sourceTag
= *aSource
- (aTagOffset
* kOldMaxType
);
1564 MOZ_ASSERT(sourceTag
);
1566 if (NS_WARN_IF(sourceTag
> kOldMaxType
* Key::kMaxArrayCollapse
)) {
1567 IDB_REPORT_INTERNAL_ERR();
1568 return NS_ERROR_FILE_CORRUPTED
;
1571 if (sourceTag
== kOldNumberTag
|| sourceTag
== kOldDateTag
) {
1572 // Write the new tag.
1573 *aDestination
++ = (sourceTag
== kOldNumberTag
? Key::eFloat
: Key::eDate
) +
1574 (aTagOffset
* Key::eMaxType
);
1577 // Numbers and Dates are encoded as 64-bit integers, but trailing 0
1578 // bytes have been removed.
1579 const uint32_t byteCount
=
1580 AdjustedSize(sizeof(uint64_t), aSource
, aSourceEnd
);
1582 aDestination
= std::copy(aSource
, aSource
+ byteCount
, aDestination
);
1583 aSource
+= byteCount
;
1588 if (sourceTag
== kOldStringTag
) {
1589 // Write the new tag.
1590 *aDestination
++ = Key::eString
+ (aTagOffset
* Key::eMaxType
);
1593 while (aSource
< aSourceEnd
) {
1594 const uint8_t byte
= *aSource
++;
1595 *aDestination
++ = byte
;
1598 // Just copied the terminator.
1602 // Maybe copy one or two extra bytes if the byte is tagged and we have
1603 // enough source space.
1605 const uint32_t byteCount
=
1606 AdjustedSize((byte
& 0x40) ? 2 : 1, aSource
, aSourceEnd
);
1608 aDestination
= std::copy(aSource
, aSource
+ byteCount
, aDestination
);
1609 aSource
+= byteCount
;
1616 if (NS_WARN_IF(sourceTag
< kOldArrayTag
)) {
1617 IDB_REPORT_INTERNAL_ERR();
1618 return NS_ERROR_FILE_CORRUPTED
;
1623 if (aTagOffset
== Key::kMaxArrayCollapse
) {
1624 MOZ_ASSERT(sourceTag
== kOldArrayTag
);
1626 *aDestination
++ = (aTagOffset
* Key::eMaxType
);
1632 while (aSource
< aSourceEnd
&&
1633 (*aSource
- (aTagOffset
* kOldMaxType
)) != Key::eTerminator
) {
1634 nsresult rv
= CopyAndUpgradeKeyBufferInternal(
1635 aSource
, aSourceEnd
, aDestination
, aTagOffset
, aRecursionDepth
+ 1);
1636 if (NS_WARN_IF(NS_FAILED(rv
))) {
1643 if (aSource
< aSourceEnd
) {
1644 MOZ_ASSERT((*aSource
- (aTagOffset
* kOldMaxType
)) == Key::eTerminator
);
1645 *aDestination
++ = Key::eTerminator
+ (aTagOffset
* Key::eMaxType
);
1652 NS_IMPL_ISUPPORTS(UpgradeSchemaFrom17_0To18_0Helper::UpgradeKeyFunction
,
1653 mozIStorageFunction
);
1656 UpgradeSchemaFrom17_0To18_0Helper::UpgradeKeyFunction::OnFunctionCall(
1657 mozIStorageValueArray
* aValues
, nsIVariant
** _retval
) {
1658 MOZ_ASSERT(!NS_IsMainThread());
1659 MOZ_ASSERT(!IsOnBackgroundThread());
1660 MOZ_ASSERT(aValues
);
1661 MOZ_ASSERT(_retval
);
1666 MOZ_ALWAYS_SUCCEEDS(aValues
->GetNumEntries(&argCount
));
1667 MOZ_ASSERT(argCount
== 1);
1670 MOZ_ALWAYS_SUCCEEDS(aValues
->GetTypeOfIndex(0, &valueType
));
1671 MOZ_ASSERT(valueType
== mozIStorageValueArray::VALUE_TYPE_BLOB
);
1675 // Dig the old key out of the values.
1676 const uint8_t* blobData
;
1677 uint32_t blobDataLength
;
1678 nsresult rv
= aValues
->GetSharedBlob(0, &blobDataLength
, &blobData
);
1679 if (NS_WARN_IF(NS_FAILED(rv
))) {
1683 // Upgrading the key doesn't change the amount of space needed to hold it.
1684 UniqueFreePtr
<uint8_t> upgradedBlobData(
1685 static_cast<uint8_t*>(malloc(blobDataLength
)));
1686 if (NS_WARN_IF(!upgradedBlobData
)) {
1687 IDB_REPORT_INTERNAL_ERR();
1688 return NS_ERROR_OUT_OF_MEMORY
;
1691 rv
= CopyAndUpgradeKeyBuffer(blobData
, blobData
+ blobDataLength
,
1692 upgradedBlobData
.get());
1693 if (NS_WARN_IF(NS_FAILED(rv
))) {
1697 // The upgraded key is the result of this function.
1698 std::pair
<uint8_t*, int> data(upgradedBlobData
.release(),
1699 int(blobDataLength
));
1701 nsCOMPtr
<nsIVariant
> result
= new mozilla::storage::AdoptedBlobVariant(data
);
1703 result
.forget(_retval
);
1708 nsresult
UpgradeSchemaFrom17_0To18_0Helper::DoUpgrade(
1709 mozIStorageConnection
& aConnection
, const nsACString
& aOrigin
) {
1710 MOZ_ASSERT(!aOrigin
.IsEmpty());
1712 // Register the |upgrade_key| function.
1713 RefPtr
<UpgradeKeyFunction
> updateFunction
= new UpgradeKeyFunction();
1715 constexpr auto upgradeKeyFunctionName
= "upgrade_key"_ns
;
1718 aConnection
.CreateFunction(upgradeKeyFunctionName
, 1, updateFunction
);
1719 if (NS_WARN_IF(NS_FAILED(rv
))) {
1723 // Register the |insert_idv| function.
1724 RefPtr
<InsertIndexDataValuesFunction
> insertIDVFunction
=
1725 new InsertIndexDataValuesFunction();
1727 constexpr auto insertIDVFunctionName
= "insert_idv"_ns
;
1729 rv
= aConnection
.CreateFunction(insertIDVFunctionName
, 4, insertIDVFunction
);
1730 if (NS_WARN_IF(NS_FAILED(rv
))) {
1731 MOZ_ALWAYS_SUCCEEDS(aConnection
.RemoveFunction(upgradeKeyFunctionName
));
1735 rv
= DoUpgradeInternal(aConnection
, aOrigin
);
1737 MOZ_ALWAYS_SUCCEEDS(aConnection
.RemoveFunction(upgradeKeyFunctionName
));
1738 MOZ_ALWAYS_SUCCEEDS(aConnection
.RemoveFunction(insertIDVFunctionName
));
1740 if (NS_WARN_IF(NS_FAILED(rv
))) {
1748 nsresult
UpgradeSchemaFrom17_0To18_0Helper::DoUpgradeInternal(
1749 mozIStorageConnection
& aConnection
, const nsACString
& aOrigin
) {
1750 MOZ_ASSERT(!aOrigin
.IsEmpty());
1752 nsresult rv
= aConnection
.ExecuteSimpleSQL(
1753 // Drop these triggers to avoid unnecessary work during the upgrade
1755 "DROP TRIGGER object_data_insert_trigger;"
1756 "DROP TRIGGER object_data_update_trigger;"
1757 "DROP TRIGGER object_data_delete_trigger;"_ns
);
1758 if (NS_WARN_IF(NS_FAILED(rv
))) {
1762 rv
= aConnection
.ExecuteSimpleSQL(
1763 // Drop these indexes before we do anything else to free disk space.
1764 "DROP INDEX index_data_object_data_id_index;"
1765 "DROP INDEX unique_index_data_object_data_id_index;"_ns
);
1766 if (NS_WARN_IF(NS_FAILED(rv
))) {
1770 // Create the new tables and triggers first.
1772 rv
= aConnection
.ExecuteSimpleSQL(
1773 // This will eventually become the |database| table.
1774 "CREATE TABLE database_upgrade "
1775 "( name TEXT PRIMARY KEY"
1776 ", origin TEXT NOT NULL"
1777 ", version INTEGER NOT NULL DEFAULT 0"
1778 ", last_vacuum_time INTEGER NOT NULL DEFAULT 0"
1779 ", last_analyze_time INTEGER NOT NULL DEFAULT 0"
1780 ", last_vacuum_size INTEGER NOT NULL DEFAULT 0"
1781 ") WITHOUT ROWID;"_ns
);
1782 if (NS_WARN_IF(NS_FAILED(rv
))) {
1786 rv
= aConnection
.ExecuteSimpleSQL(
1787 // This will eventually become the |object_store| table.
1788 "CREATE TABLE object_store_upgrade"
1789 "( id INTEGER PRIMARY KEY"
1790 ", auto_increment INTEGER NOT NULL DEFAULT 0"
1791 ", name TEXT NOT NULL"
1794 if (NS_WARN_IF(NS_FAILED(rv
))) {
1798 rv
= aConnection
.ExecuteSimpleSQL(
1799 // This will eventually become the |object_store_index| table.
1800 "CREATE TABLE object_store_index_upgrade"
1801 "( id INTEGER PRIMARY KEY"
1802 ", object_store_id INTEGER NOT NULL"
1803 ", name TEXT NOT NULL"
1804 ", key_path TEXT NOT NULL"
1805 ", unique_index INTEGER NOT NULL"
1806 ", multientry INTEGER NOT NULL"
1807 ", FOREIGN KEY (object_store_id) "
1808 "REFERENCES object_store(id) "
1810 if (NS_WARN_IF(NS_FAILED(rv
))) {
1814 rv
= aConnection
.ExecuteSimpleSQL(
1815 // This will eventually become the |object_data| table.
1816 "CREATE TABLE object_data_upgrade"
1817 "( object_store_id INTEGER NOT NULL"
1818 ", key BLOB NOT NULL"
1819 ", index_data_values BLOB DEFAULT NULL"
1821 ", data BLOB NOT NULL"
1822 ", PRIMARY KEY (object_store_id, key)"
1823 ", FOREIGN KEY (object_store_id) "
1824 "REFERENCES object_store(id) "
1825 ") WITHOUT ROWID;"_ns
);
1826 if (NS_WARN_IF(NS_FAILED(rv
))) {
1830 rv
= aConnection
.ExecuteSimpleSQL(
1831 // This will eventually become the |index_data| table.
1832 "CREATE TABLE index_data_upgrade"
1833 "( index_id INTEGER NOT NULL"
1834 ", value BLOB NOT NULL"
1835 ", object_data_key BLOB NOT NULL"
1836 ", object_store_id INTEGER NOT NULL"
1837 ", PRIMARY KEY (index_id, value, object_data_key)"
1838 ", FOREIGN KEY (index_id) "
1839 "REFERENCES object_store_index(id) "
1840 ", FOREIGN KEY (object_store_id, object_data_key) "
1841 "REFERENCES object_data(object_store_id, key) "
1842 ") WITHOUT ROWID;"_ns
);
1843 if (NS_WARN_IF(NS_FAILED(rv
))) {
1847 rv
= aConnection
.ExecuteSimpleSQL(
1848 // This will eventually become the |unique_index_data| table.
1849 "CREATE TABLE unique_index_data_upgrade"
1850 "( index_id INTEGER NOT NULL"
1851 ", value BLOB NOT NULL"
1852 ", object_store_id INTEGER NOT NULL"
1853 ", object_data_key BLOB NOT NULL"
1854 ", PRIMARY KEY (index_id, value)"
1855 ", FOREIGN KEY (index_id) "
1856 "REFERENCES object_store_index(id) "
1857 ", FOREIGN KEY (object_store_id, object_data_key) "
1858 "REFERENCES object_data(object_store_id, key) "
1859 ") WITHOUT ROWID;"_ns
);
1860 if (NS_WARN_IF(NS_FAILED(rv
))) {
1864 rv
= aConnection
.ExecuteSimpleSQL(
1865 // Temporarily store |index_data_values| that we build during the upgrade
1866 // of the index tables. We will later move this to the |object_data|
1868 "CREATE TEMPORARY TABLE temp_index_data_values "
1869 "( object_store_id INTEGER NOT NULL"
1870 ", key BLOB NOT NULL"
1871 ", index_data_values BLOB DEFAULT NULL"
1872 ", PRIMARY KEY (object_store_id, key)"
1873 ") WITHOUT ROWID;"_ns
);
1874 if (NS_WARN_IF(NS_FAILED(rv
))) {
1878 rv
= aConnection
.ExecuteSimpleSQL(
1879 // These two triggers help build the |index_data_values| blobs. The nested
1880 // SELECT statements help us achieve an "INSERT OR UPDATE"-like behavior.
1881 "CREATE TEMPORARY TRIGGER unique_index_data_upgrade_insert_trigger "
1882 "AFTER INSERT ON unique_index_data_upgrade "
1884 "INSERT OR REPLACE INTO temp_index_data_values "
1886 "( NEW.object_store_id"
1887 ", NEW.object_data_key"
1889 "( SELECT index_data_values "
1890 "FROM temp_index_data_values "
1891 "WHERE object_store_id = NEW.object_store_id "
1892 "AND key = NEW.object_data_key "
1899 if (NS_WARN_IF(NS_FAILED(rv
))) {
1903 rv
= aConnection
.ExecuteSimpleSQL(
1904 "CREATE TEMPORARY TRIGGER index_data_upgrade_insert_trigger "
1905 "AFTER INSERT ON index_data_upgrade "
1907 "INSERT OR REPLACE INTO temp_index_data_values "
1909 "( NEW.object_store_id"
1910 ", NEW.object_data_key"
1913 "SELECT index_data_values "
1914 "FROM temp_index_data_values "
1915 "WHERE object_store_id = NEW.object_store_id "
1916 "AND key = NEW.object_data_key "
1918 ", 0" /* not unique */
1923 if (NS_WARN_IF(NS_FAILED(rv
))) {
1927 // Update the |unique_index_data| table to change the column order, remove the
1928 // ON DELETE CASCADE clauses, and to apply the WITHOUT ROWID optimization.
1929 rv
= aConnection
.ExecuteSimpleSQL(
1930 // Insert all the data.
1931 "INSERT INTO unique_index_data_upgrade "
1933 "unique_index_data.index_id, "
1934 "upgrade_key(unique_index_data.value), "
1935 "object_data.object_store_id, "
1936 "upgrade_key(unique_index_data.object_data_key) "
1937 "FROM unique_index_data "
1939 "ON unique_index_data.object_data_id = object_data.id;"_ns
);
1940 if (NS_WARN_IF(NS_FAILED(rv
))) {
1944 rv
= aConnection
.ExecuteSimpleSQL(
1945 // The trigger is no longer needed.
1946 "DROP TRIGGER unique_index_data_upgrade_insert_trigger;"_ns
);
1947 if (NS_WARN_IF(NS_FAILED(rv
))) {
1951 rv
= aConnection
.ExecuteSimpleSQL(
1952 // The old table is no longer needed.
1953 "DROP TABLE unique_index_data;"_ns
);
1954 if (NS_WARN_IF(NS_FAILED(rv
))) {
1958 rv
= aConnection
.ExecuteSimpleSQL(
1959 // Rename the table.
1960 "ALTER TABLE unique_index_data_upgrade "
1961 "RENAME TO unique_index_data;"_ns
);
1962 if (NS_WARN_IF(NS_FAILED(rv
))) {
1966 // Update the |index_data| table to change the column order, remove the ON
1967 // DELETE CASCADE clauses, and to apply the WITHOUT ROWID optimization.
1968 rv
= aConnection
.ExecuteSimpleSQL(
1969 // Insert all the data.
1970 "INSERT INTO index_data_upgrade "
1972 "index_data.index_id, "
1973 "upgrade_key(index_data.value), "
1974 "upgrade_key(index_data.object_data_key), "
1975 "object_data.object_store_id "
1978 "ON index_data.object_data_id = object_data.id;"_ns
);
1979 if (NS_WARN_IF(NS_FAILED(rv
))) {
1983 rv
= aConnection
.ExecuteSimpleSQL(
1984 // The trigger is no longer needed.
1985 "DROP TRIGGER index_data_upgrade_insert_trigger;"_ns
);
1986 if (NS_WARN_IF(NS_FAILED(rv
))) {
1990 rv
= aConnection
.ExecuteSimpleSQL(
1991 // The old table is no longer needed.
1992 "DROP TABLE index_data;"_ns
);
1993 if (NS_WARN_IF(NS_FAILED(rv
))) {
1997 rv
= aConnection
.ExecuteSimpleSQL(
1998 // Rename the table.
1999 "ALTER TABLE index_data_upgrade "
2000 "RENAME TO index_data;"_ns
);
2001 if (NS_WARN_IF(NS_FAILED(rv
))) {
2005 // Update the |object_data| table to add the |index_data_values| column,
2006 // remove the ON DELETE CASCADE clause, and apply the WITHOUT ROWID
2008 rv
= aConnection
.ExecuteSimpleSQL(
2009 // Insert all the data.
2010 "INSERT INTO object_data_upgrade "
2012 "object_data.object_store_id, "
2013 "upgrade_key(object_data.key_value), "
2014 "temp_index_data_values.index_data_values, "
2015 "object_data.file_ids, "
2018 "LEFT JOIN temp_index_data_values "
2019 "ON object_data.object_store_id = "
2020 "temp_index_data_values.object_store_id "
2021 "AND upgrade_key(object_data.key_value) = "
2022 "temp_index_data_values.key;"_ns
);
2023 if (NS_WARN_IF(NS_FAILED(rv
))) {
2027 rv
= aConnection
.ExecuteSimpleSQL(
2028 // The temporary table is no longer needed.
2029 "DROP TABLE temp_index_data_values;"_ns
);
2030 if (NS_WARN_IF(NS_FAILED(rv
))) {
2034 rv
= aConnection
.ExecuteSimpleSQL(
2035 // The old table is no longer needed.
2036 "DROP TABLE object_data;"_ns
);
2037 if (NS_WARN_IF(NS_FAILED(rv
))) {
2041 rv
= aConnection
.ExecuteSimpleSQL(
2042 // Rename the table.
2043 "ALTER TABLE object_data_upgrade "
2044 "RENAME TO object_data;"_ns
);
2045 if (NS_WARN_IF(NS_FAILED(rv
))) {
2049 // Update the |object_store_index| table to remove the UNIQUE constraint and
2050 // the ON DELETE CASCADE clause.
2051 rv
= aConnection
.ExecuteSimpleSQL(
2052 "INSERT INTO object_store_index_upgrade "
2054 "FROM object_store_index;"_ns
);
2055 if (NS_WARN_IF(NS_FAILED(rv
))) {
2059 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_store_index;"_ns
);
2060 if (NS_WARN_IF(NS_FAILED(rv
))) {
2064 rv
= aConnection
.ExecuteSimpleSQL(
2065 "ALTER TABLE object_store_index_upgrade "
2066 "RENAME TO object_store_index;"_ns
);
2067 if (NS_WARN_IF(NS_FAILED(rv
))) {
2071 // Update the |object_store| table to remove the UNIQUE constraint.
2072 rv
= aConnection
.ExecuteSimpleSQL(
2073 "INSERT INTO object_store_upgrade "
2075 "FROM object_store;"_ns
);
2076 if (NS_WARN_IF(NS_FAILED(rv
))) {
2080 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE object_store;"_ns
);
2081 if (NS_WARN_IF(NS_FAILED(rv
))) {
2085 rv
= aConnection
.ExecuteSimpleSQL(
2086 "ALTER TABLE object_store_upgrade "
2087 "RENAME TO object_store;"_ns
);
2088 if (NS_WARN_IF(NS_FAILED(rv
))) {
2092 // Update the |database| table to include the origin, vacuum information, and
2093 // apply the WITHOUT ROWID optimization.
2094 nsCOMPtr
<mozIStorageStatement
> stmt
;
2096 // The parameter names are not used, parameters are bound by index only
2097 // locally in the same function.
2098 rv
= aConnection
.CreateStatement(
2099 "INSERT INTO database_upgrade "
2100 "SELECT name, :origin, version, 0, 0, 0 "
2101 "FROM database;"_ns
,
2102 getter_AddRefs(stmt
));
2103 if (NS_WARN_IF(NS_FAILED(rv
))) {
2107 rv
= stmt
->BindUTF8StringByIndex(0, aOrigin
);
2108 if (NS_WARN_IF(NS_FAILED(rv
))) {
2112 rv
= stmt
->Execute();
2113 if (NS_WARN_IF(NS_FAILED(rv
))) {
2117 rv
= aConnection
.ExecuteSimpleSQL("DROP TABLE database;"_ns
);
2118 if (NS_WARN_IF(NS_FAILED(rv
))) {
2122 rv
= aConnection
.ExecuteSimpleSQL(
2123 "ALTER TABLE database_upgrade "
2124 "RENAME TO database;"_ns
);
2125 if (NS_WARN_IF(NS_FAILED(rv
))) {
2131 // Make sure there's only one entry in the |database| table.
2132 QM_TRY_INSPECT(const auto& stmt
,
2133 quota::CreateAndExecuteSingleStepStatement(
2134 aConnection
, "SELECT COUNT(*) FROM database;"_ns
),
2135 QM_ASSERT_UNREACHABLE
);
2138 MOZ_ASSERT(NS_SUCCEEDED(stmt
->GetInt64(0, &count
)));
2140 MOZ_ASSERT(count
== 1);
2144 // Recreate file table triggers.
2145 rv
= aConnection
.ExecuteSimpleSQL(
2146 "CREATE TRIGGER object_data_insert_trigger "
2147 "AFTER INSERT ON object_data "
2148 "WHEN NEW.file_ids IS NOT NULL "
2150 "SELECT update_refcount(NULL, NEW.file_ids);"
2152 if (NS_WARN_IF(NS_FAILED(rv
))) {
2156 rv
= aConnection
.ExecuteSimpleSQL(
2157 "CREATE TRIGGER object_data_update_trigger "
2158 "AFTER UPDATE OF file_ids ON object_data "
2159 "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
2161 "SELECT update_refcount(OLD.file_ids, NEW.file_ids);"
2163 if (NS_WARN_IF(NS_FAILED(rv
))) {
2167 rv
= aConnection
.ExecuteSimpleSQL(
2168 "CREATE TRIGGER object_data_delete_trigger "
2169 "AFTER DELETE ON object_data "
2170 "WHEN OLD.file_ids IS NOT NULL "
2172 "SELECT update_refcount(OLD.file_ids, NULL);"
2174 if (NS_WARN_IF(NS_FAILED(rv
))) {
2178 // Finally, turn on auto_vacuum mode. We use full auto_vacuum mode to reclaim
2179 // disk space on mobile devices (at the cost of some COMMIT speed), and
2180 // incremental auto_vacuum mode on desktop builds.
2181 rv
= aConnection
.ExecuteSimpleSQL(
2183 "PRAGMA auto_vacuum = FULL;"_ns
2185 "PRAGMA auto_vacuum = INCREMENTAL;"_ns
2188 if (NS_WARN_IF(NS_FAILED(rv
))) {
2192 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(18, 0));
2193 if (NS_WARN_IF(NS_FAILED(rv
))) {
2200 nsresult
UpgradeSchemaFrom17_0To18_0(mozIStorageConnection
& aConnection
,
2201 const nsACString
& aOrigin
) {
2202 MOZ_ASSERT(!aOrigin
.IsEmpty());
2204 AUTO_PROFILER_LABEL("UpgradeSchemaFrom17_0To18_0", DOM
);
2206 return UpgradeSchemaFrom17_0To18_0Helper::DoUpgrade(aConnection
, aOrigin
);
2209 nsresult
UpgradeSchemaFrom18_0To19_0(mozIStorageConnection
& aConnection
) {
2210 AssertIsOnIOThread();
2213 AUTO_PROFILER_LABEL("UpgradeSchemaFrom18_0To19_0", DOM
);
2215 rv
= aConnection
.ExecuteSimpleSQL(
2216 "ALTER TABLE object_store_index "
2217 "ADD COLUMN locale TEXT;"_ns
);
2218 if (NS_WARN_IF(NS_FAILED(rv
))) {
2222 rv
= aConnection
.ExecuteSimpleSQL(
2223 "ALTER TABLE object_store_index "
2224 "ADD COLUMN is_auto_locale BOOLEAN;"_ns
);
2225 if (NS_WARN_IF(NS_FAILED(rv
))) {
2229 rv
= aConnection
.ExecuteSimpleSQL(
2230 "ALTER TABLE index_data "
2231 "ADD COLUMN value_locale BLOB;"_ns
);
2232 if (NS_WARN_IF(NS_FAILED(rv
))) {
2236 rv
= aConnection
.ExecuteSimpleSQL(
2237 "ALTER TABLE unique_index_data "
2238 "ADD COLUMN value_locale BLOB;"_ns
);
2239 if (NS_WARN_IF(NS_FAILED(rv
))) {
2243 rv
= aConnection
.ExecuteSimpleSQL(
2244 "CREATE INDEX index_data_value_locale_index "
2245 "ON index_data (index_id, value_locale, object_data_key, value) "
2246 "WHERE value_locale IS NOT NULL;"_ns
);
2247 if (NS_WARN_IF(NS_FAILED(rv
))) {
2251 rv
= aConnection
.ExecuteSimpleSQL(
2252 "CREATE INDEX unique_index_data_value_locale_index "
2253 "ON unique_index_data (index_id, value_locale, object_data_key, value) "
2254 "WHERE value_locale IS NOT NULL;"_ns
);
2255 if (NS_WARN_IF(NS_FAILED(rv
))) {
2259 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(19, 0));
2260 if (NS_WARN_IF(NS_FAILED(rv
))) {
2267 class UpgradeFileIdsFunction final
: public mozIStorageFunction
{
2268 SafeRefPtr
<DatabaseFileManager
> mFileManager
;
2271 UpgradeFileIdsFunction() { AssertIsOnIOThread(); }
2273 nsresult
Init(nsIFile
* aFMDirectory
, mozIStorageConnection
& aConnection
);
2278 ~UpgradeFileIdsFunction() {
2279 AssertIsOnIOThread();
2282 mFileManager
->Invalidate();
2287 OnFunctionCall(mozIStorageValueArray
* aArguments
,
2288 nsIVariant
** aResult
) override
;
2291 nsresult
UpgradeSchemaFrom19_0To20_0(nsIFile
* aFMDirectory
,
2292 mozIStorageConnection
& aConnection
) {
2293 AssertIsOnIOThread();
2295 AUTO_PROFILER_LABEL("UpgradeSchemaFrom19_0To20_0", DOM
);
2297 nsCOMPtr
<mozIStorageStatement
> stmt
;
2298 nsresult rv
= aConnection
.CreateStatement(
2301 "WHERE file_ids IS NOT NULL"_ns
,
2302 getter_AddRefs(stmt
));
2303 if (NS_WARN_IF(NS_FAILED(rv
))) {
2310 mozStorageStatementScoper
scoper(stmt
);
2312 QM_TRY_INSPECT(const bool& hasResult
,
2313 MOZ_TO_RESULT_INVOKE_MEMBER(stmt
, ExecuteStep
));
2315 if (NS_WARN_IF(!hasResult
)) {
2316 MOZ_ASSERT(false, "This should never be possible!");
2317 return NS_ERROR_FAILURE
;
2320 count
= stmt
->AsInt64(0);
2321 if (NS_WARN_IF(count
< 0)) {
2322 MOZ_ASSERT(false, "This should never be possible!");
2323 return NS_ERROR_FAILURE
;
2328 // Nothing to upgrade.
2329 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(20, 0));
2330 if (NS_WARN_IF(NS_FAILED(rv
))) {
2337 RefPtr
<UpgradeFileIdsFunction
> function
= new UpgradeFileIdsFunction();
2339 rv
= function
->Init(aFMDirectory
, aConnection
);
2340 if (NS_WARN_IF(NS_FAILED(rv
))) {
2344 constexpr auto functionName
= "upgrade"_ns
;
2346 rv
= aConnection
.CreateFunction(functionName
, 2, function
);
2347 if (NS_WARN_IF(NS_FAILED(rv
))) {
2351 // Disable update trigger.
2352 rv
= aConnection
.ExecuteSimpleSQL(
2353 "DROP TRIGGER object_data_update_trigger;"_ns
);
2354 if (NS_WARN_IF(NS_FAILED(rv
))) {
2358 rv
= aConnection
.ExecuteSimpleSQL(
2359 "UPDATE object_data "
2360 "SET file_ids = upgrade(file_ids, data) "
2361 "WHERE file_ids IS NOT NULL;"_ns
);
2362 if (NS_WARN_IF(NS_FAILED(rv
))) {
2366 // Enable update trigger.
2367 rv
= aConnection
.ExecuteSimpleSQL(
2368 "CREATE TRIGGER object_data_update_trigger "
2369 "AFTER UPDATE OF file_ids ON object_data "
2371 "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
2373 "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
2375 if (NS_WARN_IF(NS_FAILED(rv
))) {
2379 rv
= aConnection
.RemoveFunction(functionName
);
2380 if (NS_WARN_IF(NS_FAILED(rv
))) {
2384 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(20, 0));
2385 if (NS_WARN_IF(NS_FAILED(rv
))) {
2392 class UpgradeIndexDataValuesFunction final
: public mozIStorageFunction
{
2394 UpgradeIndexDataValuesFunction() { AssertIsOnIOThread(); }
2399 ~UpgradeIndexDataValuesFunction() { AssertIsOnIOThread(); }
2401 using IndexDataValuesArray
= IndexDataValuesAutoArray
;
2402 Result
<IndexDataValuesArray
, nsresult
> ReadOldCompressedIDVFromBlob(
2403 Span
<const uint8_t> aBlobData
);
2406 OnFunctionCall(mozIStorageValueArray
* aArguments
,
2407 nsIVariant
** aResult
) override
;
2410 NS_IMPL_ISUPPORTS(UpgradeIndexDataValuesFunction
, mozIStorageFunction
)
2412 Result
<UpgradeIndexDataValuesFunction::IndexDataValuesArray
, nsresult
>
2413 UpgradeIndexDataValuesFunction::ReadOldCompressedIDVFromBlob(
2414 const Span
<const uint8_t> aBlobData
) {
2415 MOZ_ASSERT(!NS_IsMainThread());
2416 MOZ_ASSERT(!IsOnBackgroundThread());
2418 IndexOrObjectStoreId indexId
;
2420 bool nextIndexIdAlreadyRead
= false;
2422 IndexDataValuesArray result
;
2423 for (auto remainder
= aBlobData
; !remainder
.IsEmpty();) {
2424 if (!nextIndexIdAlreadyRead
) {
2425 QM_TRY_UNWRAP((std::tie(indexId
, unique
, remainder
)),
2426 ReadCompressedIndexId(remainder
));
2428 nextIndexIdAlreadyRead
= false;
2430 if (NS_WARN_IF(remainder
.IsEmpty())) {
2431 IDB_REPORT_INTERNAL_ERR();
2432 return Err(NS_ERROR_FILE_CORRUPTED
);
2435 // Read key buffer length.
2437 (const auto& [keyBufferLength
, remainderAfterKeyBufferLength
]),
2438 ReadCompressedNumber(remainder
));
2440 if (NS_WARN_IF(remainderAfterKeyBufferLength
.IsEmpty()) ||
2441 NS_WARN_IF(keyBufferLength
> uint64_t(UINT32_MAX
)) ||
2442 NS_WARN_IF(keyBufferLength
> remainderAfterKeyBufferLength
.Length())) {
2443 IDB_REPORT_INTERNAL_ERR();
2444 return Err(NS_ERROR_FILE_CORRUPTED
);
2447 const auto [keyBuffer
, remainderAfterKeyBuffer
] =
2448 remainderAfterKeyBufferLength
.SplitAt(keyBufferLength
);
2449 if (NS_WARN_IF(!result
.EmplaceBack(fallible
, indexId
, unique
,
2450 Key
{nsCString
{AsChars(keyBuffer
)}}))) {
2451 IDB_REPORT_INTERNAL_ERR();
2452 return Err(NS_ERROR_OUT_OF_MEMORY
);
2455 remainder
= remainderAfterKeyBuffer
;
2456 if (!remainder
.IsEmpty()) {
2457 // Read either a sort key buffer length or an index id.
2458 QM_TRY_INSPECT((const auto& [maybeIndexId
, remainderAfterIndexId
]),
2459 ReadCompressedNumber(remainder
));
2461 // Locale-aware indexes haven't been around long enough to have any users,
2462 // we can safely assume all sort key buffer lengths will be zero.
2463 // XXX This duplicates logic from ReadCompressedIndexId.
2464 if (maybeIndexId
!= 0) {
2465 unique
= maybeIndexId
% 2 == 1;
2466 indexId
= maybeIndexId
/ 2;
2467 nextIndexIdAlreadyRead
= true;
2470 remainder
= remainderAfterIndexId
;
2479 UpgradeIndexDataValuesFunction::OnFunctionCall(
2480 mozIStorageValueArray
* aArguments
, nsIVariant
** aResult
) {
2481 MOZ_ASSERT(aArguments
);
2482 MOZ_ASSERT(aResult
);
2484 AUTO_PROFILER_LABEL("UpgradeIndexDataValuesFunction::OnFunctionCall", DOM
);
2487 nsresult rv
= aArguments
->GetNumEntries(&argc
);
2488 if (NS_WARN_IF(NS_FAILED(rv
))) {
2493 NS_WARNING("Don't call me with the wrong number of arguments!");
2494 return NS_ERROR_UNEXPECTED
;
2498 rv
= aArguments
->GetTypeOfIndex(0, &type
);
2499 if (NS_WARN_IF(NS_FAILED(rv
))) {
2503 if (type
!= mozIStorageStatement::VALUE_TYPE_BLOB
) {
2504 NS_WARNING("Don't call me with the wrong type of arguments!");
2505 return NS_ERROR_UNEXPECTED
;
2508 const uint8_t* oldBlob
;
2509 uint32_t oldBlobLength
;
2510 rv
= aArguments
->GetSharedBlob(0, &oldBlobLength
, &oldBlob
);
2511 if (NS_WARN_IF(NS_FAILED(rv
))) {
2515 QM_TRY_INSPECT(const auto& oldIdv
,
2516 ReadOldCompressedIDVFromBlob(Span(oldBlob
, oldBlobLength
)));
2518 QM_TRY_UNWRAP((auto [newIdv
, newIdvLength
]),
2519 MakeCompressedIndexDataValues(oldIdv
));
2521 nsCOMPtr
<nsIVariant
> result
= new storage::AdoptedBlobVariant(
2522 std::pair(newIdv
.release(), newIdvLength
));
2524 result
.forget(aResult
);
2528 nsresult
UpgradeSchemaFrom20_0To21_0(mozIStorageConnection
& aConnection
) {
2529 // This should have been part of the 18 to 19 upgrade, where we changed the
2530 // layout of the index_data_values blobs but didn't upgrade the existing data.
2533 AssertIsOnIOThread();
2535 AUTO_PROFILER_LABEL("UpgradeSchemaFrom20_0To21_0", DOM
);
2537 RefPtr
<UpgradeIndexDataValuesFunction
> function
=
2538 new UpgradeIndexDataValuesFunction();
2540 constexpr auto functionName
= "upgrade_idv"_ns
;
2542 nsresult rv
= aConnection
.CreateFunction(functionName
, 1, function
);
2543 if (NS_WARN_IF(NS_FAILED(rv
))) {
2547 rv
= aConnection
.ExecuteSimpleSQL(
2548 "UPDATE object_data "
2549 "SET index_data_values = upgrade_idv(index_data_values) "
2550 "WHERE index_data_values IS NOT NULL;"_ns
);
2551 if (NS_WARN_IF(NS_FAILED(rv
))) {
2555 rv
= aConnection
.RemoveFunction(functionName
);
2556 if (NS_WARN_IF(NS_FAILED(rv
))) {
2560 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(21, 0));
2561 if (NS_WARN_IF(NS_FAILED(rv
))) {
2568 nsresult
UpgradeSchemaFrom21_0To22_0(mozIStorageConnection
& aConnection
) {
2569 // The only change between 21 and 22 was a different structured clone format,
2570 // but it's backwards-compatible.
2571 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(22, 0));
2572 if (NS_WARN_IF(NS_FAILED(rv
))) {
2579 nsresult
UpgradeSchemaFrom22_0To23_0(mozIStorageConnection
& aConnection
,
2580 const nsACString
& aOrigin
) {
2581 AssertIsOnIOThread();
2583 MOZ_ASSERT(!aOrigin
.IsEmpty());
2585 AUTO_PROFILER_LABEL("UpgradeSchemaFrom22_0To23_0", DOM
);
2587 nsCOMPtr
<mozIStorageStatement
> stmt
;
2588 // The parameter names are not used, parameters are bound by index only
2589 // locally in the same function.
2590 nsresult rv
= aConnection
.CreateStatement(
2591 "UPDATE database SET origin = :origin;"_ns
, getter_AddRefs(stmt
));
2592 if (NS_WARN_IF(NS_FAILED(rv
))) {
2596 rv
= stmt
->BindUTF8StringByIndex(0, aOrigin
);
2597 if (NS_WARN_IF(NS_FAILED(rv
))) {
2601 rv
= stmt
->Execute();
2602 if (NS_WARN_IF(NS_FAILED(rv
))) {
2606 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(23, 0));
2607 if (NS_WARN_IF(NS_FAILED(rv
))) {
2614 nsresult
UpgradeSchemaFrom23_0To24_0(mozIStorageConnection
& aConnection
) {
2615 // The only change between 23 and 24 was a different structured clone format,
2616 // but it's backwards-compatible.
2617 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(24, 0));
2618 if (NS_WARN_IF(NS_FAILED(rv
))) {
2625 nsresult
UpgradeSchemaFrom24_0To25_0(mozIStorageConnection
& aConnection
) {
2626 // The changes between 24 and 25 were an upgraded snappy library, a different
2627 // structured clone format and a different file_ds format. But everything is
2628 // backwards-compatible.
2629 nsresult rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(25, 0));
2630 if (NS_WARN_IF(NS_FAILED(rv
))) {
2637 class StripObsoleteOriginAttributesFunction final
: public mozIStorageFunction
{
2642 ~StripObsoleteOriginAttributesFunction() = default;
2645 OnFunctionCall(mozIStorageValueArray
* aArguments
,
2646 nsIVariant
** aResult
) override
{
2647 MOZ_ASSERT(aArguments
);
2648 MOZ_ASSERT(aResult
);
2650 AUTO_PROFILER_LABEL("StripObsoleteOriginAttributesFunction::OnFunctionCall",
2656 MOZ_ALWAYS_SUCCEEDS(aArguments
->GetNumEntries(&argCount
));
2657 MOZ_ASSERT(argCount
== 1);
2660 MOZ_ALWAYS_SUCCEEDS(aArguments
->GetTypeOfIndex(0, &type
));
2661 MOZ_ASSERT(type
== mozIStorageValueArray::VALUE_TYPE_TEXT
);
2666 nsresult rv
= aArguments
->GetUTF8String(0, origin
);
2667 if (NS_WARN_IF(NS_FAILED(rv
))) {
2671 // Deserialize and re-serialize to automatically drop any obsolete origin
2673 OriginAttributes oa
;
2675 nsCString originNoSuffix
;
2676 bool ok
= oa
.PopulateFromOrigin(origin
, originNoSuffix
);
2677 if (NS_WARN_IF(!ok
)) {
2678 return NS_ERROR_FAILURE
;
2682 oa
.CreateSuffix(suffix
);
2684 nsCOMPtr
<nsIVariant
> result
=
2685 new mozilla::storage::UTF8TextVariant(originNoSuffix
+ suffix
);
2687 result
.forget(aResult
);
2692 nsresult
UpgradeSchemaFrom25_0To26_0(mozIStorageConnection
& aConnection
) {
2693 AssertIsOnIOThread();
2695 AUTO_PROFILER_LABEL("UpgradeSchemaFrom25_0To26_0", DOM
);
2697 constexpr auto functionName
= "strip_obsolete_attributes"_ns
;
2699 nsCOMPtr
<mozIStorageFunction
> stripObsoleteAttributes
=
2700 new StripObsoleteOriginAttributesFunction();
2702 nsresult rv
= aConnection
.CreateFunction(functionName
,
2703 /* aNumArguments */ 1,
2704 stripObsoleteAttributes
);
2705 if (NS_WARN_IF(NS_FAILED(rv
))) {
2709 rv
= aConnection
.ExecuteSimpleSQL(
2711 "SET origin = strip_obsolete_attributes(origin) "
2712 "WHERE origin LIKE '%^%';"_ns
);
2713 if (NS_WARN_IF(NS_FAILED(rv
))) {
2717 rv
= aConnection
.RemoveFunction(functionName
);
2718 if (NS_WARN_IF(NS_FAILED(rv
))) {
2722 rv
= aConnection
.SetSchemaVersion(MakeSchemaVersion(26, 0));
2723 if (NS_WARN_IF(NS_FAILED(rv
))) {
2730 NS_IMPL_ISUPPORTS(CompressDataBlobsFunction
, mozIStorageFunction
)
2731 NS_IMPL_ISUPPORTS(EncodeKeysFunction
, mozIStorageFunction
)
2732 NS_IMPL_ISUPPORTS(StripObsoleteOriginAttributesFunction
, mozIStorageFunction
);
2734 class DeserializeUpgradeValueHelper final
: public Runnable
{
2736 explicit DeserializeUpgradeValueHelper(
2737 StructuredCloneReadInfoParent
& aCloneReadInfo
)
2738 : Runnable("DeserializeUpgradeValueHelper"),
2739 mMonitor("DeserializeUpgradeValueHelper::mMonitor"),
2740 mCloneReadInfo(aCloneReadInfo
),
2741 mStatus(NS_ERROR_FAILURE
) {}
2743 nsresult
DispatchAndWait(nsAString
& aFileIds
) {
2744 // We don't need to go to the main-thread and use the sandbox.
2745 if (!mCloneReadInfo
.Data().Size()) {
2746 PopulateFileIds(aFileIds
);
2750 // The operation will continue on the main-thread.
2752 MOZ_ASSERT(!(mCloneReadInfo
.Data().Size() % sizeof(uint64_t)));
2754 MonitorAutoLock
lock(mMonitor
);
2756 RefPtr
<Runnable
> self
= this;
2757 const nsresult rv
= SchedulerGroup::Dispatch(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
);
2844 Monitor mMonitor MOZ_UNANNOTATED
;
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
, ""_ns
, false,
2867 nsresult rv
= fileManager
->Init(aFMDirectory
, aConnection
);
2868 if (NS_WARN_IF(NS_FAILED(rv
))) {
2872 mFileManager
= std::move(fileManager
);
2876 NS_IMPL_ISUPPORTS(UpgradeFileIdsFunction
, mozIStorageFunction
)
2879 UpgradeFileIdsFunction::OnFunctionCall(mozIStorageValueArray
* aArguments
,
2880 nsIVariant
** aResult
) {
2881 MOZ_ASSERT(aArguments
);
2882 MOZ_ASSERT(aResult
);
2883 MOZ_ASSERT(mFileManager
);
2885 AUTO_PROFILER_LABEL("UpgradeFileIdsFunction::OnFunctionCall", DOM
);
2888 nsresult rv
= aArguments
->GetNumEntries(&argc
);
2889 if (NS_WARN_IF(NS_FAILED(rv
))) {
2894 NS_WARNING("Don't call me with the wrong number of arguments!");
2895 return NS_ERROR_UNEXPECTED
;
2898 QM_TRY_UNWRAP(auto cloneInfo
, GetStructuredCloneReadInfoFromValueArray(
2899 aArguments
, 1, 0, *mFileManager
));
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(MOZ_TO_RESULT(UpgradeSchemaFrom4To5(aConnection
)));
2933 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom5To6(aConnection
)));
2936 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom6To7(aConnection
)));
2939 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom7To8(aConnection
)));
2942 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom8To9_0(aConnection
)));
2943 vacuumNeeded
= true;
2945 case MakeSchemaVersion(9, 0):
2946 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom9_0To10_0(aConnection
)));
2948 case MakeSchemaVersion(10, 0):
2949 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom10_0To11_0(aConnection
)));
2951 case MakeSchemaVersion(11, 0):
2952 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom11_0To12_0(aConnection
)));
2954 case MakeSchemaVersion(12, 0):
2955 QM_TRY(MOZ_TO_RESULT(
2956 UpgradeSchemaFrom12_0To13_0(aConnection
, &vacuumNeeded
)));
2958 case MakeSchemaVersion(13, 0):
2959 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom13_0To14_0(aConnection
)));
2961 case MakeSchemaVersion(14, 0):
2962 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom14_0To15_0(aConnection
)));
2964 case MakeSchemaVersion(15, 0):
2965 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom15_0To16_0(aConnection
)));
2967 case MakeSchemaVersion(16, 0):
2968 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom16_0To17_0(aConnection
)));
2970 case MakeSchemaVersion(17, 0):
2972 MOZ_TO_RESULT(UpgradeSchemaFrom17_0To18_0(aConnection
, aOrigin
)));
2973 vacuumNeeded
= true;
2975 case MakeSchemaVersion(18, 0):
2976 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom18_0To19_0(aConnection
)));
2978 case MakeSchemaVersion(19, 0):
2979 QM_TRY(MOZ_TO_RESULT(
2980 UpgradeSchemaFrom19_0To20_0(&aFMDirectory
, aConnection
)));
2982 case MakeSchemaVersion(20, 0):
2983 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom20_0To21_0(aConnection
)));
2985 case MakeSchemaVersion(21, 0):
2986 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom21_0To22_0(aConnection
)));
2988 case MakeSchemaVersion(22, 0):
2990 MOZ_TO_RESULT(UpgradeSchemaFrom22_0To23_0(aConnection
, aOrigin
)));
2992 case MakeSchemaVersion(23, 0):
2993 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom23_0To24_0(aConnection
)));
2995 case MakeSchemaVersion(24, 0):
2996 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom24_0To25_0(aConnection
)));
2998 case MakeSchemaVersion(25, 0):
2999 QM_TRY(MOZ_TO_RESULT(UpgradeSchemaFrom25_0To26_0(aConnection
)));
3002 QM_FAIL(Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
), []() {
3004 "Unable to open IndexedDB database, no upgrade path is "
3009 QM_TRY_UNWRAP(schemaVersion
,
3010 MOZ_TO_RESULT_INVOKE_MEMBER(aConnection
, GetSchemaVersion
));
3013 MOZ_ASSERT(schemaVersion
== kSQLiteSchemaVersion
);
3015 return vacuumNeeded
;
3018 } // namespace mozilla::dom::indexedDB