2 * Copyright (C) 2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "SQLiteIDBBackingStore.h"
29 #if ENABLE(INDEXED_DATABASE)
31 #include "FileSystem.h"
32 #include "IDBBindingUtilities.h"
33 #include "IDBDatabaseException.h"
34 #include "IDBGetAllRecordsData.h"
35 #include "IDBGetAllResult.h"
36 #include "IDBGetRecordData.h"
37 #include "IDBGetResult.h"
38 #include "IDBIterateCursorData.h"
39 #include "IDBKeyData.h"
40 #include "IDBObjectStoreInfo.h"
41 #include "IDBSerialization.h"
42 #include "IDBTransactionInfo.h"
46 #include "SQLiteDatabase.h"
47 #include "SQLiteFileSystem.h"
48 #include "SQLiteIDBCursor.h"
49 #include "SQLiteStatement.h"
50 #include "SQLiteTransaction.h"
51 #include "ThreadSafeDataBuffer.h"
52 #include <heap/HeapInlines.h>
53 #include <heap/StrongInlines.h>
54 #include <runtime/AuxiliaryBarrierInlines.h>
55 #include <runtime/JSCJSValueInlines.h>
56 #include <runtime/JSGlobalObject.h>
57 #include <runtime/StructureInlines.h>
58 #include <wtf/NeverDestroyed.h>
65 // Current version of the metadata schema being used in the metadata database.
66 static const int currentMetadataVersion = 1;
68 static int idbKeyCollate(int aLength, const void* aBuffer, int bLength, const void* bBuffer)
71 if (!deserializeIDBKeyData(static_cast<const uint8_t*>(aBuffer), aLength, a)) {
72 LOG_ERROR("Unable to deserialize key A in collation function.");
74 // There's no way to indicate an error to SQLite - we have to return a sorting decision.
75 // We arbitrarily choose "A > B"
78 if (!deserializeIDBKeyData(static_cast<const uint8_t*>(bBuffer), bLength, b)) {
79 LOG_ERROR("Unable to deserialize key B in collation function.");
81 // There's no way to indicate an error to SQLite - we have to return a sorting decision.
82 // We arbitrarily choose "A > B"
89 static const String v1RecordsTableSchema(const String& tableName)
91 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)");
94 static const String& v1RecordsTableSchema()
96 static NeverDestroyed<WTF::String> v1RecordsTableSchemaString(v1RecordsTableSchema("Records"));
97 return v1RecordsTableSchemaString;
100 static const String& v1RecordsTableSchemaAlternate()
102 static NeverDestroyed<WTF::String> v1RecordsTableSchemaString(v1RecordsTableSchema("\"Records\""));
103 return v1RecordsTableSchemaString;
106 static const String v2RecordsTableSchema(const String& tableName)
108 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)");
111 static const String& v2RecordsTableSchema()
113 static NeverDestroyed<WTF::String> v2RecordsTableSchemaString(v2RecordsTableSchema("Records"));
114 return v2RecordsTableSchemaString;
117 static const String& v2RecordsTableSchemaAlternate()
119 static NeverDestroyed<WTF::String> v2RecordsTableSchemaString(v2RecordsTableSchema("\"Records\""));
120 return v2RecordsTableSchemaString;
123 static const String v3RecordsTableSchema(const String& tableName)
125 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)");
128 static const String& v3RecordsTableSchema()
130 static NeverDestroyed<WTF::String> v3RecordsTableSchemaString(v3RecordsTableSchema("Records"));
131 return v3RecordsTableSchemaString;
134 static const String& v3RecordsTableSchemaAlternate()
136 static NeverDestroyed<WTF::String> v3RecordsTableSchemaString(v3RecordsTableSchema("\"Records\""));
137 return v3RecordsTableSchemaString;
140 static const String v1IndexRecordsTableSchema(const String& tableName)
142 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)");
145 static const String& v1IndexRecordsTableSchema()
147 static NeverDestroyed<WTF::String> v1IndexRecordsTableSchemaString(v1IndexRecordsTableSchema("IndexRecords"));
148 return v1IndexRecordsTableSchemaString;
151 static const String& v1IndexRecordsTableSchemaAlternate()
153 static NeverDestroyed<WTF::String> v1IndexRecordsTableSchemaString(v1IndexRecordsTableSchema("\"IndexRecords\""));
154 return v1IndexRecordsTableSchemaString;
157 static const String v2IndexRecordsTableSchema(const String& tableName)
159 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)");
162 static const String& v2IndexRecordsTableSchema()
164 static NeverDestroyed<WTF::String> v2IndexRecordsTableSchemaString(v2IndexRecordsTableSchema("IndexRecords"));
165 return v2IndexRecordsTableSchemaString;
168 static const String& v2IndexRecordsTableSchemaAlternate()
170 static NeverDestroyed<WTF::String> v2IndexRecordsTableSchemaString(v2IndexRecordsTableSchema("\"IndexRecords\""));
171 return v2IndexRecordsTableSchemaString;
174 static const String v3IndexRecordsTableSchema(const String& tableName)
176 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)");
179 static const String v3IndexRecordsTableSchema()
181 static NeverDestroyed<WTF::String> indexRecordsTableSchemaString = v3IndexRecordsTableSchema("IndexRecords");
182 return indexRecordsTableSchemaString;
185 static const String v3IndexRecordsTableSchemaAlternate()
187 static NeverDestroyed<WTF::String> indexRecordsTableSchemaString = v3IndexRecordsTableSchema("\"IndexRecords\"");
188 return indexRecordsTableSchemaString;
191 static const String& v1IndexRecordsIndexSchema()
193 static NeverDestroyed<WTF::String> indexRecordsIndexSchemaString("CREATE INDEX IndexRecordsIndex ON IndexRecords (key)");
194 return indexRecordsIndexSchemaString;
197 static const String blobRecordsTableSchema(const String& tableName)
199 return makeString("CREATE TABLE ", tableName, " (objectStoreRow INTEGER NOT NULL ON CONFLICT FAIL, blobURL TEXT NOT NULL ON CONFLICT FAIL)");
202 static const String& blobRecordsTableSchema()
204 static NeverDestroyed<String> blobRecordsTableSchemaString(blobRecordsTableSchema("BlobRecords"));
205 return blobRecordsTableSchemaString;
208 static const String& blobRecordsTableSchemaAlternate()
210 static NeverDestroyed<String> blobRecordsTableSchemaString(blobRecordsTableSchema("\"BlobRecords\""));
211 return blobRecordsTableSchemaString;
214 static const String blobFilesTableSchema(const String& tableName)
216 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)");
219 static const String& blobFilesTableSchema()
221 static NeverDestroyed<String> blobFilesTableSchemaString(blobFilesTableSchema("BlobFiles"));
222 return blobFilesTableSchemaString;
225 static const String& blobFilesTableSchemaAlternate()
227 static NeverDestroyed<String> blobFilesTableSchemaString(blobFilesTableSchema("\"BlobFiles\""));
228 return blobFilesTableSchemaString;
231 SQLiteIDBBackingStore::SQLiteIDBBackingStore(const IDBDatabaseIdentifier& identifier, const String& databaseRootDirectory, IDBBackingStoreTemporaryFileHandler& fileHandler)
232 : m_identifier(identifier)
233 , m_temporaryFileHandler(fileHandler)
235 m_absoluteDatabaseDirectory = identifier.databaseDirectoryRelativeToRoot(databaseRootDirectory);
238 SQLiteIDBBackingStore::~SQLiteIDBBackingStore()
244 JSLockHolder locker(m_vm.get());
245 m_globalObject.clear();
251 void SQLiteIDBBackingStore::initializeVM()
254 ASSERT(!m_globalObject);
257 JSLockHolder locker(m_vm.get());
258 m_globalObject.set(*m_vm, JSGlobalObject::create(*m_vm, JSGlobalObject::createStructure(*m_vm, jsNull())));
262 VM& SQLiteIDBBackingStore::vm()
268 JSGlobalObject& SQLiteIDBBackingStore::globalObject()
271 return **m_globalObject;
274 static bool createOrMigrateRecordsTableIfNecessary(SQLiteDatabase& database)
276 String currentSchema;
278 // Fetch the schema for an existing records table.
279 SQLiteStatement statement(database, "SELECT type, sql FROM sqlite_master WHERE tbl_name='Records'");
280 if (statement.prepare() != SQLITE_OK) {
281 LOG_ERROR("Unable to prepare statement to fetch schema for the Records table.");
285 int sqliteResult = statement.step();
287 // If there is no Records table at all, create it and then bail.
288 if (sqliteResult == SQLITE_DONE) {
289 if (!database.executeCommand(v3RecordsTableSchema())) {
290 LOG_ERROR("Could not create Records table in database (%i) - %s", database.lastError(), database.lastErrorMsg());
297 if (sqliteResult != SQLITE_ROW) {
298 LOG_ERROR("Error executing statement to fetch schema for the Records table.");
302 currentSchema = statement.getColumnText(1);
305 ASSERT(!currentSchema.isEmpty());
307 // If the schema in the backing store is the current schema, we're done.
308 if (currentSchema == v3RecordsTableSchema() || currentSchema == v3RecordsTableSchemaAlternate())
311 // If the record table is not the current schema then it must be one of the previous schemas.
312 // If it is not then the database is in an unrecoverable state and this should be considered a fatal error.
313 if (currentSchema != v1RecordsTableSchema() && currentSchema != v1RecordsTableSchemaAlternate()
314 && currentSchema != v2RecordsTableSchema() && currentSchema != v2RecordsTableSchemaAlternate())
315 RELEASE_ASSERT_NOT_REACHED();
317 SQLiteTransaction transaction(database);
320 // Create a temporary table with the correct schema and migrate all existing content over.
321 if (!database.executeCommand(v3RecordsTableSchema("_Temp_Records"))) {
322 LOG_ERROR("Could not create temporary records table in database (%i) - %s", database.lastError(), database.lastErrorMsg());
326 if (!database.executeCommand("INSERT INTO _Temp_Records (objectStoreID, key, value) SELECT objectStoreID, CAST(key AS TEXT), value FROM Records")) {
327 LOG_ERROR("Could not migrate existing Records content (%i) - %s", database.lastError(), database.lastErrorMsg());
331 if (!database.executeCommand("DROP TABLE Records")) {
332 LOG_ERROR("Could not drop existing Records table (%i) - %s", database.lastError(), database.lastErrorMsg());
336 if (!database.executeCommand("ALTER TABLE _Temp_Records RENAME TO Records")) {
337 LOG_ERROR("Could not rename temporary Records table (%i) - %s", database.lastError(), database.lastErrorMsg());
341 transaction.commit();
346 bool SQLiteIDBBackingStore::ensureValidBlobTables()
349 ASSERT(m_sqliteDB->isOpen());
351 String currentSchema;
353 // Fetch the schema for an existing blob record table.
354 SQLiteStatement statement(*m_sqliteDB, "SELECT type, sql FROM sqlite_master WHERE tbl_name='BlobRecords'");
355 if (statement.prepare() != SQLITE_OK) {
356 LOG_ERROR("Unable to prepare statement to fetch schema for the BlobRecords table.");
360 int sqliteResult = statement.step();
362 // If there is no BlobRecords table at all, create it..
363 if (sqliteResult == SQLITE_DONE) {
364 if (!m_sqliteDB->executeCommand(blobRecordsTableSchema())) {
365 LOG_ERROR("Could not create BlobRecords table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
369 currentSchema = blobRecordsTableSchema();
370 } else if (sqliteResult != SQLITE_ROW) {
371 LOG_ERROR("Error executing statement to fetch schema for the BlobRecords table.");
374 currentSchema = statement.getColumnText(1);
377 if (currentSchema != blobRecordsTableSchema() && currentSchema != blobRecordsTableSchemaAlternate()) {
378 LOG_ERROR("Invalid BlobRecords table schema found");
383 // Fetch the schema for an existing blob file table.
384 SQLiteStatement statement(*m_sqliteDB, "SELECT type, sql FROM sqlite_master WHERE tbl_name='BlobFiles'");
385 if (statement.prepare() != SQLITE_OK) {
386 LOG_ERROR("Unable to prepare statement to fetch schema for the BlobFiles table.");
390 int sqliteResult = statement.step();
392 // If there is no BlobFiles table at all, create it and then bail.
393 if (sqliteResult == SQLITE_DONE) {
394 if (!m_sqliteDB->executeCommand(blobFilesTableSchema())) {
395 LOG_ERROR("Could not create BlobFiles table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
402 if (sqliteResult != SQLITE_ROW) {
403 LOG_ERROR("Error executing statement to fetch schema for the BlobFiles table.");
407 currentSchema = statement.getColumnText(1);
410 if (currentSchema != blobFilesTableSchema() && currentSchema != blobFilesTableSchemaAlternate()) {
411 LOG_ERROR("Invalid BlobFiles table schema found");
418 bool SQLiteIDBBackingStore::ensureValidRecordsTable()
421 ASSERT(m_sqliteDB->isOpen());
423 if (!createOrMigrateRecordsTableIfNecessary(*m_sqliteDB))
426 // Whether the updated records table already existed or if it was just created and the data migrated over,
427 // make sure the uniqueness index exists.
428 if (!m_sqliteDB->executeCommand("CREATE UNIQUE INDEX IF NOT EXISTS RecordsIndex ON Records (objectStoreID, key);")) {
429 LOG_ERROR("Could not create RecordsIndex on Records table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
436 bool SQLiteIDBBackingStore::ensureValidIndexRecordsTable()
439 ASSERT(m_sqliteDB->isOpen());
441 String currentSchema;
443 // Fetch the schema for an existing index record table.
444 SQLiteStatement statement(*m_sqliteDB, "SELECT type, sql FROM sqlite_master WHERE tbl_name='IndexRecords'");
445 if (statement.prepare() != SQLITE_OK) {
446 LOG_ERROR("Unable to prepare statement to fetch schema for the IndexRecords table.");
450 int sqliteResult = statement.step();
452 // If there is no IndexRecords table at all, create it and then bail.
453 if (sqliteResult == SQLITE_DONE) {
454 if (!m_sqliteDB->executeCommand(v3IndexRecordsTableSchema())) {
455 LOG_ERROR("Could not create IndexRecords table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
462 if (sqliteResult != SQLITE_ROW) {
463 LOG_ERROR("Error executing statement to fetch schema for the IndexRecords table.");
467 currentSchema = statement.getColumnText(1);
470 ASSERT(!currentSchema.isEmpty());
472 // If the schema in the backing store is the current schema, we're done.
473 if (currentSchema == v3IndexRecordsTableSchema() || currentSchema == v3IndexRecordsTableSchemaAlternate())
476 // If the record table is not the current schema then it must be one of the previous schemas.
477 // If it is not then the database is in an unrecoverable state and this should be considered a fatal error.
478 if (currentSchema != v1IndexRecordsTableSchema() && currentSchema != v1IndexRecordsTableSchemaAlternate()
479 && currentSchema != v2IndexRecordsTableSchema() && currentSchema != v2IndexRecordsTableSchemaAlternate())
480 RELEASE_ASSERT_NOT_REACHED();
482 SQLiteTransaction transaction(*m_sqliteDB);
485 // Create a temporary table with the correct schema and migrate all existing content over.
486 if (!m_sqliteDB->executeCommand(v3IndexRecordsTableSchema("_Temp_IndexRecords"))) {
487 LOG_ERROR("Could not create temporary index records table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
491 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")) {
492 LOG_ERROR("Could not migrate existing IndexRecords content (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
496 if (!m_sqliteDB->executeCommand("DROP TABLE IndexRecords")) {
497 LOG_ERROR("Could not drop existing IndexRecords table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
501 if (!m_sqliteDB->executeCommand("ALTER TABLE _Temp_IndexRecords RENAME TO IndexRecords")) {
502 LOG_ERROR("Could not rename temporary IndexRecords table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
506 transaction.commit();
511 bool SQLiteIDBBackingStore::ensureValidIndexRecordsIndex()
514 ASSERT(m_sqliteDB->isOpen());
516 String currentSchema;
518 // Fetch the schema for an existing index record index.
519 SQLiteStatement statement(*m_sqliteDB, "SELECT sql FROM sqlite_master WHERE name='IndexRecordsIndex'");
520 if (statement.prepare() != SQLITE_OK) {
521 LOG_ERROR("Unable to prepare statement to fetch schema for the IndexRecordsIndex index.");
525 int sqliteResult = statement.step();
527 // If there is no IndexRecordsIndex index at all, create it and then bail.
528 if (sqliteResult == SQLITE_DONE) {
529 if (!m_sqliteDB->executeCommand(v1IndexRecordsIndexSchema())) {
530 LOG_ERROR("Could not create IndexRecordsIndex index in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
537 if (sqliteResult != SQLITE_ROW) {
538 LOG_ERROR("Error executing statement to fetch schema for the IndexRecordsIndex index.");
542 currentSchema = statement.getColumnText(0);
545 ASSERT(!currentSchema.isEmpty());
547 // If the schema in the backing store is the current schema, we're done.
548 if (currentSchema == v1IndexRecordsIndexSchema())
551 // There is currently no outdated schema for the IndexRecordsIndex, so any other existing schema means this database is invalid.
555 std::unique_ptr<IDBDatabaseInfo> SQLiteIDBBackingStore::createAndPopulateInitialDatabaseInfo()
558 ASSERT(m_sqliteDB->isOpen());
560 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);")) {
561 LOG_ERROR("Could not create IDBDatabaseInfo table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
566 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);")) {
567 LOG_ERROR("Could not create ObjectStoreInfo table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
572 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);")) {
573 LOG_ERROR("Could not create IndexInfo table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
578 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);")) {
579 LOG_ERROR("Could not create KeyGenerators table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
585 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO IDBDatabaseInfo VALUES ('MetadataVersion', ?);"));
586 if (sql.prepare() != SQLITE_OK
587 || sql.bindInt(1, currentMetadataVersion) != SQLITE_OK
588 || sql.step() != SQLITE_DONE) {
589 LOG_ERROR("Could not insert database metadata version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
595 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO IDBDatabaseInfo VALUES ('DatabaseName', ?);"));
596 if (sql.prepare() != SQLITE_OK
597 || sql.bindText(1, m_identifier.databaseName()) != SQLITE_OK
598 || sql.step() != SQLITE_DONE) {
599 LOG_ERROR("Could not insert database name into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
605 // Database versions are defined to be a uin64_t in the spec but sqlite3 doesn't support native binding of unsigned integers.
606 // Therefore we'll store the version as a String.
607 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO IDBDatabaseInfo VALUES ('DatabaseVersion', ?);"));
608 if (sql.prepare() != SQLITE_OK
609 || sql.bindText(1, String::number(0)) != SQLITE_OK
610 || sql.step() != SQLITE_DONE) {
611 LOG_ERROR("Could not insert default version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
617 if (!m_sqliteDB->executeCommand(ASCIILiteral("INSERT INTO IDBDatabaseInfo VALUES ('MaxObjectStoreID', 1);"))) {
618 LOG_ERROR("Could not insert default version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
623 // This initial database info matches the default values we just put into the metadata database.
624 return std::make_unique<IDBDatabaseInfo>(m_identifier.databaseName(), 0);
627 std::unique_ptr<IDBDatabaseInfo> SQLiteIDBBackingStore::extractExistingDatabaseInfo()
631 if (!m_sqliteDB->tableExists(ASCIILiteral("IDBDatabaseInfo")))
636 SQLiteStatement sql(*m_sqliteDB, "SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseName';");
637 if (sql.isColumnNull(0))
639 databaseName = sql.getColumnText(0);
640 if (databaseName != m_identifier.databaseName()) {
641 LOG_ERROR("Database name in the info database ('%s') does not match the expected name ('%s')", databaseName.utf8().data(), m_identifier.databaseName().utf8().data());
645 uint64_t databaseVersion;
647 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseVersion';"));
648 if (sql.isColumnNull(0))
650 String stringVersion = sql.getColumnText(0);
652 databaseVersion = stringVersion.toUInt64Strict(&ok);
654 LOG_ERROR("Database version on disk ('%s') does not cleanly convert to an unsigned 64-bit integer version", stringVersion.utf8().data());
659 auto databaseInfo = std::make_unique<IDBDatabaseInfo>(databaseName, databaseVersion);
662 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT id, name, keyPath, autoInc, maxIndexID FROM ObjectStoreInfo;"));
663 if (sql.prepare() != SQLITE_OK)
666 int result = sql.step();
667 while (result == SQLITE_ROW) {
668 uint64_t objectStoreID = sql.getColumnInt64(0);
669 String objectStoreName = sql.getColumnText(1);
671 Vector<char> keyPathBuffer;
672 sql.getColumnBlobAsVector(2, keyPathBuffer);
674 std::optional<IDBKeyPath> objectStoreKeyPath;
675 if (!deserializeIDBKeyPath(reinterpret_cast<const uint8_t*>(keyPathBuffer.data()), keyPathBuffer.size(), objectStoreKeyPath)) {
676 LOG_ERROR("Unable to extract key path from database");
680 bool autoIncrement = sql.getColumnInt(3);
682 databaseInfo->addExistingObjectStore({ objectStoreID, objectStoreName, WTFMove(objectStoreKeyPath), autoIncrement });
687 if (result != SQLITE_DONE) {
688 LOG_ERROR("Error fetching object store info from database on disk");
694 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT id, name, objectStoreID, keyPath, isUnique, multiEntry FROM IndexInfo;"));
695 if (sql.prepare() != SQLITE_OK)
698 int result = sql.step();
699 while (result == SQLITE_ROW) {
700 uint64_t indexID = sql.getColumnInt64(0);
701 String indexName = sql.getColumnText(1);
702 uint64_t objectStoreID = sql.getColumnInt64(2);
704 Vector<char> keyPathBuffer;
705 sql.getColumnBlobAsVector(3, keyPathBuffer);
707 std::optional<IDBKeyPath> indexKeyPath;
708 if (!deserializeIDBKeyPath(reinterpret_cast<const uint8_t*>(keyPathBuffer.data()), keyPathBuffer.size(), indexKeyPath)) {
709 LOG_ERROR("Unable to extract key path from database");
713 LOG_ERROR("Unable to extract key path from database");
717 bool unique = sql.getColumnInt(4);
718 bool multiEntry = sql.getColumnInt(5);
720 auto objectStore = databaseInfo->infoForExistingObjectStore(objectStoreID);
722 LOG_ERROR("Found index referring to a non-existant object store");
726 objectStore->addExistingIndex({ indexID, objectStoreID, indexName, WTFMove(indexKeyPath.value()), unique, multiEntry });
731 if (result != SQLITE_DONE) {
732 LOG_ERROR("Error fetching index info from database on disk");
740 String SQLiteIDBBackingStore::databaseNameFromEncodedFilename(const String& encodedName)
742 if (equal(encodedName, ASCIILiteral("%00")))
745 String partiallyDecoded = encodedName;
746 partiallyDecoded.replace(ASCIILiteral("%2E"), ASCIILiteral("."));
748 return decodeFromFilename(partiallyDecoded);
751 String SQLiteIDBBackingStore::filenameForDatabaseName() const
753 ASSERT(!m_identifier.databaseName().isNull());
755 if (m_identifier.databaseName().isEmpty())
758 String filename = encodeForFileName(m_identifier.databaseName());
759 filename.replace('.', "%2E");
764 String SQLiteIDBBackingStore::fullDatabaseDirectory() const
766 ASSERT(!m_identifier.databaseName().isNull());
768 return pathByAppendingComponent(m_absoluteDatabaseDirectory, filenameForDatabaseName());
771 String SQLiteIDBBackingStore::fullDatabasePath() const
773 ASSERT(!m_identifier.databaseName().isNull());
775 return pathByAppendingComponent(fullDatabaseDirectory(), "IndexedDB.sqlite3");
778 IDBError SQLiteIDBBackingStore::getOrEstablishDatabaseInfo(IDBDatabaseInfo& info)
780 LOG(IndexedDB, "SQLiteIDBBackingStore::getOrEstablishDatabaseInfo - database %s", m_identifier.databaseName().utf8().data());
782 if (m_databaseInfo) {
783 info = *m_databaseInfo;
787 makeAllDirectories(fullDatabaseDirectory());
788 String dbFilename = fullDatabasePath();
790 m_sqliteDB = std::make_unique<SQLiteDatabase>();
791 if (!m_sqliteDB->open(dbFilename)) {
792 LOG_ERROR("Failed to open SQLite database at path '%s'", dbFilename.utf8().data());
797 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to open database file on disk") };
799 m_sqliteDB->setCollationFunction("IDBKEY", [this](int aLength, const void* a, int bLength, const void* b) {
800 return idbKeyCollate(aLength, a, bLength, b);
803 if (!ensureValidRecordsTable()) {
804 LOG_ERROR("Error creating or migrating Records table in database");
806 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error creating or migrating Records table in database") };
809 if (!ensureValidIndexRecordsTable()) {
810 LOG_ERROR("Error creating or migrating Index Records table in database");
812 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error creating or migrating Index Records table in database") };
815 if (!ensureValidIndexRecordsIndex()) {
816 LOG_ERROR("Error creating or migrating Index Records index in database");
818 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error creating or migrating Index Records index in database") };
821 if (!ensureValidBlobTables()) {
822 LOG_ERROR("Error creating or confirming Blob Records tables in database");
824 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error creating or confirming Blob Records tables in database") };
827 auto databaseInfo = extractExistingDatabaseInfo();
829 databaseInfo = createAndPopulateInitialDatabaseInfo();
832 LOG_ERROR("Unable to establish IDB database at path '%s'", dbFilename.utf8().data());
834 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to establish IDB database file") };
837 m_databaseInfo = WTFMove(databaseInfo);
838 info = *m_databaseInfo;
842 IDBError SQLiteIDBBackingStore::beginTransaction(const IDBTransactionInfo& info)
844 LOG(IndexedDB, "SQLiteIDBBackingStore::beginTransaction - %s", info.identifier().loggingString().utf8().data());
847 ASSERT(m_sqliteDB->isOpen());
848 ASSERT(m_databaseInfo);
850 auto addResult = m_transactions.add(info.identifier(), nullptr);
851 if (!addResult.isNewEntry) {
852 LOG_ERROR("Attempt to establish transaction identifier that already exists");
853 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to establish transaction identifier that already exists") };
856 addResult.iterator->value = std::make_unique<SQLiteIDBTransaction>(*this, info);
858 auto error = addResult.iterator->value->begin(*m_sqliteDB);
859 if (error.isNull() && info.mode() == IDBTransactionMode::Versionchange) {
860 m_originalDatabaseInfoBeforeVersionChange = std::make_unique<IDBDatabaseInfo>(*m_databaseInfo);
862 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("UPDATE IDBDatabaseInfo SET value = ? where key = 'DatabaseVersion';"));
863 if (sql.prepare() != SQLITE_OK
864 || sql.bindText(1, String::number(info.newVersion())) != SQLITE_OK
865 || sql.step() != SQLITE_DONE)
866 error = { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to store new database version in database") };
872 IDBError SQLiteIDBBackingStore::abortTransaction(const IDBResourceIdentifier& identifier)
874 LOG(IndexedDB, "SQLiteIDBBackingStore::abortTransaction - %s", identifier.loggingString().utf8().data());
877 ASSERT(m_sqliteDB->isOpen());
879 auto transaction = m_transactions.take(identifier);
881 LOG_ERROR("Attempt to commit a transaction that hasn't been established");
882 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to abort a transaction that hasn't been established") };
885 if (transaction->mode() == IDBTransactionMode::Versionchange && m_originalDatabaseInfoBeforeVersionChange)
886 m_databaseInfo = WTFMove(m_originalDatabaseInfoBeforeVersionChange);
888 return transaction->abort();
891 IDBError SQLiteIDBBackingStore::commitTransaction(const IDBResourceIdentifier& identifier)
893 LOG(IndexedDB, "SQLiteIDBBackingStore::commitTransaction - %s", identifier.loggingString().utf8().data());
896 ASSERT(m_sqliteDB->isOpen());
898 auto transaction = m_transactions.take(identifier);
900 LOG_ERROR("Attempt to commit a transaction that hasn't been established");
901 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to commit a transaction that hasn't been established") };
904 auto error = transaction->commit();
905 if (!error.isNull()) {
906 if (transaction->mode() == IDBTransactionMode::Versionchange) {
907 ASSERT(m_originalDatabaseInfoBeforeVersionChange);
908 m_databaseInfo = WTFMove(m_originalDatabaseInfoBeforeVersionChange);
911 m_originalDatabaseInfoBeforeVersionChange = nullptr;
916 IDBError SQLiteIDBBackingStore::createObjectStore(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info)
918 LOG(IndexedDB, "SQLiteIDBBackingStore::createObjectStore - adding OS %s with ID %" PRIu64, info.name().utf8().data(), info.identifier());
921 ASSERT(m_sqliteDB->isOpen());
923 auto* transaction = m_transactions.get(transactionIdentifier);
924 if (!transaction || !transaction->inProgress()) {
925 LOG_ERROR("Attempt to create an object store without an in-progress transaction");
926 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to create an object store without an in-progress transaction") };
928 if (transaction->mode() != IDBTransactionMode::Versionchange) {
929 LOG_ERROR("Attempt to create an object store in a non-version-change transaction");
930 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to create an object store in a non-version-change transaction") };
933 RefPtr<SharedBuffer> keyPathBlob = serializeIDBKeyPath(info.keyPath());
935 LOG_ERROR("Unable to serialize IDBKeyPath to save in database for new object store");
936 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize IDBKeyPath to save in database for new object store") };
940 auto* sql = cachedStatement(SQL::CreateObjectStoreInfo, ASCIILiteral("INSERT INTO ObjectStoreInfo VALUES (?, ?, ?, ?, ?);"));
942 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
943 || sql->bindText(2, info.name()) != SQLITE_OK
944 || sql->bindBlob(3, keyPathBlob->data(), keyPathBlob->size()) != SQLITE_OK
945 || sql->bindInt(4, info.autoIncrement()) != SQLITE_OK
946 || sql->bindInt64(5, info.maxIndexID()) != SQLITE_OK
947 || sql->step() != SQLITE_DONE) {
948 LOG_ERROR("Could not add object store '%s' to ObjectStoreInfo table (%i) - %s", info.name().utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
949 return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not create object store") };
954 auto* sql = cachedStatement(SQL::CreateObjectStoreKeyGenerator, ASCIILiteral("INSERT INTO KeyGenerators VALUES (?, 0);"));
956 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
957 || sql->step() != SQLITE_DONE) {
958 LOG_ERROR("Could not seed initial key generator value for ObjectStoreInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
959 return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not seed initial key generator value for object store") };
963 m_databaseInfo->addExistingObjectStore(info);
968 IDBError SQLiteIDBBackingStore::deleteObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
970 LOG(IndexedDB, "SQLiteIDBBackingStore::deleteObjectStore - object store %" PRIu64, objectStoreIdentifier);
973 ASSERT(m_sqliteDB->isOpen());
975 auto* transaction = m_transactions.get(transactionIdentifier);
976 if (!transaction || !transaction->inProgress()) {
977 LOG_ERROR("Attempt to delete an object store without an in-progress transaction");
978 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete an object store without an in-progress transaction") };
980 if (transaction->mode() != IDBTransactionMode::Versionchange) {
981 LOG_ERROR("Attempt to delete an object store in a non-version-change transaction");
982 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete an object store in a non-version-change transaction") };
985 // Delete the ObjectStore record
987 auto* sql = cachedStatement(SQL::DeleteObjectStoreInfo, ASCIILiteral("DELETE FROM ObjectStoreInfo WHERE id = ?;"));
989 || sql->bindInt64(1, objectStoreIdentifier) != SQLITE_OK
990 || sql->step() != SQLITE_DONE) {
991 LOG_ERROR("Could not delete object store id %" PRIi64 " from ObjectStoreInfo table (%i) - %s", objectStoreIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
992 return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not delete object store") };
996 // Delete the ObjectStore's key generator record if there is one.
998 auto* sql = cachedStatement(SQL::DeleteObjectStoreKeyGenerator, ASCIILiteral("DELETE FROM KeyGenerators WHERE objectStoreID = ?;"));
1000 || sql->bindInt64(1, objectStoreIdentifier) != SQLITE_OK
1001 || sql->step() != SQLITE_DONE) {
1002 LOG_ERROR("Could not delete object store from KeyGenerators table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1003 return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not delete key generator for deleted object store") };
1007 // Delete all associated records
1009 auto* sql = cachedStatement(SQL::DeleteObjectStoreRecords, ASCIILiteral("DELETE FROM Records WHERE objectStoreID = ?;"));
1011 || sql->bindInt64(1, objectStoreIdentifier) != SQLITE_OK
1012 || sql->step() != SQLITE_DONE) {
1013 LOG_ERROR("Could not delete records for object store %" PRIi64 " (%i) - %s", objectStoreIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1014 return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not delete records for deleted object store") };
1018 // Delete all associated Indexes
1020 auto* sql = cachedStatement(SQL::DeleteObjectStoreIndexInfo, ASCIILiteral("DELETE FROM IndexInfo WHERE objectStoreID = ?;"));
1022 || sql->bindInt64(1, objectStoreIdentifier) != SQLITE_OK
1023 || sql->step() != SQLITE_DONE) {
1024 LOG_ERROR("Could not delete index from IndexInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1025 return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not delete IDBIndex for deleted object store") };
1029 // Delete all associated Index records
1031 auto* sql = cachedStatement(SQL::DeleteObjectStoreIndexRecords, ASCIILiteral("DELETE FROM IndexRecords WHERE objectStoreID = ?;"));
1033 || sql->bindInt64(1, objectStoreIdentifier) != SQLITE_OK
1034 || sql->step() != SQLITE_DONE) {
1035 LOG_ERROR("Could not delete index records(%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1036 return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not delete IDBIndex records for deleted object store") };
1040 // Delete all unused Blob URL records.
1042 auto* sql = cachedStatement(SQL::DeleteObjectStoreBlobRecords, ASCIILiteral("DELETE FROM BlobRecords WHERE objectStoreRow NOT IN (SELECT recordID FROM Records)"));
1044 || sql->step() != SQLITE_DONE) {
1045 LOG_ERROR("Could not delete Blob URL records(%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1046 return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not delete stored blob records for deleted object store") };
1050 // Delete all unused Blob File records.
1051 auto error = deleteUnusedBlobFileRecords(*transaction);
1052 if (!error.isNull())
1055 m_databaseInfo->deleteObjectStore(objectStoreIdentifier);
1060 IDBError SQLiteIDBBackingStore::renameObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const String& newName)
1062 LOG(IndexedDB, "SQLiteIDBBackingStore::renameObjectStore - object store %" PRIu64, objectStoreIdentifier);
1065 ASSERT(m_sqliteDB->isOpen());
1067 auto* transaction = m_transactions.get(transactionIdentifier);
1068 if (!transaction || !transaction->inProgress()) {
1069 LOG_ERROR("Attempt to rename an object store without an in-progress transaction");
1070 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to rename an object store without an in-progress transaction") };
1072 if (transaction->mode() != IDBTransactionMode::Versionchange) {
1073 LOG_ERROR("Attempt to rename an object store in a non-version-change transaction");
1074 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to rename an object store in a non-version-change transaction") };
1078 auto* sql = cachedStatement(SQL::RenameObjectStore, ASCIILiteral("UPDATE ObjectStoreInfo SET name = ? WHERE id = ?;"));
1080 || sql->bindText(1, newName) != SQLITE_OK
1081 || sql->bindInt64(2, objectStoreIdentifier) != SQLITE_OK
1082 || sql->step() != SQLITE_DONE) {
1083 LOG_ERROR("Could not update name for object store id %" PRIi64 " in ObjectStoreInfo table (%i) - %s", objectStoreIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1084 return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not rename object store") };
1088 m_databaseInfo->renameObjectStore(objectStoreIdentifier, newName);
1093 IDBError SQLiteIDBBackingStore::clearObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID)
1095 LOG(IndexedDB, "SQLiteIDBBackingStore::clearObjectStore - object store %" PRIu64, objectStoreID);
1098 ASSERT(m_sqliteDB->isOpen());
1100 auto* transaction = m_transactions.get(transactionIdentifier);
1101 if (!transaction || !transaction->inProgress()) {
1102 LOG_ERROR("Attempt to clear an object store without an in-progress transaction");
1103 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to clear an object store without an in-progress transaction") };
1105 if (transaction->mode() == IDBTransactionMode::Readonly) {
1106 LOG_ERROR("Attempt to clear an object store in a read-only transaction");
1107 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to clear an object store in a read-only transaction") };
1111 auto* sql = cachedStatement(SQL::ClearObjectStoreRecords, ASCIILiteral("DELETE FROM Records WHERE objectStoreID = ?;"));
1113 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1114 || sql->step() != SQLITE_DONE) {
1115 LOG_ERROR("Could not clear records from object store id %" PRIi64 " (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1116 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to clear object store") };
1121 auto* sql = cachedStatement(SQL::ClearObjectStoreIndexRecords, ASCIILiteral("DELETE FROM IndexRecords WHERE objectStoreID = ?;"));
1123 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1124 || sql->step() != SQLITE_DONE) {
1125 LOG_ERROR("Could not delete records from index record store id %" PRIi64 " (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1126 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to delete index records while clearing object store") };
1130 transaction->notifyCursorsOfChanges(objectStoreID);
1135 IDBError SQLiteIDBBackingStore::createIndex(const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo& info)
1137 LOG(IndexedDB, "SQLiteIDBBackingStore::createIndex - ObjectStore %" PRIu64 ", Index %" PRIu64, info.objectStoreIdentifier(), info.identifier());
1139 ASSERT(m_sqliteDB->isOpen());
1141 auto* transaction = m_transactions.get(transactionIdentifier);
1142 if (!transaction || !transaction->inProgress()) {
1143 LOG_ERROR("Attempt to create an index without an in-progress transaction");
1144 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to create an index without an in-progress transaction") };
1146 if (transaction->mode() != IDBTransactionMode::Versionchange) {
1147 LOG_ERROR("Attempt to create an index in a non-version-change transaction");
1148 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to create an index in a non-version-change transaction") };
1151 RefPtr<SharedBuffer> keyPathBlob = serializeIDBKeyPath(info.keyPath());
1153 LOG_ERROR("Unable to serialize IDBKeyPath to save in database");
1154 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize IDBKeyPath to create index in database") };
1157 auto* sql = cachedStatement(SQL::CreateIndexInfo, ASCIILiteral("INSERT INTO IndexInfo VALUES (?, ?, ?, ?, ?, ?);"));
1159 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
1160 || sql->bindText(2, info.name()) != SQLITE_OK
1161 || sql->bindInt64(3, info.objectStoreIdentifier()) != SQLITE_OK
1162 || sql->bindBlob(4, keyPathBlob->data(), keyPathBlob->size()) != SQLITE_OK
1163 || sql->bindInt(5, info.unique()) != SQLITE_OK
1164 || sql->bindInt(6, info.multiEntry()) != SQLITE_OK
1165 || sql->step() != SQLITE_DONE) {
1166 LOG_ERROR("Could not add index '%s' to IndexInfo table (%i) - %s", info.name().utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1167 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to create index in database") };
1170 // Write index records for any records that already exist in this object store.
1172 auto cursor = transaction->maybeOpenBackingStoreCursor(info.objectStoreIdentifier(), 0, IDBKeyRangeData::allKeys());
1175 LOG_ERROR("Cannot open cursor to populate indexes in database");
1176 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to populate indexes in database") };
1179 while (!cursor->currentKey().isNull()) {
1180 auto& key = cursor->currentKey();
1181 auto* value = cursor->currentValue();
1182 ThreadSafeDataBuffer valueBuffer = value ? value->data() : ThreadSafeDataBuffer();
1184 ASSERT(cursor->currentRecordRowID());
1186 IDBError error = updateOneIndexForAddRecord(info, key, valueBuffer, cursor->currentRecordRowID());
1187 if (!error.isNull()) {
1188 auto* sql = cachedStatement(SQL::DeleteIndexInfo, ASCIILiteral("DELETE FROM IndexInfo WHERE id = ? AND objectStoreID = ?;"));
1190 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
1191 || sql->bindInt64(2, info.objectStoreIdentifier()) != SQLITE_OK
1192 || sql->step() != SQLITE_DONE) {
1193 LOG_ERROR("Index creation failed due to uniqueness constraint failure, but there was an error deleting the Index record from the database");
1194 return { IDBDatabaseException::UnknownError, ASCIILiteral("Index creation failed due to uniqueness constraint failure, but there was an error deleting the Index record from the database") };
1200 if (!cursor->advance(1)) {
1201 LOG_ERROR("Error advancing cursor while indexing existing records for new index.");
1202 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error advancing cursor while indexing existing records for new index") };
1206 auto* objectStore = m_databaseInfo->infoForExistingObjectStore(info.objectStoreIdentifier());
1207 ASSERT(objectStore);
1208 objectStore->addExistingIndex(info);
1213 IDBError SQLiteIDBBackingStore::uncheckedHasIndexRecord(const IDBIndexInfo& info, const IDBKeyData& indexKey, bool& hasRecord)
1217 RefPtr<SharedBuffer> indexKeyBuffer = serializeIDBKeyData(indexKey);
1218 if (!indexKeyBuffer) {
1219 LOG_ERROR("Unable to serialize index key to be stored in the database");
1220 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize IDBKey to check for index record in database") };
1223 auto* sql = cachedStatement(SQL::HasIndexRecord, ASCIILiteral("SELECT rowid FROM IndexRecords WHERE indexID = ? AND objectStoreID = ? AND key = CAST(? AS TEXT);"));
1225 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
1226 || sql->bindInt64(2, info.objectStoreIdentifier()) != SQLITE_OK
1227 || sql->bindBlob(3, indexKeyBuffer->data(), indexKeyBuffer->size()) != SQLITE_OK) {
1228 LOG_ERROR("Error checking for index record in database");
1229 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error checking for index record in database") };
1232 int sqlResult = sql->step();
1233 if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE)
1236 if (sqlResult != SQLITE_ROW) {
1237 // There was an error fetching the record from the database.
1238 LOG_ERROR("Could not check if key exists in index (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1239 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error checking for existence of IDBKey in index") };
1246 IDBError SQLiteIDBBackingStore::uncheckedPutIndexKey(const IDBIndexInfo& info, const IDBKeyData& key, const IndexKey& indexKey, int64_t recordID)
1248 LOG(IndexedDB, "SQLiteIDBBackingStore::uncheckedPutIndexKey - (%" PRIu64 ") %s, %s", info.identifier(), key.loggingString().utf8().data(), indexKey.asOneKey().loggingString().utf8().data());
1250 Vector<IDBKeyData> indexKeys;
1251 if (info.multiEntry())
1252 indexKeys = indexKey.multiEntry();
1254 indexKeys.append(indexKey.asOneKey());
1256 if (info.unique()) {
1259 for (auto& indexKey : indexKeys) {
1260 if (!indexKey.isValid())
1262 error = uncheckedHasIndexRecord(info, indexKey, hasRecord);
1263 if (!error.isNull())
1266 return IDBError(IDBDatabaseException::ConstraintError);
1270 for (auto& indexKey : indexKeys) {
1271 if (!indexKey.isValid())
1273 auto error = uncheckedPutIndexRecord(info.objectStoreIdentifier(), info.identifier(), key, indexKey, recordID);
1274 if (!error.isNull()) {
1275 LOG_ERROR("Unable to put index record for newly created index");
1283 IDBError SQLiteIDBBackingStore::uncheckedPutIndexRecord(int64_t objectStoreID, int64_t indexID, const WebCore::IDBKeyData& keyValue, const WebCore::IDBKeyData& indexKey, int64_t recordID)
1285 LOG(IndexedDB, "SQLiteIDBBackingStore::uncheckedPutIndexRecord - %s, %s", keyValue.loggingString().utf8().data(), indexKey.loggingString().utf8().data());
1287 RefPtr<SharedBuffer> indexKeyBuffer = serializeIDBKeyData(indexKey);
1288 if (!indexKeyBuffer) {
1289 LOG_ERROR("Unable to serialize index key to be stored in the database");
1290 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize index key to be stored in the database") };
1293 RefPtr<SharedBuffer> valueBuffer = serializeIDBKeyData(keyValue);
1295 LOG_ERROR("Unable to serialize the value to be stored in the database");
1296 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize value to be stored in the database") };
1300 auto* sql = cachedStatement(SQL::PutIndexRecord, ASCIILiteral("INSERT INTO IndexRecords VALUES (?, ?, CAST(? AS TEXT), CAST(? AS TEXT), ?);"));
1302 || sql->bindInt64(1, indexID) != SQLITE_OK
1303 || sql->bindInt64(2, objectStoreID) != SQLITE_OK
1304 || sql->bindBlob(3, indexKeyBuffer->data(), indexKeyBuffer->size()) != SQLITE_OK
1305 || sql->bindBlob(4, valueBuffer->data(), valueBuffer->size()) != SQLITE_OK
1306 || sql->bindInt64(5, recordID) != SQLITE_OK
1307 || sql->step() != SQLITE_DONE) {
1308 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());
1309 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error putting index record into database") };
1317 IDBError SQLiteIDBBackingStore::deleteIndex(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier)
1319 LOG(IndexedDB, "SQLiteIDBBackingStore::deleteIndex - object store %" PRIu64, objectStoreIdentifier);
1322 ASSERT(m_sqliteDB->isOpen());
1324 auto* transaction = m_transactions.get(transactionIdentifier);
1325 if (!transaction || !transaction->inProgress()) {
1326 LOG_ERROR("Attempt to delete index without an in-progress transaction");
1327 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete index without an in-progress transaction") };
1330 if (transaction->mode() != IDBTransactionMode::Versionchange) {
1331 LOG_ERROR("Attempt to delete index during a non-version-change transaction");
1332 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete index during a non-version-change transaction") };
1336 auto* sql = cachedStatement(SQL::DeleteIndexInfo, ASCIILiteral("DELETE FROM IndexInfo WHERE id = ? AND objectStoreID = ?;"));
1338 || sql->bindInt64(1, indexIdentifier) != SQLITE_OK
1339 || sql->bindInt64(2, objectStoreIdentifier) != SQLITE_OK
1340 || sql->step() != SQLITE_DONE) {
1341 LOG_ERROR("Could not delete index id %" PRIi64 " from IndexInfo table (%i) - %s", objectStoreIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1342 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error deleting index from database") };
1347 auto* sql = cachedStatement(SQL::DeleteIndexRecords, ASCIILiteral("DELETE FROM IndexRecords WHERE indexID = ? AND objectStoreID = ?;"));
1349 || sql->bindInt64(1, indexIdentifier) != SQLITE_OK
1350 || sql->bindInt64(2, objectStoreIdentifier) != SQLITE_OK
1351 || sql->step() != SQLITE_DONE) {
1352 LOG_ERROR("Could not delete index records for index id %" PRIi64 " from IndexRecords table (%i) - %s", indexIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1353 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error deleting index records from database") };
1357 auto* objectStore = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
1358 ASSERT(objectStore);
1359 objectStore->deleteIndex(indexIdentifier);
1364 IDBError SQLiteIDBBackingStore::renameIndex(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
1366 LOG(IndexedDB, "SQLiteIDBBackingStore::renameIndex - object store %" PRIu64 ", index %" PRIu64, objectStoreIdentifier, indexIdentifier);
1369 ASSERT(m_sqliteDB->isOpen());
1371 auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
1372 if (!objectStoreInfo)
1373 return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not rename index") };
1375 auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexIdentifier);
1377 return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not rename index") };
1379 auto* transaction = m_transactions.get(transactionIdentifier);
1380 if (!transaction || !transaction->inProgress()) {
1381 LOG_ERROR("Attempt to rename an index without an in-progress transaction");
1382 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to rename an index without an in-progress transaction") };
1385 if (transaction->mode() != IDBTransactionMode::Versionchange) {
1386 LOG_ERROR("Attempt to rename an index in a non-version-change transaction");
1387 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to rename an index in a non-version-change transaction") };
1391 auto* sql = cachedStatement(SQL::RenameIndex, ASCIILiteral("UPDATE IndexInfo SET name = ? WHERE objectStoreID = ? AND id = ?;"));
1393 || sql->bindText(1, newName) != SQLITE_OK
1394 || sql->bindInt64(2, objectStoreIdentifier) != SQLITE_OK
1395 || sql->bindInt64(3, indexIdentifier) != SQLITE_OK
1396 || sql->step() != SQLITE_DONE) {
1397 LOG_ERROR("Could not update name for index id (%" PRIi64 ", %" PRIi64 ") in IndexInfo table (%i) - %s", objectStoreIdentifier, indexIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1398 return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not rename index") };
1402 indexInfo->rename(newName);
1407 IDBError SQLiteIDBBackingStore::keyExistsInObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyData& keyData, bool& keyExists)
1409 LOG(IndexedDB, "SQLiteIDBBackingStore::keyExistsInObjectStore - key %s, object store %" PRIu64, keyData.loggingString().utf8().data(), objectStoreID);
1412 ASSERT(m_sqliteDB->isOpen());
1416 auto* transaction = m_transactions.get(transactionIdentifier);
1417 if (!transaction || !transaction->inProgress()) {
1418 LOG_ERROR("Attempt to see if key exists in objectstore without an in-progress transaction");
1419 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to see if key exists in objectstore without an in-progress transaction") };
1422 RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(keyData);
1424 LOG_ERROR("Unable to serialize IDBKey to check for existence in object store");
1425 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize IDBKey to check for existence in object store") };
1427 auto* sql = cachedStatement(SQL::KeyExistsInObjectStore, ASCIILiteral("SELECT key FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT) LIMIT 1;"));
1429 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1430 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK) {
1431 LOG_ERROR("Could not get record from object store %" PRIi64 " from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1432 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to check for existence of IDBKey in object store") };
1435 int sqlResult = sql->step();
1436 if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE)
1439 if (sqlResult != SQLITE_ROW) {
1440 // There was an error fetching the record from the database.
1441 LOG_ERROR("Could not check if key exists in object store (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1442 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error checking for existence of IDBKey in object store") };
1449 IDBError SQLiteIDBBackingStore::deleteUnusedBlobFileRecords(SQLiteIDBTransaction& transaction)
1451 LOG(IndexedDB, "SQLiteIDBBackingStore::deleteUnusedBlobFileRecords");
1453 // Gather the set of blob URLs and filenames that are no longer in use.
1454 HashSet<String> removedBlobFilenames;
1456 auto* sql = cachedStatement(SQL::GetUnusedBlobFilenames, ASCIILiteral("SELECT fileName FROM BlobFiles WHERE blobURL NOT IN (SELECT blobURL FROM BlobRecords)"));
1459 LOG_ERROR("Error deleting stored blobs (%i) (Could not gather unused blobURLs) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1460 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error deleting stored blobs") };
1463 int result = sql->step();
1464 while (result == SQLITE_ROW) {
1465 removedBlobFilenames.add(sql->getColumnText(0));
1466 result = sql->step();
1469 if (result != SQLITE_DONE) {
1470 LOG_ERROR("Error deleting stored blobs (%i) (Could not gather unused blobURLs) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1471 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error deleting stored blobs") };
1475 // Remove the blob records that are no longer in use.
1476 if (!removedBlobFilenames.isEmpty()) {
1477 auto* sql = cachedStatement(SQL::DeleteUnusedBlobs, ASCIILiteral("DELETE FROM BlobFiles WHERE blobURL NOT IN (SELECT blobURL FROM BlobRecords)"));
1480 || sql->step() != SQLITE_DONE) {
1481 LOG_ERROR("Error deleting stored blobs (%i) (Could not delete blobFile records) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1482 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error deleting stored blobs") };
1486 for (auto& file : removedBlobFilenames)
1487 transaction.addRemovedBlobFile(file);
1492 IDBError SQLiteIDBBackingStore::deleteRecord(SQLiteIDBTransaction& transaction, int64_t objectStoreID, const IDBKeyData& keyData)
1494 LOG(IndexedDB, "SQLiteIDBBackingStore::deleteRecord - key %s, object store %" PRIu64, keyData.loggingString().utf8().data(), objectStoreID);
1497 ASSERT(m_sqliteDB->isOpen());
1498 ASSERT(transaction.inProgress());
1499 ASSERT(transaction.mode() != IDBTransactionMode::Readonly);
1500 UNUSED_PARAM(transaction);
1502 RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(keyData);
1504 LOG_ERROR("Unable to serialize IDBKeyData to be removed from the database");
1505 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize IDBKeyData to be removed from the database") };
1508 // Get the record ID
1511 auto* sql = cachedStatement(SQL::GetObjectStoreRecordID, ASCIILiteral("SELECT recordID FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT);"));
1514 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1515 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK) {
1516 LOG_ERROR("Could not delete record from object store %" PRIi64 " (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1517 return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to delete record from object store") };
1520 int result = sql->step();
1522 // If there's no record ID, there's no record to delete.
1523 if (result == SQLITE_DONE)
1526 if (result != SQLITE_ROW) {
1527 LOG_ERROR("Could not delete record from object store %" PRIi64 " (%i) (unable to fetch record ID) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1528 return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to delete record from object store") };
1531 recordID = sql->getColumnInt64(0);
1535 LOG_ERROR("Could not delete record from object store %" PRIi64 " (%i) (record ID is invalid) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1536 return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to delete record from object store") };
1539 // Delete the blob records for this object store record.
1541 auto* sql = cachedStatement(SQL::DeleteBlobRecord, ASCIILiteral("DELETE FROM BlobRecords WHERE objectStoreRow = ?;"));
1544 || sql->bindInt64(1, recordID) != SQLITE_OK
1545 || sql->step() != SQLITE_DONE) {
1546 LOG_ERROR("Could not delete record from object store %" PRIi64 " (%i) (Could not delete BlobRecords records) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1547 return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to delete record from object store") };
1551 auto error = deleteUnusedBlobFileRecords(transaction);
1552 if (!error.isNull())
1555 // Delete record from object store
1557 auto* sql = cachedStatement(SQL::DeleteObjectStoreRecord, ASCIILiteral("DELETE FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT);"));
1560 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1561 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
1562 || sql->step() != SQLITE_DONE) {
1563 LOG_ERROR("Could not delete record from object store %" PRIi64 " (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1564 return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to delete record from object store") };
1568 // Delete record from indexes store
1570 auto* sql = cachedStatement(SQL::DeleteObjectStoreIndexRecord, ASCIILiteral("DELETE FROM IndexRecords WHERE objectStoreID = ? AND value = CAST(? AS TEXT);"));
1573 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1574 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
1575 || sql->step() != SQLITE_DONE) {
1576 LOG_ERROR("Could not delete record from indexes for object store %" PRIi64 " (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1577 return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to delete index entries for object store record") };
1584 IDBError SQLiteIDBBackingStore::deleteRange(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyRangeData& keyRange)
1586 LOG(IndexedDB, "SQLiteIDBBackingStore::deleteRange - range %s, object store %" PRIu64, keyRange.loggingString().utf8().data(), objectStoreID);
1589 ASSERT(m_sqliteDB->isOpen());
1591 auto* transaction = m_transactions.get(transactionIdentifier);
1592 if (!transaction || !transaction->inProgress()) {
1593 LOG_ERROR("Attempt to delete range from database without an in-progress transaction");
1594 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete range from database without an in-progress transaction") };
1596 if (transaction->mode() == IDBTransactionMode::Readonly) {
1597 LOG_ERROR("Attempt to delete records from an object store in a read-only transaction");
1598 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete records from an object store in a read-only transaction") };
1601 // If the range to delete is exactly one key we can delete it right now.
1602 if (keyRange.isExactlyOneKey()) {
1603 auto error = deleteRecord(*transaction, objectStoreID, keyRange.lowerKey);
1604 if (!error.isNull()) {
1605 LOG_ERROR("Failed to delete record for key '%s'", keyRange.lowerKey.loggingString().utf8().data());
1612 auto cursor = transaction->maybeOpenBackingStoreCursor(objectStoreID, 0, keyRange);
1614 LOG_ERROR("Cannot open cursor to delete range of records from the database");
1615 return { IDBDatabaseException::UnknownError, ASCIILiteral("Cannot open cursor to delete range of records from the database") };
1618 Vector<IDBKeyData> keys;
1619 while (!cursor->didComplete() && !cursor->didError()) {
1620 keys.append(cursor->currentKey());
1624 if (cursor->didError()) {
1625 LOG_ERROR("Cursor failed while accumulating range of records from the database");
1626 return { IDBDatabaseException::UnknownError, ASCIILiteral("Cursor failed while accumulating range of records from the database") };
1630 for (auto& key : keys) {
1631 error = deleteRecord(*transaction, objectStoreID, key);
1632 if (!error.isNull()) {
1633 LOG_ERROR("deleteRange: Error deleting keys in range");
1638 transaction->notifyCursorsOfChanges(objectStoreID);
1643 IDBError SQLiteIDBBackingStore::updateOneIndexForAddRecord(const IDBIndexInfo& info, const IDBKeyData& key, const ThreadSafeDataBuffer& value, int64_t recordID)
1645 JSLockHolder locker(vm());
1647 auto jsValue = deserializeIDBValueToJSValue(*globalObject().globalExec(), value);
1648 if (jsValue.isUndefinedOrNull())
1652 generateIndexKeyForValue(*m_globalObject->globalExec(), info, jsValue, indexKey);
1654 if (indexKey.isNull())
1657 return uncheckedPutIndexKey(info, key, indexKey, recordID);
1660 IDBError SQLiteIDBBackingStore::updateAllIndexesForAddRecord(const IDBObjectStoreInfo& info, const IDBKeyData& key, const ThreadSafeDataBuffer& value, int64_t recordID)
1662 JSLockHolder locker(vm());
1664 auto jsValue = deserializeIDBValueToJSValue(*globalObject().globalExec(), value);
1665 if (jsValue.isUndefinedOrNull())
1669 bool anyRecordsSucceeded = false;
1670 for (auto& index : info.indexMap().values()) {
1672 generateIndexKeyForValue(*m_globalObject->globalExec(), index, jsValue, indexKey);
1674 if (indexKey.isNull())
1677 error = uncheckedPutIndexKey(index, key, indexKey, recordID);
1678 if (!error.isNull())
1681 anyRecordsSucceeded = true;
1684 if (!error.isNull() && anyRecordsSucceeded) {
1685 RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(key);
1687 auto* sql = cachedStatement(SQL::DeleteObjectStoreIndexRecord, ASCIILiteral("DELETE FROM IndexRecords WHERE objectStoreID = ? AND value = CAST(? AS TEXT);"));
1690 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
1691 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
1692 || sql->step() != SQLITE_DONE) {
1693 LOG_ERROR("Adding one Index record failed, but failed to remove all others that previously succeeded");
1694 return { IDBDatabaseException::UnknownError, ASCIILiteral("Adding one Index record failed, but failed to remove all others that previously succeeded") };
1701 IDBError SQLiteIDBBackingStore::addRecord(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& objectStoreInfo, const IDBKeyData& keyData, const IDBValue& value)
1703 LOG(IndexedDB, "SQLiteIDBBackingStore::addRecord - key %s, object store %" PRIu64, keyData.loggingString().utf8().data(), objectStoreInfo.identifier());
1706 ASSERT(m_sqliteDB->isOpen());
1707 ASSERT(value.data().data());
1708 ASSERT(value.blobURLs().size() == value.blobFilePaths().size());
1710 auto* transaction = m_transactions.get(transactionIdentifier);
1711 if (!transaction || !transaction->inProgress()) {
1712 LOG_ERROR("Attempt to store a record in an object store without an in-progress transaction");
1713 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to store a record in an object store without an in-progress transaction") };
1715 if (transaction->mode() == IDBTransactionMode::Readonly) {
1716 LOG_ERROR("Attempt to store a record in an object store in a read-only transaction");
1717 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to store a record in an object store in a read-only transaction") };
1720 RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(keyData);
1722 LOG_ERROR("Unable to serialize IDBKey to be stored in an object store");
1723 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize IDBKey to be stored in an object store") };
1726 int64_t recordID = 0;
1728 auto* sql = cachedStatement(SQL::AddObjectStoreRecord, ASCIILiteral("INSERT INTO Records VALUES (?, CAST(? AS TEXT), ?, NULL);"));
1730 || sql->bindInt64(1, objectStoreInfo.identifier()) != SQLITE_OK
1731 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
1732 || sql->bindBlob(3, value.data().data()->data(), value.data().data()->size()) != SQLITE_OK
1733 || sql->step() != SQLITE_DONE) {
1734 LOG_ERROR("Could not put record for object store %" PRIi64 " in Records table (%i) - %s", objectStoreInfo.identifier(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1735 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to store record in object store") };
1738 recordID = m_sqliteDB->lastInsertRowID();
1741 auto error = updateAllIndexesForAddRecord(objectStoreInfo, keyData, value.data(), recordID);
1743 if (!error.isNull()) {
1744 auto* sql = cachedStatement(SQL::DeleteObjectStoreRecord, ASCIILiteral("DELETE FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT);"));
1746 || sql->bindInt64(1, objectStoreInfo.identifier()) != SQLITE_OK
1747 || sql->bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
1748 || sql->step() != SQLITE_DONE) {
1749 LOG_ERROR("Indexing new object store record failed, but unable to remove the object store record itself");
1750 return { IDBDatabaseException::UnknownError, ASCIILiteral("Indexing new object store record failed, but unable to remove the object store record itself") };
1756 const Vector<String>& blobURLs = value.blobURLs();
1757 const Vector<String>& blobFiles = value.blobFilePaths();
1758 for (size_t i = 0; i < blobURLs.size(); ++i) {
1759 auto& url = blobURLs[i];
1761 auto* sql = cachedStatement(SQL::AddBlobRecord, ASCIILiteral("INSERT INTO BlobRecords VALUES (?, ?);"));
1763 || sql->bindInt64(1, recordID) != SQLITE_OK
1764 || sql->bindText(2, url) != SQLITE_OK
1765 || sql->step() != SQLITE_DONE) {
1766 LOG_ERROR("Unable to record Blob record in database");
1767 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to record Blob record in database") };
1770 int64_t potentialFileNameInteger = m_sqliteDB->lastInsertRowID();
1772 // If we already have a file for this blobURL, nothing left to do.
1774 auto* sql = cachedStatement(SQL::BlobFilenameForBlobURL, ASCIILiteral("SELECT fileName FROM BlobFiles WHERE blobURL = ?;"));
1776 || sql->bindText(1, url) != SQLITE_OK) {
1777 LOG_ERROR("Unable to examine Blob filenames in database");
1778 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to examine Blob filenames in database") };
1781 int result = sql->step();
1782 if (result != SQLITE_ROW && result != SQLITE_DONE) {
1783 LOG_ERROR("Unable to examine Blob filenames in database");
1784 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to examine Blob filenames in database") };
1787 if (result == SQLITE_ROW)
1791 // We don't already have a file for this blobURL, so commit our file as a unique filename
1792 String storedFilename = String::format("%" PRId64 ".blob", potentialFileNameInteger);
1794 auto* sql = cachedStatement(SQL::AddBlobFilename, ASCIILiteral("INSERT INTO BlobFiles VALUES (?, ?);"));
1796 || sql->bindText(1, url) != SQLITE_OK
1797 || sql->bindText(2, storedFilename) != SQLITE_OK
1798 || sql->step() != SQLITE_DONE) {
1799 LOG_ERROR("Unable to record Blob file record in database");
1800 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to record Blob file record in database") };
1804 transaction->addBlobFile(blobFiles[i], storedFilename);
1807 transaction->notifyCursorsOfChanges(objectStoreInfo.identifier());
1812 IDBError SQLiteIDBBackingStore::getBlobRecordsForObjectStoreRecord(int64_t objectStoreRecord, Vector<String>& blobURLs, Vector<String>& blobFilePaths)
1814 ASSERT(objectStoreRecord);
1816 HashSet<String> blobURLSet;
1818 auto* sql = cachedStatement(SQL::GetBlobURL, ASCIILiteral("SELECT blobURL FROM BlobRecords WHERE objectStoreRow = ?"));
1820 || sql->bindInt64(1, objectStoreRecord) != SQLITE_OK) {
1821 LOG_ERROR("Could not prepare statement to fetch blob URLs for object store record (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1822 return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to look up blobURL records in object store by key range") };
1825 int sqlResult = sql->step();
1826 if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE) {
1827 // There are no blobURLs in the database for this object store record.
1831 while (sqlResult == SQLITE_ROW) {
1832 blobURLSet.add(sql->getColumnText(0));
1833 sqlResult = sql->step();
1836 if (sqlResult != SQLITE_DONE) {
1837 LOG_ERROR("Could not fetch blob URLs for object store record (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1838 return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to look up blobURL records in object store by key range") };
1842 ASSERT(!blobURLSet.isEmpty());
1843 String databaseDirectory = fullDatabaseDirectory();
1844 for (auto& blobURL : blobURLSet) {
1845 auto* sql = cachedStatement(SQL::BlobFilenameForBlobURL, ASCIILiteral("SELECT fileName FROM BlobFiles WHERE blobURL = ?;"));
1847 || sql->bindText(1, blobURL) != SQLITE_OK) {
1848 LOG_ERROR("Could not prepare statement to fetch blob filename for object store record (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1849 return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to look up blobURL records in object store by key range") };
1852 if (sql->step() != SQLITE_ROW) {
1853 LOG_ERROR("Entry for blob filename for blob url %s does not exist (%i) - %s", blobURL.utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1854 return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to look up blobURL records in object store by key range") };
1857 blobURLs.append(blobURL);
1859 String fileName = sql->getColumnText(0);
1860 blobFilePaths.append(pathByAppendingComponent(databaseDirectory, fileName));
1866 IDBError SQLiteIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyRangeData& keyRange, IDBGetRecordDataType type, IDBGetResult& resultValue)
1868 LOG(IndexedDB, "SQLiteIDBBackingStore::getRecord - key range %s, object store %" PRIu64, keyRange.loggingString().utf8().data(), objectStoreID);
1871 ASSERT(m_sqliteDB->isOpen());
1873 auto* transaction = m_transactions.get(transactionIdentifier);
1874 if (!transaction || !transaction->inProgress()) {
1875 LOG_ERROR("Attempt to get a record from database without an in-progress transaction");
1876 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to get a record from database without an in-progress transaction") };
1879 auto key = keyRange.lowerKey;
1881 key = IDBKeyData::minimum();
1882 RefPtr<SharedBuffer> lowerBuffer = serializeIDBKeyData(key);
1884 LOG_ERROR("Unable to serialize lower IDBKey in lookup range");
1885 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize lower IDBKey in lookup range") };
1888 key = keyRange.upperKey;
1890 key = IDBKeyData::maximum();
1891 RefPtr<SharedBuffer> upperBuffer = serializeIDBKeyData(key);
1893 LOG_ERROR("Unable to serialize upper IDBKey in lookup range");
1894 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize upper IDBKey in lookup range") };
1897 int64_t recordID = 0;
1898 ThreadSafeDataBuffer resultBuffer;
1900 static NeverDestroyed<ASCIILiteral> lowerOpenUpperOpen("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
1901 static NeverDestroyed<ASCIILiteral> lowerOpenUpperClosed("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
1902 static NeverDestroyed<ASCIILiteral> lowerClosedUpperOpen("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
1903 static NeverDestroyed<ASCIILiteral> lowerClosedUpperClosed("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
1905 static NeverDestroyed<ASCIILiteral> lowerOpenUpperOpenKeyOnly("SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
1906 static NeverDestroyed<ASCIILiteral> lowerOpenUpperClosedKeyOnly("SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
1907 static NeverDestroyed<ASCIILiteral> lowerClosedUpperOpenKeyOnly("SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
1908 static NeverDestroyed<ASCIILiteral> lowerClosedUpperClosedKeyOnly("SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
1910 SQLiteStatement* sql = nullptr;
1913 case IDBGetRecordDataType::KeyAndValue:
1914 if (keyRange.lowerOpen) {
1915 if (keyRange.upperOpen)
1916 sql = cachedStatement(SQL::GetValueRecordsLowerOpenUpperOpen, lowerOpenUpperOpen.get());
1918 sql = cachedStatement(SQL::GetValueRecordsLowerOpenUpperClosed, lowerOpenUpperClosed.get());
1920 if (keyRange.upperOpen)
1921 sql = cachedStatement(SQL::GetValueRecordsLowerClosedUpperOpen, lowerClosedUpperOpen.get());
1923 sql = cachedStatement(SQL::GetValueRecordsLowerClosedUpperClosed, lowerClosedUpperClosed.get());
1926 case IDBGetRecordDataType::KeyOnly:
1927 if (keyRange.lowerOpen) {
1928 if (keyRange.upperOpen)
1929 sql = cachedStatement(SQL::GetKeyRecordsLowerOpenUpperOpen, lowerOpenUpperOpenKeyOnly.get());
1931 sql = cachedStatement(SQL::GetKeyRecordsLowerOpenUpperClosed, lowerOpenUpperClosedKeyOnly.get());
1933 if (keyRange.upperOpen)
1934 sql = cachedStatement(SQL::GetKeyRecordsLowerClosedUpperOpen, lowerClosedUpperOpenKeyOnly.get());
1936 sql = cachedStatement(SQL::GetKeyRecordsLowerClosedUpperClosed, lowerClosedUpperClosedKeyOnly.get());
1941 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
1942 || sql->bindBlob(2, lowerBuffer->data(), lowerBuffer->size()) != SQLITE_OK
1943 || sql->bindBlob(3, upperBuffer->data(), upperBuffer->size()) != SQLITE_OK) {
1944 LOG_ERROR("Could not get key range record from object store %" PRIi64 " from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1945 return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to look up record in object store by key range") };
1948 int sqlResult = sql->step();
1950 if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE) {
1951 // There was no record for the key in the database.
1954 if (sqlResult != SQLITE_ROW) {
1955 // There was an error fetching the record from the database.
1956 LOG_ERROR("Could not get record from object store %" PRIi64 " from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
1957 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error looking up record in object store by key range") };
1960 Vector<uint8_t> buffer;
1961 sql->getColumnBlobAsVector(0, buffer);
1962 resultBuffer = ThreadSafeDataBuffer::adoptVector(buffer);
1964 if (type == IDBGetRecordDataType::KeyAndValue)
1965 recordID = sql->getColumnInt64(1);
1968 if (type == IDBGetRecordDataType::KeyOnly) {
1969 auto* vector = resultBuffer.data();
1971 LOG_ERROR("Unable to deserialize key data from database for IDBObjectStore.getKey()");
1972 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error extracting key data from database executing IDBObjectStore.getKey()") };
1976 if (!deserializeIDBKeyData(vector->data(), vector->size(), keyData)) {
1977 LOG_ERROR("Unable to deserialize key data from database for IDBObjectStore.getKey()");
1978 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error extracting key data from database executing IDBObjectStore.getKey()") };
1981 resultValue = { keyData };
1986 Vector<String> blobURLs, blobFilePaths;
1987 auto error = getBlobRecordsForObjectStoreRecord(recordID, blobURLs, blobFilePaths);
1988 ASSERT(blobURLs.size() == blobFilePaths.size());
1990 if (!error.isNull())
1993 resultValue = { { resultBuffer, WTFMove(blobURLs), WTFMove(blobFilePaths) } };
1997 IDBError SQLiteIDBBackingStore::getAllRecords(const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData& getAllRecordsData, IDBGetAllResult& result)
1999 return getAllRecordsData.indexIdentifier ? getAllIndexRecords(transactionIdentifier, getAllRecordsData, result) : getAllObjectStoreRecords(transactionIdentifier, getAllRecordsData, result);
2002 SQLiteStatement* SQLiteIDBBackingStore::cachedStatementForGetAllObjectStoreRecords(const IDBGetAllRecordsData& getAllRecordsData)
2004 static NeverDestroyed<ASCIILiteral> lowerOpenUpperOpenKey("SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
2005 static NeverDestroyed<ASCIILiteral> lowerOpenUpperClosedKey("SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
2006 static NeverDestroyed<ASCIILiteral> lowerClosedUpperOpenKey("SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
2007 static NeverDestroyed<ASCIILiteral> lowerClosedUpperClosedKey("SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
2008 static NeverDestroyed<ASCIILiteral> lowerOpenUpperOpenValue("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
2009 static NeverDestroyed<ASCIILiteral> lowerOpenUpperClosedValue("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
2010 static NeverDestroyed<ASCIILiteral> lowerClosedUpperOpenValue("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
2011 static NeverDestroyed<ASCIILiteral> lowerClosedUpperClosedValue("SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
2013 if (getAllRecordsData.getAllType == IndexedDB::GetAllType::Keys) {
2014 if (getAllRecordsData.keyRangeData.lowerOpen) {
2015 if (getAllRecordsData.keyRangeData.upperOpen)
2016 return cachedStatement(SQL::GetAllKeyRecordsLowerOpenUpperOpen, lowerOpenUpperOpenKey.get());
2017 return cachedStatement(SQL::GetAllKeyRecordsLowerOpenUpperClosed, lowerOpenUpperClosedKey.get());
2020 if (getAllRecordsData.keyRangeData.upperOpen)
2021 return cachedStatement(SQL::GetAllKeyRecordsLowerClosedUpperOpen, lowerClosedUpperOpenKey.get());
2022 return cachedStatement(SQL::GetAllKeyRecordsLowerClosedUpperClosed, lowerClosedUpperClosedKey.get());
2025 if (getAllRecordsData.keyRangeData.lowerOpen) {
2026 if (getAllRecordsData.keyRangeData.upperOpen)
2027 return cachedStatement(SQL::GetValueRecordsLowerOpenUpperOpen, lowerOpenUpperOpenValue.get());
2028 return cachedStatement(SQL::GetValueRecordsLowerOpenUpperClosed, lowerOpenUpperClosedValue.get());
2031 if (getAllRecordsData.keyRangeData.upperOpen)
2032 return cachedStatement(SQL::GetValueRecordsLowerClosedUpperOpen, lowerClosedUpperOpenValue.get());
2033 return cachedStatement(SQL::GetValueRecordsLowerClosedUpperClosed, lowerClosedUpperClosedValue.get());
2036 IDBError SQLiteIDBBackingStore::getAllObjectStoreRecords(const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData& getAllRecordsData, IDBGetAllResult& result)
2038 LOG(IndexedDB, "SQLiteIDBBackingStore::getAllObjectStoreRecords");
2041 ASSERT(m_sqliteDB->isOpen());
2043 auto* transaction = m_transactions.get(transactionIdentifier);
2044 if (!transaction || !transaction->inProgress()) {
2045 LOG_ERROR("Attempt to get records from database without an in-progress transaction");
2046 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to get records from database without an in-progress transaction") };
2049 auto key = getAllRecordsData.keyRangeData.lowerKey;
2051 key = IDBKeyData::minimum();
2052 auto lowerBuffer = serializeIDBKeyData(key);
2054 LOG_ERROR("Unable to serialize lower IDBKey in lookup range");
2055 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize lower IDBKey in lookup range") };
2058 key = getAllRecordsData.keyRangeData.upperKey;
2060 key = IDBKeyData::maximum();
2061 auto upperBuffer = serializeIDBKeyData(key);
2063 LOG_ERROR("Unable to serialize upper IDBKey in lookup range");
2064 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize upper IDBKey in lookup range") };
2067 auto* sql = cachedStatementForGetAllObjectStoreRecords(getAllRecordsData);
2069 || sql->bindInt64(1, getAllRecordsData.objectStoreIdentifier) != SQLITE_OK
2070 || sql->bindBlob(2, lowerBuffer->data(), lowerBuffer->size()) != SQLITE_OK
2071 || sql->bindBlob(3, upperBuffer->data(), upperBuffer->size()) != SQLITE_OK) {
2072 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());
2073 return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to look up record in object store by key range") };
2076 result = { getAllRecordsData.getAllType };
2078 uint32_t targetResults;
2079 if (getAllRecordsData.count && getAllRecordsData.count.value())
2080 targetResults = getAllRecordsData.count.value();
2082 targetResults = std::numeric_limits<uint32_t>::max();
2084 int sqlResult = sql->step();
2085 uint32_t returnedResults = 0;
2087 while (sqlResult == SQLITE_ROW && returnedResults < targetResults) {
2088 if (getAllRecordsData.getAllType == IndexedDB::GetAllType::Values) {
2089 Vector<uint8_t> buffer;
2090 sql->getColumnBlobAsVector(0, buffer);
2091 ThreadSafeDataBuffer resultBuffer = ThreadSafeDataBuffer::adoptVector(buffer);
2093 auto recordID = sql->getColumnInt64(1);
2096 Vector<String> blobURLs, blobFilePaths;
2097 auto error = getBlobRecordsForObjectStoreRecord(recordID, blobURLs, blobFilePaths);
2098 ASSERT(blobURLs.size() == blobFilePaths.size());
2100 if (!error.isNull())
2103 result.addValue({ resultBuffer, WTFMove(blobURLs), WTFMove(blobFilePaths) });
2105 Vector<uint8_t> keyData;
2107 sql->getColumnBlobAsVector(0, keyData);
2109 if (!deserializeIDBKeyData(keyData.data(), keyData.size(), key)) {
2110 LOG_ERROR("Unable to deserialize key data from database while getting all key records");
2111 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to deserialize key data while getting all key records") };
2114 result.addKey(WTFMove(key));
2118 sqlResult = sql->step();
2121 if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE || sqlResult == SQLITE_ROW) {
2122 // Finished getting results
2126 // There was an error fetching records from the database.
2127 LOG_ERROR("Could not get record from object store %" PRIi64 " from Records table (%i) - %s", getAllRecordsData.objectStoreIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
2128 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error looking up record in object store by key range") };
2131 IDBError SQLiteIDBBackingStore::getAllIndexRecords(const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData& getAllRecordsData, IDBGetAllResult& result)
2133 LOG(IndexedDB, "SQLiteIDBBackingStore::getAllIndexRecords - %s", getAllRecordsData.keyRangeData.loggingString().utf8().data());
2136 ASSERT(m_sqliteDB->isOpen());
2138 auto* transaction = m_transactions.get(transactionIdentifier);
2139 if (!transaction || !transaction->inProgress()) {
2140 LOG_ERROR("Attempt to get all index records from database without an in-progress transaction");
2141 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to get all index records from database without an in-progress transaction") };
2144 auto cursor = transaction->maybeOpenBackingStoreCursor(getAllRecordsData.objectStoreIdentifier, getAllRecordsData.indexIdentifier, getAllRecordsData.keyRangeData);
2146 LOG_ERROR("Cannot open cursor to perform index gets in database");
2147 return { IDBDatabaseException::UnknownError, ASCIILiteral("Cannot open cursor to perform index gets in database") };
2150 if (cursor->didError()) {
2151 LOG_ERROR("Cursor failed while looking up index records in database");
2152 return { IDBDatabaseException::UnknownError, ASCIILiteral("Cursor failed while looking up index records in database") };
2155 result = { getAllRecordsData.getAllType };
2156 uint32_t currentCount = 0;
2157 uint32_t targetCount = getAllRecordsData.count ? getAllRecordsData.count.value() : 0;
2159 targetCount = std::numeric_limits<uint32_t>::max();
2160 while (!cursor->didComplete() && !cursor->didError() && currentCount < targetCount) {
2161 if (getAllRecordsData.getAllType == IndexedDB::GetAllType::Keys) {
2162 IDBKeyData keyCopy = cursor->currentPrimaryKey();
2163 result.addKey(WTFMove(keyCopy));
2165 result.addValue(cursor->currentValue() ? *cursor->currentValue() : IDBValue());
2171 if (cursor->didError()) {
2172 LOG_ERROR("Cursor failed while looking up index records in database");
2173 return { IDBDatabaseException::UnknownError, ASCIILiteral("Cursor failed while looking up index records in database") };
2179 IDBError SQLiteIDBBackingStore::getIndexRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, uint64_t indexID, IndexedDB::IndexRecordType type, const IDBKeyRangeData& range, IDBGetResult& getResult)
2181 LOG(IndexedDB, "SQLiteIDBBackingStore::getIndexRecord - %s", range.loggingString().utf8().data());
2184 ASSERT(m_sqliteDB->isOpen());
2186 auto* transaction = m_transactions.get(transactionIdentifier);
2187 if (!transaction || !transaction->inProgress()) {
2188 LOG_ERROR("Attempt to get an index record from database without an in-progress transaction");
2189 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to get an index record from database without an in-progress transaction") };
2192 if (range.isExactlyOneKey())
2193 return uncheckedGetIndexRecordForOneKey(indexID, objectStoreID, type, range.lowerKey, getResult);
2195 auto cursor = transaction->maybeOpenBackingStoreCursor(objectStoreID, indexID, range);
2197 LOG_ERROR("Cannot open cursor to perform index get in database");
2198 return { IDBDatabaseException::UnknownError, ASCIILiteral("Cannot open cursor to perform index get in database") };
2201 if (cursor->didError()) {
2202 LOG_ERROR("Cursor failed while looking up index record in database");
2203 return { IDBDatabaseException::UnknownError, ASCIILiteral("Cursor failed while looking up index record in database") };
2206 if (cursor->didComplete())
2209 if (type == IndexedDB::IndexRecordType::Key)
2210 getResult = { cursor->currentPrimaryKey() };
2212 getResult = { cursor->currentValue() ? *cursor->currentValue() : IDBValue(), cursor->currentPrimaryKey() };
2218 IDBError SQLiteIDBBackingStore::uncheckedGetIndexRecordForOneKey(int64_t indexID, int64_t objectStoreID, IndexedDB::IndexRecordType type, const IDBKeyData& key, IDBGetResult& getResult)
2220 LOG(IndexedDB, "SQLiteIDBBackingStore::uncheckedGetIndexRecordForOneKey");
2222 ASSERT(key.isValid() && key.type() != KeyType::Max && key.type() != KeyType::Min);
2224 RefPtr<SharedBuffer> buffer = serializeIDBKeyData(key);
2226 LOG_ERROR("Unable to serialize IDBKey to look up one index record");
2227 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize IDBKey to look up one index record") };
2230 auto* sql = cachedStatement(SQL::GetIndexRecordForOneKey, ASCIILiteral("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"));
2233 || sql->bindInt64(1, indexID) != SQLITE_OK
2234 || sql->bindInt64(2, objectStoreID) != SQLITE_OK
2235 || sql->bindBlob(3, buffer->data(), buffer->size()) != SQLITE_OK) {
2236 LOG_ERROR("Unable to lookup index record in database");
2237 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to lookup index record in database") };
2240 int result = sql->step();
2241 if (result != SQLITE_ROW && result != SQLITE_DONE) {
2242 LOG_ERROR("Unable to lookup index record in database");
2243 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to lookup index record in database") };
2246 if (result == SQLITE_DONE)
2249 IDBKeyData objectStoreKey;
2250 Vector<uint8_t> keyVector;
2251 sql->getColumnBlobAsVector(0, keyVector);
2253 if (!deserializeIDBKeyData(keyVector.data(), keyVector.size(), objectStoreKey)) {
2254 LOG_ERROR("Unable to deserialize key looking up index record in database");
2255 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to deserialize key looking up index record in database") };
2258 if (type == IndexedDB::IndexRecordType::Key) {
2259 getResult = { objectStoreKey };
2263 sql->getColumnBlobAsVector(1, keyVector);
2265 int64_t recordID = sql->getColumnInt64(2);
2266 Vector<String> blobURLs, blobFilePaths;
2267 auto error = getBlobRecordsForObjectStoreRecord(recordID, blobURLs, blobFilePaths);
2268 ASSERT(blobURLs.size() == blobFilePaths.size());
2270 if (!error.isNull())
2273 getResult = { { ThreadSafeDataBuffer::adoptVector(keyVector), WTFMove(blobURLs), WTFMove(blobFilePaths) }, objectStoreKey };
2277 IDBError SQLiteIDBBackingStore::getCount(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData& range, uint64_t& outCount)
2279 LOG(IndexedDB, "SQLiteIDBBackingStore::getCount - object store %" PRIu64, objectStoreIdentifier);
2281 ASSERT(m_sqliteDB->isOpen());
2285 auto* transaction = m_transactions.get(transactionIdentifier);
2286 if (!transaction || !transaction->inProgress()) {
2287 LOG_ERROR("Attempt to get count from database without an in-progress transaction");
2288 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to get count from database without an in-progress transaction") };
2291 auto cursor = transaction->maybeOpenBackingStoreCursor(objectStoreIdentifier, indexIdentifier, range);
2293 LOG_ERROR("Cannot open cursor to populate indexes in database");
2294 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to populate indexes in database") };
2297 while (cursor->advance(1))
2303 IDBError SQLiteIDBBackingStore::uncheckedGetKeyGeneratorValue(int64_t objectStoreID, uint64_t& outValue)
2305 auto* sql = cachedStatement(SQL::GetKeyGeneratorValue, ASCIILiteral("SELECT currentKey FROM KeyGenerators WHERE objectStoreID = ?;"));
2307 || sql->bindInt64(1, objectStoreID) != SQLITE_OK) {
2308 LOG_ERROR("Could not retrieve currentKey from KeyGenerators table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
2309 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error getting current key generator value from database") };
2311 int result = sql->step();
2312 if (result != SQLITE_ROW) {
2313 LOG_ERROR("Could not retreive key generator value for object store, but it should be there.");
2314 return { IDBDatabaseException::UnknownError, ASCIILiteral("Error finding current key generator value in database") };
2317 int64_t value = sql->getColumnInt64(0);
2319 return { IDBDatabaseException::ConstraintError, "Current key generator value from database is invalid" };
2325 IDBError SQLiteIDBBackingStore::uncheckedSetKeyGeneratorValue(int64_t objectStoreID, uint64_t value)
2327 auto* sql = cachedStatement(SQL::SetKeyGeneratorValue, ASCIILiteral("INSERT INTO KeyGenerators VALUES (?, ?);"));
2329 || sql->bindInt64(1, objectStoreID) != SQLITE_OK
2330 || sql->bindInt64(2, value) != SQLITE_OK
2331 || sql->step() != SQLITE_DONE) {
2332 LOG_ERROR("Could not update key generator value (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
2333 return { IDBDatabaseException::ConstraintError, "Error storing new key generator value in database" };
2339 IDBError SQLiteIDBBackingStore::generateKeyNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, uint64_t& generatedKey)
2341 LOG(IndexedDB, "SQLiteIDBBackingStore::generateKeyNumber");
2344 ASSERT(m_sqliteDB->isOpen());
2346 // The IndexedDatabase spec defines the max key generator value as 2^53;
2347 static uint64_t maxGeneratorValue = 0x20000000000000;
2349 auto* transaction = m_transactions.get(transactionIdentifier);
2350 if (!transaction || !transaction->inProgress()) {
2351 LOG_ERROR("Attempt to generate key in database without an in-progress transaction");
2352 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to generate key in database without an in-progress transaction") };
2354 if (transaction->mode() == IDBTransactionMode::Readonly) {
2355 LOG_ERROR("Attempt to generate key in a read-only transaction");
2356 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to generate key in a read-only transaction") };
2359 uint64_t currentValue;
2360 auto error = uncheckedGetKeyGeneratorValue(objectStoreID, currentValue);
2361 if (!error.isNull())
2364 if (currentValue + 1 > maxGeneratorValue)
2365 return { IDBDatabaseException::ConstraintError, "Cannot generate new key value over 2^53 for object store operation" };
2367 generatedKey = currentValue + 1;
2368 return uncheckedSetKeyGeneratorValue(objectStoreID, generatedKey);
2371 IDBError SQLiteIDBBackingStore::revertGeneratedKeyNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, uint64_t newKeyNumber)
2373 LOG(IndexedDB, "SQLiteIDBBackingStore::revertGeneratedKeyNumber - object store %" PRIu64 ", reverted number %" PRIu64, objectStoreID, newKeyNumber);
2376 ASSERT(m_sqliteDB->isOpen());
2378 auto* transaction = m_transactions.get(transactionIdentifier);
2379 if (!transaction || !transaction->inProgress()) {
2380 LOG_ERROR("Attempt to revert key generator value in database without an in-progress transaction");
2381 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to revert key generator value in database without an in-progress transaction") };
2383 if (transaction->mode() == IDBTransactionMode::Readonly) {
2384 LOG_ERROR("Attempt to revert key generator value in a read-only transaction");
2385 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to revert key generator value in a read-only transaction") };
2388 ASSERT(newKeyNumber);
2389 return uncheckedSetKeyGeneratorValue(objectStoreID, newKeyNumber - 1);
2392 IDBError SQLiteIDBBackingStore::maybeUpdateKeyGeneratorNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, double newKeyNumber)
2394 LOG(IndexedDB, "SQLiteIDBBackingStore::maybeUpdateKeyGeneratorNumber");
2397 ASSERT(m_sqliteDB->isOpen());
2399 auto* transaction = m_transactions.get(transactionIdentifier);
2400 if (!transaction || !transaction->inProgress()) {
2401 LOG_ERROR("Attempt to update key generator value in database without an in-progress transaction");
2402 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to update key generator value in database without an in-progress transaction") };
2404 if (transaction->mode() == IDBTransactionMode::Readonly) {
2405 LOG_ERROR("Attempt to update key generator value in a read-only transaction");
2406 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to update key generator value in a read-only transaction") };
2409 uint64_t currentValue;
2410 auto error = uncheckedGetKeyGeneratorValue(objectStoreID, currentValue);
2411 if (!error.isNull())
2414 if (newKeyNumber <= currentValue)
2417 uint64_t newKeyInteger(newKeyNumber);
2418 if (newKeyInteger <= uint64_t(newKeyNumber))
2421 ASSERT(newKeyInteger > uint64_t(newKeyNumber));
2423 return uncheckedSetKeyGeneratorValue(objectStoreID, newKeyInteger - 1);
2426 IDBError SQLiteIDBBackingStore::openCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo& info, IDBGetResult& result)
2429 ASSERT(m_sqliteDB->isOpen());
2431 auto* transaction = m_transactions.get(transactionIdentifier);
2432 if (!transaction || !transaction->inProgress()) {
2433 LOG_ERROR("Attempt to open a cursor in database without an in-progress transaction");
2434 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to open a cursor in database without an in-progress transaction") };
2437 auto* cursor = transaction->maybeOpenCursor(info);
2439 LOG_ERROR("Unable to open cursor");
2440 return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to open cursor") };
2443 m_cursors.set(cursor->identifier(), cursor);
2445 cursor->currentData(result);
2449 IDBError SQLiteIDBBackingStore::iterateCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBIterateCursorData& data, IDBGetResult& result)
2451 LOG(IndexedDB, "SQLiteIDBBackingStore::iterateCursor");
2454 ASSERT(m_sqliteDB->isOpen());
2456 auto* cursor = m_cursors.get(cursorIdentifier);
2458 LOG_ERROR("Attempt to iterate a cursor that doesn't exist");
2459 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to iterate a cursor that doesn't exist") };
2462 ASSERT_UNUSED(transactionIdentifier, cursor->transaction()->transactionIdentifier() == transactionIdentifier);
2464 if (!cursor->transaction() || !cursor->transaction()->inProgress()) {
2465 LOG_ERROR("Attempt to iterate a cursor without an in-progress transaction");
2466 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to iterate a cursor without an in-progress transaction") };
2469 auto key = data.keyData;
2470 auto primaryKey = data.primaryKeyData;
2471 auto count = data.count;
2473 if (key.isValid()) {
2474 if (!cursor->iterate(key, primaryKey)) {
2475 LOG_ERROR("Attempt to iterate cursor failed");
2476 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to iterate cursor failed") };
2479 ASSERT(!primaryKey.isValid());
2482 if (!cursor->advance(count)) {
2483 LOG_ERROR("Attempt to advance cursor failed");
2484 return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to advance cursor failed") };
2488 cursor->currentData(result);
2492 IDBObjectStoreInfo* SQLiteIDBBackingStore::infoForObjectStore(uint64_t objectStoreIdentifier)
2494 ASSERT(m_databaseInfo);
2495 return m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
2498 void SQLiteIDBBackingStore::deleteBackingStore()
2500 String dbFilename = fullDatabasePath();
2502 LOG(IndexedDB, "SQLiteIDBBackingStore::deleteBackingStore deleting file '%s' on disk", dbFilename.utf8().data());
2504 Vector<String> blobFiles;
2506 bool errored = true;
2509 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT fileName FROM BlobFiles;"));
2510 if (sql.prepare() == SQLITE_OK) {
2511 int result = sql.step();
2512 while (result == SQLITE_ROW) {
2513 blobFiles.append(sql.getColumnText(0));
2514 result = sql.step();
2517 if (result == SQLITE_DONE)
2523 LOG_ERROR("Error getting all blob filenames to be deleted");
2526 String databaseDirectory = fullDatabaseDirectory();
2527 for (auto& file : blobFiles) {
2528 String fullPath = pathByAppendingComponent(databaseDirectory, file);
2529 if (!deleteFile(fullPath))
2530 LOG_ERROR("Error deleting blob file %s", fullPath.utf8().data());
2536 SQLiteFileSystem::deleteDatabaseFile(dbFilename);
2537 SQLiteFileSystem::deleteEmptyDatabaseDirectory(fullDatabaseDirectory());
2538 SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_absoluteDatabaseDirectory);
2541 void SQLiteIDBBackingStore::unregisterCursor(SQLiteIDBCursor& cursor)
2543 ASSERT(m_cursors.contains(cursor.identifier()));
2544 m_cursors.remove(cursor.identifier());
2547 SQLiteStatement* SQLiteIDBBackingStore::cachedStatement(SQLiteIDBBackingStore::SQL sql, const char* statement)
2549 if (sql >= SQL::Count) {
2550 LOG_ERROR("Invalid SQL statement ID passed to cachedStatement()");
2554 if (m_cachedStatements[static_cast<size_t>(sql)]) {
2555 if (m_cachedStatements[static_cast<size_t>(sql)]->reset() == SQLITE_OK)
2556 return m_cachedStatements[static_cast<size_t>(sql)].get();
2557 m_cachedStatements[static_cast<size_t>(sql)] = nullptr;
2561 m_cachedStatements[static_cast<size_t>(sql)] = std::make_unique<SQLiteStatement>(*m_sqliteDB, statement);
2562 if (m_cachedStatements[static_cast<size_t>(sql)]->prepare() != SQLITE_OK)
2563 m_cachedStatements[static_cast<size_t>(sql)] = nullptr;
2566 return m_cachedStatements[static_cast<size_t>(sql)].get();
2569 void SQLiteIDBBackingStore::closeSQLiteDB()
2571 for (size_t i = 0; i < static_cast<int>(SQL::Count); ++i)
2572 m_cachedStatements[i] = nullptr;
2575 m_sqliteDB->close();
2577 m_sqliteDB = nullptr;
2580 } // namespace IDBServer
2581 } // namespace WebCore
2583 #endif // ENABLE(INDEXED_DATABASE)