Title: [243807] trunk
Revision
243807
Author
[email protected]
Date
2019-04-03 10:03:59 -0700 (Wed, 03 Apr 2019)

Log Message

Blob type cannot be stored correctly in IDB when IDBObjectStore has autoIncrement and keyPath options
https://bugs.webkit.org/show_bug.cgi?id=196128

Reviewed by Geoffrey Garen.

LayoutTests/imported/w3c:

Updated test expectations to PASS.

* web-platform-tests/IndexedDB/nested-cloning-large-expected.txt:
* web-platform-tests/IndexedDB/nested-cloning-large-multiple-expected.txt:
* web-platform-tests/IndexedDB/nested-cloning-small-expected.txt:

Source/WebCore:

If a key is auto-generated, it should become a property of the value object. Network process would perform the
key injection by deserializing IDBValue into script value, setting the property, serializing the result and
storing it in a database record. But network process does not have a JSDOMGlobalObject, so it would fail to
deserialize types including Blob and File.

To solve this issue, we move the key injection to web process and let network process store the original value
it gets. In this case, when web process asks for some value, network process should return key, value and key
path so that web process can decide whether it should perform a key injection before returning the result. Note
that the auto-generated key would always be stored as the key in a ObjectStore record.

Test: storage/indexeddb/modern/objectstore-autoincrement-types.html

* Modules/indexeddb/IDBCursor.cpp:
(WebCore::IDBCursor::setGetResult):
* Modules/indexeddb/IDBCursor.h:
(WebCore::IDBCursor::primaryKeyPath):
* Modules/indexeddb/IDBGetAllResult.cpp:
(WebCore::IDBGetAllResult::isolatedCopy):
(WebCore::IDBGetAllResult::addKey):
(WebCore::IDBGetAllResult::addValue):
(WebCore::IDBGetAllResult::keys const):
(WebCore::IDBGetAllResult::values const):
(WebCore::IDBGetAllResult::allBlobFilePaths const):
(WebCore::isolatedCopyOfVariant): Deleted.

* Modules/indexeddb/IDBGetAllResult.h: Introduce an IDBKeyPath parameter. Also replace Variant with two Vectors,
because we only needed to store either key or value before, and now the stored value could be incomplete.
(WebCore::IDBGetAllResult::IDBGetAllResult):
(WebCore::IDBGetAllResult::keyPath const):
(WebCore::IDBGetAllResult::encode const):
(WebCore::IDBGetAllResult::decode):

* Modules/indexeddb/IDBGetResult.cpp:
(WebCore::IDBGetResult::setValue):
* Modules/indexeddb/IDBGetResult.h:
(WebCore::IDBGetResult::IDBGetResult):
(WebCore::IDBGetResult::keyPath const):
* Modules/indexeddb/IDBObjectStore.cpp:
* Modules/indexeddb/IDBRequest.cpp:
(WebCore::IDBRequest::setResult):
(WebCore::IDBRequest::setResultToStructuredClone):
* Modules/indexeddb/IDBRequest.h:
* Modules/indexeddb/IDBTransaction.cpp:
(WebCore::IDBTransaction::didGetAllRecordsOnServer):
(WebCore::IDBTransaction::didGetRecordOnServer):
* Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
(WebCore::IDBServer::MemoryIDBBackingStore::getRecord):
* Modules/indexeddb/server/MemoryIndex.cpp:
(WebCore::IDBServer::MemoryIndex::getResultForKeyRange const):
(WebCore::IDBServer::MemoryIndex::getAllRecords const):
* Modules/indexeddb/server/MemoryIndexCursor.cpp:
(WebCore::IDBServer::MemoryIndexCursor::currentData):
* Modules/indexeddb/server/MemoryObjectStore.cpp:
(WebCore::IDBServer::MemoryObjectStore::updateIndexesForPutRecord):
(WebCore::IDBServer::MemoryObjectStore::populateIndexWithExistingRecords):
(WebCore::IDBServer::MemoryObjectStore::getAllRecords const):
* Modules/indexeddb/server/MemoryObjectStoreCursor.cpp:
(WebCore::IDBServer::MemoryObjectStoreCursor::currentData):
* Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
(WebCore::IDBServer::SQLiteIDBBackingStore::updateOneIndexForAddRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::updateAllIndexesForAddRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::getRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::cachedStatementForGetAllObjectStoreRecords):
(WebCore::IDBServer::SQLiteIDBBackingStore::getAllObjectStoreRecords):
(WebCore::IDBServer::SQLiteIDBBackingStore::getAllIndexRecords):
(WebCore::IDBServer::SQLiteIDBBackingStore::getIndexRecord):
(WebCore::IDBServer::SQLiteIDBBackingStore::uncheckedGetIndexRecordForOneKey):
(WebCore::IDBServer::SQLiteIDBBackingStore::openCursor):
(WebCore::IDBServer::SQLiteIDBBackingStore::iterateCursor):
* Modules/indexeddb/server/SQLiteIDBCursor.cpp:
(WebCore::IDBServer::SQLiteIDBCursor::currentData):
* Modules/indexeddb/server/SQLiteIDBCursor.h:

* Modules/indexeddb/server/UniqueIDBDatabase.cpp:
(WebCore::IDBServer::UniqueIDBDatabase::performPutOrAdd): Remove the key injection from network process.
UniqueIDBDatabase stores any value it gets from IDBClient.

* Modules/indexeddb/shared/IDBResultData.cpp:
(WebCore::IDBResultData::getResultRef):
* Modules/indexeddb/shared/IDBResultData.h:

* bindings/js/IDBBindingUtilities.cpp:
(WebCore::injectIDBKeyIntoScriptValue): If property is read-only, set would fail and injectKeyIntoResult would
return null, but we expect it to return result as long as the property value is the same as target. Therefore,
we can add an early return here.
(WebCore::createKeyPathArray):

(WebCore::generateIndexKeyForValue): We used to generate IndexKey from value stored in database but now the
value gets stored does not include auto-generated key, as we remove the key injection from network process. In
this case if the IDBIndex has the same key path as the auto-generated key, IndexKey would be failed to create
for it cannot extract auto-generated key from value. Since the auto-generated key would always be the key in
database record, we could use value of that key when we find a match in key path.

(WebCore::deserializeIDBValueWithKeyInjection): If the key path in the result is single entry, the key is
probably auto-generated, so we could inject the result key into the result value unconditionally.

* bindings/js/IDBBindingUtilities.h:
* bindings/js/JSIDBCursorWithValueCustom.cpp:
(WebCore::JSIDBCursorWithValue::value const):
* bindings/js/JSIDBRequestCustom.cpp:
(WebCore::JSIDBRequest::result const):

LayoutTests:

* TestExpectations:
* storage/indexeddb/modern/objectstore-autoincrement-types-expected.txt: Added.
* storage/indexeddb/modern/objectstore-autoincrement-types.html: Added.
* storage/indexeddb/modern/resources/objectstore-autoincrement-types.js: Added.
(next):
(prepareDatabase.event.target.onsuccess):
(prepareDatabase):
(testSteps):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (243806 => 243807)


--- trunk/LayoutTests/ChangeLog	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/LayoutTests/ChangeLog	2019-04-03 17:03:59 UTC (rev 243807)
@@ -1,3 +1,19 @@
+2019-04-03  Sihui Liu  <[email protected]>
+
+        Blob type cannot be stored correctly in IDB when IDBObjectStore has autoIncrement and keyPath options
+        https://bugs.webkit.org/show_bug.cgi?id=196128
+
+        Reviewed by Geoffrey Garen.
+
+        * TestExpectations:
+        * storage/indexeddb/modern/objectstore-autoincrement-types-expected.txt: Added.
+        * storage/indexeddb/modern/objectstore-autoincrement-types.html: Added.
+        * storage/indexeddb/modern/resources/objectstore-autoincrement-types.js: Added.
+        (next):
+        (prepareDatabase.event.target.onsuccess):
+        (prepareDatabase):
+        (testSteps):
+
 2019-04-03  Youenn Fablet  <[email protected]>
 
         Resetting quota should take into account third party origins

Modified: trunk/LayoutTests/TestExpectations (243806 => 243807)


--- trunk/LayoutTests/TestExpectations	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/LayoutTests/TestExpectations	2019-04-03 17:03:59 UTC (rev 243807)
@@ -358,8 +358,6 @@
 webkit.org/b/179608 imported/w3c/web-platform-tests/xhr/send-conditional-cors.htm [ Failure ]
 webkit.org/b/179611 imported/w3c/web-platform-tests/xhr/send-entity-body-document.htm [ Pass Failure ]
 imported/w3c/web-platform-tests/IndexedDB/nested-cloning-large-multiple.html [ Skip ]
-imported/w3c/web-platform-tests/IndexedDB/nested-cloning-large.html [ Skip ]
-imported/w3c/web-platform-tests/IndexedDB/nested-cloning-small.html [ Skip ]
 imported/w3c/web-platform-tests/css/cssom/interfaces.html [ Pass Timeout ]
 [ Debug ] imported/w3c/web-platform-tests/css/cssom-view/interfaces.html [ Skip ]
 webkit.org/b/182292 imported/w3c/web-platform-tests/css/cssom-view/scrollingElement-quirks-dynamic-001.html [ ImageOnlyFailure ]

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (243806 => 243807)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2019-04-03 17:03:59 UTC (rev 243807)
@@ -1,3 +1,16 @@
+2019-04-03  Sihui Liu  <[email protected]>
+
+        Blob type cannot be stored correctly in IDB when IDBObjectStore has autoIncrement and keyPath options
+        https://bugs.webkit.org/show_bug.cgi?id=196128
+
+        Reviewed by Geoffrey Garen.
+
+        Updated test expectations to PASS.
+
+        * web-platform-tests/IndexedDB/nested-cloning-large-expected.txt:
+        * web-platform-tests/IndexedDB/nested-cloning-large-multiple-expected.txt:
+        * web-platform-tests/IndexedDB/nested-cloning-small-expected.txt:
+
 2019-04-02  Chris Dumez  <[email protected]>
 
         HTML Parser: Remove conditional parsing of <noembed> content

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/IndexedDB/nested-cloning-large-expected.txt (243806 => 243807)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/IndexedDB/nested-cloning-large-expected.txt	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/IndexedDB/nested-cloning-large-expected.txt	2019-04-03 17:03:59 UTC (rev 243807)
@@ -1,9 +1,9 @@
 
 PASS large typed array 
 PASS blob with large typed array 
-FAIL blob with large typed array with key generator assert_equals: IndexedDB result class should match put() argument expected "[object Blob]" but got "[object Null]"
+PASS blob with large typed array with key generator 
 PASS array of blobs and large typed arrays 
-FAIL array of blobs and large typed arrays with key generator assert_equals: IndexedDB result class should match put() argument expected "[object Blob]" but got "[object Null]"
+PASS array of blobs and large typed arrays with key generator 
 PASS object with blobs and large typed arrays 
-FAIL object with blobs and large typed arrays with key generator assert_equals: IndexedDB result class should match put() argument expected "[object Blob]" but got "[object Null]"
+PASS object with blobs and large typed arrays with key generator 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/IndexedDB/nested-cloning-large-multiple-expected.txt (243806 => 243807)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/IndexedDB/nested-cloning-large-multiple-expected.txt	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/IndexedDB/nested-cloning-large-multiple-expected.txt	2019-04-03 17:03:59 UTC (rev 243807)
@@ -1,4 +1,4 @@
 
 PASS multiple requests of objects with blobs and large typed arrays 
-FAIL multiple requests of objects with blobs and large typed arrays with key generator assert_equals: IndexedDB result class should match put() argument expected "[object Blob]" but got "[object Null]"
+PASS multiple requests of objects with blobs and large typed arrays with key generator 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/IndexedDB/nested-cloning-small-expected.txt (243806 => 243807)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/IndexedDB/nested-cloning-small-expected.txt	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/IndexedDB/nested-cloning-small-expected.txt	2019-04-03 17:03:59 UTC (rev 243807)
@@ -2,9 +2,9 @@
 PASS small typed array 
 PASS blob 
 PASS blob with small typed array 
-FAIL blob with small typed array with key generator assert_equals: IndexedDB result class should match put() argument expected "[object Blob]" but got "[object Null]"
+PASS blob with small typed array with key generator 
 PASS blob array 
-FAIL blob array with key generator assert_equals: IndexedDB result class should match put() argument expected "[object Blob]" but got "[object Null]"
+PASS blob array with key generator 
 PASS array of blobs and small typed arrays 
-FAIL array of blobs and small typed arrays with key generator assert_equals: IndexedDB result class should match put() argument expected "[object Blob]" but got "[object Null]"
+PASS array of blobs and small typed arrays with key generator 
 

Added: trunk/LayoutTests/storage/indexeddb/modern/objectstore-autoincrement-types-expected.txt (0 => 243807)


--- trunk/LayoutTests/storage/indexeddb/modern/objectstore-autoincrement-types-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/objectstore-autoincrement-types-expected.txt	2019-04-03 17:03:59 UTC (rev 243807)
@@ -0,0 +1,27 @@
+Test IndexedDB's IDBObjectStore auto-increment feature with more types.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB = self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.msIndexedDB || self.OIndexedDB;
+
+indexedDB.deleteDatabase(dbname)
+indexedDB.open(dbname)
+createObjectStore():
+store = db.createObjectStore('Store', {keyPath: 'primaryKey', autoIncrement: true})
+PASS request.result.size is blob.size
+PASS request.result.type is blob.type
+PASS request.result.primaryKey is primaryKey
+PASS request.result.name is file.name
+PASS request.result.lastModified is file.lastModified
+PASS request.result.primaryKey is primaryKey
+PASS request.result.height is imageData.height
+PASS request.result.width is imageData.width
+PASS JSON.stringify(request.result.data) is JSON.stringify(imageData.data)
+PASS request.result.primaryKey is primaryKey
+PASS request.result.length is fileList.length
+PASS request.result.primaryKey is primaryKey
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/storage/indexeddb/modern/objectstore-autoincrement-types.html (0 => 243807)


--- trunk/LayoutTests/storage/indexeddb/modern/objectstore-autoincrement-types.html	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/objectstore-autoincrement-types.html	2019-04-03 17:03:59 UTC (rev 243807)
@@ -0,0 +1,10 @@
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<input id="fileInput" multiple type="file">
+<script src=""
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/storage/indexeddb/modern/resources/objectstore-autoincrement-types.js (0 => 243807)


--- trunk/LayoutTests/storage/indexeddb/modern/resources/objectstore-autoincrement-types.js	                        (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/resources/objectstore-autoincrement-types.js	2019-04-03 17:03:59 UTC (rev 243807)
@@ -0,0 +1,95 @@
+if (this.importScripts) {
+    importScripts('../../../resources/js-test.js');
+    importScripts('shared.js');
+}
+
+description("Test IndexedDB's IDBObjectStore auto-increment feature with more types.");
+
+indexedDBTest(prepareDatabase);
+
+var db;
+var testGenerator;
+function next()
+{
+    testGenerator.next();
+}
+
+function prepareDatabase()
+{
+    db = event.target.result;
+    event.target.transaction._onabort_ = unexpectedAbortCallback;
+
+    debug("createObjectStore():");
+    evalAndLog("store = db.createObjectStore('Store', {keyPath: 'primaryKey', autoIncrement: true})");
+    event.target._onsuccess_ = function() {
+        testGenerator = testSteps();
+        testGenerator.next();
+    };
+}
+
+
+function* testSteps()
+{
+    transaction = db.transaction("Store", "readwrite");
+    objectStore = transaction.objectStore("Store");
+    primaryKey = 1;
+
+    // Blob
+    var imageURL = "data:image/png;base64,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
 kJggg==";
+    const [typePart, partRest] = imageURL.split(',');
+    const contentType = typePart.split(':')[1].split(';')[0];
+    const raw = atob(partRest);
+    const rawLength = raw.length;
+    const uInt8Array = new Uint8Array(rawLength);
+    for (let i = 0; i < rawLength; ++i)
+        uInt8Array[i] = raw.charCodeAt(i);
+    blob = new Blob([uInt8Array], { type: contentType });
+    objectStore.put(blob)._onsuccess_ = next;
+    yield;
+    request = objectStore.get(primaryKey);
+    request._onsuccess_ = next;
+    yield;
+    shouldBe("request.result.size", "blob.size");
+    shouldBe("request.result.type", "blob.type");
+    shouldBe("request.result.primaryKey", "primaryKey");
+    ++ primaryKey;
+
+    // File
+    file = new File([blob], "Filename");
+    objectStore.put(file)._onsuccess_ = next;
+    yield;
+    request = objectStore.get(primaryKey);
+    request._onsuccess_ = next;
+    yield;
+    shouldBe("request.result.name", "file.name");
+    shouldBe("request.result.lastModified", "file.lastModified");
+    shouldBe("request.result.primaryKey", "primaryKey");
+    ++ primaryKey;
+
+    // ImageData
+    canvas = document.createElement('canvas');
+    context = canvas.getContext('2d');
+    imageData = context.createImageData(1, 1);
+    objectStore.put(imageData)._onsuccess_ = next;
+    yield;
+    request = objectStore.get(primaryKey);
+    request._onsuccess_ = next;
+    yield;
+    shouldBe("request.result.height", "imageData.height");
+    shouldBe("request.result.width", "imageData.width");
+    shouldBe("JSON.stringify(request.result.data)", "JSON.stringify(imageData.data)");
+    shouldBe("request.result.primaryKey", "primaryKey");
+    ++ primaryKey;
+
+    // Filelist
+    fileList = document.getElementById("fileInput").files;
+    objectStore.put(fileList)._onsuccess_ = next;
+    yield;
+    request = objectStore.get(primaryKey);
+    request._onsuccess_ = next;
+    yield;
+    shouldBe("request.result.length", "fileList.length");
+    shouldBe("request.result.primaryKey", "primaryKey");
+
+    finishJSTest();
+}
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (243806 => 243807)


--- trunk/Source/WebCore/ChangeLog	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/ChangeLog	2019-04-03 17:03:59 UTC (rev 243807)
@@ -1,3 +1,112 @@
+2019-04-03  Sihui Liu  <[email protected]>
+
+        Blob type cannot be stored correctly in IDB when IDBObjectStore has autoIncrement and keyPath options
+        https://bugs.webkit.org/show_bug.cgi?id=196128
+
+        Reviewed by Geoffrey Garen.
+
+        If a key is auto-generated, it should become a property of the value object. Network process would perform the 
+        key injection by deserializing IDBValue into script value, setting the property, serializing the result and 
+        storing it in a database record. But network process does not have a JSDOMGlobalObject, so it would fail to 
+        deserialize types including Blob and File.
+
+        To solve this issue, we move the key injection to web process and let network process store the original value 
+        it gets. In this case, when web process asks for some value, network process should return key, value and key 
+        path so that web process can decide whether it should perform a key injection before returning the result. Note
+        that the auto-generated key would always be stored as the key in a ObjectStore record.
+
+        Test: storage/indexeddb/modern/objectstore-autoincrement-types.html
+
+        * Modules/indexeddb/IDBCursor.cpp:
+        (WebCore::IDBCursor::setGetResult):
+        * Modules/indexeddb/IDBCursor.h:
+        (WebCore::IDBCursor::primaryKeyPath):
+        * Modules/indexeddb/IDBGetAllResult.cpp:
+        (WebCore::IDBGetAllResult::isolatedCopy):
+        (WebCore::IDBGetAllResult::addKey):
+        (WebCore::IDBGetAllResult::addValue):
+        (WebCore::IDBGetAllResult::keys const):
+        (WebCore::IDBGetAllResult::values const):
+        (WebCore::IDBGetAllResult::allBlobFilePaths const):
+        (WebCore::isolatedCopyOfVariant): Deleted.
+
+        * Modules/indexeddb/IDBGetAllResult.h: Introduce an IDBKeyPath parameter. Also replace Variant with two Vectors,
+        because we only needed to store either key or value before, and now the stored value could be incomplete.
+        (WebCore::IDBGetAllResult::IDBGetAllResult):
+        (WebCore::IDBGetAllResult::keyPath const):
+        (WebCore::IDBGetAllResult::encode const):
+        (WebCore::IDBGetAllResult::decode):
+
+        * Modules/indexeddb/IDBGetResult.cpp:
+        (WebCore::IDBGetResult::setValue):
+        * Modules/indexeddb/IDBGetResult.h:
+        (WebCore::IDBGetResult::IDBGetResult):
+        (WebCore::IDBGetResult::keyPath const):
+        * Modules/indexeddb/IDBObjectStore.cpp:
+        * Modules/indexeddb/IDBRequest.cpp:
+        (WebCore::IDBRequest::setResult):
+        (WebCore::IDBRequest::setResultToStructuredClone):
+        * Modules/indexeddb/IDBRequest.h:
+        * Modules/indexeddb/IDBTransaction.cpp:
+        (WebCore::IDBTransaction::didGetAllRecordsOnServer):
+        (WebCore::IDBTransaction::didGetRecordOnServer):
+        * Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
+        (WebCore::IDBServer::MemoryIDBBackingStore::getRecord):
+        * Modules/indexeddb/server/MemoryIndex.cpp:
+        (WebCore::IDBServer::MemoryIndex::getResultForKeyRange const):
+        (WebCore::IDBServer::MemoryIndex::getAllRecords const):
+        * Modules/indexeddb/server/MemoryIndexCursor.cpp:
+        (WebCore::IDBServer::MemoryIndexCursor::currentData):
+        * Modules/indexeddb/server/MemoryObjectStore.cpp:
+        (WebCore::IDBServer::MemoryObjectStore::updateIndexesForPutRecord):
+        (WebCore::IDBServer::MemoryObjectStore::populateIndexWithExistingRecords):
+        (WebCore::IDBServer::MemoryObjectStore::getAllRecords const):
+        * Modules/indexeddb/server/MemoryObjectStoreCursor.cpp:
+        (WebCore::IDBServer::MemoryObjectStoreCursor::currentData):
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
+        (WebCore::IDBServer::SQLiteIDBBackingStore::updateOneIndexForAddRecord):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::updateAllIndexesForAddRecord):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::getRecord):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::cachedStatementForGetAllObjectStoreRecords):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::getAllObjectStoreRecords):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::getAllIndexRecords):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::getIndexRecord):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::uncheckedGetIndexRecordForOneKey):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::openCursor):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::iterateCursor):
+        * Modules/indexeddb/server/SQLiteIDBCursor.cpp:
+        (WebCore::IDBServer::SQLiteIDBCursor::currentData):
+        * Modules/indexeddb/server/SQLiteIDBCursor.h:
+
+        * Modules/indexeddb/server/UniqueIDBDatabase.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabase::performPutOrAdd): Remove the key injection from network process. 
+        UniqueIDBDatabase stores any value it gets from IDBClient.
+
+        * Modules/indexeddb/shared/IDBResultData.cpp:
+        (WebCore::IDBResultData::getResultRef):
+        * Modules/indexeddb/shared/IDBResultData.h:
+
+        * bindings/js/IDBBindingUtilities.cpp:
+        (WebCore::injectIDBKeyIntoScriptValue): If property is read-only, set would fail and injectKeyIntoResult would
+        return null, but we expect it to return result as long as the property value is the same as target. Therefore, 
+        we can add an early return here.
+        (WebCore::createKeyPathArray):
+
+        (WebCore::generateIndexKeyForValue): We used to generate IndexKey from value stored in database but now the
+        value gets stored does not include auto-generated key, as we remove the key injection from network process. In 
+        this case if the IDBIndex has the same key path as the auto-generated key, IndexKey would be failed to create
+        for it cannot extract auto-generated key from value. Since the auto-generated key would always be the key in 
+        database record, we could use value of that key when we find a match in key path.
+
+        (WebCore::deserializeIDBValueWithKeyInjection): If the key path in the result is single entry, the key is 
+        probably auto-generated, so we could inject the result key into the result value unconditionally.
+
+        * bindings/js/IDBBindingUtilities.h:
+        * bindings/js/JSIDBCursorWithValueCustom.cpp:
+        (WebCore::JSIDBCursorWithValue::value const):
+        * bindings/js/JSIDBRequestCustom.cpp:
+        (WebCore::JSIDBRequest::result const):
+
 2019-04-03  Michael Catanzaro  <[email protected]>
 
         Get rid of HTMLInputElement::setEditingValue

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBCursor.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/IDBCursor.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBCursor.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -341,8 +341,10 @@
     m_primaryKeyData = getResult.primaryKeyData();
     m_primaryKey = m_primaryKeyData.maybeCreateIDBKey();
 
-    if (isKeyCursorWithValue())
+    if (isKeyCursorWithValue()) {
         m_value = getResult.value();
+        m_keyPath = getResult.keyPath();
+    }
 
     m_gotValue = true;
     return true;

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBCursor.h (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/IDBCursor.h	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBCursor.h	2019-04-03 17:03:59 UTC (rev 243807)
@@ -30,6 +30,7 @@
 #include "ExceptionOr.h"
 #include "IDBCursorDirection.h"
 #include "IDBCursorInfo.h"
+#include "IDBKeyPath.h"
 #include "IDBValue.h"
 #include "JSValueInWrappedObject.h"
 #include <_javascript_Core/Strong.h>
@@ -58,6 +59,7 @@
     IDBKey* key() { return m_key.get(); };
     IDBKey* primaryKey() { return m_primaryKey.get(); };
     IDBValue value() { return m_value; };
+    const Optional<IDBKeyPath>& primaryKeyPath() { return m_keyPath; };
     JSValueInWrappedObject& keyWrapper() { return m_keyWrapper; }
     JSValueInWrappedObject& primaryKeyWrapper() { return m_primaryKeyWrapper; }
     JSValueInWrappedObject& valueWrapper() { return m_valueWrapper; }
@@ -104,6 +106,7 @@
     IDBKeyData m_keyData;
     IDBKeyData m_primaryKeyData;
     IDBValue m_value;
+    Optional<IDBKeyPath> m_keyPath;
 
     JSValueInWrappedObject m_keyWrapper;
     JSValueInWrappedObject m_primaryKeyWrapper;

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBGetAllResult.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/IDBGetAllResult.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBGetAllResult.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -28,20 +28,11 @@
 
 #if ENABLE(INDEXED_DATABASE)
 
+#include <wtf/CrossThreadCopier.h>
 #include <wtf/HashSet.h>
 
 namespace WebCore {
 
-template<typename T> void isolatedCopyOfVariant(const WTF::Variant<Vector<IDBKeyData>, Vector<IDBValue>, std::nullptr_t>& source, WTF::Variant<Vector<IDBKeyData>, Vector<IDBValue>, std::nullptr_t>& target)
-{
-    target = Vector<T>();
-    auto& sourceVector = WTF::get<Vector<T>>(source);
-    auto& targetVector = WTF::get<Vector<T>>(target);
-    targetVector.reserveInitialCapacity(sourceVector.size());
-    for (auto& element : sourceVector)
-        targetVector.uncheckedAppend(element.isolatedCopy());
-}
-
 IDBGetAllResult::IDBGetAllResult(const IDBGetAllResult& that, IsolatedCopyTag)
 {
     isolatedCopy(that, *this);
@@ -55,46 +46,29 @@
 void IDBGetAllResult::isolatedCopy(const IDBGetAllResult& source, IDBGetAllResult& destination)
 {
     destination.m_type = source.m_type;
-
-    if (WTF::holds_alternative<std::nullptr_t>(source.m_results))
-        return;
-
-    switch (source.m_type) {
-    case IndexedDB::GetAllType::Keys:
-        isolatedCopyOfVariant<IDBKeyData>(source.m_results, destination.m_results);
-        break;
-    case IndexedDB::GetAllType::Values:
-        isolatedCopyOfVariant<IDBValue>(source.m_results, destination.m_results);
-        break;
-    }
+    destination.m_keys = crossThreadCopy(source.m_keys);
+    destination.m_values = crossThreadCopy(source.m_values);
+    destination.m_keyPath = WebCore::isolatedCopy(source.m_keyPath);
 }
 
 void IDBGetAllResult::addKey(IDBKeyData&& key)
 {
-    ASSERT(m_type == IndexedDB::GetAllType::Keys);
-    ASSERT(WTF::holds_alternative<Vector<IDBKeyData>>(m_results));
-    WTF::get<Vector<IDBKeyData>>(m_results).append(WTFMove(key));
+    m_keys.append(WTFMove(key));
 }
 
 void IDBGetAllResult::addValue(IDBValue&& value)
 {
-    ASSERT(m_type == IndexedDB::GetAllType::Values);
-    ASSERT(WTF::holds_alternative<Vector<IDBValue>>(m_results));
-    WTF::get<Vector<IDBValue>>(m_results).append(WTFMove(value));
+    m_values.append(WTFMove(value));
 }
 
 const Vector<IDBKeyData>& IDBGetAllResult::keys() const
 {
-    ASSERT(m_type == IndexedDB::GetAllType::Keys);
-    ASSERT(WTF::holds_alternative<Vector<IDBKeyData>>(m_results));
-    return WTF::get<Vector<IDBKeyData>>(m_results);
+    return m_keys;
 }
 
 const Vector<IDBValue>& IDBGetAllResult::values() const
 {
-    ASSERT(m_type == IndexedDB::GetAllType::Values);
-    ASSERT(WTF::holds_alternative<Vector<IDBValue>>(m_results));
-    return WTF::get<Vector<IDBValue>>(m_results);
+    return m_values;
 }
 
 Vector<String> IDBGetAllResult::allBlobFilePaths() const
@@ -102,7 +76,7 @@
     ASSERT(m_type == IndexedDB::GetAllType::Values);
 
     HashSet<String> pathSet;
-    for (auto& value : WTF::get<Vector<IDBValue>>(m_results)) {
+    for (auto& value : m_values) {
         for (auto& path : value.blobFilePaths())
             pathSet.add(path);
     }

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBGetAllResult.h (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/IDBGetAllResult.h	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBGetAllResult.h	2019-04-03 17:03:59 UTC (rev 243807)
@@ -28,6 +28,7 @@
 #if ENABLE(INDEXED_DATABASE)
 
 #include "IDBKeyData.h"
+#include "IDBKeyPath.h"
 #include "IDBValue.h"
 #include "IndexedDB.h"
 
@@ -42,17 +43,10 @@
     {
     }
 
-    IDBGetAllResult(IndexedDB::GetAllType type)
+    IDBGetAllResult(IndexedDB::GetAllType type, const Optional<IDBKeyPath>& keyPath)
         : m_type(type)
+        , m_keyPath(keyPath)
     {
-        switch (m_type) {
-        case IndexedDB::GetAllType::Keys:
-            m_results = Vector<IDBKeyData>();
-            break;
-        case IndexedDB::GetAllType::Values:
-            m_results = Vector<IDBValue>();
-            break;
-        }
     }
 
     enum IsolatedCopyTag { IsolatedCopy };
@@ -60,6 +54,7 @@
     IDBGetAllResult isolatedCopy() const;
 
     IndexedDB::GetAllType type() const { return m_type; }
+    const Optional<IDBKeyPath>& keyPath() const { return m_keyPath; }
     const Vector<IDBKeyData>& keys() const;
     const Vector<IDBValue>& values() const;
 
@@ -75,26 +70,15 @@
     static void isolatedCopy(const IDBGetAllResult& source, IDBGetAllResult& destination);
 
     IndexedDB::GetAllType m_type { IndexedDB::GetAllType::Keys };
-    WTF::Variant<Vector<IDBKeyData>, Vector<IDBValue>, std::nullptr_t> m_results { nullptr };
+    Vector<IDBKeyData> m_keys;
+    Vector<IDBValue> m_values;
+    Optional<IDBKeyPath> m_keyPath;
 };
 
 template<class Encoder>
 void IDBGetAllResult::encode(Encoder& encoder) const
 {
-    encoder << m_type << static_cast<uint64_t>(m_results.index());
-
-    switch (m_results.index()) {
-    case 0:
-        encoder << WTF::get<Vector<IDBKeyData>>(m_results);
-        break;
-    case 1:
-        encoder << WTF::get<Vector<IDBValue>>(m_results);
-        break;
-    case 2:
-        break;
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-    }
+    encoder << m_type << m_keys << m_values << m_keyPath;
 }
 
 template<class Decoder>
@@ -103,32 +87,14 @@
     if (!decoder.decode(result.m_type))
         return false;
 
-    uint64_t index;
-    if (!decoder.decode(index))
+    if (!decoder.decode(result.m_keys))
         return false;
 
-    switch (index) {
-    case 0: {
-        result.m_results = Vector<IDBKeyData>();
-        if (!decoder.decode(WTF::get<Vector<IDBKeyData>>(result.m_results)))
-            return false;
-        break;
-    }
-    case 1: {
-        result.m_results = Vector<IDBValue>();
-        Optional<Vector<IDBValue>> optional;
-        decoder >> optional;
-        if (!optional)
-            return false;
-        WTF::get<Vector<IDBValue>>(result.m_results) = WTFMove(*optional);
-        break;
-    }
-    case 2:
-        result.m_results = nullptr;
-        break;
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-    }
+    if (!decoder.decode(result.m_values))
+        return false;
+    
+    if (!decoder.decode(result.m_keyPath))
+        return false;
 
     return true;
 }

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBGetResult.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/IDBGetResult.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBGetResult.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -57,6 +57,11 @@
     destination.m_isDefined = source.m_isDefined;
 }
 
+void IDBGetResult::setValue(IDBValue&& value)
+{
+    m_value = WTFMove(value);
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBGetResult.h (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/IDBGetResult.h	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBGetResult.h	2019-04-03 17:03:59 UTC (rev 243807)
@@ -43,40 +43,11 @@
     {
     }
 
-    IDBGetResult(const IDBValue& value, const IDBKeyData& currentPrimaryKey)
-        : m_value(value)
-        , m_primaryKeyData(currentPrimaryKey)
-    {
-    }
-
-    IDBGetResult(const ThreadSafeDataBuffer& buffer)
-        : m_value(buffer)
-    {
-    }
-
-    IDBGetResult(IDBValue&& buffer)
-        : m_value(WTFMove(buffer))
-    {
-    }
-
-    IDBGetResult(IDBKey& key)
-        : m_keyData(&key)
-    {
-    }
-
     IDBGetResult(const IDBKeyData& keyData)
         : m_keyData(keyData)
     {
     }
 
-    IDBGetResult(SharedBuffer* buffer, IDBKey& key, const IDBKeyPath& path)
-        : m_keyData(&key)
-        , m_keyPath(path)
-    {
-        if (buffer)
-            dataFromBuffer(*buffer);
-    }
-
     IDBGetResult(const IDBKeyData& keyData, const IDBKeyData& primaryKeyData)
         : m_keyData(keyData)
         , m_primaryKeyData(primaryKeyData)
@@ -83,17 +54,25 @@
     {
     }
 
-    IDBGetResult(const IDBKeyData& keyData, const IDBKeyData& primaryKeyData, IDBValue&& value)
+    IDBGetResult(const IDBKeyData& keyData, const ThreadSafeDataBuffer& buffer, const Optional<IDBKeyPath>& keyPath)
+        : m_value(buffer)
+        , m_keyData(keyData)
+        , m_keyPath(keyPath)
+    {
+    }
+
+    IDBGetResult(const IDBKeyData& keyData, IDBValue&& value, const Optional<IDBKeyPath>& keyPath)
         : m_value(WTFMove(value))
         , m_keyData(keyData)
-        , m_primaryKeyData(primaryKeyData)
+        , m_keyPath(keyPath)
     {
     }
 
-    IDBGetResult(const IDBKeyData& keyData, const IDBKeyData& primaryKeyData, const IDBValue& value)
-        : m_value(value)
+    IDBGetResult(const IDBKeyData& keyData, const IDBKeyData& primaryKeyData, IDBValue&& value, const Optional<IDBKeyPath>& keyPath)
+        : m_value(WTFMove(value))
         , m_keyData(keyData)
         , m_primaryKeyData(primaryKeyData)
+        , m_keyPath(keyPath)
     {
     }
 
@@ -102,10 +81,12 @@
 
     IDBGetResult isolatedCopy() const;
 
+    void setValue(IDBValue&&);
+
     const IDBValue& value() const { return m_value; }
     const IDBKeyData& keyData() const { return m_keyData; }
     const IDBKeyData& primaryKeyData() const { return m_primaryKeyData; }
-    const IDBKeyPath& keyPath() const { return m_keyPath; }
+    const Optional<IDBKeyPath>& keyPath() const { return m_keyPath; }
     bool isDefined() const { return m_isDefined; }
 
     template<class Encoder> void encode(Encoder&) const;
@@ -119,7 +100,7 @@
     IDBValue m_value;
     IDBKeyData m_keyData;
     IDBKeyData m_primaryKeyData;
-    IDBKeyPath m_keyPath;
+    Optional<IDBKeyPath> m_keyPath;
     bool m_isDefined { true };
 };
 

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -391,7 +391,7 @@
     m_resultWrapper = { };
 }
 
-void IDBRequest::setResult(const Vector<IDBValue>& values)
+void IDBRequest::setResult(const IDBGetAllResult& result)
 {
     ASSERT(&originThread() == &Thread::current());
 
@@ -401,7 +401,7 @@
 
     VM& vm = context->vm();
     JSLockHolder lock(vm);
-    m_result = values;
+    m_result = result;
     m_resultWrapper = { };
 }
 
@@ -419,7 +419,7 @@
     m_resultWrapper = { };
 }
 
-void IDBRequest::setResultToStructuredClone(const IDBValue& value)
+void IDBRequest::setResultToStructuredClone(const IDBGetResult& result)
 {
     ASSERT(&originThread() == &Thread::current());
 
@@ -431,7 +431,7 @@
 
     VM& vm = context->vm();
     JSLockHolder lock(vm);
-    m_result = value;
+    m_result = result;
     m_resultWrapper = { };
 }
 

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h	2019-04-03 17:03:59 UTC (rev 243807)
@@ -31,6 +31,8 @@
 #include "ExceptionOr.h"
 #include "IDBActiveDOMObject.h"
 #include "IDBError.h"
+#include "IDBGetAllResult.h"
+#include "IDBGetResult.h"
 #include "IDBKeyData.h"
 #include "IDBResourceIdentifier.h"
 #include "IDBValue.h"
@@ -75,7 +77,7 @@
 
     virtual ~IDBRequest();
 
-    using Result = Variant<RefPtr<IDBCursor>, RefPtr<IDBDatabase>, IDBKeyData, Vector<IDBKeyData>, IDBValue, Vector<IDBValue>, uint64_t, NullResultType>;
+    using Result = Variant<RefPtr<IDBCursor>, RefPtr<IDBDatabase>, IDBKeyData, Vector<IDBKeyData>, IDBGetResult, IDBGetAllResult, uint64_t, NullResultType>;
     ExceptionOr<Result> result() const;
     JSValueInWrappedObject& resultWrapper() { return m_resultWrapper; }
     JSValueInWrappedObject& cursorWrapper() { return m_cursorWrapper; }
@@ -106,9 +108,9 @@
 
     void setResult(const IDBKeyData&);
     void setResult(const Vector<IDBKeyData>&);
-    void setResult(const Vector<IDBValue>&);
+    void setResultToStructuredClone(const IDBGetResult&);
+    void setResult(const IDBGetAllResult&);
     void setResult(uint64_t);
-    void setResultToStructuredClone(const IDBValue&);
     void setResultToUndefined();
 
     void willIterateCursor(IDBCursor&);

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -986,7 +986,7 @@
         request.setResult(getAllResult.keys());
         break;
     case IndexedDB::GetAllType::Values:
-        request.setResult(getAllResult.values());
+        request.setResult(getAllResult);
         break;
     }
 
@@ -1090,7 +1090,7 @@
             request.setResultToUndefined();
     } else {
         if (resultData.getResult().value().data().data())
-            request.setResultToStructuredClone(resultData.getResult().value());
+            request.setResultToStructuredClone(resultData.getResult());
         else
             request.setResultToUndefined();
     }

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -363,9 +363,11 @@
         return IDBError { UnknownError, "No backing store object store found"_s };
 
     switch (type) {
-    case IDBGetRecordDataType::KeyAndValue:
-        outValue = objectStore->valueForKeyRange(range);
+    case IDBGetRecordDataType::KeyAndValue: {
+        auto key = objectStore->lowestKeyWithRecordInRange(range);
+        outValue = { key, key.isNull() ? ThreadSafeDataBuffer() : objectStore->valueForKey(key), objectStore->info().keyPath() };
         break;
+    }
     case IDBGetRecordDataType::KeyOnly:
         outValue = objectStore->lowestKeyWithRecordInRange(range);
         break;

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -126,7 +126,7 @@
     if (!keyValue)
         return { };
 
-    return type == IndexedDB::IndexRecordType::Key ? IDBGetResult(*keyValue) : IDBGetResult(m_objectStore.valueForKeyRange(*keyValue));
+    return type == IndexedDB::IndexRecordType::Key ? IDBGetResult(*keyValue) : IDBGetResult(*keyValue, m_objectStore.valueForKeyRange(*keyValue), m_objectStore.info().keyPath());
 }
 
 uint64_t MemoryIndex::countForKeyRange(const IDBKeyRangeData& inRange)
@@ -156,7 +156,7 @@
 {
     LOG(IndexedDB, "MemoryIndex::getAllRecords");
 
-    result = { type };
+    result = { type, m_objectStore.info().keyPath() };
 
     if (!m_records)
         return;
@@ -179,10 +179,8 @@
 
         auto allValues = m_records->allValuesForKey(key, targetCount - currentCount);
         for (auto& keyValue : allValues) {
-            if (type == IndexedDB::GetAllType::Keys) {
-                IDBKeyData keyCopy { keyValue };
-                result.addKey(WTFMove(keyCopy));
-            } else
+            result.addKey(IDBKeyData(keyValue));
+            if (type == IndexedDB::GetAllType::Values)
                 result.addValue(m_objectStore.valueForKeyRange(keyValue));
         }
 

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -75,7 +75,7 @@
         getResult = { m_currentKey, m_currentPrimaryKey };
     else {
         IDBValue value = { m_index.objectStore().valueForKey(m_currentPrimaryKey), { }, { }, { } };
-        getResult = { m_currentKey, m_currentPrimaryKey, WTFMove(value) };
+        getResult = { m_currentKey, m_currentPrimaryKey, WTFMove(value), m_index.objectStore().info().keyPath() };
     }
 }
 

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -310,7 +310,7 @@
 
     for (auto& index : m_indexesByName.values()) {
         IndexKey indexKey;
-        generateIndexKeyForValue(UniqueIDBDatabase::databaseThreadExecState(), index->info(), jsValue, indexKey);
+        generateIndexKeyForValue(UniqueIDBDatabase::databaseThreadExecState(), index->info(), jsValue, indexKey, m_info.keyPath(), key);
 
         if (indexKey.isNull())
             continue;
@@ -344,7 +344,7 @@
             return IDBError { };
 
         IndexKey indexKey;
-        generateIndexKeyForValue(UniqueIDBDatabase::databaseThreadExecState(), index.info(), jsValue, indexKey);
+        generateIndexKeyForValue(UniqueIDBDatabase::databaseThreadExecState(), index.info(), jsValue, indexKey, m_info.keyPath(), iterator.key);
 
         if (indexKey.isNull())
             continue;
@@ -407,7 +407,7 @@
 
 void MemoryObjectStore::getAllRecords(const IDBKeyRangeData& keyRangeData, Optional<uint32_t> count, IndexedDB::GetAllType type, IDBGetAllResult& result) const
 {
-    result = { type };
+    result = { type, m_info.keyPath() };
 
     uint32_t targetCount;
     if (count && count.value())
@@ -424,11 +424,9 @@
 
         range.lowerKey = key;
         range.lowerOpen = true;
-
-        if (type == IndexedDB::GetAllType::Keys)
-            result.addKey(WTFMove(key));
-        else
+        if (type == IndexedDB::GetAllType::Values)
             result.addValue(valueForKey(key));
+        result.addKey(WTFMove(key));
 
         ++currentCount;
     }

Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStoreCursor.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStoreCursor.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStoreCursor.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -194,7 +194,7 @@
         data = { m_currentPositionKey, m_currentPositionKey };
     else {
         IDBValue value = { m_objectStore.valueForKeyRange(m_currentPositionKey), { }, { }, { } };
-        data = { m_currentPositionKey, m_currentPositionKey, WTFMove(value) };
+        data = { m_currentPositionKey, m_currentPositionKey, WTFMove(value), m_objectStore.info().keyPath() };
     }
 }
 

Modified: trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -29,6 +29,7 @@
 #if ENABLE(INDEXED_DATABASE)
 
 #include "IDBBindingUtilities.h"
+#include "IDBCursorInfo.h"
 #include "IDBGetAllRecordsData.h"
 #include "IDBGetAllResult.h"
 #include "IDBGetRecordData.h"
@@ -1752,7 +1753,9 @@
         return IDBError { };
 
     IndexKey indexKey;
-    generateIndexKeyForValue(*m_globalObject->globalExec(), info, jsValue, indexKey);
+    auto* objectStoreInfo = infoForObjectStore(info.objectStoreIdentifier());
+    ASSERT(objectStoreInfo);
+    generateIndexKeyForValue(*m_globalObject->globalExec(), info, jsValue, indexKey, objectStoreInfo->keyPath(), key);
 
     if (indexKey.isNull())
         return IDBError { };
@@ -1772,7 +1775,7 @@
     bool anyRecordsSucceeded = false;
     for (auto& index : info.indexMap().values()) {
         IndexKey indexKey;
-        generateIndexKeyForValue(*m_globalObject->globalExec(), index, jsValue, indexKey);
+        generateIndexKeyForValue(*m_globalObject->globalExec(), index, jsValue, indexKey, info.keyPath(), key);
 
         if (indexKey.isNull())
             continue;
@@ -2004,12 +2007,12 @@
     }
 
     int64_t recordID = 0;
-    ThreadSafeDataBuffer resultBuffer;
+    ThreadSafeDataBuffer keyResultBuffer, valueResultBuffer;
     {
-        static const char* const lowerOpenUpperOpen = "SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
-        static const char* const lowerOpenUpperClosed = "SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
-        static const char* const lowerClosedUpperOpen = "SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
-        static const char* const lowerClosedUpperClosed = "SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
+        static const char* const lowerOpenUpperOpen = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
+        static const char* const lowerOpenUpperClosed = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
+        static const char* const lowerClosedUpperOpen = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
+        static const char* const lowerClosedUpperClosed = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
 
         static const char* const lowerOpenUpperOpenKeyOnly = "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
         static const char* const lowerOpenUpperClosedKeyOnly = "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
@@ -2066,27 +2069,31 @@
             return IDBError { UnknownError, "Error looking up record in object store by key range"_s };
         }
 
-        Vector<uint8_t> buffer;
-        sql->getColumnBlobAsVector(0, buffer);
-        resultBuffer = ThreadSafeDataBuffer::create(WTFMove(buffer));
+        Vector<uint8_t> keyBuffer;
+        sql->getColumnBlobAsVector(0, keyBuffer);
+        keyResultBuffer = ThreadSafeDataBuffer::create(WTFMove(keyBuffer));
 
-        if (type == IDBGetRecordDataType::KeyAndValue)
-            recordID = sql->getColumnInt64(1);
+        if (type == IDBGetRecordDataType::KeyAndValue) {
+            Vector<uint8_t> valueBuffer;
+            sql->getColumnBlobAsVector(1, valueBuffer);
+            valueResultBuffer = ThreadSafeDataBuffer::create(WTFMove(valueBuffer));
+            recordID = sql->getColumnInt64(2);
+        }
     }
 
+    auto* keyVector = keyResultBuffer.data();
+    if (!keyVector) {
+        LOG_ERROR("Unable to deserialize key data from database for IDBObjectStore");
+        return IDBError { UnknownError, "Error extracting key data from database executing IDBObjectStore get"_s };
+    }
+    
+    IDBKeyData keyData;
+    if (!deserializeIDBKeyData(keyVector->data(), keyVector->size(), keyData)) {
+        LOG_ERROR("Unable to deserialize key data from database for IDBObjectStore");
+        return IDBError { UnknownError, "Error extracting key data from database executing IDBObjectStore get"_s };
+    }
+
     if (type == IDBGetRecordDataType::KeyOnly) {
-        auto* vector = resultBuffer.data();
-        if (!vector) {
-            LOG_ERROR("Unable to deserialize key data from database for IDBObjectStore.getKey()");
-            return IDBError { UnknownError, "Error extracting key data from database executing IDBObjectStore.getKey()"_s };
-        }
-
-        IDBKeyData keyData;
-        if (!deserializeIDBKeyData(vector->data(), vector->size(), keyData)) {
-            LOG_ERROR("Unable to deserialize key data from database for IDBObjectStore.getKey()");
-            return IDBError { UnknownError, "Error extracting key data from database executing IDBObjectStore.getKey()"_s };
-        }
-
         resultValue = { keyData };
         return IDBError { };
     }
@@ -2100,7 +2107,9 @@
     if (!error.isNull())
         return error;
 
-    resultValue = { { resultBuffer, WTFMove(blobURLs), sessionID, WTFMove(blobFilePaths) } };
+    auto* objectStoreInfo = infoForObjectStore(objectStoreID);
+    ASSERT(objectStoreInfo);
+    resultValue = { keyData, { valueResultBuffer, WTFMove(blobURLs), sessionID, WTFMove(blobFilePaths) }, objectStoreInfo->keyPath()};
     return IDBError { };
 }
 
@@ -2115,10 +2124,10 @@
     static const char* const lowerOpenUpperClosedKey = "SELECT key FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
     static const char* const lowerClosedUpperOpenKey = "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
     static const char* const lowerClosedUpperClosedKey = "SELECT key FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
-    static const char* const lowerOpenUpperOpenValue = "SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
-    static const char* const lowerOpenUpperClosedValue = "SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
-    static const char* const lowerClosedUpperOpenValue = "SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
-    static const char* const lowerClosedUpperClosedValue = "SELECT value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
+    static const char* const lowerOpenUpperOpenValue = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
+    static const char* const lowerOpenUpperClosedValue = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
+    static const char* const lowerClosedUpperOpenValue = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;";
+    static const char* const lowerClosedUpperClosedValue = "SELECT key, value, ROWID FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;";
 
     if (getAllRecordsData.getAllType == IndexedDB::GetAllType::Keys) {
         if (getAllRecordsData.keyRangeData.lowerOpen) {
@@ -2183,7 +2192,9 @@
         return IDBError { UnknownError, "Failed to look up record in object store by key range"_s };
     }
 
-    result = { getAllRecordsData.getAllType };
+    auto* objectStoreInfo = infoForObjectStore(getAllRecordsData.objectStoreIdentifier);
+    ASSERT(objectStoreInfo);
+    result = { getAllRecordsData.getAllType, objectStoreInfo->keyPath() };
 
     uint32_t targetResults;
     if (getAllRecordsData.count && getAllRecordsData.count.value())
@@ -2195,12 +2206,21 @@
     uint32_t returnedResults = 0;
 
     while (sqlResult == SQLITE_ROW && returnedResults < targetResults) {
+        Vector<uint8_t> keyBuffer;
+        IDBKeyData keyData;
+        sql->getColumnBlobAsVector(0, keyBuffer);
+        if (!deserializeIDBKeyData(keyBuffer.data(), keyBuffer.size(), keyData)) {
+            LOG_ERROR("Unable to deserialize key data from database while getting all records");
+            return IDBError { UnknownError, "Unable to deserialize key data while getting all records"_s };
+        }
+        result.addKey(WTFMove(keyData));
+
         if (getAllRecordsData.getAllType == IndexedDB::GetAllType::Values) {
-            Vector<uint8_t> buffer;
-            sql->getColumnBlobAsVector(0, buffer);
-            ThreadSafeDataBuffer resultBuffer = ThreadSafeDataBuffer::create(WTFMove(buffer));
+            Vector<uint8_t> valueBuffer;
+            sql->getColumnBlobAsVector(1, valueBuffer);
+            ThreadSafeDataBuffer valueResultBuffer = ThreadSafeDataBuffer::create(WTFMove(valueBuffer));
 
-            auto recordID = sql->getColumnInt64(1);
+            auto recordID = sql->getColumnInt64(2);
 
             ASSERT(recordID);
             Vector<String> blobURLs, blobFilePaths;
@@ -2211,18 +2231,7 @@
             if (!error.isNull())
                 return error;
 
-            result.addValue({ resultBuffer, WTFMove(blobURLs), sessionID, WTFMove(blobFilePaths) });
-        } else {
-            Vector<uint8_t> keyData;
-            IDBKeyData key;
-            sql->getColumnBlobAsVector(0, keyData);
-
-            if (!deserializeIDBKeyData(keyData.data(), keyData.size(), key)) {
-                LOG_ERROR("Unable to deserialize key data from database while getting all key records");
-                return IDBError { UnknownError, "Unable to deserialize key data while getting all key records"_s };
-            }
-
-            result.addKey(WTFMove(key));
+            result.addValue({ valueResultBuffer, WTFMove(blobURLs), sessionID, WTFMove(blobFilePaths) });
         }
 
         ++returnedResults;
@@ -2263,16 +2272,18 @@
         return IDBError { UnknownError, "Cursor failed while looking up index records in database"_s };
     }
 
-    result = { getAllRecordsData.getAllType };
+    auto* objectStoreInfo = infoForObjectStore(getAllRecordsData.objectStoreIdentifier);
+    ASSERT(objectStoreInfo);
+    result = { getAllRecordsData.getAllType, objectStoreInfo->keyPath() };
+
     uint32_t currentCount = 0;
     uint32_t targetCount = getAllRecordsData.count ? getAllRecordsData.count.value() : 0;
     if (!targetCount)
         targetCount = std::numeric_limits<uint32_t>::max();
     while (!cursor->didComplete() && !cursor->didError() && currentCount < targetCount) {
-        if (getAllRecordsData.getAllType == IndexedDB::GetAllType::Keys) {
-            IDBKeyData keyCopy = cursor->currentPrimaryKey();
-            result.addKey(WTFMove(keyCopy));
-        } else
+        IDBKeyData keyCopy = cursor->currentPrimaryKey();
+        result.addKey(WTFMove(keyCopy));
+        if (getAllRecordsData.getAllType == IndexedDB::GetAllType::Values)
             result.addValue(cursor->currentValue() ? *cursor->currentValue() : IDBValue());
 
         ++currentCount;
@@ -2319,8 +2330,11 @@
     else {
         if (type == IndexedDB::IndexRecordType::Key)
             getResult = { cursor->currentPrimaryKey() };
-        else
-            getResult = { cursor->currentValue() ? *cursor->currentValue() : IDBValue(), cursor->currentPrimaryKey() };
+        else {
+            auto* objectStoreInfo = infoForObjectStore(objectStoreID);
+            ASSERT(objectStoreInfo);
+            getResult = { cursor->currentPrimaryKey(), cursor->currentPrimaryKey(), cursor->currentValue() ? *cursor->currentValue() : IDBValue(), objectStoreInfo->keyPath() };
+        }
     }
 
     return IDBError { };
@@ -2371,7 +2385,8 @@
         return IDBError { };
     }
 
-    sql->getColumnBlobAsVector(1, keyVector);
+    Vector<uint8_t> valueVector;
+    sql->getColumnBlobAsVector(1, valueVector);
 
     int64_t recordID = sql->getColumnInt64(2);
     Vector<String> blobURLs, blobFilePaths;
@@ -2382,7 +2397,9 @@
     if (!error.isNull())
         return error;
 
-    getResult = { { ThreadSafeDataBuffer::create(WTFMove(keyVector)), WTFMove(blobURLs), sessionID, WTFMove(blobFilePaths) }, objectStoreKey };
+    auto* objectStoreInfo = infoForObjectStore(objectStoreID);
+    ASSERT(objectStoreInfo);
+    getResult = { objectStoreKey, objectStoreKey, { ThreadSafeDataBuffer::create(WTFMove(valueVector)), WTFMove(blobURLs), sessionID, WTFMove(blobFilePaths) }, objectStoreInfo->keyPath() };
     return IDBError { };
 }
 
@@ -2547,7 +2564,9 @@
 
     m_cursors.set(cursor->identifier(), cursor);
 
-    cursor->currentData(result);
+    auto* objectStoreInfo = infoForObjectStore(info.objectStoreIdentifier());
+    ASSERT(objectStoreInfo);
+    cursor->currentData(result, objectStoreInfo->keyPath());
     return IDBError { };
 }
 
@@ -2590,7 +2609,9 @@
         }
     }
 
-    cursor->currentData(result);
+    auto* objectStoreInfo = infoForObjectStore(cursor->objectStoreID());
+    ASSERT(objectStoreInfo);
+    cursor->currentData(result, objectStoreInfo->keyPath());
     return IDBError { };
 }
 

Modified: trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -101,7 +101,7 @@
         m_transaction->closeCursor(*this);
 }
 
-void SQLiteIDBCursor::currentData(IDBGetResult& result)
+void SQLiteIDBCursor::currentData(IDBGetResult& result, const Optional<IDBKeyPath>& keyPath)
 {
     ASSERT(!m_fetchedRecords.isEmpty());
 
@@ -112,7 +112,7 @@
         return;
     }
 
-    result = { currentRecord.record.key, currentRecord.record.primaryKey, currentRecord.record.value ? *currentRecord.record.value : IDBValue() };
+    result = { currentRecord.record.key, currentRecord.record.primaryKey, currentRecord.record.value ? *currentRecord.record.value : IDBValue(), keyPath};
 }
 
 static String buildIndexStatement(const IDBKeyRangeData& keyRange, IndexedDB::CursorDirection cursorDirection)

Modified: trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.h (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.h	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.h	2019-04-03 17:03:59 UTC (rev 243807)
@@ -79,7 +79,7 @@
 
     void objectStoreRecordsChanged();
 
-    void currentData(IDBGetResult&);
+    void currentData(IDBGetResult&, const Optional<IDBKeyPath>&);
 
 private:
     bool establishStatement();

Modified: trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -1251,35 +1251,6 @@
         }
     }
 
-    // 3.4.1.2 Object Store Storage Operation
-    // If ObjectStore has a key path and the key is autogenerated, then inject the key into the value
-    // using steps to assign a key to a value using a key path.
-    ThreadSafeDataBuffer injectedRecordValue;
-    if (usedKeyIsGenerated && objectStoreInfo->keyPath()) {
-        VM& vm = databaseThreadVM();
-        JSLockHolder locker(vm);
-        auto scope = DECLARE_THROW_SCOPE(vm);
-
-        auto value = deserializeIDBValueToJSValue(databaseThreadExecState(), originalRecordValue.data());
-        if (value.isUndefined()) {
-            postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(ConstraintError, "Unable to deserialize record value for record key injection"_s), usedKey));
-            return;
-        }
-
-        if (!injectIDBKeyIntoScriptValue(databaseThreadExecState(), usedKey, value, objectStoreInfo->keyPath().value())) {
-            postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(ConstraintError, "Unable to inject record key into record value"_s), usedKey));
-            return;
-        }
-
-        auto serializedValue = SerializedScriptValue::create(databaseThreadExecState(), value);
-        if (UNLIKELY(scope.exception())) {
-            postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, IDBError(ConstraintError, "Unable to serialize record value after injecting record key"_s), usedKey));
-            return;
-        }
-
-        injectedRecordValue = ThreadSafeDataBuffer::copyVector(serializedValue->data());
-    }
-
     // 3.4.1 Object Store Storage Operation
     // ...If a record already exists in store ...
     // then remove the record from store using the steps for deleting records from an object store...
@@ -1290,10 +1261,7 @@
         return;
     }
 
-    if (injectedRecordValue.data())
-        error = m_backingStore->addRecord(transactionIdentifier, *objectStoreInfo, usedKey, { injectedRecordValue, originalRecordValue.blobURLs(), originalRecordValue.sessionID(), originalRecordValue.blobFilePaths() });
-    else
-        error = m_backingStore->addRecord(transactionIdentifier, *objectStoreInfo, usedKey, originalRecordValue);
+    error = m_backingStore->addRecord(transactionIdentifier, *objectStoreInfo, usedKey, originalRecordValue);
 
     if (!error.isNull()) {
         postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));

Modified: trunk/Source/WebCore/Modules/indexeddb/shared/IDBResultData.cpp (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/shared/IDBResultData.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IDBResultData.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -233,6 +233,12 @@
     return *m_getResult;
 }
 
+IDBGetResult& IDBResultData::getResultRef()
+{
+    RELEASE_ASSERT(m_getResult);
+    return *m_getResult;
+}
+
 const IDBGetAllResult& IDBResultData::getAllResult() const
 {
     RELEASE_ASSERT(m_getAllResult);

Modified: trunk/Source/WebCore/Modules/indexeddb/shared/IDBResultData.h (243806 => 243807)


--- trunk/Source/WebCore/Modules/indexeddb/shared/IDBResultData.h	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IDBResultData.h	2019-04-03 17:03:59 UTC (rev 243807)
@@ -107,6 +107,7 @@
     uint64_t resultInteger() const { return m_resultInteger; }
 
     WEBCORE_EXPORT const IDBGetResult& getResult() const;
+    WEBCORE_EXPORT IDBGetResult& getResultRef();
     WEBCORE_EXPORT const IDBGetAllResult& getAllResult() const;
 
     WEBCORE_EXPORT IDBResultData();

Modified: trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp (243806 => 243807)


--- trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -31,6 +31,7 @@
 
 #include "IDBBindingUtilities.h"
 
+#include "ExceptionCode.h"
 #include "IDBIndexInfo.h"
 #include "IDBKey.h"
 #include "IDBKeyData.h"
@@ -41,6 +42,7 @@
 #include "JSDOMBinding.h"
 #include "JSDOMConvertDate.h"
 #include "JSDOMConvertNullable.h"
+#include "JSDOMExceptionHandling.h"
 #include "JSFile.h"
 #include "Logging.h"
 #include "MessagePort.h"
@@ -324,6 +326,12 @@
     if (!key)
         return false;
 
+    // Do not set if object already has the correct property value.
+    auto jsKey = toJS(exec, *exec.lexicalGlobalObject(), key.get());
+    JSValue existingKey;
+    if (get(exec, parent, keyPathElements.last(), existingKey) && existingKey == jsKey)
+        return true;
+
     if (!set(exec, parent, keyPathElements.last(), toJS(exec, *exec.lexicalGlobalObject(), key.get())))
         return false;
 
@@ -411,9 +419,13 @@
     return toJS(*state, *globalObject, keyData.maybeCreateIDBKey().get());
 }
 
-static Vector<IDBKeyData> createKeyPathArray(ExecState& exec, JSValue value, const IDBIndexInfo& info)
+static Vector<IDBKeyData> createKeyPathArray(ExecState& exec, JSValue value, const IDBIndexInfo& info, Optional<IDBKeyPath> objectStoreKeyPath, const IDBKeyData& objectStoreKey)
 {
     auto visitor = WTF::makeVisitor([&](const String& string) -> Vector<IDBKeyData> {
+        // Value doesn't contain auto-generated key, so we need to manually add key if it is possibly auto-generated.
+        if (objectStoreKeyPath && WTF::holds_alternative<String>(objectStoreKeyPath.value()) && IDBKeyPath(string) == objectStoreKeyPath.value())
+            return { objectStoreKey };
+
         auto idbKey = internalCreateIDBKeyFromScriptValueAndKeyPath(exec, value, string);
         if (!idbKey)
             return { };
@@ -428,10 +440,14 @@
     }, [&](const Vector<String>& vector) -> Vector<IDBKeyData> {
         Vector<IDBKeyData> keys;
         for (auto& entry : vector) {
-            auto key = internalCreateIDBKeyFromScriptValueAndKeyPath(exec, value, entry);
-            if (!key || !key->isValid())
-                return { };
-            keys.append(key.get());
+            if (objectStoreKeyPath && WTF::holds_alternative<String>(objectStoreKeyPath.value()) && IDBKeyPath(entry) == objectStoreKeyPath.value())
+                keys.append(objectStoreKey);
+            else {
+                auto key = internalCreateIDBKeyFromScriptValueAndKeyPath(exec, value, entry);
+                if (!key || !key->isValid())
+                    return { };
+                keys.append(key.get());
+            }
         }
         return keys;
     });
@@ -439,10 +455,9 @@
     return WTF::visit(visitor, info.keyPath());
 }
 
-void generateIndexKeyForValue(ExecState& exec, const IDBIndexInfo& info, JSValue value, IndexKey& outKey)
+void generateIndexKeyForValue(ExecState& exec, const IDBIndexInfo& info, JSValue value, IndexKey& outKey, const Optional<IDBKeyPath>& objectStoreKeyPath, const IDBKeyData& objectStoreKey)
 {
-    auto keyDatas = createKeyPathArray(exec, value, info);
-
+    auto keyDatas = createKeyPathArray(exec, value, info, objectStoreKeyPath, objectStoreKey);
     if (keyDatas.isEmpty())
         return;
 
@@ -449,6 +464,22 @@
     outKey = IndexKey(WTFMove(keyDatas));
 }
 
+Optional<JSC::JSValue> deserializeIDBValueWithKeyInjection(ExecState& state, const IDBValue& value, const IDBKeyData& key, const Optional<IDBKeyPath>& keyPath)
+{
+    auto jsValue = deserializeIDBValueToJSValue(state, value);
+    if (jsValue.isUndefined() || !keyPath || !WTF::holds_alternative<String>(keyPath.value()) || !isIDBKeyPathValid(keyPath.value()))
+        return jsValue;
+
+    JSLockHolder locker(state.vm());
+    if (!injectIDBKeyIntoScriptValue(state, key, jsValue, keyPath.value())) {
+        auto throwScope = DECLARE_THROW_SCOPE(state.vm());
+        propagateException(state, throwScope, Exception(UnknownError, "Cannot inject key into script value"_s));
+        return WTF::nullopt;
+    }
+
+    return jsValue;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)

Modified: trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h (243806 => 243807)


--- trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h	2019-04-03 17:03:59 UTC (rev 243807)
@@ -50,15 +50,17 @@
 bool canInjectIDBKeyIntoScriptValue(JSC::ExecState&, const JSC::JSValue&, const IDBKeyPath&);
 bool injectIDBKeyIntoScriptValue(JSC::ExecState&, const IDBKeyData&, JSC::JSValue, const IDBKeyPath&);
 
-void generateIndexKeyForValue(JSC::ExecState&, const IDBIndexInfo&, JSC::JSValue, IndexKey& outKey);
+void generateIndexKeyForValue(JSC::ExecState&, const IDBIndexInfo&, JSC::JSValue, IndexKey& outKey, const Optional<IDBKeyPath>&, const IDBKeyData&);
 
 Ref<IDBKey> scriptValueToIDBKey(JSC::ExecState&, const JSC::JSValue&);
 
+JSC::JSValue deserializeIDBValueToJSValue(JSC::ExecState&, const IDBValue&, Vector<std::pair<String, String>>&);
 JSC::JSValue deserializeIDBValueToJSValue(JSC::ExecState&, const IDBValue&);
 JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, const IDBValue&);
 JSC::JSValue toJS(JSC::ExecState&, JSC::JSGlobalObject&, IDBKey*);
 JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, const IDBKeyData&);
 
+Optional<JSC::JSValue> deserializeIDBValueWithKeyInjection(JSC::ExecState&, const IDBValue&, const IDBKeyData&, const Optional<IDBKeyPath>&);
 }
 
 #endif // ENABLE(INDEXED_DATABASE)

Modified: trunk/Source/WebCore/bindings/js/JSIDBCursorWithValueCustom.cpp (243806 => 243807)


--- trunk/Source/WebCore/bindings/js/JSIDBCursorWithValueCustom.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/bindings/js/JSIDBCursorWithValueCustom.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -38,7 +38,8 @@
 JSC::JSValue JSIDBCursorWithValue::value(JSC::ExecState& state) const
 {
     return cachedPropertyValue(state, *this, wrapped().valueWrapper(), [&] {
-        return deserializeIDBValueToJSValue(state, wrapped().value());
+        auto result = deserializeIDBValueWithKeyInjection(state, wrapped().value(), wrapped().primaryKey(), wrapped().primaryKeyPath());
+        return result ? result.value() : jsNull();
     });
 }
 

Modified: trunk/Source/WebCore/bindings/js/JSIDBRequestCustom.cpp (243806 => 243807)


--- trunk/Source/WebCore/bindings/js/JSIDBRequestCustom.cpp	2019-04-03 17:00:36 UTC (rev 243806)
+++ trunk/Source/WebCore/bindings/js/JSIDBRequestCustom.cpp	2019-04-03 17:03:59 UTC (rev 243807)
@@ -57,10 +57,21 @@
             return toJS<IDLIDBKeyData>(state, *jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject()), keyData);
         }, [&state] (Vector<IDBKeyData> keyDatas) {
             return toJS<IDLSequence<IDLIDBKeyData>>(state, *jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject()), keyDatas);
-        }, [&state] (IDBValue value) {
-            return toJS<IDLIDBValue>(state, *jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject()), value);
-        }, [&state] (Vector<IDBValue> values) {
-            return toJS<IDLSequence<IDLIDBValue>>(state, *jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject()), values);
+        }, [&state] (IDBGetResult getResult) {
+            auto result = deserializeIDBValueWithKeyInjection(state, getResult.value(), getResult.keyData(), getResult.keyPath());
+            return result ? result.value() : jsNull();
+        }, [&state] (IDBGetAllResult getAllResult) {
+            auto& keys = getAllResult.keys();
+            auto& values = getAllResult.values();
+            auto& keyPath = getAllResult.keyPath();
+            Vector<JSC::JSValue> results;
+            for (unsigned i = 0; i < values.size(); i ++) {
+                auto result = deserializeIDBValueWithKeyInjection(state, values[i], keys[i], keyPath);
+                if (!result)
+                    return jsNull();
+                results.append(result.value());
+            }
+            return JSValue(JSC::constructArray(&state, nullptr, state.lexicalGlobalObject(), results.data(), results.size()));
         }, [] (uint64_t number) {
             return toJS<IDLUnsignedLongLong>(number);
         }, [] (IDBRequest::NullResultType other) {
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to