1/*
2 * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "SQLiteIDBBackingStore.h"
28
29#if ENABLE(INDEXED_DATABASE)
30
31#include "IDBBindingUtilities.h"
32#include "IDBCursorInfo.h"
33#include "IDBGetAllRecordsData.h"
34#include "IDBGetAllResult.h"
35#include "IDBGetRecordData.h"
36#include "IDBGetResult.h"
37#include "IDBIterateCursorData.h"
38#include "IDBKeyData.h"
39#include "IDBObjectStoreInfo.h"
40#include "IDBSerialization.h"
41#include "IDBTransactionInfo.h"
42#include "IDBValue.h"
43#include "IndexKey.h"
44#include "Logging.h"
45#include "SQLiteDatabase.h"
46#include "SQLiteFileSystem.h"
47#include "SQLiteIDBCursor.h"
48#include "SQLiteStatement.h"
49#include "SQLiteTransaction.h"
50#include "ThreadSafeDataBuffer.h"
51#include <JavaScriptCore/AuxiliaryBarrierInlines.h>
52#include <JavaScriptCore/HeapInlines.h>
53#include <JavaScriptCore/JSCJSValueInlines.h>
54#include <JavaScriptCore/JSGlobalObject.h>
55#include <JavaScriptCore/StrongInlines.h>
56#include <JavaScriptCore/StructureInlines.h>
57#include <wtf/FileSystem.h>
58#include <wtf/NeverDestroyed.h>
59#include <wtf/text/StringConcatenateNumbers.h>
60
61namespace WebCore {
62using namespace JSC;
63namespace IDBServer {
64
65// Current version of the metadata schema being used in the metadata database.
66static const int currentMetadataVersion = 1;
67
68// The IndexedDatabase spec defines the max key generator value as 2^53.
69static const uint64_t maxGeneratorValue = 0x20000000000000;
70
71static int idbKeyCollate(int aLength, const void* aBuffer, int bLength, const void* bBuffer)
72{
73 IDBKeyData a, b;
74 if (!deserializeIDBKeyData(static_cast<const uint8_t*>(aBuffer), aLength, a)) {
75 LOG_ERROR("Unable to deserialize key A in collation function.");
76
77 // There's no way to indicate an error to SQLite - we have to return a sorting decision.
78 // We arbitrarily choose "A > B"
79 return 1;
80 }
81 if (!deserializeIDBKeyData(static_cast<const uint8_t*>(bBuffer), bLength, b)) {
82 LOG_ERROR("Unable to deserialize key B in collation function.");
83
84 // There's no way to indicate an error to SQLite - we have to return a sorting decision.
85 // We arbitrarily choose "A > B"
86 return 1;
87 }
88
89 return a.compare(b);
90}
91
92static const String v1RecordsTableSchema(const String& tableName)
93{
94 return makeString("CREATE TABLE ", tableName, " (objectStoreID INTEGER NOT NULL ON CONFLICT FAIL, key TEXT COLLATE IDBKEY NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, value NOT NULL ON CONFLICT FAIL)");
95}
96
97static const String& v1RecordsTableSchema()
98{
99 static NeverDestroyed<WTF::String> v1RecordsTableSchemaString(v1RecordsTableSchema("Records"));
100 return v1RecordsTableSchemaString;
101}
102
103static const String& v1RecordsTableSchemaAlternate()
104{
105 static NeverDestroyed<WTF::String> v1RecordsTableSchemaString(v1RecordsTableSchema("\"Records\""));
106 return v1RecordsTableSchemaString;
107}
108
109static const String v2RecordsTableSchema(const String& tableName)
110{
111 return makeString("CREATE TABLE ", tableName, " (objectStoreID INTEGER NOT NULL ON CONFLICT FAIL, key TEXT COLLATE IDBKEY NOT NULL ON CONFLICT FAIL, value NOT NULL ON CONFLICT FAIL)");
112}
113
114static const String& v2RecordsTableSchema()
115{
116 static NeverDestroyed<WTF::String> v2RecordsTableSchemaString(v2RecordsTableSchema("Records"));
117 return v2RecordsTableSchemaString;
118}
119
120static const String& v2RecordsTableSchemaAlternate()
121{
122 static NeverDestroyed<WTF::String> v2RecordsTableSchemaString(v2RecordsTableSchema("\"Records\""));
123 return v2RecordsTableSchemaString;
124}
125
126static const String v3RecordsTableSchema(const String& tableName)
127{
128 return makeString("CREATE TABLE ", tableName, " (objectStoreID INTEGER NOT NULL ON CONFLICT FAIL, key TEXT COLLATE IDBKEY NOT NULL ON CONFLICT FAIL, value NOT NULL ON CONFLICT FAIL, recordID INTEGER PRIMARY KEY)");
129}
130
131static const String& v3RecordsTableSchema()
132{
133 static NeverDestroyed<WTF::String> v3RecordsTableSchemaString(v3RecordsTableSchema("Records"));
134 return v3RecordsTableSchemaString;
135}
136
137static const String& v3RecordsTableSchemaAlternate()
138{
139 static NeverDestroyed<WTF::String> v3RecordsTableSchemaString(v3RecordsTableSchema("\"Records\""));
140 return v3RecordsTableSchemaString;
141}
142
143static const String v1IndexRecordsTableSchema(const String& tableName)
144{
145 return makeString("CREATE TABLE ", tableName, " (indexID INTEGER NOT NULL ON CONFLICT FAIL, objectStoreID INTEGER NOT NULL ON CONFLICT FAIL, key TEXT COLLATE IDBKEY NOT NULL ON CONFLICT FAIL, value NOT NULL ON CONFLICT FAIL)");
146}
147
148static const String& v1IndexRecordsTableSchema()
149{
150 static NeverDestroyed<WTF::String> v1IndexRecordsTableSchemaString(v1IndexRecordsTableSchema("IndexRecords"));
151 return v1IndexRecordsTableSchemaString;
152}
153
154static const String& v1IndexRecordsTableSchemaAlternate()
155{
156 static NeverDestroyed<WTF::String> v1IndexRecordsTableSchemaString(v1IndexRecordsTableSchema("\"IndexRecords\""));
157 return v1IndexRecordsTableSchemaString;
158}
159
160static const String v2IndexRecordsTableSchema(const String& tableName)
161{
162 return makeString("CREATE TABLE ", tableName, " (indexID INTEGER NOT NULL ON CONFLICT FAIL, objectStoreID INTEGER NOT NULL ON CONFLICT FAIL, key TEXT COLLATE IDBKEY NOT NULL ON CONFLICT FAIL, value TEXT COLLATE IDBKEY NOT NULL ON CONFLICT FAIL)");
163}
164
165static const String& v2IndexRecordsTableSchema()
166{
167 static NeverDestroyed<WTF::String> v2IndexRecordsTableSchemaString(v2IndexRecordsTableSchema("IndexRecords"));
168 return v2IndexRecordsTableSchemaString;
169}
170
171static const String& v2IndexRecordsTableSchemaAlternate()
172{
173 static NeverDestroyed<WTF::String> v2IndexRecordsTableSchemaString(v2IndexRecordsTableSchema("\"IndexRecords\""));
174 return v2IndexRecordsTableSchemaString;
175}
176
177static const String v3IndexRecordsTableSchema(const String& tableName)
178{
179 return makeString("CREATE TABLE ", tableName, " (indexID INTEGER NOT NULL ON CONFLICT FAIL, objectStoreID INTEGER NOT NULL ON CONFLICT FAIL, key TEXT COLLATE IDBKEY NOT NULL ON CONFLICT FAIL, value TEXT COLLATE IDBKEY NOT NULL ON CONFLICT FAIL, objectStoreRecordID INTEGER NOT NULL ON CONFLICT FAIL)");
180}
181
182static const String v3IndexRecordsTableSchema()
183{
184 static NeverDestroyed<WTF::String> indexRecordsTableSchemaString = v3IndexRecordsTableSchema("IndexRecords");
185 return indexRecordsTableSchemaString;
186}
187
188static const String v3IndexRecordsTableSchemaAlternate()
189{
190 static NeverDestroyed<WTF::String> indexRecordsTableSchemaString = v3IndexRecordsTableSchema("\"IndexRecords\"");
191 return indexRecordsTableSchemaString;
192}
193
194static const String& v1IndexRecordsIndexSchema()
195{
196 static NeverDestroyed<WTF::String> indexRecordsIndexSchemaString("CREATE INDEX IndexRecordsIndex ON IndexRecords (key)");
197 return indexRecordsIndexSchemaString;
198}
199
200static const String blobRecordsTableSchema(const String& tableName)
201{
202 return makeString("CREATE TABLE ", tableName, " (objectStoreRow INTEGER NOT NULL ON CONFLICT FAIL, blobURL TEXT NOT NULL ON CONFLICT FAIL)");
203}
204
205static const String& blobRecordsTableSchema()
206{
207 static NeverDestroyed<String> blobRecordsTableSchemaString(blobRecordsTableSchema("BlobRecords"));
208 return blobRecordsTableSchemaString;
209}
210
211static const String& blobRecordsTableSchemaAlternate()
212{
213 static NeverDestroyed<String> blobRecordsTableSchemaString(blobRecordsTableSchema("\"BlobRecords\""));
214 return blobRecordsTableSchemaString;
215}
216
217static const String blobFilesTableSchema(const String& tableName)
218{
219 return makeString("CREATE TABLE ", tableName, " (blobURL TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT FAIL, fileName TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT FAIL)");
220}
221
222static const String& blobFilesTableSchema()
223{
224 static NeverDestroyed<String> blobFilesTableSchemaString(blobFilesTableSchema("BlobFiles"));
225 return blobFilesTableSchemaString;
226}
227
228static const String& blobFilesTableSchemaAlternate()
229{
230 static NeverDestroyed<String> blobFilesTableSchemaString(blobFilesTableSchema("\"BlobFiles\""));
231 return blobFilesTableSchemaString;
232}
233
234SQLiteIDBBackingStore::SQLiteIDBBackingStore(const IDBDatabaseIdentifier& identifier, const String& databaseRootDirectory, IDBBackingStoreTemporaryFileHandler& fileHandler, uint64_t quota)
235 : m_identifier(identifier)
236 , m_databaseRootDirectory(databaseRootDirectory)
237 , m_temporaryFileHandler(fileHandler)
238 , m_quota(quota)
239{
240 m_databaseDirectory = fullDatabaseDirectoryWithUpgrade();
241}
242
243SQLiteIDBBackingStore::~SQLiteIDBBackingStore()
244{
245 if (m_sqliteDB)
246 closeSQLiteDB();
247
248 if (m_vm) {
249 JSLockHolder locker(m_vm.get());
250 m_globalObject.clear();
251 m_vm = nullptr;
252 }
253}
254
255
256void SQLiteIDBBackingStore::initializeVM()
257{
258 if (!m_vm) {
259 ASSERT(!m_globalObject);
260 m_vm = VM::create();
261
262 JSLockHolder locker(m_vm.get());
263 m_globalObject.set(*m_vm, JSGlobalObject::create(*m_vm, JSGlobalObject::createStructure(*m_vm, jsNull())));
264 }
265}
266
267VM& SQLiteIDBBackingStore::vm()
268{
269 initializeVM();
270 return *m_vm;
271}
272
273JSGlobalObject& SQLiteIDBBackingStore::globalObject()
274{
275 initializeVM();
276 return **m_globalObject;
277}
278
279static bool createOrMigrateRecordsTableIfNecessary(SQLiteDatabase& database)
280{
281 String currentSchema;
282 {
283 // Fetch the schema for an existing records table.
284 SQLiteStatement statement(database, "SELECT type, sql FROM sqlite_master WHERE tbl_name='Records'");
285 if (statement.prepare() != SQLITE_OK) {
286 LOG_ERROR("Unable to prepare statement to fetch schema for the Records table.");
287 return false;
288 }
289
290 int sqliteResult = statement.step();
291
292 // If there is no Records table at all, create it and then bail.
293 if (sqliteResult == SQLITE_DONE) {
294 if (!database.executeCommand(v3RecordsTableSchema())) {
295 LOG_ERROR("Could not create Records table in database (%i) - %s", database.lastError(), database.lastErrorMsg());
296 return false;
297 }
298
299 return true;
300 }
301
302 if (sqliteResult != SQLITE_ROW) {
303 LOG_ERROR("Error executing statement to fetch schema for the Records table.");
304 return false;
305 }
306
307 currentSchema = statement.getColumnText(1);
308 }
309
310 ASSERT(!currentSchema.isEmpty());
311
312 // If the schema in the backing store is the current schema, we're done.
313 if (currentSchema == v3RecordsTableSchema() || currentSchema == v3RecordsTableSchemaAlternate())
314 return true;
315
316 // If the record table is not the current schema then it must be one of the previous schemas.
317 // If it is not then the database is in an unrecoverable state and this should be considered a fatal error.
318 if (currentSchema != v1RecordsTableSchema() && currentSchema != v1RecordsTableSchemaAlternate()
319 && currentSchema != v2RecordsTableSchema() && currentSchema != v2RecordsTableSchemaAlternate())
320 RELEASE_ASSERT_NOT_REACHED();
321
322 SQLiteTransaction transaction(database);
323 transaction.begin();
324
325 // Create a temporary table with the correct schema and migrate all existing content over.
326 if (!database.executeCommand(v3RecordsTableSchema("_Temp_Records"))) {
327 LOG_ERROR("Could not create temporary records table in database (%i) - %s", database.lastError(), database.lastErrorMsg());
328 return false;
329 }
330
331 if (!database.executeCommand("INSERT INTO _Temp_Records (objectStoreID, key, value) SELECT objectStoreID, CAST(key AS TEXT), value FROM Records")) {
332 LOG_ERROR("Could not migrate existing Records content (%i) - %s", database.lastError(), database.lastErrorMsg());
333 return false;
334 }
335
336 if (!database.executeCommand("DROP TABLE Records")) {
337 LOG_ERROR("Could not drop existing Records table (%i) - %s", database.lastError(), database.lastErrorMsg());
338 return false;
339 }
340
341 if (!database.executeCommand("ALTER TABLE _Temp_Records RENAME TO Records")) {
342 LOG_ERROR("Could not rename temporary Records table (%i) - %s", database.lastError(), database.lastErrorMsg());
343 return false;
344 }
345
346 transaction.commit();
347
348 return true;
349}
350
351bool SQLiteIDBBackingStore::ensureValidBlobTables()
352{
353 ASSERT(m_sqliteDB);
354 ASSERT(m_sqliteDB->isOpen());
355
356 String currentSchema;
357 {
358 // Fetch the schema for an existing blob record table.
359 SQLiteStatement statement(*m_sqliteDB, "SELECT type, sql FROM sqlite_master WHERE tbl_name='BlobRecords'");
360 if (statement.prepare() != SQLITE_OK) {
361 LOG_ERROR("Unable to prepare statement to fetch schema for the BlobRecords table.");
362 return false;
363 }
364
365 int sqliteResult = statement.step();
366
367 // If there is no BlobRecords table at all, create it..
368 if (sqliteResult == SQLITE_DONE) {
369 if (!m_sqliteDB->executeCommand(blobRecordsTableSchema())) {
370 LOG_ERROR("Could not create BlobRecords table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
371 return false;
372 }
373
374 currentSchema = blobRecordsTableSchema();
375 } else if (sqliteResult != SQLITE_ROW) {
376 LOG_ERROR("Error executing statement to fetch schema for the BlobRecords table.");
377 return false;
378 } else
379 currentSchema = statement.getColumnText(1);
380 }
381
382 if (currentSchema != blobRecordsTableSchema() && currentSchema != blobRecordsTableSchemaAlternate()) {
383 LOG_ERROR("Invalid BlobRecords table schema found");
384 return false;
385 }
386
387 {
388 // Fetch the schema for an existing blob file table.
389 SQLiteStatement statement(*m_sqliteDB, "SELECT type, sql FROM sqlite_master WHERE tbl_name='BlobFiles'");
390 if (statement.prepare() != SQLITE_OK) {
391 LOG_ERROR("Unable to prepare statement to fetch schema for the BlobFiles table.");
392 return false;
393 }
394
395 int sqliteResult = statement.step();
396
397 // If there is no BlobFiles table at all, create it and then bail.
398 if (sqliteResult == SQLITE_DONE) {
399 if (!m_sqliteDB->executeCommand(blobFilesTableSchema())) {
400 LOG_ERROR("Could not create BlobFiles table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
401 return false;
402 }
403
404 return true;
405 }
406
407 if (sqliteResult != SQLITE_ROW) {
408 LOG_ERROR("Error executing statement to fetch schema for the BlobFiles table.");
409 return false;
410 }
411
412 currentSchema = statement.getColumnText(1);
413 }
414
415 if (currentSchema != blobFilesTableSchema() && currentSchema != blobFilesTableSchemaAlternate()) {
416 LOG_ERROR("Invalid BlobFiles table schema found");
417 return false;
418 }
419
420 return true;
421}
422
423bool SQLiteIDBBackingStore::ensureValidRecordsTable()
424{
425 ASSERT(m_sqliteDB);
426 ASSERT(m_sqliteDB->isOpen());
427
428 if (!createOrMigrateRecordsTableIfNecessary(*m_sqliteDB))
429 return false;
430
431 // Whether the updated records table already existed or if it was just created and the data migrated over,
432 // make sure the uniqueness index exists.
433 if (!m_sqliteDB->executeCommand("CREATE UNIQUE INDEX IF NOT EXISTS RecordsIndex ON Records (objectStoreID, key);")) {
434 LOG_ERROR("Could not create RecordsIndex on Records table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
435 return false;
436 }
437
438 return true;
439}
440
441bool SQLiteIDBBackingStore::ensureValidIndexRecordsTable()
442{
443 ASSERT(m_sqliteDB);
444 ASSERT(m_sqliteDB->isOpen());
445
446 String currentSchema;
447 {
448 // Fetch the schema for an existing index record table.
449 SQLiteStatement statement(*m_sqliteDB, "SELECT type, sql FROM sqlite_master WHERE tbl_name='IndexRecords'");
450 if (statement.prepare() != SQLITE_OK) {
451 LOG_ERROR("Unable to prepare statement to fetch schema for the IndexRecords table.");
452 return false;
453 }
454
455 int sqliteResult = statement.step();
456
457 // If there is no IndexRecords table at all, create it and then bail.
458 if (sqliteResult == SQLITE_DONE) {
459 if (!m_sqliteDB->executeCommand(v3IndexRecordsTableSchema())) {
460 LOG_ERROR("Could not create IndexRecords table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
461 return false;
462 }
463
464 return true;
465 }
466
467 if (sqliteResult != SQLITE_ROW) {
468 LOG_ERROR("Error executing statement to fetch schema for the IndexRecords table.");
469 return false;
470 }
471
472 currentSchema = statement.getColumnText(1);
473 }
474
475 ASSERT(!currentSchema.isEmpty());
476
477 // If the schema in the backing store is the current schema, we're done.
478 if (currentSchema == v3IndexRecordsTableSchema() || currentSchema == v3IndexRecordsTableSchemaAlternate())
479 return true;
480
481 // If the record table is not the current schema then it must be one of the previous schemas.
482 // If it is not then the database is in an unrecoverable state and this should be considered a fatal error.
483 if (currentSchema != v1IndexRecordsTableSchema() && currentSchema != v1IndexRecordsTableSchemaAlternate()
484 && currentSchema != v2IndexRecordsTableSchema() && currentSchema != v2IndexRecordsTableSchemaAlternate())
485 RELEASE_ASSERT_NOT_REACHED();
486
487 SQLiteTransaction transaction(*m_sqliteDB);
488 transaction.begin();
489
490 // Create a temporary table with the correct schema and migrate all existing content over.
491 if (!m_sqliteDB->executeCommand(v3IndexRecordsTableSchema("_Temp_IndexRecords"))) {
492 LOG_ERROR("Could not create temporary index records table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
493 return false;
494 }
495
496 if (!m_sqliteDB->executeCommand("INSERT INTO _Temp_IndexRecords SELECT IndexRecords.indexID, IndexRecords.objectStoreID, IndexRecords.key, IndexRecords.value, Records.rowid FROM IndexRecords INNER JOIN Records ON Records.key = IndexRecords.value AND Records.objectStoreID = IndexRecords.objectStoreID")) {
497 LOG_ERROR("Could not migrate existing IndexRecords content (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
498 return false;
499 }
500
501 if (!m_sqliteDB->executeCommand("DROP TABLE IndexRecords")) {
502 LOG_ERROR("Could not drop existing IndexRecords table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
503 return false;
504 }
505
506 if (!m_sqliteDB->executeCommand("ALTER TABLE _Temp_IndexRecords RENAME TO IndexRecords")) {
507 LOG_ERROR("Could not rename temporary IndexRecords table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
508 return false;
509 }
510
511 transaction.commit();
512
513 return true;
514}
515
516bool SQLiteIDBBackingStore::ensureValidIndexRecordsIndex()
517{
518 ASSERT(m_sqliteDB);
519 ASSERT(m_sqliteDB->isOpen());
520
521 String currentSchema;
522 {
523 // Fetch the schema for an existing index record index.
524 SQLiteStatement statement(*m_sqliteDB, "SELECT sql FROM sqlite_master WHERE name='IndexRecordsIndex'");
525 if (statement.prepare() != SQLITE_OK) {
526 LOG_ERROR("Unable to prepare statement to fetch schema for the IndexRecordsIndex index.");
527 return false;
528 }
529
530 int sqliteResult = statement.step();
531
532 // If there is no IndexRecordsIndex index at all, create it and then bail.
533 if (sqliteResult == SQLITE_DONE) {
534 if (!m_sqliteDB->executeCommand(v1IndexRecordsIndexSchema())) {
535 LOG_ERROR("Could not create IndexRecordsIndex index in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
536 return false;
537 }
538
539 return true;
540 }
541
542 if (sqliteResult != SQLITE_ROW) {
543 LOG_ERROR("Error executing statement to fetch schema for the IndexRecordsIndex index.");
544 return false;
545 }
546
547 currentSchema = statement.getColumnText(0);
548 }
549
550 ASSERT(!currentSchema.isEmpty());
551
552 // If the schema in the backing store is the current schema, we're done.
553 if (currentSchema == v1IndexRecordsIndexSchema())
554 return true;
555
556 // There is currently no outdated schema for the IndexRecordsIndex, so any other existing schema means this database is invalid.
557 return false;
558}
559
560std::unique_ptr<IDBDatabaseInfo> SQLiteIDBBackingStore::createAndPopulateInitialDatabaseInfo()
561{
562 ASSERT(m_sqliteDB);
563 ASSERT(m_sqliteDB->isOpen());
564
565 if (!m_sqliteDB->executeCommand("CREATE TABLE IDBDatabaseInfo (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, value TEXT NOT NULL ON CONFLICT FAIL);")) {
566 LOG_ERROR("Could not create IDBDatabaseInfo table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
567 closeSQLiteDB();
568 return nullptr;
569 }
570
571 if (!m_sqliteDB->executeCommand("CREATE TABLE ObjectStoreInfo (id INTEGER PRIMARY KEY NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT FAIL, name TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT FAIL, keyPath BLOB NOT NULL ON CONFLICT FAIL, autoInc INTEGER NOT NULL ON CONFLICT FAIL, maxIndexID INTEGER NOT NULL ON CONFLICT FAIL);")) {
572 LOG_ERROR("Could not create ObjectStoreInfo table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
573 closeSQLiteDB();
574 return nullptr;
575 }
576
577 if (!m_sqliteDB->executeCommand("CREATE TABLE IndexInfo (id INTEGER NOT NULL ON CONFLICT FAIL, name TEXT NOT NULL ON CONFLICT FAIL, objectStoreID INTEGER NOT NULL ON CONFLICT FAIL, keyPath BLOB NOT NULL ON CONFLICT FAIL, isUnique INTEGER NOT NULL ON CONFLICT FAIL, multiEntry INTEGER NOT NULL ON CONFLICT FAIL);")) {
578 LOG_ERROR("Could not create IndexInfo table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
579 closeSQLiteDB();
580 return nullptr;
581 }
582
583 if (!m_sqliteDB->executeCommand("CREATE TABLE KeyGenerators (objectStoreID INTEGER NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, currentKey INTEGER NOT NULL ON CONFLICT FAIL);")) {
584 LOG_ERROR("Could not create KeyGenerators table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
585 closeSQLiteDB();
586 return nullptr;
587 }
588
589 {
590 SQLiteStatement sql(*m_sqliteDB, "INSERT INTO IDBDatabaseInfo VALUES ('MetadataVersion', ?);"_s);
591 if (sql.prepare() != SQLITE_OK
592 || sql.bindInt(1, currentMetadataVersion) != SQLITE_OK
593 || sql.step() != SQLITE_DONE) {
594 LOG_ERROR("Could not insert database metadata version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
595 closeSQLiteDB();
596 return nullptr;
597 }
598 }
599 {
600 SQLiteStatement sql(*m_sqliteDB, "INSERT INTO IDBDatabaseInfo VALUES ('DatabaseName', ?);"_s);
601 if (sql.prepare() != SQLITE_OK
602 || sql.bindText(1, m_identifier.databaseName()) != SQLITE_OK
603 || sql.step() != SQLITE_DONE) {
604 LOG_ERROR("Could not insert database name into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
605 closeSQLiteDB();
606 return nullptr;
607 }
608 }
609 {
610 // Database versions are defined to be a uin64_t in the spec but sqlite3 doesn't support native binding of unsigned integers.
611 // Therefore we'll store the version as a String.
612 SQLiteStatement sql(*m_sqliteDB, "INSERT INTO IDBDatabaseInfo VALUES ('DatabaseVersion', ?);"_s);
613 if (sql.prepare() != SQLITE_OK
614 || sql.bindText(1, String::number(0)) != SQLITE_OK
615 || sql.step() != SQLITE_DONE) {
616 LOG_ERROR("Could not insert default version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
617 closeSQLiteDB();
618 return nullptr;
619 }
620 }
621
622 if (!m_sqliteDB->executeCommand("INSERT INTO IDBDatabaseInfo VALUES ('MaxObjectStoreID', 1);"_s)) {
623 LOG_ERROR("Could not insert default version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
624 closeSQLiteDB();
625 return nullptr;
626 }
627
628 // This initial database info matches the default values we just put into the metadata database.
629 return std::make_unique<IDBDatabaseInfo>(m_identifier.databaseName(), 0);
630}
631
632std::unique_ptr<IDBDatabaseInfo> SQLiteIDBBackingStore::extractExistingDatabaseInfo()
633{
634 ASSERT(m_sqliteDB);
635
636 if (!m_sqliteDB->tableExists("IDBDatabaseInfo"_s))
637 return nullptr;
638
639 String databaseName;
640 {
641 SQLiteStatement sql(*m_sqliteDB, "SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseName';");
642 if (sql.isColumnNull(0))
643 return nullptr;
644 databaseName = sql.getColumnText(0);
645 if (databaseName != m_identifier.databaseName()) {
646 LOG_ERROR("Database name in the info database ('%s') does not match the expected name ('%s')", databaseName.utf8().data(), m_identifier.databaseName().utf8().data());
647 return nullptr;
648 }
649 }
650 uint64_t databaseVersion;
651 {
652 SQLiteStatement sql(*m_sqliteDB, "SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseVersion';"_s);
653 if (sql.isColumnNull(0))
654 return nullptr;
655 String stringVersion = sql.getColumnText(0);
656 bool ok;
657 databaseVersion = stringVersion.toUInt64Strict(&ok);
658 if (!ok) {
659 LOG_ERROR("Database version on disk ('%s') does not cleanly convert to an unsigned 64-bit integer version", stringVersion.utf8().data());
660 return nullptr;
661 }
662 }
663
664 auto databaseInfo = std::make_unique<IDBDatabaseInfo>(databaseName, databaseVersion);
665
666 {
667 SQLiteStatement sql(*m_sqliteDB, "SELECT id, name, keyPath, autoInc, maxIndexID FROM ObjectStoreInfo;"_s);
668 if (sql.prepare() != SQLITE_OK)
669 return nullptr;
670
671 int result = sql.step();
672 while (result == SQLITE_ROW) {
673 uint64_t objectStoreID = sql.getColumnInt64(0);
674 String objectStoreName = sql.getColumnText(1);
675
676 Vector<char> keyPathBuffer;
677 sql.getColumnBlobAsVector(2, keyPathBuffer);
678
679 Optional<IDBKeyPath> objectStoreKeyPath;
680 if (!deserializeIDBKeyPath(reinterpret_cast<const uint8_t*>(keyPathBuffer.data()), keyPathBuffer.size(), objectStoreKeyPath)) {
681 LOG_ERROR("Unable to extract key path from database");
682 return nullptr;
683 }
684
685 bool autoIncrement = sql.getColumnInt(3);
686
687 databaseInfo->addExistingObjectStore({ objectStoreID, objectStoreName, WTFMove(objectStoreKeyPath), autoIncrement });
688
689 result = sql.step();
690 }
691
692 if (result != SQLITE_DONE) {
693 LOG_ERROR("Error fetching object store info from database on disk");
694 return nullptr;
695 }
696 }
697
698 {
699 SQLiteStatement sql(*m_sqliteDB, "SELECT id, name, objectStoreID, keyPath, isUnique, multiEntry FROM IndexInfo;"_s);
700 if (sql.prepare() != SQLITE_OK)
701 return nullptr;
702
703 int result = sql.step();
704 while (result == SQLITE_ROW) {
705 uint64_t indexID = sql.getColumnInt64(0);
706 String indexName = sql.getColumnText(1);
707 uint64_t objectStoreID = sql.getColumnInt64(2);
708
709 Vector<char> keyPathBuffer;
710 sql.getColumnBlobAsVector(3, keyPathBuffer);
711
712 Optional<IDBKeyPath> indexKeyPath;
713 if (!deserializeIDBKeyPath(reinterpret_cast<const uint8_t*>(keyPathBuffer.data()), keyPathBuffer.size(), indexKeyPath)) {
714 LOG_ERROR("Unable to extract key path from database");
715 return nullptr;
716 }
717 if (!indexKeyPath) {
718 LOG_ERROR("Unable to extract key path from database");
719 return nullptr;
720 }
721
722 bool unique = sql.getColumnInt(4);
723 bool multiEntry = sql.getColumnInt(5);
724
725 auto objectStore = databaseInfo->infoForExistingObjectStore(objectStoreID);
726 if (!objectStore) {
727 LOG_ERROR("Found index referring to a non-existant object store");
728 return nullptr;
729 }
730
731 objectStore->addExistingIndex({ indexID, objectStoreID, indexName, WTFMove(indexKeyPath.value()), unique, multiEntry });
732
733 result = sql.step();
734 }
735
736 if (result != SQLITE_DONE) {
737 LOG_ERROR("Error fetching index info from database on disk");
738 return nullptr;
739 }
740 }
741
742 return databaseInfo;
743}
744
745String SQLiteIDBBackingStore::databaseNameFromEncodedFilename(const String& encodedName)
746{
747 if (encodedName == "%00"_s)
748 return { };
749
750 String partiallyDecoded = encodedName;
751 partiallyDecoded.replace("%2E"_s, "."_s);
752
753 return FileSystem::decodeFromFilename(partiallyDecoded);
754}
755
756String SQLiteIDBBackingStore::filenameForDatabaseName() const
757{
758 ASSERT(!m_identifier.databaseName().isNull());
759
760 if (m_identifier.databaseName().isEmpty())
761 return "%00";
762
763 String filename = FileSystem::encodeForFileName(m_identifier.databaseName());
764 filename.replace('.', "%2E");
765
766 return filename;
767}
768
769String SQLiteIDBBackingStore::fullDatabasePathForDirectory(const String& fullDatabaseDirectory)
770{
771 return FileSystem::pathByAppendingComponent(fullDatabaseDirectory, "IndexedDB.sqlite3");
772}
773
774String SQLiteIDBBackingStore::fullDatabasePath() const
775{
776 return fullDatabasePathForDirectory(m_databaseDirectory);
777}
778
779String SQLiteIDBBackingStore::databaseNameFromFile(const String& databasePath)
780{
781 SQLiteDatabase database;
782 if (!database.open(databasePath)) {
783 LOG_ERROR("Failed to open SQLite database at path '%s' when getting database name", databasePath.utf8().data());
784 return { };
785 }
786 if (!database.tableExists("IDBDatabaseInfo"_s)) {
787 LOG_ERROR("Could not find IDBDatabaseInfo table and get database name(%i) - %s", database.lastError(), database.lastErrorMsg());
788 database.close();
789 return { };
790 }
791 SQLiteStatement sql(database, "SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseName';");
792 auto databaseName = sql.getColumnText(0);
793 database.close();
794 return databaseName;
795}
796
797String SQLiteIDBBackingStore::fullDatabaseDirectoryWithUpgrade()
798{
799 String oldOriginDirectory = m_identifier.databaseDirectoryRelativeToRoot(m_databaseRootDirectory, "v0");
800 String oldDatabaseDirectory = FileSystem::pathByAppendingComponent(oldOriginDirectory, filenameForDatabaseName());
801 String newOriginDirectory = m_identifier.databaseDirectoryRelativeToRoot(m_databaseRootDirectory, "v1");
802 String fileNameHash = SQLiteFileSystem::computeHashForFileName(m_identifier.databaseName());
803 Vector<String> directoriesWithSameHash = FileSystem::listDirectory(newOriginDirectory, fileNameHash + "*");
804 String newDatabaseDirectory = FileSystem::pathByAppendingComponent(newOriginDirectory, fileNameHash);
805 FileSystem::makeAllDirectories(newDatabaseDirectory);
806
807 if (FileSystem::fileExists(oldDatabaseDirectory)) {
808 FileSystem::moveFile(oldDatabaseDirectory, newDatabaseDirectory);
809 FileSystem::deleteEmptyDirectory(oldOriginDirectory);
810 }
811
812 return newDatabaseDirectory;
813}
814
815IDBError SQLiteIDBBackingStore::getOrEstablishDatabaseInfo(IDBDatabaseInfo& info)
816{
817 LOG(IndexedDB, "SQLiteIDBBackingStore::getOrEstablishDatabaseInfo - database %s", m_identifier.databaseName().utf8().data());
818
819 if (m_databaseInfo) {
820 info = *m_databaseInfo;
821 return IDBError { };
822 }
823
824 String dbFilename = fullDatabasePath();
825
826 m_sqliteDB = std::make_unique<SQLiteDatabase>();
827 if (!m_sqliteDB->open(dbFilename)) {
828 LOG_ERROR("Failed to open SQLite database at path '%s'", dbFilename.utf8().data());
829 closeSQLiteDB();
830 }
831
832 if (!m_sqliteDB)
833 return IDBError { UnknownError, "Unable to open database file on disk"_s };
834
835 m_sqliteDB->setCollationFunction("IDBKEY", [](int aLength, const void* a, int bLength, const void* b) {
836 return idbKeyCollate(aLength, a, bLength, b);
837 });
838
839 if (!ensureValidRecordsTable()) {
840 LOG_ERROR("Error creating or migrating Records table in database");
841 closeSQLiteDB();
842 return IDBError { UnknownError, "Error creating or migrating Records table in database"_s };
843 }
844
845 if (!ensureValidIndexRecordsTable()) {
846 LOG_ERROR("Error creating or migrating Index Records table in database");
847 closeSQLiteDB();
848 return IDBError { UnknownError, "Error creating or migrating Index Records table in database"_s };
849 }
850
851 if (!ensureValidIndexRecordsIndex()) {
852 LOG_ERROR("Error creating or migrating Index Records index in database");
853 closeSQLiteDB();
854 return IDBError { UnknownError, "Error creating or migrating Index Records index in database"_s };
855 }
856
857 if (!ensureValidBlobTables()) {
858 LOG_ERROR("Error creating or confirming Blob Records tables in database");
859 closeSQLiteDB();
860 return IDBError { UnknownError, "Error creating or confirming Blob Records tables in database"_s };
861 }
862
863 auto databaseInfo = extractExistingDatabaseInfo();
864 if (!databaseInfo)
865 databaseInfo = createAndPopulateInitialDatabaseInfo();
866
867 if (!databaseInfo) {
868 LOG_ERROR("Unable to establish IDB database at path '%s'", dbFilename.utf8().data());
869 closeSQLiteDB();
870 return IDBError { UnknownError, "Unable to establish IDB database file"_s };
871 }
872
873 m_databaseInfo = WTFMove(databaseInfo);
874 info = *m_databaseInfo;
875 return IDBError { };
876}
877
878uint64_t SQLiteIDBBackingStore::quotaForOrigin() const
879{
880 ASSERT(!isMainThread());
881 uint64_t diskFreeSpaceSize = 0;
882 FileSystem::getVolumeFreeSpace(m_identifier.databaseDirectoryRelativeToRoot(m_databaseRootDirectory), diskFreeSpaceSize);
883 return std::min(diskFreeSpaceSize / 2, m_quota);
884}
885
886uint64_t SQLiteIDBBackingStore::databasesSizeForFolder(const String& folder)
887{
888 uint64_t diskUsage = 0;
889 for (auto& directory : FileSystem::listDirectory(folder, "*")) {
890 for (auto& file : FileSystem::listDirectory(directory, "*.sqlite3"_s))
891 diskUsage += SQLiteFileSystem::getDatabaseFileSize(file);
892 }
893 return diskUsage;
894}
895
896uint64_t SQLiteIDBBackingStore::databasesSizeForOrigin() const
897{
898 String oldVersionOriginDirectory = m_identifier.databaseDirectoryRelativeToRoot(m_databaseRootDirectory, "v0");
899 String newVersionOriginDirectory = m_identifier.databaseDirectoryRelativeToRoot(m_databaseRootDirectory, "v1");
900 return databasesSizeForFolder(oldVersionOriginDirectory) + databasesSizeForFolder(newVersionOriginDirectory);
901}
902
903uint64_t SQLiteIDBBackingStore::maximumSize() const
904{
905 ASSERT(!isMainThread());
906
907 // The maximum size for one database file is the quota for its origin, minus size of all databases within that origin,
908 // and plus current size of the database file.
909 uint64_t databaseFileSize = SQLiteFileSystem::getDatabaseFileSize(fullDatabasePath());
910 uint64_t quota = quotaForOrigin();
911
912 uint64_t diskUsage = databasesSizeForOrigin();
913 ASSERT(diskUsage >= databaseFileSize);
914
915 if (quota < diskUsage)
916 return databaseFileSize;
917
918 return quota - diskUsage + databaseFileSize;
919}
920
921IDBError SQLiteIDBBackingStore::beginTransaction(const IDBTransactionInfo& info)
922{
923 LOG(IndexedDB, "SQLiteIDBBackingStore::beginTransaction - %s", info.identifier().loggingString().utf8().data());
924
925 ASSERT(m_sqliteDB);
926 ASSERT(m_sqliteDB->isOpen());
927 ASSERT(m_databaseInfo);
928
929 m_sqliteDB->setMaximumSize(maximumSize());
930 auto addResult = m_transactions.add(info.identifier(), nullptr);
931 if (!addResult.isNewEntry) {
932 LOG_ERROR("Attempt to establish transaction identifier that already exists");
933 return IDBError { UnknownError, "Attempt to establish transaction identifier that already exists"_s };
934 }
935
936 addResult.iterator->value = std::make_unique<SQLiteIDBTransaction>(*this, info);
937
938 auto error = addResult.iterator->value->begin(*m_sqliteDB);
939 if (error.isNull() && info.mode() == IDBTransactionMode::Versionchange) {
940 m_originalDatabaseInfoBeforeVersionChange = std::make_unique<IDBDatabaseInfo>(*m_databaseInfo);
941
942 SQLiteStatement sql(*m_sqliteDB, "UPDATE IDBDatabaseInfo SET value = ? where key = 'DatabaseVersion';"_s);
943 if (sql.prepare() != SQLITE_OK
944 || sql.bindText(1, String::number(info.newVersion())) != SQLITE_OK
945 || sql.step() != SQLITE_DONE) {
946 if (m_sqliteDB->lastError() == SQLITE_FULL)
947 error = IDBError { QuotaExceededError, "Failed to store new database version in database because no enough space for domain"_s };
948 else
949 error = IDBError { UnknownError, "Failed to store new database version in database"_s };
950 }
951 }
952
953 return error;
954}
955
956IDBError SQLiteIDBBackingStore::abortTransaction(const IDBResourceIdentifier& identifier)
957{
958 LOG(IndexedDB, "SQLiteIDBBackingStore::abortTransaction - %s", identifier.loggingString().utf8().data());
959
960 ASSERT(m_sqliteDB);
961 ASSERT(m_sqliteDB->isOpen());
962
963 auto transaction = m_transactions.take(identifier);
964 if (!transaction) {
965 LOG_ERROR("Attempt to commit a transaction that hasn't been established");
966 return IDBError { UnknownError, "Attempt to abort a transaction that hasn't been established"_s };
967 }
968
969 if (transaction->mode() == IDBTransactionMode::Versionchange && m_originalDatabaseInfoBeforeVersionChange)
970 m_databaseInfo = WTFMove(m_originalDatabaseInfoBeforeVersionChange);
971
972 return transaction->abort();
973}
974
975IDBError SQLiteIDBBackingStore::commitTransaction(const IDBResourceIdentifier& identifier)
976{
977 LOG(IndexedDB, "SQLiteIDBBackingStore::commitTransaction - %s", identifier.loggingString().utf8().data());
978
979 ASSERT(m_sqliteDB);
980 ASSERT(m_sqliteDB->isOpen());
981
982 auto transaction = m_transactions.take(identifier);
983 if (!transaction) {
984 LOG_ERROR("Attempt to commit a transaction that hasn't been established");
985 return IDBError { UnknownError, "Attempt to commit a transaction that hasn't been established"_s };
986 }
987
988 auto error = transaction->commit();
989 if (!error.isNull()) {
990 if (transaction->mode() == IDBTransactionMode::Versionchange) {
991 ASSERT(m_originalDatabaseInfoBeforeVersionChange);
992 m_databaseInfo = WTFMove(m_originalDatabaseInfoBeforeVersionChange);
993 }
994 } else
995 m_originalDatabaseInfoBeforeVersionChange = nullptr;
996
997 return error;
998}
999
1000IDBError SQLiteIDBBackingStore::createObjectStore(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info)
1001{
1002 LOG(IndexedDB, "SQLiteIDBBackingStore::createObjectStore - adding OS %s with ID %" PRIu64, info.name().utf8().data(), info.identifier());
1003
1004 ASSERT(m_sqliteDB);
1005 ASSERT(m_sqliteDB->isOpen());
1006
1007 auto* transaction = m_transactions.get(transactionIdentifier);
1008 if (!transaction || !transaction->inProgress())
1009 return IDBError { UnknownError, "Attempt to create an object store without an in-progress transaction"_s };
1010
1011 if (transaction->mode() != IDBTransactionMode::Versionchange) {
1012 LOG_ERROR("Attempt to create an object store in a non-version-change transaction");
1013 return IDBError { UnknownError, "Attempt to create an object store in a non-version-change transaction"_s };
1014 }
1015
1016 RefPtr<SharedBuffer> keyPathBlob = serializeIDBKeyPath(info.keyPath());
1017 if (!keyPathBlob) {
1018 LOG_ERROR("Unable to serialize IDBKeyPath to save in database for new object store");
1019 return IDBError { UnknownError, "Unable to serialize IDBKeyPath to save in database for new object store"_s };
1020 }
1021
1022 {
1023 auto* sql = cachedStatement(SQL::CreateObjectStoreInfo, "INSERT INTO ObjectStoreInfo VALUES (?, ?, ?, ?, ?);"_s);
1024 if (!sql
1025 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
1026 || sql->bindText(2, info.name()) != SQLITE_OK
1027 || sql->bindBlob(3, keyPathBlob->data(), keyPathBlob->size()) != SQLITE_OK
1028 || sql->bindInt(4, info.autoIncrement()) != SQLITE_OK
1029 || sql->bindInt64(5, info.maxIndexID()) != SQLITE_OK
1030 || sql->step() != SQLITE_DONE) {
1031 LOG_ERROR("Could not add object store '%s' to ObjectStoreInfo table (%i) - %s", info.name().utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1032 if (m_sqliteDB->lastError() == SQLITE_FULL)
1033 return IDBError { QuotaExceededError, "Could not create object store because no enough space for domain"_s };
1034 return IDBError { UnknownError, "Could not create object store"_s };
1035 }
1036 }
1037
1038 {
1039 auto* sql = cachedStatement(SQL::CreateObjectStoreKeyGenerator, "INSERT INTO KeyGenerators VALUES (?, 0);"_s);
1040 if (!sql
1041 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
1042 || sql->step() != SQLITE_DONE) {
1043 LOG_ERROR("Could not seed initial key generator value for ObjectStoreInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1044 if (m_sqliteDB->lastError() == SQLITE_FULL)
1045 return IDBError { QuotaExceededError, "Could not seed initial key generator value for object store because no enough space for domain"_s };
1046 return IDBError { UnknownError, "Could not seed initial key generator value for object store"_s };
1047 }
1048 }
1049
1050 m_databaseInfo->addExistingObjectStore(info);
1051
1052 return IDBError { };
1053}
1054
1055IDBError SQLiteIDBBackingStore::deleteObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
1056{
1057 LOG(IndexedDB, "SQLiteIDBBackingStore::deleteObjectStore - object store %" PRIu64, objectStoreIdentifier);
1058
1059 ASSERT(m_sqliteDB);
1060 ASSERT(m_sqliteDB->isOpen());
1061
1062 auto* transaction = m_transactions.get(transactionIdentifier);
1063 if (!transaction || !transaction->inProgress())
1064 return IDBError { UnknownError, "Attempt to delete an object store without an in-progress transaction"_s };
1065
1066 if (transaction->mode() != IDBTransactionMode::Versionchange) {
1067 LOG_ERROR("Attempt to delete an object store in a non-version-change transaction");
1068 return IDBError { UnknownError, "Attempt to delete an object store in a non-version-change transaction"_s };
1069 }
1070
1071 // Delete the ObjectStore record
1072 {
1073 auto* sql = cachedStatement(SQL::DeleteObjectStoreInfo, "DELETE FROM ObjectStoreInfo WHERE id = ?;"_s);
1074 if (!sql
1075 || sql->bindInt64(1, objectStoreIdentifier) != SQLITE_OK
1076 || sql->step() != SQLITE_DONE) {
1077 LOG_ERROR("Could not delete object store id %" PRIi64 " from ObjectStoreInfo table (%i) - %s", objectStoreIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1078 return IDBError { UnknownError, "Could not delete object store"_s };
1079 }
1080 }
1081
1082 // Delete the ObjectStore's key generator record if there is one.
1083 {
1084 auto* sql = cachedStatement(SQL::DeleteObjectStoreKeyGenerator, "DELETE FROM KeyGenerators WHERE objectStoreID = ?;"_s);
1085 if (!sql
1086 || sql->bindInt64(1, objectStoreIdentifier) != SQLITE_OK
1087 || sql->step() != SQLITE_DONE) {
1088 LOG_ERROR("Could not delete object store from KeyGenerators table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1089 return IDBError { UnknownError, "Could not delete key generator for deleted object store"_s };
1090 }
1091 }
1092
1093 // Delete all associated records
1094 {
1095 auto* sql = cachedStatement(SQL::DeleteObjectStoreRecords, "DELETE FROM Records WHERE objectStoreID = ?;"_s);
1096 if (!sql
1097 || sql->bindInt64(1, objectStoreIdentifier) != SQLITE_OK
1098 || sql->step() != SQLITE_DONE) {
1099 LOG_ERROR("Could not delete records for object store %" PRIi64 " (%i) - %s", objectStoreIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1100 return IDBError { UnknownError, "Could not delete records for deleted object store"_s };
1101 }
1102 }
1103
1104 // Delete all associated Indexes
1105 {
1106 auto* sql = cachedStatement(SQL::DeleteObjectStoreIndexInfo, "DELETE FROM IndexInfo WHERE objectStoreID = ?;"_s);
1107 if (!sql
1108 || sql->bindInt64(1, objectStoreIdentifier) != SQLITE_OK
1109 || sql->step() != SQLITE_DONE) {
1110 LOG_ERROR("Could not delete index from IndexInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1111 return IDBError { UnknownError, "Could not delete IDBIndex for deleted object store"_s };
1112 }
1113 }
1114
1115 // Delete all associated Index records
1116 {
1117 auto* sql = cachedStatement(SQL::DeleteObjectStoreIndexRecords, "DELETE FROM IndexRecords WHERE objectStoreID = ?;"_s);
1118 if (!sql
1119 || sql->bindInt64(1, objectStoreIdentifier) != SQLITE_OK
1120 || sql->step() != SQLITE_DONE) {
1121 LOG_ERROR("Could not delete index records(%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1122 return IDBError { UnknownError, "Could not delete IDBIndex records for deleted object store"_s };
1123 }
1124 }
1125
1126 // Delete all unused Blob URL records.
1127 {
1128 auto* sql = cachedStatement(SQL::DeleteObjectStoreBlobRecords, "DELETE FROM BlobRecords WHERE objectStoreRow NOT IN (SELECT recordID FROM Records)"_s);
1129 if (!sql
1130 || sql->step() != SQLITE_DONE) {
1131 LOG_ERROR("Could not delete Blob URL records(%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1132 return IDBError { UnknownError, "Could not delete stored blob records for deleted object store"_s };
1133 }
1134 }
1135
1136 // Delete all unused Blob File records.
1137 auto error = deleteUnusedBlobFileRecords(*transaction);
1138 if (!error.isNull())
1139 return error;
1140
1141 m_databaseInfo->deleteObjectStore(objectStoreIdentifier);
1142
1143 return IDBError { };
1144}
1145
1146IDBError SQLiteIDBBackingStore::renameObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const String& newName)
1147{
1148 LOG(IndexedDB, "SQLiteIDBBackingStore::renameObjectStore - object store %" PRIu64, objectStoreIdentifier);
1149
1150 ASSERT(m_sqliteDB);
1151 ASSERT(m_sqliteDB->isOpen());
1152
1153 auto* transaction = m_transactions.get(transactionIdentifier);
1154 if (!transaction || !transaction->inProgress())
1155 return IDBError { UnknownError, "Attempt to rename an object store without an in-progress transaction"_s };
1156
1157 if (transaction->mode() != IDBTransactionMode::Versionchange) {
1158 LOG_ERROR("Attempt to rename an object store in a non-version-change transaction");
1159 return IDBError { UnknownError, "Attempt to rename an object store in a non-version-change transaction"_s };
1160 }
1161
1162 {
1163 auto* sql = cachedStatement(SQL::RenameObjectStore, "UPDATE ObjectStoreInfo SET name = ? WHERE id = ?;"_s);
1164 if (!sql
1165 || sql->bindText(1, newName) != SQLITE_OK
1166 || sql->bindInt64(2, objectStoreIdentifier) != SQLITE_OK
1167 || sql->step() != SQLITE_DONE) {
1168 LOG_ERROR("Could not update name for object store id %" PRIi64 " in ObjectStoreInfo table (%i) - %s", objectStoreIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1169 if (m_sqliteDB->lastError() == SQLITE_FULL)
1170 return IDBError { QuotaExceededError, "Could not rename object store because no enough space for domain"_s };
1171 return IDBError { UnknownError, "Could not rename object store"_s };
1172 }
1173 }
1174
1175 m_databaseInfo->renameObjectStore(objectStoreIdentifier, newName);
1176
1177 return IDBError { };
1178}
1179
1180IDBError SQLiteIDBBackingStore::clearObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID)
1181{
1182 LOG(IndexedDB, "SQLiteIDBBackingStore::clearObjectStore - object store %" PRIu64, objectStoreID);
1183
1184 ASSERT(m_sqliteDB);
1185 ASSERT(m_sqliteDB->isOpen());
1186
1187 auto* transaction = m_transactions.get(transactionIdentifier);
1188 if (!transaction || !transaction->inProgress())
1189 return IDBError { UnknownError, "Attempt to clear an object store without an in-progress transaction"_s };
1190
1191 if (transaction->mode() == IDBTransactionMode::Readonly) {
1192 LOG_ERROR("Attempt to clear an object store in a read-only transaction");
1193 return IDBError { UnknownError, "Attempt to clear an object store in a read-only transaction"_s };
1194 }
1195
1196 {
1197 auto* sql = cachedStatement(SQL::ClearObjectStoreRecords, "DELETE FROM Records WHERE objectStoreID = ?;"_s);
1198 if (!sql
1199 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1200 || sql->step() != SQLITE_DONE) {
1201 LOG_ERROR("Could not clear records from object store id %" PRIi64 " (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1202 return IDBError { UnknownError, "Unable to clear object store"_s };
1203 }
1204 }
1205
1206 {
1207 auto* sql = cachedStatement(SQL::ClearObjectStoreIndexRecords, "DELETE FROM IndexRecords WHERE objectStoreID = ?;"_s);
1208 if (!sql
1209 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1210 || sql->step() != SQLITE_DONE) {
1211 LOG_ERROR("Could not delete records from index record store id %" PRIi64 " (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1212 return IDBError { UnknownError, "Unable to delete index records while clearing object store"_s };
1213 }
1214 }
1215
1216 transaction->notifyCursorsOfChanges(objectStoreID);
1217
1218 return IDBError { };
1219}
1220
1221IDBError SQLiteIDBBackingStore::createIndex(const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo& info)
1222{
1223 LOG(IndexedDB, "SQLiteIDBBackingStore::createIndex - ObjectStore %" PRIu64 ", Index %" PRIu64, info.objectStoreIdentifier(), info.identifier());
1224 ASSERT(m_sqliteDB);
1225 ASSERT(m_sqliteDB->isOpen());
1226
1227 auto* transaction = m_transactions.get(transactionIdentifier);
1228 if (!transaction || !transaction->inProgress())
1229 return IDBError { UnknownError, "Attempt to create an index without an in-progress transaction"_s };
1230
1231 if (transaction->mode() != IDBTransactionMode::Versionchange) {
1232 LOG_ERROR("Attempt to create an index in a non-version-change transaction");
1233 return IDBError { UnknownError, "Attempt to create an index in a non-version-change transaction"_s };
1234 }
1235
1236 RefPtr<SharedBuffer> keyPathBlob = serializeIDBKeyPath(info.keyPath());
1237 if (!keyPathBlob) {
1238 LOG_ERROR("Unable to serialize IDBKeyPath to save in database");
1239 return IDBError { UnknownError, "Unable to serialize IDBKeyPath to create index in database"_s };
1240 }
1241
1242 auto* sql = cachedStatement(SQL::CreateIndexInfo, "INSERT INTO IndexInfo VALUES (?, ?, ?, ?, ?, ?);"_s);
1243 if (!sql
1244 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
1245 || sql->bindText(2, info.name()) != SQLITE_OK
1246 || sql->bindInt64(3, info.objectStoreIdentifier()) != SQLITE_OK
1247 || sql->bindBlob(4, keyPathBlob->data(), keyPathBlob->size()) != SQLITE_OK
1248 || sql->bindInt(5, info.unique()) != SQLITE_OK
1249 || sql->bindInt(6, info.multiEntry()) != SQLITE_OK
1250 || sql->step() != SQLITE_DONE) {
1251 LOG_ERROR("Could not add index '%s' to IndexInfo table (%i) - %s", info.name().utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1252 if (m_sqliteDB->lastError() == SQLITE_FULL)
1253 return IDBError { QuotaExceededError, "Unable to create index in database because no enough space for domain"_s };
1254 return IDBError { UnknownError, "Unable to create index in database"_s };
1255 }
1256
1257 // Write index records for any records that already exist in this object store.
1258
1259 auto cursor = transaction->maybeOpenBackingStoreCursor(info.objectStoreIdentifier(), 0, IDBKeyRangeData::allKeys());
1260
1261 if (!cursor) {
1262 LOG_ERROR("Cannot open cursor to populate indexes in database");
1263 return IDBError { UnknownError, "Unable to populate indexes in database"_s };
1264 }
1265
1266 while (!cursor->currentKey().isNull()) {
1267 auto& key = cursor->currentKey();
1268 auto* value = cursor->currentValue();
1269 ThreadSafeDataBuffer valueBuffer = value ? value->data() : ThreadSafeDataBuffer();
1270
1271 ASSERT(cursor->currentRecordRowID());
1272
1273 IDBError error = updateOneIndexForAddRecord(info, key, valueBuffer, cursor->currentRecordRowID());
1274 if (!error.isNull()) {
1275 auto* sql = cachedStatement(SQL::DeleteIndexInfo, "DELETE FROM IndexInfo WHERE id = ? AND objectStoreID = ?;"_s);
1276 if (!sql
1277 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
1278 || sql->bindInt64(2, info.objectStoreIdentifier()) != SQLITE_OK
1279 || sql->step() != SQLITE_DONE) {
1280 LOG_ERROR("Index creation failed due to uniqueness constraint failure, but there was an error deleting the Index record from the database");
1281 return IDBError { UnknownError, "Index creation failed due to uniqueness constraint failure, but there was an error deleting the Index record from the database"_s };
1282 }
1283
1284 return error;
1285 }
1286
1287 if (!cursor->advance(1)) {
1288 LOG_ERROR("Error advancing cursor while indexing existing records for new index.");
1289 return IDBError { UnknownError, "Error advancing cursor while indexing existing records for new index"_s };
1290 }
1291 }
1292
1293 ASSERT(m_databaseInfo);
1294 if (!m_databaseInfo) {
1295 RELEASE_LOG_ERROR(IndexedDB, "%p - SQLiteIDBBackingStore::clearObjectStore: m_databaseInfo is null", this);
1296 return IDBError { UnknownError, "Database info is invalid"_s };
1297 }
1298
1299 auto* objectStore = m_databaseInfo->infoForExistingObjectStore(info.objectStoreIdentifier());
1300 ASSERT(objectStore);
1301 objectStore->addExistingIndex(info);
1302
1303 return IDBError { };
1304}
1305
1306IDBError SQLiteIDBBackingStore::uncheckedHasIndexRecord(const IDBIndexInfo& info, const IDBKeyData& indexKey, bool& hasRecord)
1307{
1308 hasRecord = false;
1309
1310 RefPtr<SharedBuffer> indexKeyBuffer = serializeIDBKeyData(indexKey);
1311 if (!indexKeyBuffer) {
1312 LOG_ERROR("Unable to serialize index key to be stored in the database");
1313 return IDBError { UnknownError, "Unable to serialize IDBKey to check for index record in database"_s };
1314 }
1315
1316 auto* sql = cachedStatement(SQL::HasIndexRecord, "SELECT rowid FROM IndexRecords WHERE indexID = ? AND objectStoreID = ? AND key = CAST(? AS TEXT);"_s);
1317 if (!sql
1318 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
1319 || sql->bindInt64(2, info.objectStoreIdentifier()) != SQLITE_OK
1320 || sql->bindBlob(3, indexKeyBuffer->data(), indexKeyBuffer->size()) != SQLITE_OK) {
1321 LOG_ERROR("Error checking for index record in database");
1322 return IDBError { UnknownError, "Error checking for index record in database"_s };
1323 }
1324
1325 int sqlResult = sql->step();
1326 if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE)
1327 return IDBError { };
1328
1329 if (sqlResult != SQLITE_ROW) {
1330 // There was an error fetching the record from the database.
1331 LOG_ERROR("Could not check if key exists in index (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1332 return IDBError { UnknownError, "Error checking for existence of IDBKey in index"_s };
1333 }
1334
1335 hasRecord = true;
1336 return IDBError { };
1337}
1338
1339IDBError SQLiteIDBBackingStore::uncheckedPutIndexKey(const IDBIndexInfo& info, const IDBKeyData& key, const IndexKey& indexKey, int64_t recordID)
1340{
1341 LOG(IndexedDB, "SQLiteIDBBackingStore::uncheckedPutIndexKey - (%" PRIu64 ") %s, %s", info.identifier(), key.loggingString().utf8().data(), indexKey.asOneKey().loggingString().utf8().data());
1342
1343 Vector<IDBKeyData> indexKeys;
1344 if (info.multiEntry())
1345 indexKeys = indexKey.multiEntry();
1346 else
1347 indexKeys.append(indexKey.asOneKey());
1348
1349 if (info.unique()) {
1350 bool hasRecord;
1351 IDBError error;
1352 for (auto& indexKey : indexKeys) {
1353 if (!indexKey.isValid())
1354 continue;
1355 error = uncheckedHasIndexRecord(info, indexKey, hasRecord);
1356 if (!error.isNull())
1357 return error;
1358 if (hasRecord)
1359 return IDBError(ConstraintError);
1360 }
1361 }
1362
1363 for (auto& indexKey : indexKeys) {
1364 if (!indexKey.isValid())
1365 continue;
1366 auto error = uncheckedPutIndexRecord(info.objectStoreIdentifier(), info.identifier(), key, indexKey, recordID);
1367 if (!error.isNull()) {
1368 LOG_ERROR("Unable to put index record for newly created index");
1369 return error;
1370 }
1371 }
1372
1373 return IDBError { };
1374}
1375
1376IDBError SQLiteIDBBackingStore::uncheckedPutIndexRecord(int64_t objectStoreID, int64_t indexID, const WebCore::IDBKeyData& keyValue, const WebCore::IDBKeyData& indexKey, int64_t recordID)
1377{
1378 LOG(IndexedDB, "SQLiteIDBBackingStore::uncheckedPutIndexRecord - %s, %s", keyValue.loggingString().utf8().data(), indexKey.loggingString().utf8().data());
1379
1380 RefPtr<SharedBuffer> indexKeyBuffer = serializeIDBKeyData(indexKey);
1381 if (!indexKeyBuffer) {
1382 LOG_ERROR("Unable to serialize index key to be stored in the database");
1383 return IDBError { UnknownError, "Unable to serialize index key to be stored in the database"_s };
1384 }
1385
1386 RefPtr<SharedBuffer> valueBuffer = serializeIDBKeyData(keyValue);
1387 if (!valueBuffer) {
1388 LOG_ERROR("Unable to serialize the value to be stored in the database");
1389 return IDBError { UnknownError, "Unable to serialize value to be stored in the database"_s };
1390 }
1391
1392 {
1393 auto* sql = cachedStatement(SQL::PutIndexRecord, "INSERT INTO IndexRecords VALUES (?, ?, CAST(? AS TEXT), CAST(? AS TEXT), ?);"_s);
1394 if (!sql
1395 || sql->bindInt64(1, indexID) != SQLITE_OK
1396 || sql->bindInt64(2, objectStoreID) != SQLITE_OK
1397 || sql->bindBlob(3, indexKeyBuffer->data(), indexKeyBuffer->size()) != SQLITE_OK
1398 || sql->bindBlob(4, valueBuffer->data(), valueBuffer->size()) != SQLITE_OK
1399 || sql->bindInt64(5, recordID) != SQLITE_OK
1400 || sql->step() != SQLITE_DONE) {
1401 LOG_ERROR("Could not put index record for index %" PRIi64 " in object store %" PRIi64 " in Records table (%i) - %s", indexID, objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1402 if (m_sqliteDB->lastError() == SQLITE_FULL)
1403 return IDBError { QuotaExceededError, "Error putting index record into database because no enough space for domain"_s };
1404 return IDBError { UnknownError, "Error putting index record into database"_s };
1405 }
1406 }
1407
1408 return IDBError { };
1409}
1410
1411
1412IDBError SQLiteIDBBackingStore::deleteIndex(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier)
1413{
1414 LOG(IndexedDB, "SQLiteIDBBackingStore::deleteIndex - object store %" PRIu64, objectStoreIdentifier);
1415
1416 ASSERT(m_sqliteDB);
1417 ASSERT(m_sqliteDB->isOpen());
1418
1419 auto* transaction = m_transactions.get(transactionIdentifier);
1420 if (!transaction || !transaction->inProgress())
1421 return IDBError { UnknownError, "Attempt to delete index without an in-progress transaction"_s };
1422
1423 if (transaction->mode() != IDBTransactionMode::Versionchange) {
1424 LOG_ERROR("Attempt to delete index during a non-version-change transaction");
1425 return IDBError { UnknownError, "Attempt to delete index during a non-version-change transaction"_s };
1426 }
1427
1428 {
1429 auto* sql = cachedStatement(SQL::DeleteIndexInfo, "DELETE FROM IndexInfo WHERE id = ? AND objectStoreID = ?;"_s);
1430 if (!sql
1431 || sql->bindInt64(1, indexIdentifier) != SQLITE_OK
1432 || sql->bindInt64(2, objectStoreIdentifier) != SQLITE_OK
1433 || sql->step() != SQLITE_DONE) {
1434 LOG_ERROR("Could not delete index id %" PRIi64 " from IndexInfo table (%i) - %s", objectStoreIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1435 return IDBError { UnknownError, "Error deleting index from database"_s };
1436 }
1437 }
1438
1439 {
1440 auto* sql = cachedStatement(SQL::DeleteIndexRecords, "DELETE FROM IndexRecords WHERE indexID = ? AND objectStoreID = ?;"_s);
1441 if (!sql
1442 || sql->bindInt64(1, indexIdentifier) != SQLITE_OK
1443 || sql->bindInt64(2, objectStoreIdentifier) != SQLITE_OK
1444 || sql->step() != SQLITE_DONE) {
1445 LOG_ERROR("Could not delete index records for index id %" PRIi64 " from IndexRecords table (%i) - %s", indexIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1446 return IDBError { UnknownError, "Error deleting index records from database"_s };
1447 }
1448 }
1449
1450 auto* objectStore = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
1451 ASSERT(objectStore);
1452 objectStore->deleteIndex(indexIdentifier);
1453
1454 return IDBError { };
1455}
1456
1457IDBError SQLiteIDBBackingStore::renameIndex(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
1458{
1459 LOG(IndexedDB, "SQLiteIDBBackingStore::renameIndex - object store %" PRIu64 ", index %" PRIu64, objectStoreIdentifier, indexIdentifier);
1460
1461 ASSERT(m_sqliteDB);
1462 ASSERT(m_sqliteDB->isOpen());
1463
1464 auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
1465 if (!objectStoreInfo)
1466 return IDBError { UnknownError, "Could not rename index"_s };
1467
1468 auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexIdentifier);
1469 if (!indexInfo)
1470 return IDBError { UnknownError, "Could not rename index"_s };
1471
1472 auto* transaction = m_transactions.get(transactionIdentifier);
1473 if (!transaction || !transaction->inProgress())
1474 return IDBError { UnknownError, "Attempt to rename an index without an in-progress transaction"_s };
1475
1476 if (transaction->mode() != IDBTransactionMode::Versionchange) {
1477 LOG_ERROR("Attempt to rename an index in a non-version-change transaction");
1478 return IDBError { UnknownError, "Attempt to rename an index in a non-version-change transaction"_s };
1479 }
1480
1481 {
1482 auto* sql = cachedStatement(SQL::RenameIndex, "UPDATE IndexInfo SET name = ? WHERE objectStoreID = ? AND id = ?;"_s);
1483 if (!sql
1484 || sql->bindText(1, newName) != SQLITE_OK
1485 || sql->bindInt64(2, objectStoreIdentifier) != SQLITE_OK
1486 || sql->bindInt64(3, indexIdentifier) != SQLITE_OK
1487 || sql->step() != SQLITE_DONE) {
1488 LOG_ERROR("Could not update name for index id (%" PRIi64 ", %" PRIi64 ") in IndexInfo table (%i) - %s", objectStoreIdentifier, indexIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1489 if (m_sqliteDB->lastError() == SQLITE_FULL)
1490 return IDBError { QuotaExceededError, "Could not rename index because no enough space for domain"_s };
1491 return IDBError { UnknownError, "Could not rename index"_s };
1492 }
1493 }
1494
1495 indexInfo->rename(newName);
1496
1497 return IDBError { };
1498}
1499
1500IDBError SQLiteIDBBackingStore::keyExistsInObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyData& keyData, bool& keyExists)
1501{
1502 LOG(IndexedDB, "SQLiteIDBBackingStore::keyExistsInObjectStore - key %s, object store %" PRIu64, keyData.loggingString().utf8().data(), objectStoreID);
1503
1504 ASSERT(m_sqliteDB);
1505 ASSERT(m_sqliteDB->isOpen());
1506
1507 keyExists = false;
1508
1509 auto* transaction = m_transactions.get(transactionIdentifier);
1510 if (!transaction || !transaction->inProgress())
1511 return IDBError { UnknownError, "Attempt to see if key exists in objectstore without an in-progress transaction"_s };
1512
1513 RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(keyData);
1514 if (!keyBuffer) {
1515 LOG_ERROR("Unable to serialize IDBKey to check for existence in object store");
1516 return IDBError { UnknownError, "Unable to serialize IDBKey to check for existence in object store"_s };
1517 }
1518 auto* sql = cachedStatement(SQL::KeyExistsInObjectStore, "SELECT key FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT) LIMIT 1;"_s);
1519 if (!sql
1520 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1521 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK) {
1522 LOG_ERROR("Could not get record from object store %" PRIi64 " from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1523 return IDBError { UnknownError, "Unable to check for existence of IDBKey in object store"_s };
1524 }
1525
1526 int sqlResult = sql->step();
1527 if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE)
1528 return IDBError { };
1529
1530 if (sqlResult != SQLITE_ROW) {
1531 // There was an error fetching the record from the database.
1532 LOG_ERROR("Could not check if key exists in object store (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1533 return IDBError { UnknownError, "Error checking for existence of IDBKey in object store"_s };
1534 }
1535
1536 keyExists = true;
1537 return IDBError { };
1538}
1539
1540IDBError SQLiteIDBBackingStore::deleteUnusedBlobFileRecords(SQLiteIDBTransaction& transaction)
1541{
1542 LOG(IndexedDB, "SQLiteIDBBackingStore::deleteUnusedBlobFileRecords");
1543
1544 // Gather the set of blob URLs and filenames that are no longer in use.
1545 HashSet<String> removedBlobFilenames;
1546 {
1547 auto* sql = cachedStatement(SQL::GetUnusedBlobFilenames, "SELECT fileName FROM BlobFiles WHERE blobURL NOT IN (SELECT blobURL FROM BlobRecords)"_s);
1548
1549 if (!sql) {
1550 LOG_ERROR("Error deleting stored blobs (%i) (Could not gather unused blobURLs) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1551 return IDBError { UnknownError, "Error deleting stored blobs"_s };
1552 }
1553
1554 int result = sql->step();
1555 while (result == SQLITE_ROW) {
1556 removedBlobFilenames.add(sql->getColumnText(0));
1557 result = sql->step();
1558 }
1559
1560 if (result != SQLITE_DONE) {
1561 LOG_ERROR("Error deleting stored blobs (%i) (Could not gather unused blobURLs) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1562 return IDBError { UnknownError, "Error deleting stored blobs"_s };
1563 }
1564 }
1565
1566 // Remove the blob records that are no longer in use.
1567 if (!removedBlobFilenames.isEmpty()) {
1568 auto* sql = cachedStatement(SQL::DeleteUnusedBlobs, "DELETE FROM BlobFiles WHERE blobURL NOT IN (SELECT blobURL FROM BlobRecords)"_s);
1569
1570 if (!sql
1571 || sql->step() != SQLITE_DONE) {
1572 LOG_ERROR("Error deleting stored blobs (%i) (Could not delete blobFile records) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1573 return IDBError { UnknownError, "Error deleting stored blobs"_s };
1574 }
1575 }
1576
1577 for (auto& file : removedBlobFilenames)
1578 transaction.addRemovedBlobFile(file);
1579
1580 return IDBError { };
1581}
1582
1583IDBError SQLiteIDBBackingStore::deleteRecord(SQLiteIDBTransaction& transaction, int64_t objectStoreID, const IDBKeyData& keyData)
1584{
1585 LOG(IndexedDB, "SQLiteIDBBackingStore::deleteRecord - key %s, object store %" PRIu64, keyData.loggingString().utf8().data(), objectStoreID);
1586
1587 ASSERT(m_sqliteDB);
1588 ASSERT(m_sqliteDB->isOpen());
1589 ASSERT(transaction.inProgress());
1590 ASSERT(transaction.mode() != IDBTransactionMode::Readonly);
1591 UNUSED_PARAM(transaction);
1592
1593 RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(keyData);
1594 if (!keyBuffer) {
1595 LOG_ERROR("Unable to serialize IDBKeyData to be removed from the database");
1596 return IDBError { UnknownError, "Unable to serialize IDBKeyData to be removed from the database"_s };
1597 }
1598
1599 // Get the record ID
1600 int64_t recordID;
1601 {
1602 auto* sql = cachedStatement(SQL::GetObjectStoreRecordID, "SELECT recordID FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT);"_s);
1603
1604 if (!sql
1605 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1606 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK) {
1607 LOG_ERROR("Could not delete record from object store %" PRIi64 " (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1608 return IDBError { UnknownError, "Failed to delete record from object store"_s };
1609 }
1610
1611 int result = sql->step();
1612
1613 // If there's no record ID, there's no record to delete.
1614 if (result == SQLITE_DONE)
1615 return IDBError { };
1616
1617 if (result != SQLITE_ROW) {
1618 LOG_ERROR("Could not delete record from object store %" PRIi64 " (%i) (unable to fetch record ID) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1619 return IDBError { UnknownError, "Failed to delete record from object store"_s };
1620 }
1621
1622 recordID = sql->getColumnInt64(0);
1623 }
1624
1625 if (recordID < 1) {
1626 LOG_ERROR("Could not delete record from object store %" PRIi64 " (%i) (record ID is invalid) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1627 return IDBError { UnknownError, "Failed to delete record from object store"_s };
1628 }
1629
1630 // Delete the blob records for this object store record.
1631 {
1632 auto* sql = cachedStatement(SQL::DeleteBlobRecord, "DELETE FROM BlobRecords WHERE objectStoreRow = ?;"_s);
1633
1634 if (!sql
1635 || sql->bindInt64(1, recordID) != SQLITE_OK
1636 || sql->step() != SQLITE_DONE) {
1637 LOG_ERROR("Could not delete record from object store %" PRIi64 " (%i) (Could not delete BlobRecords records) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1638 return IDBError { UnknownError, "Failed to delete record from object store"_s };
1639 }
1640 }
1641
1642 auto error = deleteUnusedBlobFileRecords(transaction);
1643 if (!error.isNull())
1644 return error;
1645
1646 // Delete record from object store
1647 {
1648 auto* sql = cachedStatement(SQL::DeleteObjectStoreRecord, "DELETE FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT);"_s);
1649
1650 if (!sql
1651 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1652 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
1653 || sql->step() != SQLITE_DONE) {
1654 LOG_ERROR("Could not delete record from object store %" PRIi64 " (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1655 return IDBError { UnknownError, "Failed to delete record from object store"_s };
1656 }
1657 }
1658
1659 // Delete record from indexes store
1660 {
1661 auto* sql = cachedStatement(SQL::DeleteObjectStoreIndexRecord, "DELETE FROM IndexRecords WHERE objectStoreID = ? AND value = CAST(? AS TEXT);"_s);
1662
1663 if (!sql
1664 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1665 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
1666 || sql->step() != SQLITE_DONE) {
1667 LOG_ERROR("Could not delete record from indexes for object store %" PRIi64 " (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1668 return IDBError { UnknownError, "Failed to delete index entries for object store record"_s };
1669 }
1670 }
1671
1672 return IDBError { };
1673}
1674
1675IDBError SQLiteIDBBackingStore::deleteRange(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyRangeData& keyRange)
1676{
1677 LOG(IndexedDB, "SQLiteIDBBackingStore::deleteRange - range %s, object store %" PRIu64, keyRange.loggingString().utf8().data(), objectStoreID);
1678
1679 ASSERT(m_sqliteDB);
1680 ASSERT(m_sqliteDB->isOpen());
1681
1682 auto* transaction = m_transactions.get(transactionIdentifier);
1683 if (!transaction || !transaction->inProgress())
1684 return IDBError { UnknownError, "Attempt to delete range from database without an in-progress transaction"_s };
1685
1686 if (transaction->mode() == IDBTransactionMode::Readonly) {
1687 LOG_ERROR("Attempt to delete records from an object store in a read-only transaction");
1688 return IDBError { UnknownError, "Attempt to delete records from an object store in a read-only transaction"_s };
1689 }
1690
1691 // If the range to delete is exactly one key we can delete it right now.
1692 if (keyRange.isExactlyOneKey()) {
1693 auto error = deleteRecord(*transaction, objectStoreID, keyRange.lowerKey);
1694 if (!error.isNull()) {
1695 LOG_ERROR("Failed to delete record for key '%s'", keyRange.lowerKey.loggingString().utf8().data());
1696 return error;
1697 }
1698
1699 transaction->notifyCursorsOfChanges(objectStoreID);
1700
1701 return IDBError { };
1702 }
1703
1704 auto cursor = transaction->maybeOpenBackingStoreCursor(objectStoreID, 0, keyRange);
1705 if (!cursor) {
1706 LOG_ERROR("Cannot open cursor to delete range of records from the database");
1707 return IDBError { UnknownError, "Cannot open cursor to delete range of records from the database"_s };
1708 }
1709
1710 Vector<IDBKeyData> keys;
1711 while (!cursor->didComplete() && !cursor->didError()) {
1712 keys.append(cursor->currentKey());
1713 cursor->advance(1);
1714 }
1715
1716 if (cursor->didError()) {
1717 LOG_ERROR("Cursor failed while accumulating range of records from the database");
1718 return IDBError { UnknownError, "Cursor failed while accumulating range of records from the database"_s };
1719 }
1720
1721 IDBError error;
1722 for (auto& key : keys) {
1723 error = deleteRecord(*transaction, objectStoreID, key);
1724 if (!error.isNull()) {
1725 LOG_ERROR("deleteRange: Error deleting keys in range");
1726 break;
1727 }
1728 }
1729
1730 transaction->notifyCursorsOfChanges(objectStoreID);
1731
1732 return error;
1733}
1734
1735IDBError SQLiteIDBBackingStore::updateOneIndexForAddRecord(const IDBIndexInfo& info, const IDBKeyData& key, const ThreadSafeDataBuffer& value, int64_t recordID)
1736{
1737 JSLockHolder locker(vm());
1738
1739 auto jsValue = deserializeIDBValueToJSValue(*globalObject().globalExec(), value);
1740 if (jsValue.isUndefinedOrNull())
1741 return IDBError { };
1742
1743 IndexKey indexKey;
1744 auto* objectStoreInfo = infoForObjectStore(info.objectStoreIdentifier());
1745 ASSERT(objectStoreInfo);
1746 generateIndexKeyForValue(*m_globalObject->globalExec(), info, jsValue, indexKey, objectStoreInfo->keyPath(), key);
1747
1748 if (indexKey.isNull())
1749 return IDBError { };
1750
1751 return uncheckedPutIndexKey(info, key, indexKey, recordID);
1752}
1753
1754IDBError SQLiteIDBBackingStore::updateAllIndexesForAddRecord(const IDBObjectStoreInfo& info, const IDBKeyData& key, const ThreadSafeDataBuffer& value, int64_t recordID)
1755{
1756 JSLockHolder locker(vm());
1757
1758 auto jsValue = deserializeIDBValueToJSValue(*globalObject().globalExec(), value);
1759 if (jsValue.isUndefinedOrNull())
1760 return IDBError { };
1761
1762 IDBError error;
1763 bool anyRecordsSucceeded = false;
1764 for (auto& index : info.indexMap().values()) {
1765 IndexKey indexKey;
1766 generateIndexKeyForValue(*m_globalObject->globalExec(), index, jsValue, indexKey, info.keyPath(), key);
1767
1768 if (indexKey.isNull())
1769 continue;
1770
1771 error = uncheckedPutIndexKey(index, key, indexKey, recordID);
1772 if (!error.isNull())
1773 break;
1774
1775 anyRecordsSucceeded = true;
1776 }
1777
1778 if (!error.isNull() && anyRecordsSucceeded) {
1779 RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(key);
1780
1781 auto* sql = cachedStatement(SQL::DeleteObjectStoreIndexRecord, "DELETE FROM IndexRecords WHERE objectStoreID = ? AND value = CAST(? AS TEXT);"_s);
1782
1783 if (!sql
1784 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
1785 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
1786 || sql->step() != SQLITE_DONE) {
1787 LOG_ERROR("Adding one Index record failed, but failed to remove all others that previously succeeded");
1788 return IDBError { UnknownError, "Adding one Index record failed, but failed to remove all others that previously succeeded"_s };
1789 }
1790 }
1791
1792 return error;
1793}
1794
1795IDBError SQLiteIDBBackingStore::addRecord(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& objectStoreInfo, const IDBKeyData& keyData, const IDBValue& value)
1796{
1797 LOG(IndexedDB, "SQLiteIDBBackingStore::addRecord - key %s, object store %" PRIu64, keyData.loggingString().utf8().data(), objectStoreInfo.identifier());
1798
1799 ASSERT(m_sqliteDB);
1800 ASSERT(m_sqliteDB->isOpen());
1801 ASSERT(value.data().data());
1802 ASSERT(value.blobURLs().size() == value.blobFilePaths().size());
1803
1804 auto* transaction = m_transactions.get(transactionIdentifier);
1805 if (!transaction || !transaction->inProgress())
1806 return IDBError { UnknownError, "Attempt to store a record in an object store without an in-progress transaction"_s };
1807
1808 if (transaction->mode() == IDBTransactionMode::Readonly) {
1809 LOG_ERROR("Attempt to store a record in an object store in a read-only transaction");
1810 return IDBError { UnknownError, "Attempt to store a record in an object store in a read-only transaction"_s };
1811 }
1812
1813 RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(keyData);
1814 if (!keyBuffer) {
1815 LOG_ERROR("Unable to serialize IDBKey to be stored in an object store");
1816 return IDBError { UnknownError, "Unable to serialize IDBKey to be stored in an object store"_s };
1817 }
1818
1819 int64_t recordID = 0;
1820 {
1821 auto* sql = cachedStatement(SQL::AddObjectStoreRecord, "INSERT INTO Records VALUES (?, CAST(? AS TEXT), ?, NULL);"_s);
1822 if (!sql
1823 || sql->bindInt64(1, objectStoreInfo.identifier()) != SQLITE_OK
1824 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
1825 || sql->bindBlob(3, value.data().data()->data(), value.data().data()->size()) != SQLITE_OK
1826 || sql->step() != SQLITE_DONE) {
1827 LOG_ERROR("Could not put record for object store %" PRIi64 " in Records table (%i) - %s", objectStoreInfo.identifier(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1828 if (m_sqliteDB->lastError() == SQLITE_FULL)
1829 return IDBError { QuotaExceededError, "Unable to store record in object store because no enough space for domain"_s };
1830 return IDBError { UnknownError, "Unable to store record in object store"_s };
1831 }
1832
1833 recordID = m_sqliteDB->lastInsertRowID();
1834 }
1835
1836 auto error = updateAllIndexesForAddRecord(objectStoreInfo, keyData, value.data(), recordID);
1837
1838 if (!error.isNull()) {
1839 auto* sql = cachedStatement(SQL::DeleteObjectStoreRecord, "DELETE FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT);"_s);
1840 if (!sql
1841 || sql->bindInt64(1, objectStoreInfo.identifier()) != SQLITE_OK
1842 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
1843 || sql->step() != SQLITE_DONE) {
1844 LOG_ERROR("Indexing new object store record failed, but unable to remove the object store record itself");
1845 return IDBError { UnknownError, "Indexing new object store record failed, but unable to remove the object store record itself"_s };
1846 }
1847
1848 return error;
1849 }
1850
1851 const Vector<String>& blobURLs = value.blobURLs();
1852 const Vector<String>& blobFiles = value.blobFilePaths();
1853 for (size_t i = 0; i < blobURLs.size(); ++i) {
1854 auto& url = blobURLs[i];
1855 {
1856 auto* sql = cachedStatement(SQL::AddBlobRecord, "INSERT INTO BlobRecords VALUES (?, ?);"_s);
1857 if (!sql
1858 || sql->bindInt64(1, recordID) != SQLITE_OK
1859 || sql->bindText(2, url) != SQLITE_OK
1860 || sql->step() != SQLITE_DONE) {
1861 LOG_ERROR("Unable to record Blob record in database");
1862 if (m_sqliteDB->lastError() == SQLITE_FULL)
1863 return IDBError { QuotaExceededError, "Unable to record Blob record in database because no enough space for domain"_s };
1864 return IDBError { UnknownError, "Unable to record Blob record in database"_s };
1865 }
1866 }
1867 int64_t potentialFileNameInteger = m_sqliteDB->lastInsertRowID();
1868
1869 // If we already have a file for this blobURL, nothing left to do.
1870 {
1871 auto* sql = cachedStatement(SQL::BlobFilenameForBlobURL, "SELECT fileName FROM BlobFiles WHERE blobURL = ?;"_s);
1872 if (!sql
1873 || sql->bindText(1, url) != SQLITE_OK) {
1874 LOG_ERROR("Unable to examine Blob filenames in database");
1875 return IDBError { UnknownError, "Unable to examine Blob filenames in database"_s };
1876 }
1877
1878 int result = sql->step();
1879 if (result != SQLITE_ROW && result != SQLITE_DONE) {
1880 LOG_ERROR("Unable to examine Blob filenames in database");
1881 return IDBError { UnknownError, "Unable to examine Blob filenames in database"_s };
1882 }
1883
1884 if (result == SQLITE_ROW)
1885 continue;
1886 }
1887
1888 // We don't already have a file for this blobURL, so commit our file as a unique filename
1889 String storedFilename = makeString(potentialFileNameInteger, ".blob");
1890 {
1891 auto* sql = cachedStatement(SQL::AddBlobFilename, "INSERT INTO BlobFiles VALUES (?, ?);"_s);
1892 if (!sql
1893 || sql->bindText(1, url) != SQLITE_OK
1894 || sql->bindText(2, storedFilename) != SQLITE_OK
1895 || sql->step() != SQLITE_DONE) {
1896 LOG_ERROR("Unable to record Blob file record in database");
1897 if (m_sqliteDB->lastError() == SQLITE_FULL)
1898 return IDBError { QuotaExceededError, "Unable to record Blob file in database because no enough space for domain"_s };
1899 return IDBError { UnknownError, "Unable to record Blob file record in database"_s };
1900 }
1901 }
1902
1903 transaction->addBlobFile(blobFiles[i], storedFilename);
1904 }
1905
1906 transaction->notifyCursorsOfChanges(objectStoreInfo.identifier());
1907
1908 return error;
1909}
1910
1911IDBError SQLiteIDBBackingStore::getBlobRecordsForObjectStoreRecord(int64_t objectStoreRecord, Vector<String>& blobURLs, PAL::SessionID& sessionID, Vector<String>& blobFilePaths)
1912{
1913 ASSERT(objectStoreRecord);
1914
1915 HashSet<String> blobURLSet;
1916 {
1917 auto* sql = cachedStatement(SQL::GetBlobURL, "SELECT blobURL FROM BlobRecords WHERE objectStoreRow = ?"_s);
1918 if (!sql
1919 || sql->bindInt64(1, objectStoreRecord) != SQLITE_OK) {
1920 LOG_ERROR("Could not prepare statement to fetch blob URLs for object store record (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1921 return IDBError { UnknownError, "Failed to look up blobURL records in object store by key range"_s };
1922 }
1923
1924 int sqlResult = sql->step();
1925 if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE) {
1926 // There are no blobURLs in the database for this object store record.
1927 return IDBError { };
1928 }
1929
1930 while (sqlResult == SQLITE_ROW) {
1931 blobURLSet.add(sql->getColumnText(0));
1932 sqlResult = sql->step();
1933 }
1934
1935 if (sqlResult != SQLITE_DONE) {
1936 LOG_ERROR("Could not fetch blob URLs for object store record (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1937 return IDBError { UnknownError, "Failed to look up blobURL records in object store by key range"_s };
1938 }
1939 }
1940
1941 ASSERT(!blobURLSet.isEmpty());
1942 for (auto& blobURL : blobURLSet) {
1943 auto* sql = cachedStatement(SQL::BlobFilenameForBlobURL, "SELECT fileName FROM BlobFiles WHERE blobURL = ?;"_s);
1944 if (!sql
1945 || sql->bindText(1, blobURL) != SQLITE_OK) {
1946 LOG_ERROR("Could not prepare statement to fetch blob filename for object store record (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1947 return IDBError { UnknownError, "Failed to look up blobURL records in object store by key range"_s };
1948 }
1949
1950 if (sql->step() != SQLITE_ROW) {
1951 LOG_ERROR("Entry for blob filename for blob url %s does not exist (%i) - %s", blobURL.utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1952 return IDBError { UnknownError, "Failed to look up blobURL records in object store by key range"_s };
1953 }
1954
1955 blobURLs.append(blobURL);
1956
1957 String fileName = sql->getColumnText(0);
1958 blobFilePaths.append(FileSystem::pathByAppendingComponent(m_databaseDirectory, fileName));
1959 }
1960 sessionID = m_identifier.sessionID();
1961
1962 return IDBError { };
1963}
1964
1965IDBError SQLiteIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyRangeData& keyRange, IDBGetRecordDataType type, IDBGetResult& resultValue)
1966{
1967 LOG(IndexedDB, "SQLiteIDBBackingStore::getRecord - key range %s, object store %" PRIu64, keyRange.loggingString().utf8().data(), objectStoreID);
1968
1969 ASSERT(m_sqliteDB);
1970 ASSERT(m_sqliteDB->isOpen());
1971
1972 auto* transaction = m_transactions.get(transactionIdentifier);
1973 if (!transaction || !transaction->inProgress())
1974 return IDBError { UnknownError, "Attempt to get a record from database without an in-progress transaction"_s };
1975
1976 auto key = keyRange.lowerKey;
1977 if (key.isNull())
1978 key = IDBKeyData::minimum();
1979 RefPtr<SharedBuffer> lowerBuffer = serializeIDBKeyData(key);
1980 if (!lowerBuffer) {
1981 LOG_ERROR("Unable to serialize lower IDBKey in lookup range");
1982 return IDBError { UnknownError, "Unable to serialize lower IDBKey in lookup range"_s };
1983 }
1984
1985 key = keyRange.upperKey;
1986 if (key.isNull())
1987 key = IDBKeyData::maximum();
1988 RefPtr<SharedBuffer> upperBuffer = serializeIDBKeyData(key);
1989 if (!upperBuffer) {
1990 LOG_ERROR("Unable to serialize upper IDBKey in lookup range");
1991 return IDBError { UnknownError, "Unable to serialize upper IDBKey in lookup range"_s };
1992 }
1993
1994 int64_t recordID = 0;
1995 ThreadSafeDataBuffer keyResultBuffer, valueResultBuffer;
1996 {
1997 static const char* const lowerOpenUpperOpen = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
1998 static const char* const lowerOpenUpperClosed = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
1999 static const char* const lowerClosedUpperOpen = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
2000 static const char* const lowerClosedUpperClosed = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
2001
2002 static const char* const lowerOpenUpperOpenKeyOnly = "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
2003 static const char* const lowerOpenUpperClosedKeyOnly = "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
2004 static const char* const lowerClosedUpperOpenKeyOnly = "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
2005 static const char* const lowerClosedUpperClosedKeyOnly = "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
2006
2007 SQLiteStatement* sql = nullptr;
2008
2009 switch (type) {
2010 case IDBGetRecordDataType::KeyAndValue:
2011 if (keyRange.lowerOpen) {
2012 if (keyRange.upperOpen)
2013 sql = cachedStatement(SQL::GetValueRecordsLowerOpenUpperOpen, lowerOpenUpperOpen);
2014 else
2015 sql = cachedStatement(SQL::GetValueRecordsLowerOpenUpperClosed, lowerOpenUpperClosed);
2016 } else {
2017 if (keyRange.upperOpen)
2018 sql = cachedStatement(SQL::GetValueRecordsLowerClosedUpperOpen, lowerClosedUpperOpen);
2019 else
2020 sql = cachedStatement(SQL::GetValueRecordsLowerClosedUpperClosed, lowerClosedUpperClosed);
2021 }
2022 break;
2023 case IDBGetRecordDataType::KeyOnly:
2024 if (keyRange.lowerOpen) {
2025 if (keyRange.upperOpen)
2026 sql = cachedStatement(SQL::GetKeyRecordsLowerOpenUpperOpen, lowerOpenUpperOpenKeyOnly);
2027 else
2028 sql = cachedStatement(SQL::GetKeyRecordsLowerOpenUpperClosed, lowerOpenUpperClosedKeyOnly);
2029 } else {
2030 if (keyRange.upperOpen)
2031 sql = cachedStatement(SQL::GetKeyRecordsLowerClosedUpperOpen, lowerClosedUpperOpenKeyOnly);
2032 else
2033 sql = cachedStatement(SQL::GetKeyRecordsLowerClosedUpperClosed, lowerClosedUpperClosedKeyOnly);
2034 }
2035 }
2036
2037 if (!sql
2038 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
2039 || sql->bindBlob(2, lowerBuffer->data(), lowerBuffer->size()) != SQLITE_OK
2040 || sql->bindBlob(3, upperBuffer->data(), upperBuffer->size()) != SQLITE_OK) {
2041 LOG_ERROR("Could not get key range record from object store %" PRIi64 " from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
2042 return IDBError { UnknownError, "Failed to look up record in object store by key range"_s };
2043 }
2044
2045 int sqlResult = sql->step();
2046
2047 if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE) {
2048 // There was no record for the key in the database.
2049 return IDBError { };
2050 }
2051 if (sqlResult != SQLITE_ROW) {
2052 // There was an error fetching the record from the database.
2053 LOG_ERROR("Could not get record from object store %" PRIi64 " from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
2054 return IDBError { UnknownError, "Error looking up record in object store by key range"_s };
2055 }
2056
2057 Vector<uint8_t> keyBuffer;
2058 sql->getColumnBlobAsVector(0, keyBuffer);
2059 keyResultBuffer = ThreadSafeDataBuffer::create(WTFMove(keyBuffer));
2060
2061 if (type == IDBGetRecordDataType::KeyAndValue) {
2062 Vector<uint8_t> valueBuffer;
2063 sql->getColumnBlobAsVector(1, valueBuffer);
2064 valueResultBuffer = ThreadSafeDataBuffer::create(WTFMove(valueBuffer));
2065 recordID = sql->getColumnInt64(2);
2066 }
2067 }
2068
2069 auto* keyVector = keyResultBuffer.data();
2070 if (!keyVector) {
2071 LOG_ERROR("Unable to deserialize key data from database for IDBObjectStore");
2072 return IDBError { UnknownError, "Error extracting key data from database executing IDBObjectStore get"_s };
2073 }
2074
2075 IDBKeyData keyData;
2076 if (!deserializeIDBKeyData(keyVector->data(), keyVector->size(), keyData)) {
2077 LOG_ERROR("Unable to deserialize key data from database for IDBObjectStore");
2078 return IDBError { UnknownError, "Error extracting key data from database executing IDBObjectStore get"_s };
2079 }
2080
2081 if (type == IDBGetRecordDataType::KeyOnly) {
2082 resultValue = { keyData };
2083 return IDBError { };
2084 }
2085
2086 ASSERT(recordID);
2087 Vector<String> blobURLs, blobFilePaths;
2088 PAL::SessionID sessionID;
2089 auto error = getBlobRecordsForObjectStoreRecord(recordID, blobURLs, sessionID, blobFilePaths);
2090 ASSERT(blobURLs.size() == blobFilePaths.size());
2091
2092 if (!error.isNull())
2093 return error;
2094
2095 auto* objectStoreInfo = infoForObjectStore(objectStoreID);
2096 ASSERT(objectStoreInfo);
2097 resultValue = { keyData, { valueResultBuffer, WTFMove(blobURLs), sessionID, WTFMove(blobFilePaths) }, objectStoreInfo->keyPath()};
2098 return IDBError { };
2099}
2100
2101IDBError SQLiteIDBBackingStore::getAllRecords(const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData& getAllRecordsData, IDBGetAllResult& result)
2102{
2103 return getAllRecordsData.indexIdentifier ? getAllIndexRecords(transactionIdentifier, getAllRecordsData, result) : getAllObjectStoreRecords(transactionIdentifier, getAllRecordsData, result);
2104}
2105
2106SQLiteStatement* SQLiteIDBBackingStore::cachedStatementForGetAllObjectStoreRecords(const IDBGetAllRecordsData& getAllRecordsData)
2107{
2108 static const char* const lowerOpenUpperOpenKey ="SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
2109 static const char* const lowerOpenUpperClosedKey = "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
2110 static const char* const lowerClosedUpperOpenKey = "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
2111 static const char* const lowerClosedUpperClosedKey = "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
2112 static const char* const lowerOpenUpperOpenValue = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
2113 static const char* const lowerOpenUpperClosedValue = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
2114 static const char* const lowerClosedUpperOpenValue = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
2115 static const char* const lowerClosedUpperClosedValue = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
2116
2117 if (getAllRecordsData.getAllType == IndexedDB::GetAllType::Keys) {
2118 if (getAllRecordsData.keyRangeData.lowerOpen) {
2119 if (getAllRecordsData.keyRangeData.upperOpen)
2120 return cachedStatement(SQL::GetAllKeyRecordsLowerOpenUpperOpen, lowerOpenUpperOpenKey);
2121 return cachedStatement(SQL::GetAllKeyRecordsLowerOpenUpperClosed, lowerOpenUpperClosedKey);
2122 }
2123
2124 if (getAllRecordsData.keyRangeData.upperOpen)
2125 return cachedStatement(SQL::GetAllKeyRecordsLowerClosedUpperOpen, lowerClosedUpperOpenKey);
2126 return cachedStatement(SQL::GetAllKeyRecordsLowerClosedUpperClosed, lowerClosedUpperClosedKey);
2127 }
2128
2129 if (getAllRecordsData.keyRangeData.lowerOpen) {
2130 if (getAllRecordsData.keyRangeData.upperOpen)
2131 return cachedStatement(SQL::GetValueRecordsLowerOpenUpperOpen, lowerOpenUpperOpenValue);
2132 return cachedStatement(SQL::GetValueRecordsLowerOpenUpperClosed, lowerOpenUpperClosedValue);
2133 }
2134
2135 if (getAllRecordsData.keyRangeData.upperOpen)
2136 return cachedStatement(SQL::GetValueRecordsLowerClosedUpperOpen, lowerClosedUpperOpenValue);
2137 return cachedStatement(SQL::GetValueRecordsLowerClosedUpperClosed, lowerClosedUpperClosedValue);
2138}
2139
2140IDBError SQLiteIDBBackingStore::getAllObjectStoreRecords(const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData& getAllRecordsData, IDBGetAllResult& result)
2141{
2142 LOG(IndexedDB, "SQLiteIDBBackingStore::getAllObjectStoreRecords");
2143
2144 ASSERT(m_sqliteDB);
2145 ASSERT(m_sqliteDB->isOpen());
2146
2147 auto* transaction = m_transactions.get(transactionIdentifier);
2148 if (!transaction || !transaction->inProgress())
2149 return IDBError { UnknownError, "Attempt to get records from database without an in-progress transaction"_s };
2150
2151 auto key = getAllRecordsData.keyRangeData.lowerKey;
2152 if (key.isNull())
2153 key = IDBKeyData::minimum();
2154 auto lowerBuffer = serializeIDBKeyData(key);
2155 if (!lowerBuffer) {
2156 LOG_ERROR("Unable to serialize lower IDBKey in lookup range");
2157 return IDBError { UnknownError, "Unable to serialize lower IDBKey in lookup range"_s };
2158 }
2159
2160 key = getAllRecordsData.keyRangeData.upperKey;
2161 if (key.isNull())
2162 key = IDBKeyData::maximum();
2163 auto upperBuffer = serializeIDBKeyData(key);
2164 if (!upperBuffer) {
2165 LOG_ERROR("Unable to serialize upper IDBKey in lookup range");
2166 return IDBError { UnknownError, "Unable to serialize upper IDBKey in lookup range"_s };
2167 }
2168
2169 auto* sql = cachedStatementForGetAllObjectStoreRecords(getAllRecordsData);
2170 if (!sql
2171 || sql->bindInt64(1, getAllRecordsData.objectStoreIdentifier) != SQLITE_OK
2172 || sql->bindBlob(2, lowerBuffer->data(), lowerBuffer->size()) != SQLITE_OK
2173 || sql->bindBlob(3, upperBuffer->data(), upperBuffer->size()) != SQLITE_OK) {
2174 LOG_ERROR("Could not get key range record from object store %" PRIi64 " from Records table (%i) - %s", getAllRecordsData.objectStoreIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
2175 return IDBError { UnknownError, "Failed to look up record in object store by key range"_s };
2176 }
2177
2178 auto* objectStoreInfo = infoForObjectStore(getAllRecordsData.objectStoreIdentifier);
2179 ASSERT(objectStoreInfo);
2180 result = { getAllRecordsData.getAllType, objectStoreInfo->keyPath() };
2181
2182 uint32_t targetResults;
2183 if (getAllRecordsData.count && getAllRecordsData.count.value())
2184 targetResults = getAllRecordsData.count.value();
2185 else
2186 targetResults = std::numeric_limits<uint32_t>::max();
2187
2188 int sqlResult = sql->step();
2189 uint32_t returnedResults = 0;
2190
2191 while (sqlResult == SQLITE_ROW && returnedResults < targetResults) {
2192 Vector<uint8_t> keyBuffer;
2193 IDBKeyData keyData;
2194 sql->getColumnBlobAsVector(0, keyBuffer);
2195 if (!deserializeIDBKeyData(keyBuffer.data(), keyBuffer.size(), keyData)) {
2196 LOG_ERROR("Unable to deserialize key data from database while getting all records");
2197 return IDBError { UnknownError, "Unable to deserialize key data while getting all records"_s };
2198 }
2199 result.addKey(WTFMove(keyData));
2200
2201 if (getAllRecordsData.getAllType == IndexedDB::GetAllType::Values) {
2202 Vector<uint8_t> valueBuffer;
2203 sql->getColumnBlobAsVector(1, valueBuffer);
2204 ThreadSafeDataBuffer valueResultBuffer = ThreadSafeDataBuffer::create(WTFMove(valueBuffer));
2205
2206 auto recordID = sql->getColumnInt64(2);
2207
2208 ASSERT(recordID);
2209 Vector<String> blobURLs, blobFilePaths;
2210 PAL::SessionID sessionID;
2211 auto error = getBlobRecordsForObjectStoreRecord(recordID, blobURLs, sessionID, blobFilePaths);
2212 ASSERT(blobURLs.size() == blobFilePaths.size());
2213
2214 if (!error.isNull())
2215 return error;
2216
2217 result.addValue({ valueResultBuffer, WTFMove(blobURLs), sessionID, WTFMove(blobFilePaths) });
2218 }
2219
2220 ++returnedResults;
2221 sqlResult = sql->step();
2222 }
2223
2224 if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE || sqlResult == SQLITE_ROW) {
2225 // Finished getting results
2226 return IDBError { };
2227 }
2228
2229 // There was an error fetching records from the database.
2230 LOG_ERROR("Could not get record from object store %" PRIi64 " from Records table (%i) - %s", getAllRecordsData.objectStoreIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
2231 return IDBError { UnknownError, "Error looking up record in object store by key range"_s };
2232}
2233
2234IDBError SQLiteIDBBackingStore::getAllIndexRecords(const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData& getAllRecordsData, IDBGetAllResult& result)
2235{
2236 LOG(IndexedDB, "SQLiteIDBBackingStore::getAllIndexRecords - %s", getAllRecordsData.keyRangeData.loggingString().utf8().data());
2237
2238 ASSERT(m_sqliteDB);
2239 ASSERT(m_sqliteDB->isOpen());
2240
2241 auto* transaction = m_transactions.get(transactionIdentifier);
2242 if (!transaction || !transaction->inProgress())
2243 return IDBError { UnknownError, "Attempt to get all index records from database without an in-progress transaction"_s };
2244
2245 auto cursor = transaction->maybeOpenBackingStoreCursor(getAllRecordsData.objectStoreIdentifier, getAllRecordsData.indexIdentifier, getAllRecordsData.keyRangeData);
2246 if (!cursor) {
2247 LOG_ERROR("Cannot open cursor to perform index gets in database");
2248 return IDBError { UnknownError, "Cannot open cursor to perform index gets in database"_s };
2249 }
2250
2251 if (cursor->didError()) {
2252 LOG_ERROR("Cursor failed while looking up index records in database");
2253 return IDBError { UnknownError, "Cursor failed while looking up index records in database"_s };
2254 }
2255
2256 auto* objectStoreInfo = infoForObjectStore(getAllRecordsData.objectStoreIdentifier);
2257 ASSERT(objectStoreInfo);
2258 result = { getAllRecordsData.getAllType, objectStoreInfo->keyPath() };
2259
2260 uint32_t currentCount = 0;
2261 uint32_t targetCount = getAllRecordsData.count ? getAllRecordsData.count.value() : 0;
2262 if (!targetCount)
2263 targetCount = std::numeric_limits<uint32_t>::max();
2264 while (!cursor->didComplete() && !cursor->didError() && currentCount < targetCount) {
2265 IDBKeyData keyCopy = cursor->currentPrimaryKey();
2266 result.addKey(WTFMove(keyCopy));
2267 if (getAllRecordsData.getAllType == IndexedDB::GetAllType::Values)
2268 result.addValue(cursor->currentValue() ? *cursor->currentValue() : IDBValue());
2269
2270 ++currentCount;
2271 cursor->advance(1);
2272 }
2273
2274 if (cursor->didError()) {
2275 LOG_ERROR("Cursor failed while looking up index records in database");
2276 return IDBError { UnknownError, "Cursor failed while looking up index records in database"_s };
2277 }
2278
2279 return IDBError { };
2280}
2281
2282IDBError SQLiteIDBBackingStore::getIndexRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, uint64_t indexID, IndexedDB::IndexRecordType type, const IDBKeyRangeData& range, IDBGetResult& getResult)
2283{
2284 LOG(IndexedDB, "SQLiteIDBBackingStore::getIndexRecord - %s", range.loggingString().utf8().data());
2285
2286 ASSERT(m_sqliteDB);
2287 ASSERT(m_sqliteDB->isOpen());
2288
2289 auto* transaction = m_transactions.get(transactionIdentifier);
2290 if (!transaction || !transaction->inProgress())
2291 return IDBError { UnknownError, "Attempt to get an index record from database without an in-progress transaction"_s };
2292
2293 if (range.isExactlyOneKey())
2294 return uncheckedGetIndexRecordForOneKey(indexID, objectStoreID, type, range.lowerKey, getResult);
2295
2296 auto cursor = transaction->maybeOpenBackingStoreCursor(objectStoreID, indexID, range);
2297 if (!cursor) {
2298 LOG_ERROR("Cannot open cursor to perform index get in database");
2299 return IDBError { UnknownError, "Cannot open cursor to perform index get in database"_s };
2300 }
2301
2302 if (cursor->didError()) {
2303 LOG_ERROR("Cursor failed while looking up index record in database");
2304 return IDBError { UnknownError, "Cursor failed while looking up index record in database"_s };
2305 }
2306
2307 if (cursor->didComplete())
2308 getResult = { };
2309 else {
2310 if (type == IndexedDB::IndexRecordType::Key)
2311 getResult = { cursor->currentPrimaryKey() };
2312 else {
2313 auto* objectStoreInfo = infoForObjectStore(objectStoreID);
2314 ASSERT(objectStoreInfo);
2315 getResult = { cursor->currentPrimaryKey(), cursor->currentPrimaryKey(), cursor->currentValue() ? *cursor->currentValue() : IDBValue(), objectStoreInfo->keyPath() };
2316 }
2317 }
2318
2319 return IDBError { };
2320}
2321
2322IDBError SQLiteIDBBackingStore::uncheckedGetIndexRecordForOneKey(int64_t indexID, int64_t objectStoreID, IndexedDB::IndexRecordType type, const IDBKeyData& key, IDBGetResult& getResult)
2323{
2324 LOG(IndexedDB, "SQLiteIDBBackingStore::uncheckedGetIndexRecordForOneKey");
2325
2326 ASSERT(key.isValid() && key.type() != IndexedDB::KeyType::Max && key.type() != IndexedDB::KeyType::Min);
2327
2328 RefPtr<SharedBuffer> buffer = serializeIDBKeyData(key);
2329 if (!buffer) {
2330 LOG_ERROR("Unable to serialize IDBKey to look up one index record");
2331 return IDBError { UnknownError, "Unable to serialize IDBKey to look up one index record"_s };
2332 }
2333
2334 auto* sql = cachedStatement(SQL::GetIndexRecordForOneKey, "SELECT IndexRecords.value, Records.value, Records.recordID FROM Records INNER JOIN IndexRecords ON Records.recordID = IndexRecords.objectStoreRecordID WHERE IndexRecords.indexID = ? AND IndexRecords.objectStoreID = ? AND IndexRecords.key = CAST(? AS TEXT) ORDER BY IndexRecords.key, IndexRecords.value"_s);
2335
2336 if (!sql
2337 || sql->bindInt64(1, indexID) != SQLITE_OK
2338 || sql->bindInt64(2, objectStoreID) != SQLITE_OK
2339 || sql->bindBlob(3, buffer->data(), buffer->size()) != SQLITE_OK) {
2340 LOG_ERROR("Unable to lookup index record in database");
2341 return IDBError { UnknownError, "Unable to lookup index record in database"_s };
2342 }
2343
2344 int result = sql->step();
2345 if (result != SQLITE_ROW && result != SQLITE_DONE) {
2346 LOG_ERROR("Unable to lookup index record in database");
2347 return IDBError { UnknownError, "Unable to lookup index record in database"_s };
2348 }
2349
2350 if (result == SQLITE_DONE)
2351 return IDBError { };
2352
2353 IDBKeyData objectStoreKey;
2354 Vector<uint8_t> keyVector;
2355 sql->getColumnBlobAsVector(0, keyVector);
2356
2357 if (!deserializeIDBKeyData(keyVector.data(), keyVector.size(), objectStoreKey)) {
2358 LOG_ERROR("Unable to deserialize key looking up index record in database");
2359 return IDBError { UnknownError, "Unable to deserialize key looking up index record in database"_s };
2360 }
2361
2362 if (type == IndexedDB::IndexRecordType::Key) {
2363 getResult = { objectStoreKey };
2364 return IDBError { };
2365 }
2366
2367 Vector<uint8_t> valueVector;
2368 sql->getColumnBlobAsVector(1, valueVector);
2369
2370 int64_t recordID = sql->getColumnInt64(2);
2371 Vector<String> blobURLs, blobFilePaths;
2372 PAL::SessionID sessionID;
2373 auto error = getBlobRecordsForObjectStoreRecord(recordID, blobURLs, sessionID, blobFilePaths);
2374 ASSERT(blobURLs.size() == blobFilePaths.size());
2375
2376 if (!error.isNull())
2377 return error;
2378
2379 auto* objectStoreInfo = infoForObjectStore(objectStoreID);
2380 ASSERT(objectStoreInfo);
2381 getResult = { objectStoreKey, objectStoreKey, { ThreadSafeDataBuffer::create(WTFMove(valueVector)), WTFMove(blobURLs), sessionID, WTFMove(blobFilePaths) }, objectStoreInfo->keyPath() };
2382 return IDBError { };
2383}
2384
2385IDBError SQLiteIDBBackingStore::getCount(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData& range, uint64_t& outCount)
2386{
2387 LOG(IndexedDB, "SQLiteIDBBackingStore::getCount - object store %" PRIu64, objectStoreIdentifier);
2388 ASSERT(m_sqliteDB);
2389 ASSERT(m_sqliteDB->isOpen());
2390
2391 outCount = 0;
2392
2393 auto* transaction = m_transactions.get(transactionIdentifier);
2394 if (!transaction || !transaction->inProgress())
2395 return IDBError { UnknownError, "Attempt to get count from database without an in-progress transaction"_s };
2396
2397 auto cursor = transaction->maybeOpenBackingStoreCursor(objectStoreIdentifier, indexIdentifier, range);
2398 if (!cursor) {
2399 LOG_ERROR("Cannot open cursor to populate indexes in database");
2400 return IDBError { UnknownError, "Unable to populate indexes in database"_s };
2401 }
2402
2403 while (cursor->advance(1))
2404 ++outCount;
2405
2406 return IDBError { };
2407}
2408
2409IDBError SQLiteIDBBackingStore::uncheckedGetKeyGeneratorValue(int64_t objectStoreID, uint64_t& outValue)
2410{
2411 auto* sql = cachedStatement(SQL::GetKeyGeneratorValue, "SELECT currentKey FROM KeyGenerators WHERE objectStoreID = ?;"_s);
2412 if (!sql
2413 || sql->bindInt64(1, objectStoreID) != SQLITE_OK) {
2414 LOG_ERROR("Could not retrieve currentKey from KeyGenerators table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
2415 return IDBError { UnknownError, "Error getting current key generator value from database"_s };
2416 }
2417 int result = sql->step();
2418 if (result != SQLITE_ROW) {
2419 LOG_ERROR("Could not retreive key generator value for object store, but it should be there.");
2420 return IDBError { UnknownError, "Error finding current key generator value in database"_s };
2421 }
2422
2423 int64_t value = sql->getColumnInt64(0);
2424 if (value < 0)
2425 return IDBError { ConstraintError, "Current key generator value from database is invalid" };
2426
2427 outValue = value;
2428 return IDBError { };
2429}
2430
2431IDBError SQLiteIDBBackingStore::uncheckedSetKeyGeneratorValue(int64_t objectStoreID, uint64_t value)
2432{
2433 auto* sql = cachedStatement(SQL::SetKeyGeneratorValue, "INSERT INTO KeyGenerators VALUES (?, ?);"_s);
2434 if (!sql
2435 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
2436 || sql->bindInt64(2, value) != SQLITE_OK
2437 || sql->step() != SQLITE_DONE) {
2438 LOG_ERROR("Could not update key generator value (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
2439 if (m_sqliteDB->lastError() == SQLITE_FULL)
2440 return IDBError { QuotaExceededError, "Error storing new key generator value in database because no enough space for domain"_s };
2441 return IDBError { ConstraintError, "Error storing new key generator value in database" };
2442 }
2443
2444 return IDBError { };
2445}
2446
2447IDBError SQLiteIDBBackingStore::generateKeyNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, uint64_t& generatedKey)
2448{
2449 LOG(IndexedDB, "SQLiteIDBBackingStore::generateKeyNumber");
2450
2451 ASSERT(m_sqliteDB);
2452 ASSERT(m_sqliteDB->isOpen());
2453
2454 auto* transaction = m_transactions.get(transactionIdentifier);
2455 if (!transaction || !transaction->inProgress())
2456 return IDBError { UnknownError, "Attempt to generate key in database without an in-progress transaction"_s };
2457
2458 if (transaction->mode() == IDBTransactionMode::Readonly) {
2459 LOG_ERROR("Attempt to generate key in a read-only transaction");
2460 return IDBError { UnknownError, "Attempt to generate key in a read-only transaction"_s };
2461 }
2462
2463 uint64_t currentValue;
2464 auto error = uncheckedGetKeyGeneratorValue(objectStoreID, currentValue);
2465 if (!error.isNull())
2466 return error;
2467
2468 if (currentValue + 1 > maxGeneratorValue)
2469 return IDBError { ConstraintError, "Cannot generate new key value over 2^53 for object store operation" };
2470
2471 generatedKey = currentValue + 1;
2472 return uncheckedSetKeyGeneratorValue(objectStoreID, generatedKey);
2473}
2474
2475IDBError SQLiteIDBBackingStore::revertGeneratedKeyNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, uint64_t newKeyNumber)
2476{
2477 LOG(IndexedDB, "SQLiteIDBBackingStore::revertGeneratedKeyNumber - object store %" PRIu64 ", reverted number %" PRIu64, objectStoreID, newKeyNumber);
2478
2479 ASSERT(m_sqliteDB);
2480 ASSERT(m_sqliteDB->isOpen());
2481
2482 auto* transaction = m_transactions.get(transactionIdentifier);
2483 if (!transaction || !transaction->inProgress())
2484 return IDBError { UnknownError, "Attempt to revert key generator value in database without an in-progress transaction"_s };
2485
2486 if (transaction->mode() == IDBTransactionMode::Readonly) {
2487 LOG_ERROR("Attempt to revert key generator value in a read-only transaction");
2488 return IDBError { UnknownError, "Attempt to revert key generator value in a read-only transaction"_s };
2489 }
2490
2491 ASSERT(newKeyNumber);
2492 return uncheckedSetKeyGeneratorValue(objectStoreID, newKeyNumber - 1);
2493}
2494
2495IDBError SQLiteIDBBackingStore::maybeUpdateKeyGeneratorNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, double newKeyNumber)
2496{
2497 LOG(IndexedDB, "SQLiteIDBBackingStore::maybeUpdateKeyGeneratorNumber");
2498
2499 ASSERT(m_sqliteDB);
2500 ASSERT(m_sqliteDB->isOpen());
2501
2502 auto* transaction = m_transactions.get(transactionIdentifier);
2503 if (!transaction || !transaction->inProgress())
2504 return IDBError { UnknownError, "Attempt to update key generator value in database without an in-progress transaction"_s };
2505
2506 if (transaction->mode() == IDBTransactionMode::Readonly) {
2507 LOG_ERROR("Attempt to update key generator value in a read-only transaction");
2508 return IDBError { UnknownError, "Attempt to update key generator value in a read-only transaction"_s };
2509 }
2510
2511 uint64_t currentValue;
2512 auto error = uncheckedGetKeyGeneratorValue(objectStoreID, currentValue);
2513 if (!error.isNull())
2514 return error;
2515
2516 if (newKeyNumber <= currentValue)
2517 return IDBError { };
2518
2519 return uncheckedSetKeyGeneratorValue(objectStoreID, std::min(newKeyNumber, (double)maxGeneratorValue));
2520}
2521
2522IDBError SQLiteIDBBackingStore::openCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo& info, IDBGetResult& result)
2523{
2524 ASSERT(m_sqliteDB);
2525 ASSERT(m_sqliteDB->isOpen());
2526
2527 auto* transaction = m_transactions.get(transactionIdentifier);
2528 if (!transaction || !transaction->inProgress())
2529 return IDBError { UnknownError, "Attempt to open a cursor in database without an in-progress transaction"_s };
2530
2531 auto* cursor = transaction->maybeOpenCursor(info);
2532 if (!cursor) {
2533 LOG_ERROR("Unable to open cursor");
2534 return IDBError { UnknownError, "Unable to open cursor"_s };
2535 }
2536
2537 m_cursors.set(cursor->identifier(), cursor);
2538
2539 auto* objectStoreInfo = infoForObjectStore(info.objectStoreIdentifier());
2540 ASSERT(objectStoreInfo);
2541 cursor->currentData(result, objectStoreInfo->keyPath());
2542 return IDBError { };
2543}
2544
2545IDBError SQLiteIDBBackingStore::iterateCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBIterateCursorData& data, IDBGetResult& result)
2546{
2547 LOG(IndexedDB, "SQLiteIDBBackingStore::iterateCursor");
2548
2549 ASSERT(m_sqliteDB);
2550 ASSERT(m_sqliteDB->isOpen());
2551
2552 auto* cursor = m_cursors.get(cursorIdentifier);
2553 if (!cursor) {
2554 LOG_ERROR("Attempt to iterate a cursor that doesn't exist");
2555 return IDBError { UnknownError, "Attempt to iterate a cursor that doesn't exist"_s };
2556 }
2557
2558 ASSERT_UNUSED(transactionIdentifier, cursor->transaction()->transactionIdentifier() == transactionIdentifier);
2559
2560 if (!cursor->transaction() || !cursor->transaction()->inProgress())
2561 return IDBError { UnknownError, "Attempt to iterate a cursor without an in-progress transaction"_s };
2562
2563 auto key = data.keyData;
2564 auto primaryKey = data.primaryKeyData;
2565 auto count = data.count;
2566
2567 if (key.isValid()) {
2568 if (!cursor->iterate(key, primaryKey)) {
2569 LOG_ERROR("Attempt to iterate cursor failed");
2570 return IDBError { UnknownError, "Attempt to iterate cursor failed"_s };
2571 }
2572 } else {
2573 ASSERT(!primaryKey.isValid());
2574 if (!count)
2575 count = 1;
2576 if (!cursor->advance(count)) {
2577 LOG_ERROR("Attempt to advance cursor failed");
2578 return IDBError { UnknownError, "Attempt to advance cursor failed"_s };
2579 }
2580 }
2581
2582 auto* objectStoreInfo = infoForObjectStore(cursor->objectStoreID());
2583 ASSERT(objectStoreInfo);
2584 cursor->currentData(result, objectStoreInfo->keyPath());
2585 return IDBError { };
2586}
2587
2588bool SQLiteIDBBackingStore::prefetchCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier)
2589{
2590 LOG(IndexedDB, "SQLiteIDBBackingStore::prefetchCursor");
2591
2592 ASSERT(m_sqliteDB);
2593 ASSERT(m_sqliteDB->isOpen());
2594
2595 auto* cursor = m_cursors.get(cursorIdentifier);
2596 if (!cursor || !cursor->transaction() || !cursor->transaction()->inProgress())
2597 return false;
2598
2599 ASSERT_UNUSED(transactionIdentifier, cursor->transaction()->transactionIdentifier() == transactionIdentifier);
2600
2601 return cursor->prefetch();
2602}
2603
2604IDBObjectStoreInfo* SQLiteIDBBackingStore::infoForObjectStore(uint64_t objectStoreIdentifier)
2605{
2606 ASSERT(m_databaseInfo);
2607 return m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
2608}
2609
2610void SQLiteIDBBackingStore::deleteBackingStore()
2611{
2612 String dbFilename = fullDatabasePath();
2613
2614 LOG(IndexedDB, "SQLiteIDBBackingStore::deleteBackingStore deleting file '%s' on disk", dbFilename.utf8().data());
2615
2616 Vector<String> blobFiles;
2617 {
2618 bool errored = true;
2619
2620 if (m_sqliteDB) {
2621 SQLiteStatement sql(*m_sqliteDB, "SELECT fileName FROM BlobFiles;"_s);
2622 if (sql.prepare() == SQLITE_OK) {
2623 int result = sql.step();
2624 while (result == SQLITE_ROW) {
2625 blobFiles.append(sql.getColumnText(0));
2626 result = sql.step();
2627 }
2628
2629 if (result == SQLITE_DONE)
2630 errored = false;
2631 }
2632 }
2633
2634 if (errored)
2635 LOG_ERROR("Error getting all blob filenames to be deleted");
2636 }
2637
2638 for (auto& file : blobFiles) {
2639 String fullPath = FileSystem::pathByAppendingComponent(m_databaseDirectory, file);
2640 if (!FileSystem::deleteFile(fullPath))
2641 LOG_ERROR("Error deleting blob file %s", fullPath.utf8().data());
2642 }
2643
2644 if (m_sqliteDB)
2645 closeSQLiteDB();
2646
2647 SQLiteFileSystem::deleteDatabaseFile(dbFilename);
2648 SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_databaseDirectory);
2649 SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_identifier.databaseDirectoryRelativeToRoot(m_databaseRootDirectory));
2650}
2651
2652void SQLiteIDBBackingStore::unregisterCursor(SQLiteIDBCursor& cursor)
2653{
2654 ASSERT(m_cursors.contains(cursor.identifier()));
2655 m_cursors.remove(cursor.identifier());
2656}
2657
2658SQLiteStatement* SQLiteIDBBackingStore::cachedStatement(SQLiteIDBBackingStore::SQL sql, const char* statement)
2659{
2660 if (sql >= SQL::Count) {
2661 LOG_ERROR("Invalid SQL statement ID passed to cachedStatement()");
2662 return nullptr;
2663 }
2664
2665 if (m_cachedStatements[static_cast<size_t>(sql)]) {
2666 if (m_cachedStatements[static_cast<size_t>(sql)]->reset() == SQLITE_OK)
2667 return m_cachedStatements[static_cast<size_t>(sql)].get();
2668 m_cachedStatements[static_cast<size_t>(sql)] = nullptr;
2669 }
2670
2671 if (m_sqliteDB) {
2672 m_cachedStatements[static_cast<size_t>(sql)] = std::make_unique<SQLiteStatement>(*m_sqliteDB, statement);
2673 if (m_cachedStatements[static_cast<size_t>(sql)]->prepare() != SQLITE_OK)
2674 m_cachedStatements[static_cast<size_t>(sql)] = nullptr;
2675 }
2676
2677 return m_cachedStatements[static_cast<size_t>(sql)].get();
2678}
2679
2680void SQLiteIDBBackingStore::closeSQLiteDB()
2681{
2682 for (size_t i = 0; i < static_cast<int>(SQL::Count); ++i)
2683 m_cachedStatements[i] = nullptr;
2684
2685 if (m_sqliteDB)
2686 m_sqliteDB->close();
2687
2688 m_sqliteDB = nullptr;
2689}
2690
2691bool SQLiteIDBBackingStore::hasTransaction(const IDBResourceIdentifier& transactionIdentifier) const
2692{
2693 ASSERT(isMainThread());
2694 return m_transactions.contains(transactionIdentifier);
2695}
2696
2697} // namespace IDBServer
2698} // namespace WebCore
2699
2700#endif // ENABLE(INDEXED_DATABASE)
2701