Modern IDB: Implement put, get, and delete records for the SQLite backend.
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 23 Jan 2016 00:41:06 +0000 (00:41 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 23 Jan 2016 00:41:06 +0000 (00:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=153375

Reviewed by Alex Christensen.

Source/WebCore:

No new tests (Covered by many existing tests now passing).

* Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
(WebCore::IDBServer::SQLiteIDBBackingStore::keyExistsInObjectStore):
(WebCore::IDBServer::SQLiteIDBBackingStore::deleteRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::deleteRange):
(WebCore::IDBServer::SQLiteIDBBackingStore::addRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::getRecord):
* Modules/indexeddb/server/SQLiteIDBBackingStore.h:

LayoutTests:

* platform/mac-wk1/TestExpectations:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@195495 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/platform/mac-wk1/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp
Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h

index 3aca15b..dc7cc55 100644 (file)
@@ -1,3 +1,12 @@
+2016-01-22  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB: Implement put, get, and delete records for the SQLite backend.
+        https://bugs.webkit.org/show_bug.cgi?id=153375
+
+        Reviewed by Alex Christensen.
+
+        * platform/mac-wk1/TestExpectations:
+
 2016-01-22  Daniel Bates  <dabates@apple.com>
 
         LayoutTest http/tests/security/xssAuditor/embed-tag-in-path-unterminated.html crashing
index 5cbd73b..81fe835 100644 (file)
@@ -91,9 +91,9 @@ storage/indexeddb/open-db-private-browsing.html [ Failure ]
 storage/indexeddb/connection-leak-private.html [ Skip ]
 storage/indexeddb/connection-leak.html [ Skip ]
 storage/indexeddb/cursor-leak-private.html [ Failure ]
-storage/indexeddb/cursor-leak.html [ Failure ]
+storage/indexeddb/cursor-leak.html [ Skip ]
 storage/indexeddb/cursor-request-cycle-private.html [ Failure ]
-storage/indexeddb/cursor-request-cycle.html [ Failure ]
+storage/indexeddb/cursor-request-cycle.html [ Skip ]
 storage/indexeddb/delete-closed-database-object-private.html [ Skip ]
 storage/indexeddb/delete-closed-database-object.html [ Skip ]
 storage/indexeddb/request-leak-private.html [ Failure ]
@@ -254,9 +254,6 @@ imported/w3c/indexeddb/close-in-upgradeneeded.html [ Failure ]
 imported/w3c/indexeddb/cursor-overloads.htm [ Failure ]
 imported/w3c/indexeddb/idbcursor-direction-index-keyrange.htm [ Failure ]
 imported/w3c/indexeddb/idbcursor-direction-index.htm [ Failure ]
-imported/w3c/indexeddb/idbcursor-direction-objectstore-keyrange.htm [ Failure ]
-imported/w3c/indexeddb/idbcursor-direction-objectstore.htm [ Failure ]
-imported/w3c/indexeddb/idbcursor-direction.htm [ Failure ]
 imported/w3c/indexeddb/idbcursor-key.htm [ Failure ]
 imported/w3c/indexeddb/idbcursor-primarykey.htm [ Failure ]
 imported/w3c/indexeddb/idbcursor-reused.htm [ Failure ]
@@ -423,11 +420,9 @@ imported/w3c/indexeddb/idbtransaction-oncomplete.htm [ Failure ]
 imported/w3c/indexeddb/idbtransaction_abort.htm [ Failure ]
 imported/w3c/indexeddb/idbversionchangeevent.htm [ Failure ]
 imported/w3c/indexeddb/index_sort_order.htm [ Failure ]
-imported/w3c/indexeddb/key_valid.html [ Failure ]
 imported/w3c/indexeddb/keygenerator-constrainterror.htm [ Failure ]
 imported/w3c/indexeddb/keygenerator-overflow.htm [ Failure ]
 imported/w3c/indexeddb/keygenerator.htm [ Failure ]
-imported/w3c/indexeddb/keyorder.htm [ Failure ]
 imported/w3c/indexeddb/keypath_maxsize.htm [ Failure ]
 imported/w3c/indexeddb/list_ordering.htm [ Failure ]
 imported/w3c/indexeddb/objectstore_keyorder.htm [ Failure ]
@@ -440,15 +435,10 @@ imported/w3c/indexeddb/transaction-requestqueue.htm [ Failure ]
 imported/w3c/indexeddb/transaction_bubble-and-capture.htm [ Failure ]
 imported/w3c/indexeddb/value.htm [ Failure ]
 imported/w3c/indexeddb/value_recursive.htm [ Failure ]
-imported/w3c/indexeddb/writer-starvation.htm [ Failure ]
-storage/indexeddb/closed-cursor.html [ Failure ]
-storage/indexeddb/create-and-remove-object-store.html [ Failure ]
-storage/indexeddb/create-object-store-options.html [ Failure ]
 storage/indexeddb/createIndex-after-failure.html [ Failure ]
 storage/indexeddb/cursor-added-bug.html [ Failure ]
 storage/indexeddb/cursor-advance.html [ Failure ]
 storage/indexeddb/cursor-basics.html [ Failure ]
-storage/indexeddb/cursor-cast.html [ Failure ]
 storage/indexeddb/cursor-continue-dir.html [ Failure ]
 storage/indexeddb/cursor-continue-validity.html [ Failure ]
 storage/indexeddb/cursor-continue.html [ Failure ]
@@ -466,14 +456,11 @@ storage/indexeddb/cursor-skip-deleted.html [ Failure ]
 storage/indexeddb/cursor-update-value-argument-required.html [ Failure ]
 storage/indexeddb/cursor-update.html [ Failure ]
 storage/indexeddb/cursor-value.html [ Failure ]
-storage/indexeddb/database-close.html [ Failure ]
 storage/indexeddb/database-wrapper.html [ Failure ]
 storage/indexeddb/delete-range.html [ Failure ]
 storage/indexeddb/deleteIndex.html [ Failure ]
 storage/indexeddb/deleted-objects.html [ Failure ]
 storage/indexeddb/duplicates.html [ Failure ]
-storage/indexeddb/error-causes-abort-by-default.html [ Failure ]
-storage/indexeddb/exception-in-event-aborts.html [ Failure ]
 storage/indexeddb/exceptions.html [ Failure ]
 storage/indexeddb/factory-deletedatabase.html [ Failure ]
 storage/indexeddb/get-keyrange.html [ Failure ]
@@ -487,8 +474,6 @@ storage/indexeddb/index-unique.html [ Failure ]
 storage/indexeddb/key-generator.html [ Failure ]
 storage/indexeddb/key-sort-order-across-types.html [ Failure ]
 storage/indexeddb/key-sort-order-date.html [ Failure ]
-storage/indexeddb/key-type-array.html [ Failure ]
-storage/indexeddb/key-type-infinity.html [ Failure ]
 storage/indexeddb/keypath-arrays.html [ Failure ]
 storage/indexeddb/keypath-edges.html [ Failure ]
 storage/indexeddb/keypath-fetch-key.html [ Failure ]
@@ -499,13 +484,8 @@ storage/indexeddb/list-ordering.html [ Failure ]
 storage/indexeddb/metadata-race.html [ Failure ]
 storage/indexeddb/metadata.html [ Failure ]
 storage/indexeddb/modern/abort-objectstore-info.html [ Failure ]
-storage/indexeddb/modern/abort-requests-cancelled.html [ Failure ]
-storage/indexeddb/modern/aborted-put.html [ Failure ]
 storage/indexeddb/modern/autoincrement-abort.html [ Failure ]
-storage/indexeddb/modern/basic-add.html [ Failure ]
-storage/indexeddb/modern/basic-put.html [ Failure ]
 storage/indexeddb/modern/create-index-failures.html [ Failure ]
-storage/indexeddb/modern/createobjectstore-basic.html [ Failure ]
 storage/indexeddb/modern/cursor-1.html [ Failure ]
 storage/indexeddb/modern/cursor-2.html [ Failure ]
 storage/indexeddb/modern/cursor-3.html [ Failure ]
@@ -514,52 +494,32 @@ storage/indexeddb/modern/cursor-5.html [ Failure ]
 storage/indexeddb/modern/cursor-6.html [ Failure ]
 storage/indexeddb/modern/cursor-7.html [ Failure ]
 storage/indexeddb/modern/cursor-8.html [ Failure ]
-storage/indexeddb/modern/date-basic.html [ Failure ]
-storage/indexeddb/modern/deletedatabase-1.html [ Failure ]
-storage/indexeddb/modern/deletedatabase-2.html [ Failure ]
 storage/indexeddb/modern/deleteindex-1.html [ Failure ]
 storage/indexeddb/modern/deleteindex-2.html [ Failure ]
-storage/indexeddb/modern/deleteobjectstore-1.html [ Failure ]
 storage/indexeddb/modern/get-index-failures.html [ Failure ]
 storage/indexeddb/modern/get-keyrange.html [ Failure ]
-storage/indexeddb/modern/idbdatabase-deleteobjectstore-failures.html [ Failure ]
-storage/indexeddb/modern/idbdatabase-transaction-failures.html [ Failure ]
 storage/indexeddb/modern/idbindex-properties-basic.html [ Failure ]
 storage/indexeddb/modern/idbobjectstore-clear-1.html [ Failure ]
 storage/indexeddb/modern/idbobjectstore-clear-2.html [ Failure ]
 storage/indexeddb/modern/idbobjectstore-count-1.html [ Failure ]
-storage/indexeddb/modern/idbobjectstore-count-failures.html [ Failure ]
 storage/indexeddb/modern/idbobjectstore-delete-1.html [ Failure ]
-storage/indexeddb/modern/idbobjectstore-delete-2.html [ Failure ]
-storage/indexeddb/modern/idbobjectstore-delete-failures.html [ Failure ]
-storage/indexeddb/modern/idbobjectstore-get-failures.html [ Failure ]
-storage/indexeddb/modern/idbobjectstore-put-and-clear-failures.html [ Failure ]
 storage/indexeddb/modern/index-1.html [ Failure ]
 storage/indexeddb/modern/index-2.html [ Failure ]
 storage/indexeddb/modern/index-3.html [ Failure ]
 storage/indexeddb/modern/index-4.html [ Failure ]
-storage/indexeddb/modern/index-5.html [ Failure ]
 storage/indexeddb/modern/index-cursor-1.html [ Failure ]
 storage/indexeddb/modern/index-cursor-2.html [ Failure ]
 storage/indexeddb/modern/index-cursor-3.html [ Failure ]
 storage/indexeddb/modern/index-get-count-basic.html [ Failure ]
 storage/indexeddb/modern/index-get-count-failures.html [ Failure ]
-storage/indexeddb/modern/keypath-basic.html [ Failure ]
 storage/indexeddb/modern/memory-index-not-deleted-with-objectstore.html [ Failure ]
 storage/indexeddb/modern/objectstore-attributes.html [ Failure ]
 storage/indexeddb/modern/objectstore-cursor-advance-failures.html [ Failure ]
 storage/indexeddb/modern/objectstore-cursor-continue-failures.html [ Failure ]
 storage/indexeddb/modern/opencursor-failures.html [ Failure ]
 storage/indexeddb/modern/request-readystate.html [ Failure ]
-storage/indexeddb/modern/transaction-scheduler-1.html [ Failure ]
-storage/indexeddb/modern/transaction-scheduler-2.html [ Failure ]
-storage/indexeddb/modern/transaction-scheduler-3.html [ Failure ]
-storage/indexeddb/modern/transaction-scheduler-5.html [ Failure ]
-storage/indexeddb/modern/transaction-scheduler-6.html [ Failure ]
 storage/indexeddb/modern/transactions-stop-on-navigation.html [ Failure ]
-storage/indexeddb/mozilla/add-twice-failure.html [ Failure ]
 storage/indexeddb/mozilla/autoincrement-indexes.html [ Failure ]
-storage/indexeddb/mozilla/bad-keypath.html [ Failure ]
 storage/indexeddb/mozilla/clear.html [ Failure ]
 storage/indexeddb/mozilla/create-index-with-integer-keys.html [ Failure ]
 storage/indexeddb/mozilla/cursor-mutation-objectstore-only.html [ Failure ]
@@ -578,47 +538,29 @@ storage/indexeddb/mozilla/object-store-remove-values.html [ Failure ]
 storage/indexeddb/mozilla/odd-result-order.html [ Failure ]
 storage/indexeddb/mozilla/put-get-values.html [ Failure ]
 storage/indexeddb/mozilla/readwrite-transactions.html [ Failure ]
-storage/indexeddb/mozilla/readyState.html [ Failure ]
 storage/indexeddb/mozilla/remove-objectstore.html [ Failure ]
 storage/indexeddb/mutating-cursor.html [ Failure ]
-storage/indexeddb/noblobs.html [ Failure ]
 storage/indexeddb/objectstore-autoincrement.html [ Failure ]
 storage/indexeddb/objectstore-basics.html [ Failure ]
 storage/indexeddb/objectstore-clear.html [ Failure ]
 storage/indexeddb/objectstore-count.html [ Failure ]
 storage/indexeddb/objectstore-cursor.html [ Failure ]
 storage/indexeddb/objectstore-removeobjectstore.html [ Failure ]
-storage/indexeddb/odd-strings.html [ Failure ]
 storage/indexeddb/open-cursor.html [ Failure ]
-storage/indexeddb/open-during-transaction.html [ Failure ]
 storage/indexeddb/opencursor-key.html [ Failure ]
 storage/indexeddb/optional-arguments.html [ Failure ]
-storage/indexeddb/pending-activity.html [ Failure ]
 storage/indexeddb/prefetch-bugfix-108071.html [ Failure ]
-storage/indexeddb/prefetch-race.html [ Failure ]
 storage/indexeddb/queued-commands.html [ Failure ]
 storage/indexeddb/readonly.html [ Failure ]
 storage/indexeddb/request-continue-abort.html [ Failure ]
-storage/indexeddb/request-event-propagation.html [ Failure ]
-storage/indexeddb/request-result-cache.html [ Failure ]
 storage/indexeddb/structured-clone.html [ Failure ]
-storage/indexeddb/transaction-abort.html [ Failure ]
 storage/indexeddb/transaction-active-flag.html [ Failure ]
-storage/indexeddb/transaction-after-close.html [ Failure ]
 storage/indexeddb/transaction-and-objectstore-calls.html [ Failure ]
 storage/indexeddb/transaction-basics.html [ Failure ]
-storage/indexeddb/transaction-coordination-across-databases.html [ Failure ]
-storage/indexeddb/transaction-coordination-within-database.html [ Failure ]
 storage/indexeddb/transaction-error.html [ Failure ]
-storage/indexeddb/transaction-event-propagation.html [ Failure ]
-storage/indexeddb/transaction-overlapping.html [ Failure ]
-storage/indexeddb/transaction-read-only.html [ Failure ]
-storage/indexeddb/transaction-readwrite-exclusive.html [ Failure ]
 storage/indexeddb/transaction-rollback.html [ Failure ]
-storage/indexeddb/transaction-scope-sequencing.html [ Failure ]
 storage/indexeddb/value-undefined.html [ Failure ]
 storage/indexeddb/values-odd-types.html [ Failure ]
-storage/indexeddb/version-change-exclusive.html [ Failure ]
 
 # SQLite backend tests that timeout
 crypto/subtle/rsa-indexeddb.html [ Skip ]
@@ -637,10 +579,34 @@ storage/indexeddb/modern/transaction-scheduler-4.html [ Skip ]
 storage/indexeddb/prefetch-invalidation.html [ Skip ]
 storage/indexeddb/primary-key-unique-to-objectstore.html [ Skip ]
 storage/indexeddb/transaction-ordering.html [ Skip ]
+storage/indexeddb/closed-cursor.html [ Skip ]
+storage/indexeddb/cursor-cast.html [ Skip ]
+storage/indexeddb/noblobs.html [ Skip ]
+storage/indexeddb/prefetch-race.html [ Skip ]
+storage/indexeddb/request-result-cache.html [ Skip ]
 
 # SQLite backend tests that ASSERT
+imported/w3c/indexeddb/idbcursor-direction-objectstore-keyrange.htm [ Skip ]
+imported/w3c/indexeddb/idbcursor-direction-objectstore.htm [ Skip ]
+imported/w3c/indexeddb/idbcursor-direction.htm [ Skip ]
+imported/w3c/indexeddb/key_valid.html [ Skip ]
+imported/w3c/indexeddb/writer-starvation.htm [ Skip ]
+storage/indexeddb/database-close.html [ Skip ]
 storage/indexeddb/database-odd-names.html [ Skip ]
 storage/indexeddb/dont-wedge.html [ Skip ]
+storage/indexeddb/modern/transaction-scheduler-1.html [ Skip ]
+storage/indexeddb/modern/transaction-scheduler-2.html [ Skip ]
+storage/indexeddb/modern/transaction-scheduler-5.html [ Skip ]
+storage/indexeddb/modern/transaction-scheduler-6.html [ Skip ]
+storage/indexeddb/odd-strings.html [ Skip ]
+storage/indexeddb/pending-activity.html [ Skip ]
+storage/indexeddb/transaction-coordination-within-database.html [ Skip ]
+storage/indexeddb/transaction-overlapping.html [ Skip ]
+storage/indexeddb/transaction-read-only.html [ Skip ]
+
+# SQLite backend tests that wedge the entire testing harness
+imported/w3c/indexeddb/keyorder.htm [ Skip ]
+storage/indexeddb/key-type-array.html [ Skip ]
 
 ### END OF (3) IndexedDB failures with SQLite
 ########################################
index 71f3890..087eea7 100644 (file)
@@ -1,3 +1,20 @@
+2016-01-22  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB: Implement put, get, and delete records for the SQLite backend.
+        https://bugs.webkit.org/show_bug.cgi?id=153375
+
+        Reviewed by Alex Christensen.
+
+        No new tests (Covered by many existing tests now passing).
+
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
+        (WebCore::IDBServer::SQLiteIDBBackingStore::keyExistsInObjectStore):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::deleteRecord):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::deleteRange):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::addRecord):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::getRecord):
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.h:
+
 2016-01-22  Enrica Casucci  <enrica@apple.com>
 
         Add support for DataDetectors in WK (iOS).
index 6ba7e41..dbafdff 100644 (file)
@@ -41,6 +41,7 @@
 #include "SQLiteIDBCursor.h"
 #include "SQLiteStatement.h"
 #include "SQLiteTransaction.h"
+#include "ThreadSafeDataBuffer.h"
 #include <wtf/NeverDestroyed.h>
 
 using namespace JSC;
@@ -653,24 +654,238 @@ IDBError SQLiteIDBBackingStore::deleteIndex(const IDBResourceIdentifier&, uint64
     return { IDBDatabaseException::UnknownError, ASCIILiteral("Not implemented") };
 }
 
-IDBError SQLiteIDBBackingStore::keyExistsInObjectStore(const IDBResourceIdentifier&, uint64_t, const IDBKeyData&, bool&)
+IDBError SQLiteIDBBackingStore::keyExistsInObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyData& keyData, bool& keyExists)
 {
-    return { IDBDatabaseException::UnknownError, ASCIILiteral("Not implemented") };
+    LOG(IndexedDB, "SQLiteIDBBackingStore::keyExistsInObjectStore - key %s, object store %" PRIu64, keyData.loggingString().utf8().data(), objectStoreID);
+
+    ASSERT(m_sqliteDB);
+    ASSERT(m_sqliteDB->isOpen());
+
+    keyExists = false;
+
+    auto* transaction = m_transactions.get(transactionIdentifier);
+    if (!transaction || !transaction->inProgress()) {
+        LOG_ERROR("Attempt to see if key exists in objectstore without an in-progress transaction");
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to see if key exists in objectstore without an in-progress transaction") };
+    }
+
+    RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(keyData);
+    if (!keyBuffer) {
+        LOG_ERROR("Unable to serialize IDBKey to check for existence in object store");
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize IDBKey to check for existence in object store") };
+    }
+    SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT key FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT) LIMIT 1;"));
+    if (sql.prepare() != SQLITE_OK
+        || sql.bindInt64(1, objectStoreID) != SQLITE_OK
+        || sql.bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK) {
+        LOG_ERROR("Could not get record from object store %" PRIi64 " from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to check for existence of IDBKey in object store") };
+    }
+
+    int sqlResult = sql.step();
+    if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE)
+        return { };
+
+    if (sqlResult != SQLITE_ROW) {
+        // There was an error fetching the record from the database.
+        LOG_ERROR("Could not check if key exists in object store (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Error checking for existence of IDBKey in object store") };
+    }
+
+    keyExists = true;
+    return { };
 }
 
-IDBError SQLiteIDBBackingStore::deleteRange(const IDBResourceIdentifier&, uint64_t, const IDBKeyRangeData&)
+IDBError SQLiteIDBBackingStore::deleteRecord(SQLiteIDBTransaction& transaction, int64_t objectStoreID, const IDBKeyData& keyData)
 {
-    return { IDBDatabaseException::UnknownError, ASCIILiteral("Not implemented") };
+    LOG(IndexedDB, "SQLiteIDBBackingStore::deleteRecord - key %s, object store %" PRIu64, keyData.loggingString().utf8().data(), objectStoreID);
+
+    ASSERT(m_sqliteDB);
+    ASSERT(m_sqliteDB->isOpen());
+    ASSERT(transaction.inProgress());
+    ASSERT(transaction.mode() != IndexedDB::TransactionMode::ReadOnly);
+    UNUSED_PARAM(transaction);
+
+    RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(keyData);
+    if (!keyBuffer) {
+        LOG_ERROR("Unable to serialize IDBKeyData to be removed from the database");
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize IDBKeyData to be removed from the database") };
+    }
+
+    // Delete record from object store
+    {
+        SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT);"));
+
+        if (sql.prepare() != SQLITE_OK
+            || sql.bindInt64(1, objectStoreID) != SQLITE_OK
+            || sql.bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
+            || sql.step() != SQLITE_DONE) {
+            LOG_ERROR("Could not delete record from object store %" PRIi64 " (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to delete record from object store") };
+        }
+    }
+
+    // Delete record from indexes store
+    {
+        SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM IndexRecords WHERE objectStoreID = ? AND value = CAST(? AS TEXT);"));
+
+        if (sql.prepare() != SQLITE_OK
+            || sql.bindInt64(1, objectStoreID) != SQLITE_OK
+            || sql.bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
+            || sql.step() != SQLITE_DONE) {
+            LOG_ERROR("Could not delete record from indexes for object store %" PRIi64 " (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to delete index entries for object store record") };
+        }
+    }
+
+    return { };
 }
 
-IDBError SQLiteIDBBackingStore::addRecord(const IDBResourceIdentifier&, uint64_t, const IDBKeyData&, const ThreadSafeDataBuffer&)
+IDBError SQLiteIDBBackingStore::deleteRange(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyRangeData& keyRange)
 {
-    return { IDBDatabaseException::UnknownError, ASCIILiteral("Not implemented") };
+    LOG(IndexedDB, "SQLiteIDBBackingStore::deleteRange - range %s, object store %" PRIu64, keyRange.loggingString().utf8().data(), objectStoreID);
+
+    ASSERT(m_sqliteDB);
+    ASSERT(m_sqliteDB->isOpen());
+
+    auto* transaction = m_transactions.get(transactionIdentifier);
+    if (!transaction || !transaction->inProgress()) {
+        LOG_ERROR("Attempt to delete range from database without an in-progress transaction");
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete range from database without an in-progress transaction") };
+    }
+    if (transaction->mode() == IndexedDB::TransactionMode::ReadOnly) {
+        LOG_ERROR("Attempt to delete records from an object store in a read-only transaction");
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to delete records from an object store in a read-only transaction") };
+    }
+
+    // If the range to delete is exactly one key we can delete it right now.
+    if (keyRange.isExactlyOneKey()) {
+        auto error = deleteRecord(*transaction, objectStoreID, keyRange.lowerKey);
+        if (!error.isNull()) {
+            LOG_ERROR("Failed to delete record for key '%s'", keyRange.lowerKey.loggingString().utf8().data());
+            return error;
+        }
+
+        return { };
+    }
+
+    // FIXME: Once cursor support is in place, use a cursor to delete every record in the range.
+    LOG_ERROR("Currently unable to delete all records in a multi-key range");
+    return { IDBDatabaseException::UnknownError, ASCIILiteral("Currently unable to delete all records in a multi-key range") };
 }
 
-IDBError SQLiteIDBBackingStore::getRecord(const IDBResourceIdentifier&, uint64_t, const IDBKeyRangeData&, ThreadSafeDataBuffer&)
+IDBError SQLiteIDBBackingStore::addRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyData& keyData, const ThreadSafeDataBuffer& value)
 {
-    return { IDBDatabaseException::UnknownError, ASCIILiteral("Not implemented") };
+    LOG(IndexedDB, "SQLiteIDBBackingStore::addRecord - key %s, object store %" PRIu64, keyData.loggingString().utf8().data(), objectStoreID);
+
+    ASSERT(m_sqliteDB);
+    ASSERT(m_sqliteDB->isOpen());
+    ASSERT(value.data());
+
+    auto* transaction = m_transactions.get(transactionIdentifier);
+    if (!transaction || !transaction->inProgress()) {
+        LOG_ERROR("Attempt to store a record in an object store without an in-progress transaction");
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to store a record in an object store without an in-progress transaction") };
+    }
+    if (transaction->mode() == IndexedDB::TransactionMode::ReadOnly) {
+        LOG_ERROR("Attempt to store a record in an object store in a read-only transaction");
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to store a record in an object store in a read-only transaction") };
+    }
+
+    RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(keyData);
+    if (!keyBuffer) {
+        LOG_ERROR("Unable to serialize IDBKey to be stored in an object store");
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize IDBKey to be stored in an object store") };
+    }
+    {
+        SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO Records VALUES (?, CAST(? AS TEXT), ?);"));
+        if (sql.prepare() != SQLITE_OK
+            || sql.bindInt64(1, objectStoreID) != SQLITE_OK
+            || sql.bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLITE_OK
+            || sql.bindBlob(3, value.data()->data(), value.data()->size()) != SQLITE_OK
+            || sql.step() != SQLITE_DONE) {
+            LOG_ERROR("Could not put record for object store %" PRIi64 " in Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to store record in object store") };
+        }
+    }
+
+    return { };
+}
+
+IDBError SQLiteIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreID, const IDBKeyRangeData& keyRange, ThreadSafeDataBuffer& resultValue)
+{
+    LOG(IndexedDB, "SQLiteIDBBackingStore::getRecord - key range %s, object store %" PRIu64, keyRange.loggingString().utf8().data(), objectStoreID);
+
+    ASSERT(m_sqliteDB);
+    ASSERT(m_sqliteDB->isOpen());
+
+    auto* transaction = m_transactions.get(transactionIdentifier);
+    if (!transaction || !transaction->inProgress()) {
+        LOG_ERROR("Attempt to get a record from database without an in-progress transaction");
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to get a record from database without an in-progress transaction") };
+    }
+
+    RefPtr<SharedBuffer> lowerBuffer = serializeIDBKeyData(IDBKeyData(keyRange.lowerKey));
+    if (!lowerBuffer) {
+        LOG_ERROR("Unable to serialize lower IDBKey in lookup range");
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize lower IDBKey in lookup range") };
+    }
+
+    RefPtr<SharedBuffer> upperBuffer = serializeIDBKeyData(IDBKeyData(keyRange.upperKey));
+    if (!upperBuffer) {
+        LOG_ERROR("Unable to serialize upper IDBKey in lookup range");
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("Unable to serialize upper IDBKey in lookup range") };
+    }
+
+    {
+        static NeverDestroyed<const ASCIILiteral> lowerOpenUpperOpen("SELECT value FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
+        static NeverDestroyed<const ASCIILiteral> lowerOpenUpperClosed("SELECT value FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
+        static NeverDestroyed<const ASCIILiteral> lowerClosedUpperOpen("SELECT value FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;");
+        static NeverDestroyed<const ASCIILiteral> lowerClosedUpperClosed("SELECT value FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;");
+
+        const ASCIILiteral* query = nullptr;
+
+        if (keyRange.lowerOpen) {
+            if (keyRange.upperOpen)
+                query = &lowerOpenUpperOpen.get();
+            else
+                query = &lowerOpenUpperClosed.get();
+        } else {
+            if (keyRange.upperOpen)
+                query = &lowerClosedUpperOpen.get();
+            else
+                query = &lowerClosedUpperClosed.get();
+        }
+
+        ASSERT(query);
+
+        SQLiteStatement sql(*m_sqliteDB, *query);
+        if (sql.prepare() != SQLITE_OK
+            || sql.bindInt64(1, objectStoreID) != SQLITE_OK
+            || sql.bindBlob(2, lowerBuffer->data(), lowerBuffer->size()) != SQLITE_OK
+            || sql.bindBlob(3, upperBuffer->data(), upperBuffer->size()) != SQLITE_OK) {
+            LOG_ERROR("Could not get key range record from object store %" PRIi64 " from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Failed to look up record in object store by key range") };
+        }
+
+        int sqlResult = sql.step();
+
+        if (sqlResult == SQLITE_OK || sqlResult == SQLITE_DONE) {
+            // There was no record for the key in the database.
+            return { };
+        }
+        if (sqlResult != SQLITE_ROW) {
+            // There was an error fetching the record from the database.
+            LOG_ERROR("Could not get record from object store %" PRIi64 " from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Error looking up record in object store by key range") };
+        }
+
+        Vector<uint8_t> buffer;
+        sql.getColumnBlobAsVector(0, buffer);
+        resultValue = ThreadSafeDataBuffer::adoptVector(buffer);
+    }
+
+    return { };
 }
 
 IDBError SQLiteIDBBackingStore::getIndexRecord(const IDBResourceIdentifier&, uint64_t, uint64_t, IndexedDB::IndexRecordType, const IDBKeyRangeData&, IDBGetResult&)
index be2cfc2..87b9093 100644 (file)
@@ -84,6 +84,8 @@ private:
     std::unique_ptr<IDBDatabaseInfo> createAndPopulateInitialDatabaseInfo();
     std::unique_ptr<IDBDatabaseInfo> extractExistingDatabaseInfo();
 
+    IDBError deleteRecord(SQLiteIDBTransaction&, int64_t objectStoreID, const IDBKeyData&);
+
     IDBDatabaseIdentifier m_identifier;
     std::unique_ptr<IDBDatabaseInfo> m_databaseInfo;