<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[192294] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/192294">192294</a></dd>
<dt>Author</dt> <dd>beidson@apple.com</dd>
<dt>Date</dt> <dd>2015-11-10 22:07:03 -0800 (Tue, 10 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Modern IDB: Make indexes actually index.
https://bugs.webkit.org/show_bug.cgi?id=150939

Reviewed by Alex Christensen.

Source/WebCore:

Tests: storage/indexeddb/modern/index-1.html
       storage/indexeddb/modern/index-2.html
       storage/indexeddb/modern/index-3.html

* CMakeLists.txt:
* WebCore.xcodeproj/project.pbxproj:

* Modules/indexeddb/IDBKeyData.h:
(WebCore::IDBKeyData::hash): Deleted.

* Modules/indexeddb/IDBKeyRangeData.cpp:
(WebCore::IDBKeyRangeData::isExactlyOneKey):

* Modules/indexeddb/client/IDBTransactionImpl.cpp:
(WebCore::IDBClient::IDBTransaction::didGetRecordOnServer):

* Modules/indexeddb/server/IndexValueEntry.cpp: Copied from Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp.
(WebCore::IDBServer::IndexValueEntry::IndexValueEntry):
(WebCore::IDBServer::IndexValueEntry::~IndexValueEntry):
(WebCore::IDBServer::IndexValueEntry::addKey):
(WebCore::IDBServer::IndexValueEntry::removeKey):
(WebCore::IDBServer::IndexValueEntry::getLowest):
(WebCore::IDBServer::IndexValueEntry::getCount):
* Modules/indexeddb/server/IndexValueEntry.h: Copied from Source/WebCore/Modules/indexeddb/server/MemoryIndex.h.

* Modules/indexeddb/server/IndexValueStore.cpp: Added.
(WebCore::IDBServer::IndexValueStore::IndexValueStore):
(WebCore::IDBServer::IndexValueStore::lowestValueForKey):
(WebCore::IDBServer::IndexValueStore::countForKey):
(WebCore::IDBServer::IndexValueStore::contains):
(WebCore::IDBServer::IndexValueStore::addRecord):
(WebCore::IDBServer::IndexValueStore::removeRecord):
(WebCore::IDBServer::IndexValueStore::removeEntriesWithValueKey):
(WebCore::IDBServer::IndexValueStore::lowestKeyWithRecordInRange):
* Modules/indexeddb/server/IndexValueStore.h: Copied from Source/WebCore/Modules/indexeddb/server/MemoryIndex.h.

* Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp:
(WebCore::IDBServer::MemoryBackingStoreTransaction::objectStoreCleared):
(WebCore::IDBServer::MemoryBackingStoreTransaction::indexCleared):
(WebCore::IDBServer::MemoryBackingStoreTransaction::abort):
* Modules/indexeddb/server/MemoryBackingStoreTransaction.h:

* Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
(WebCore::IDBServer::MemoryIDBBackingStore::addRecord):

* Modules/indexeddb/server/MemoryIndex.cpp:
(WebCore::IDBServer::MemoryIndex::create):
(WebCore::IDBServer::MemoryIndex::MemoryIndex):
(WebCore::IDBServer::MemoryIndex::objectStoreCleared):
(WebCore::IDBServer::MemoryIndex::replaceIndexValueStore):
(WebCore::IDBServer::MemoryIndex::getResultForKeyRange):
(WebCore::IDBServer::MemoryIndex::countForKeyRange):
(WebCore::IDBServer::MemoryIndex::putIndexKey):
(WebCore::IDBServer::MemoryIndex::removeRecord):
(WebCore::IDBServer::MemoryIndex::removeEntriesWithValueKey):
(WebCore::IDBServer::MemoryIndex::valueForKeyRange): Deleted.
* Modules/indexeddb/server/MemoryIndex.h:

* Modules/indexeddb/server/MemoryObjectStore.cpp:
(WebCore::IDBServer::MemoryObjectStore::createIndex):
(WebCore::IDBServer::MemoryObjectStore::clear):
(WebCore::IDBServer::MemoryObjectStore::deleteRecord):
(WebCore::IDBServer::MemoryObjectStore::addRecord):
(WebCore::IDBServer::indexVM):
(WebCore::IDBServer::indexGlobalExec):
(WebCore::IDBServer::MemoryObjectStore::updateIndexesForDeleteRecord):
(WebCore::IDBServer::MemoryObjectStore::updateIndexesForPutRecord):
(WebCore::IDBServer::MemoryObjectStore::indexValueForKeyRange):
* Modules/indexeddb/server/MemoryObjectStore.h:
(WebCore::IDBServer::MemoryObjectStore::writeTransaction):

* Modules/indexeddb/shared/IndexKey.cpp: Copied from Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp.
(WebCore::IndexKey::IndexKey):
(WebCore::IndexKey::isolatedCopy):
(WebCore::IndexKey::asOneKey):
(WebCore::IndexKey::multiEntry):
* Modules/indexeddb/shared/IndexKey.h: Added.
(WebCore::IndexKey::isNull):

* bindings/js/IDBBindingUtilities.cpp:
(WebCore::idbValueDataToJSValue):
(WebCore::deserializeIDBValueBuffer):
(WebCore::idbKeyDataToScriptValue):
(WebCore::createKeyPathArray):
(WebCore::generateIndexKeyForValue):
* bindings/js/IDBBindingUtilities.h:

LayoutTests:

* storage/indexeddb/modern/index-1-expected.txt: Added.
* storage/indexeddb/modern/index-1.html: Added.
* storage/indexeddb/modern/index-2-expected.txt: Added.
* storage/indexeddb/modern/index-2.html: Added.
* storage/indexeddb/modern/index-3-expected.txt: Added.
* storage/indexeddb/modern/index-3.html: Added.
* storage/indexeddb/modern/index-get-count-basic-expected.txt:
* storage/indexeddb/modern/index-get-count-basic.html:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindexgetcountbasicexpectedtxt">trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic-expected.txt</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindexgetcountbasichtml">trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic.html</a></li>
<li><a href="#trunkSourceWebCoreCMakeListstxt">trunk/Source/WebCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbIDBKeyDatah">trunk/Source/WebCore/Modules/indexeddb/IDBKeyData.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbIDBKeyRangeDatacpp">trunk/Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbclientIDBTransactionImplcpp">trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryBackingStoreTransactioncpp">trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryBackingStoreTransactionh">trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryIDBBackingStorecpp">trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryIndexcpp">trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryIndexh">trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryObjectStorecpp">trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryObjectStoreh">trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCorebindingsjsIDBBindingUtilitiescpp">trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp</a></li>
<li><a href="#trunkSourceWebCorebindingsjsIDBBindingUtilitiesh">trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindex1expectedtxt">trunk/LayoutTests/storage/indexeddb/modern/index-1-expected.txt</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindex1html">trunk/LayoutTests/storage/indexeddb/modern/index-1.html</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindex2expectedtxt">trunk/LayoutTests/storage/indexeddb/modern/index-2-expected.txt</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindex2html">trunk/LayoutTests/storage/indexeddb/modern/index-2.html</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindex3expectedtxt">trunk/LayoutTests/storage/indexeddb/modern/index-3-expected.txt</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindex3html">trunk/LayoutTests/storage/indexeddb/modern/index-3.html</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIndexValueEntrycpp">trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIndexValueEntryh">trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIndexValueStorecpp">trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIndexValueStoreh">trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbsharedIndexKeycpp">trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbsharedIndexKeyh">trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/LayoutTests/ChangeLog        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2015-11-10  Brady Eidson  &lt;beidson@apple.com&gt;
+
+        Modern IDB: Make indexes actually index.
+        https://bugs.webkit.org/show_bug.cgi?id=150939
+
+        Reviewed by Alex Christensen.
+
+        * storage/indexeddb/modern/index-1-expected.txt: Added.
+        * storage/indexeddb/modern/index-1.html: Added.
+        * storage/indexeddb/modern/index-2-expected.txt: Added.
+        * storage/indexeddb/modern/index-2.html: Added.
+        * storage/indexeddb/modern/index-3-expected.txt: Added.
+        * storage/indexeddb/modern/index-3.html: Added.
+        * storage/indexeddb/modern/index-get-count-basic-expected.txt:
+        * storage/indexeddb/modern/index-get-count-basic.html:
+
</ins><span class="cx"> 2015-11-10  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Updating test expected results after r192269
</span></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindex1expectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/index-1-expected.txt (0 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-1-expected.txt                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-1-expected.txt        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -0,0 +1,136 @@
</span><ins>+This tests the expected values from some more complex index situations.
+Initial upgrade needed: Old version - 0 New version - 1
+get &quot;good&quot; result is: [object Object]
+bar is good
+baz is bad
+getKey &quot;good&quot; result is: 1
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;ok&quot; result is: [object Object]
+bar is ok
+baz is meh
+getKey &quot;ok&quot; result is: 4
+get &quot;meh&quot; result is: undefined
+getKey &quot;meh&quot; result is: undefined
+get &quot;super&quot; result is: [object Object]
+bar is super
+baz is thanksForAsking
+getKey &quot;super&quot; result is: 7
+get &quot;thanksForAsking&quot; result is: undefined
+getKey &quot;thanksForAsking&quot; result is: undefined
+get &quot;good,bad&quot; result is: undefined
+getKey &quot;good,bad&quot; result is: undefined
+get &quot;ok,meh&quot; result is: undefined
+getKey &quot;ok,meh&quot; result is: undefined
+get &quot;super,thanksForAsking&quot; result is: undefined
+getKey &quot;super,thanksForAsking&quot; result is: undefined
+get &quot;This is to test&quot; result is: undefined
+getKey &quot;This is to test&quot; result is: undefined
+get &quot;multiEntry indexes&quot; result is: undefined
+getKey &quot;multiEntry indexes&quot; result is: undefined
+get &quot;This is to test,multiEntry indexes&quot; result is: [object Object]
+bar is This is to test,multiEntry indexes
+getKey &quot;This is to test,multiEntry indexes&quot; result is: 10
+count result is: 10
+
+get &quot;good&quot; result is: undefined
+getKey &quot;good&quot; result is: undefined
+get &quot;bad&quot; result is: [object Object]
+bar is good
+baz is bad
+getKey &quot;bad&quot; result is: 1
+get &quot;ok&quot; result is: undefined
+getKey &quot;ok&quot; result is: undefined
+get &quot;meh&quot; result is: [object Object]
+bar is ok
+baz is meh
+getKey &quot;meh&quot; result is: 4
+get &quot;super&quot; result is: undefined
+getKey &quot;super&quot; result is: undefined
+get &quot;thanksForAsking&quot; result is: [object Object]
+bar is super
+baz is thanksForAsking
+getKey &quot;thanksForAsking&quot; result is: 7
+get &quot;good,bad&quot; result is: undefined
+getKey &quot;good,bad&quot; result is: undefined
+get &quot;ok,meh&quot; result is: undefined
+getKey &quot;ok,meh&quot; result is: undefined
+get &quot;super,thanksForAsking&quot; result is: undefined
+getKey &quot;super,thanksForAsking&quot; result is: undefined
+get &quot;This is to test&quot; result is: undefined
+getKey &quot;This is to test&quot; result is: undefined
+get &quot;multiEntry indexes&quot; result is: undefined
+getKey &quot;multiEntry indexes&quot; result is: undefined
+get &quot;This is to test,multiEntry indexes&quot; result is: undefined
+getKey &quot;This is to test,multiEntry indexes&quot; result is: undefined
+count result is: 9
+
+get &quot;good&quot; result is: undefined
+getKey &quot;good&quot; result is: undefined
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;ok&quot; result is: undefined
+getKey &quot;ok&quot; result is: undefined
+get &quot;meh&quot; result is: undefined
+getKey &quot;meh&quot; result is: undefined
+get &quot;super&quot; result is: undefined
+getKey &quot;super&quot; result is: undefined
+get &quot;thanksForAsking&quot; result is: undefined
+getKey &quot;thanksForAsking&quot; result is: undefined
+get &quot;good,bad&quot; result is: [object Object]
+bar is good
+baz is bad
+getKey &quot;good,bad&quot; result is: 1
+get &quot;ok,meh&quot; result is: [object Object]
+bar is ok
+baz is meh
+getKey &quot;ok,meh&quot; result is: 4
+get &quot;super,thanksForAsking&quot; result is: [object Object]
+bar is super
+baz is thanksForAsking
+getKey &quot;super,thanksForAsking&quot; result is: 7
+get &quot;This is to test&quot; result is: undefined
+getKey &quot;This is to test&quot; result is: undefined
+get &quot;multiEntry indexes&quot; result is: undefined
+getKey &quot;multiEntry indexes&quot; result is: undefined
+get &quot;This is to test,multiEntry indexes&quot; result is: undefined
+getKey &quot;This is to test,multiEntry indexes&quot; result is: undefined
+count result is: 9
+
+get &quot;good&quot; result is: [object Object]
+bar is good
+baz is bad
+getKey &quot;good&quot; result is: 1
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;ok&quot; result is: [object Object]
+bar is ok
+baz is meh
+getKey &quot;ok&quot; result is: 4
+get &quot;meh&quot; result is: undefined
+getKey &quot;meh&quot; result is: undefined
+get &quot;super&quot; result is: [object Object]
+bar is super
+baz is thanksForAsking
+getKey &quot;super&quot; result is: 7
+get &quot;thanksForAsking&quot; result is: undefined
+getKey &quot;thanksForAsking&quot; result is: undefined
+get &quot;good,bad&quot; result is: undefined
+getKey &quot;good,bad&quot; result is: undefined
+get &quot;ok,meh&quot; result is: undefined
+getKey &quot;ok,meh&quot; result is: undefined
+get &quot;super,thanksForAsking&quot; result is: undefined
+getKey &quot;super,thanksForAsking&quot; result is: undefined
+get &quot;This is to test&quot; result is: [object Object]
+bar is This is to test,multiEntry indexes
+getKey &quot;This is to test&quot; result is: 10
+get &quot;multiEntry indexes&quot; result is: [object Object]
+bar is This is to test,multiEntry indexes
+getKey &quot;multiEntry indexes&quot; result is: 10
+get &quot;This is to test,multiEntry indexes&quot; result is: undefined
+getKey &quot;This is to test,multiEntry indexes&quot; result is: undefined
+count result is: 11
+
+Initial upgrade versionchange transaction complete
+Done
+
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindex1html"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/index-1.html (0 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-1.html                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-1.html        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -0,0 +1,106 @@
</span><ins>+This tests the expected values from some more complex index situations.&lt;br&gt;
+&lt;div id=&quot;logger&quot;&gt;&lt;/div&gt;
+&lt;script&gt;
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+function done()
+{
+    log(&quot;Done&quot;);
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function log(message)
+{
+    document.getElementById(&quot;logger&quot;).innerHTML += message + &quot;&lt;br&gt;&quot;;
+}
+
+var createRequest = window.indexedDB.open(&quot;Index1Database&quot;, 1);
+
+function checkKey(index, key)
+{
+    var request1 = index.get(key);
+    var request2 = index.getKey(key);
+
+    request1.onsuccess = function() {
+        log(&quot;get \&quot;&quot; + key + &quot;\&quot; result is: &quot; + request1.result);
+        for (n in request1.result)
+            log(n + &quot; is &quot; + request1.result[n]);
+    }
+    request2.onsuccess = function() {
+        log(&quot;getKey \&quot;&quot; + key + &quot;\&quot; result is: &quot; + request2.result);
+        for (n in request2.result)
+            log(n + &quot; is &quot; + request2.result[n]);
+    } 
+}
+
+function checkIndex(index)
+{
+    checkKey(index, &quot;good&quot;);
+    checkKey(index, &quot;bad&quot;);
+    checkKey(index, &quot;ok&quot;);
+    checkKey(index, &quot;meh&quot;);
+    checkKey(index, &quot;super&quot;);
+    checkKey(index, &quot;thanksForAsking&quot;);
+    checkKey(index, [ &quot;good&quot;, &quot;bad&quot; ]);
+    checkKey(index, [ &quot;ok&quot;, &quot;meh&quot; ]);
+    checkKey(index, [ &quot;super&quot;, &quot;thanksForAsking&quot; ]);
+    checkKey(index, &quot;This is to test&quot;);
+    checkKey(index, &quot;multiEntry indexes&quot;);
+    checkKey(index, [&quot;This is to test&quot;, &quot;multiEntry indexes&quot; ]);
+    
+    var request = index.count();
+    request.onsuccess = function() {
+        log(&quot;count result is: &quot; + request.result);
+        log(&quot; &quot;);
+    }
+}
+
+createRequest.onupgradeneeded = function(event) {
+    log(&quot;Initial upgrade needed: Old version - &quot; + event.oldVersion + &quot; New version - &quot; + event.newVersion);
+
+    var versionTransaction = createRequest.transaction;
+    var database = event.target.result;
+    var objectStore = database.createObjectStore(&quot;TestObjectStore&quot;);
+    var index1 = objectStore.createIndex(&quot;TestIndex1&quot;, &quot;bar&quot;);
+    var index2 = objectStore.createIndex(&quot;TestIndex2&quot;, &quot;baz&quot;);
+    var index3 = objectStore.createIndex(&quot;TestIndex3&quot;, [ &quot;bar&quot;, &quot;baz&quot; ]);
+    var index4 = objectStore.createIndex(&quot;TestIndex4&quot;, &quot;bar&quot;, { multiEntry: true });
+
+    objectStore.put({ bar: &quot;good&quot;, baz: &quot;bad&quot; }, 1);
+    objectStore.put({ bar: &quot;good&quot;, baz: &quot;bad&quot; }, 2);
+    objectStore.put({ bar: &quot;good&quot;, baz: &quot;bad&quot; }, 3);
+    objectStore.put({ bar: &quot;ok&quot;, baz: &quot;meh&quot; }, 4);
+    objectStore.put({ bar: &quot;ok&quot;, baz: &quot;meh&quot; }, 5);
+    objectStore.put({ bar: &quot;ok&quot;, baz: &quot;meh&quot; }, 6);
+    objectStore.put({ bar: &quot;super&quot;, baz: &quot;thanksForAsking&quot; }, 7);
+    objectStore.put({ bar: &quot;super&quot;, baz: &quot;thanksForAsking&quot; }, 8);
+    objectStore.put({ bar: &quot;super&quot;, baz: &quot;thanksForAsking&quot; }, 9);
+    objectStore.put({ bar: [ &quot;This is to test&quot;, &quot;multiEntry indexes&quot; ]}, 10);
+    
+    checkIndex(index1);
+    checkIndex(index2);
+    checkIndex(index3);
+    checkIndex(index4);
+  
+    versionTransaction.onabort = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected aborted&quot;);
+        done();
+    }
+
+    versionTransaction.oncomplete = function(event) {
+        log(&quot;Initial upgrade versionchange transaction complete&quot;);
+        done();
+    }
+
+    versionTransaction.onerror = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected error&quot; + event);
+        done();
+    }
+}
+
+&lt;/script&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindex2expectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/index-2-expected.txt (0 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-2-expected.txt                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-2-expected.txt        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -0,0 +1,150 @@
</span><ins>+This tests indexes are left in appropriate states after aborted transactions.
+Initial upgrade needed: Old version - 0 New version - 1
+get &quot;good&quot; result is: [object Object]
+bar is good
+baz is bad
+getKey &quot;good&quot; result is: 1
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;multiEntry&quot; result is: undefined
+getKey &quot;multiEntry&quot; result is: undefined
+get &quot;test&quot; result is: undefined
+getKey &quot;test&quot; result is: undefined
+count result is: 2
+
+get &quot;good&quot; result is: undefined
+getKey &quot;good&quot; result is: undefined
+get &quot;bad&quot; result is: [object Object]
+bar is good
+baz is bad
+getKey &quot;bad&quot; result is: 1
+get &quot;multiEntry&quot; result is: undefined
+getKey &quot;multiEntry&quot; result is: undefined
+get &quot;test&quot; result is: undefined
+getKey &quot;test&quot; result is: undefined
+count result is: 1
+
+get &quot;good&quot; result is: [object Object]
+bar is good
+baz is bad
+getKey &quot;good&quot; result is: 1
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;multiEntry&quot; result is: [object Object]
+bar is multiEntry,test
+getKey &quot;multiEntry&quot; result is: 2
+get &quot;test&quot; result is: [object Object]
+bar is multiEntry,test
+getKey &quot;test&quot; result is: 2
+count result is: 3
+
+Initial upgrade versionchange transaction complete
+Deleted key 1 from objectstore
+
+get &quot;good&quot; result is: undefined
+getKey &quot;good&quot; result is: undefined
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;multiEntry&quot; result is: undefined
+getKey &quot;multiEntry&quot; result is: undefined
+get &quot;test&quot; result is: undefined
+getKey &quot;test&quot; result is: undefined
+count result is: 1
+
+get &quot;good&quot; result is: undefined
+getKey &quot;good&quot; result is: undefined
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;multiEntry&quot; result is: undefined
+getKey &quot;multiEntry&quot; result is: undefined
+get &quot;test&quot; result is: undefined
+getKey &quot;test&quot; result is: undefined
+count result is: 0
+
+get &quot;good&quot; result is: undefined
+getKey &quot;good&quot; result is: undefined
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;multiEntry&quot; result is: [object Object]
+bar is multiEntry,test
+getKey &quot;multiEntry&quot; result is: 2
+get &quot;test&quot; result is: [object Object]
+bar is multiEntry,test
+getKey &quot;test&quot; result is: 2
+count result is: 2
+
+Cleared objectstore
+
+get &quot;good&quot; result is: undefined
+getKey &quot;good&quot; result is: undefined
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;multiEntry&quot; result is: undefined
+getKey &quot;multiEntry&quot; result is: undefined
+get &quot;test&quot; result is: undefined
+getKey &quot;test&quot; result is: undefined
+count result is: 0
+
+get &quot;good&quot; result is: undefined
+getKey &quot;good&quot; result is: undefined
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;multiEntry&quot; result is: undefined
+getKey &quot;multiEntry&quot; result is: undefined
+get &quot;test&quot; result is: undefined
+getKey &quot;test&quot; result is: undefined
+count result is: 0
+
+get &quot;good&quot; result is: undefined
+getKey &quot;good&quot; result is: undefined
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;multiEntry&quot; result is: undefined
+getKey &quot;multiEntry&quot; result is: undefined
+get &quot;test&quot; result is: undefined
+getKey &quot;test&quot; result is: undefined
+count result is: 0
+
+All done. Moving on to final part
+readwrite transaction aborted
+get &quot;good&quot; result is: [object Object]
+bar is good
+baz is bad
+getKey &quot;good&quot; result is: 1
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;multiEntry&quot; result is: undefined
+getKey &quot;multiEntry&quot; result is: undefined
+get &quot;test&quot; result is: undefined
+getKey &quot;test&quot; result is: undefined
+count result is: 2
+
+get &quot;good&quot; result is: undefined
+getKey &quot;good&quot; result is: undefined
+get &quot;bad&quot; result is: [object Object]
+bar is good
+baz is bad
+getKey &quot;bad&quot; result is: 1
+get &quot;multiEntry&quot; result is: undefined
+getKey &quot;multiEntry&quot; result is: undefined
+get &quot;test&quot; result is: undefined
+getKey &quot;test&quot; result is: undefined
+count result is: 1
+
+get &quot;good&quot; result is: [object Object]
+bar is good
+baz is bad
+getKey &quot;good&quot; result is: 1
+get &quot;bad&quot; result is: undefined
+getKey &quot;bad&quot; result is: undefined
+get &quot;multiEntry&quot; result is: [object Object]
+bar is multiEntry,test
+getKey &quot;multiEntry&quot; result is: 2
+get &quot;test&quot; result is: [object Object]
+bar is multiEntry,test
+getKey &quot;test&quot; result is: 2
+count result is: 3
+
+readwrite transaction complete
+Done
+
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindex2html"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/index-2.html (0 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-2.html                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-2.html        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -0,0 +1,165 @@
</span><ins>+This tests indexes are left in appropriate states after aborted transactions.&lt;br&gt;
+&lt;div id=&quot;logger&quot;&gt;&lt;/div&gt;
+&lt;script&gt;
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+function done()
+{
+    log(&quot;Done&quot;);
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function log(message)
+{
+    document.getElementById(&quot;logger&quot;).innerHTML += message + &quot;&lt;br&gt;&quot;;
+}
+
+var createRequest = window.indexedDB.open(&quot;Index2Database&quot;, 1);
+
+function checkKey(index, key)
+{
+    var request1 = index.get(key);
+    var request2 = index.getKey(key);
+
+    request1.onsuccess = function() {
+        log(&quot;get \&quot;&quot; + key + &quot;\&quot; result is: &quot; + request1.result);
+        for (n in request1.result)
+            log(n + &quot; is &quot; + request1.result[n]);
+    }
+    request2.onsuccess = function() {
+        log(&quot;getKey \&quot;&quot; + key + &quot;\&quot; result is: &quot; + request2.result);
+        for (n in request2.result)
+            log(n + &quot; is &quot; + request2.result[n]);
+    } 
+}
+
+function checkIndex(index)
+{
+    checkKey(index, &quot;good&quot;);
+    checkKey(index, &quot;bad&quot;);
+    checkKey(index, &quot;multiEntry&quot;);
+    checkKey(index, &quot;test&quot;);
+    
+    var request = index.count();
+    request.onsuccess = function() {
+        log(&quot;count result is: &quot; + request.result);
+        log(&quot; &quot;);
+    }
+}
+
+var database;
+
+createRequest.onupgradeneeded = function(event) {
+    log(&quot;Initial upgrade needed: Old version - &quot; + event.oldVersion + &quot; New version - &quot; + event.newVersion);
+
+    var versionTransaction = createRequest.transaction;
+    database = event.target.result;
+    var objectStore = database.createObjectStore(&quot;TestObjectStore&quot;);
+    var index1 = objectStore.createIndex(&quot;TestIndex1&quot;, &quot;bar&quot;);
+    var index2 = objectStore.createIndex(&quot;TestIndex2&quot;, &quot;baz&quot;);
+    var index3 = objectStore.createIndex(&quot;TestIndex3&quot;, &quot;bar&quot;, { multiEntry: true });
+
+    objectStore.put({ bar: &quot;good&quot;, baz: &quot;bad&quot; }, 1);
+    objectStore.put({ bar: [ &quot;multiEntry&quot;, &quot;test&quot; ]}, 2);
+    
+    checkIndex(index1);
+    checkIndex(index2);
+    checkIndex(index3);
+
+    versionTransaction.onabort = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected abort&quot;);
+        done();
+    }
+
+    versionTransaction.oncomplete = function(event) {
+        log(&quot;Initial upgrade versionchange transaction complete&quot;);
+        continueTest1();
+    }
+
+    versionTransaction.onerror = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected error&quot; + event);
+        done();
+    }
+}
+
+function continueTest1()
+{   
+    var transaction = database.transaction(&quot;TestObjectStore&quot;, &quot;readwrite&quot;);
+    var objectStore = transaction.objectStore(&quot;TestObjectStore&quot;);
+    var index1 = objectStore.index(&quot;TestIndex1&quot;);
+    var index2 = objectStore.index(&quot;TestIndex2&quot;);
+    var index3 = objectStore.index(&quot;TestIndex3&quot;);
+    
+    objectStore.delete(1).onsuccess = function() {
+       log(&quot;Deleted key 1 from objectstore&quot;);
+       log(&quot;&quot;);
+    }
+
+    checkIndex(index1);
+    checkIndex(index2);
+    checkIndex(index3);
+
+    objectStore.clear().onsuccess = function() {
+       log(&quot;Cleared objectstore&quot;);
+       log(&quot;&quot;);
+    }
+    
+    checkIndex(index1);
+    checkIndex(index2);
+    checkIndex(index3);
+    
+    objectStore.get(0).onsuccess = function() {
+        log(&quot;All done. Moving on to final part&quot;);
+        transaction.abort();
+    }
+    
+    transaction.onabort = function(event) {
+        log(&quot;readwrite transaction aborted&quot;);
+        continueTest2();
+    }
+
+    transaction.oncomplete = function(event) {
+        log(&quot;readwrite transaction unexpected complete&quot;);
+        done();
+    }
+
+    transaction.onerror = function(event) {
+        log(&quot;readwrite transaction unexpected error&quot;);
+        done();
+    }
+}
+
+function continueTest2()
+{   
+    var transaction = database.transaction(&quot;TestObjectStore&quot;, &quot;readonly&quot;);
+    var objectStore = transaction.objectStore(&quot;TestObjectStore&quot;);
+    var index1 = objectStore.index(&quot;TestIndex1&quot;);
+    var index2 = objectStore.index(&quot;TestIndex2&quot;);
+    var index3 = objectStore.index(&quot;TestIndex3&quot;);
+    
+    checkIndex(index1);
+    checkIndex(index2);
+    checkIndex(index3);
+    
+    transaction.onabort = function(event) {
+        log(&quot;readwrite transaction unexpected abort&quot;);
+        done();
+    }
+
+    transaction.oncomplete = function(event) {
+        log(&quot;readwrite transaction complete&quot;);
+        done();
+    }
+
+    transaction.onerror = function(event) {
+        log(&quot;readwrite transaction unexpected error&quot;);
+        done();
+    }
+}
+
+&lt;/script&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindex3expectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/index-3-expected.txt (0 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-3-expected.txt                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-3-expected.txt        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+This test exercises the &quot;unique&quot; constraint of indexes.
+Initial upgrade needed: Old version - 0 New version - 1
+First put success
+Value of 1 is: [object Object]
+Value of 2 is: undefined
+Value of 3 is: undefined
+Count in index 1 is: 1
+Count in index 2 is: 1
+Second put failure
+Value of 1 is: [object Object]
+Value of 2 is: undefined
+Value of 3 is: undefined
+Count in index 1 is: 1
+Count in index 2 is: 1
+Third put failure
+Value of 1 is: [object Object]
+Value of 2 is: undefined
+Value of 3 is: undefined
+Count in index 1 is: 1
+Count in index 2 is: 1
+Initial upgrade versionchange transaction complete
+Done
+
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindex3html"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/index-3.html (0 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-3.html                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-3.html        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -0,0 +1,115 @@
</span><ins>+This test exercises the &quot;unique&quot; constraint of indexes.&lt;br&gt;
+&lt;div id=&quot;logger&quot;&gt;&lt;/div&gt;
+&lt;script&gt;
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+function done()
+{
+    log(&quot;Done&quot;);
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function log(message)
+{
+    document.getElementById(&quot;logger&quot;).innerHTML += message + &quot;&lt;br&gt;&quot;;
+}
+
+var createRequest = window.indexedDB.open(&quot;Index3Database&quot;, 1);
+var objectStore;
+
+function checkObjectStore()
+{
+    var req1 = objectStore.get(1);
+    req1.onsuccess = function() {
+        log(&quot;Value of 1 is: &quot; + req1.result);
+    }
+    var req2 = objectStore.get(2);
+    req2.onsuccess = function() {
+        log(&quot;Value of 2 is: &quot; + req2.result);
+    }
+    var req3 = objectStore.get(3);
+    req3.onsuccess = function() {
+        log(&quot;Value of 3 is: &quot; + req3.result);
+    }
+}
+
+function checkIndex(index, name)
+{
+    var req = index.count();
+    req.onsuccess = function() {
+        log(&quot;Count in index &quot; + name + &quot; is: &quot; + req.result);
+    }
+}
+
+createRequest.onupgradeneeded = function(event) {
+    log(&quot;Initial upgrade needed: Old version - &quot; + event.oldVersion + &quot; New version - &quot; + event.newVersion);
+
+    var versionTransaction = createRequest.transaction;
+    var database = event.target.result;
+    objectStore = database.createObjectStore(&quot;TestObjectStore&quot;);
+    var i1 = objectStore.createIndex(&quot;TestIndex1&quot;, &quot;bar&quot;, { unique: true });
+    var i2 = objectStore.createIndex(&quot;TestIndex2&quot;, &quot;bar&quot;, { multiEntry: true, unique: true });
+
+    var request1 = objectStore.put({ bar: &quot;good&quot;, baz: &quot;bad&quot; }, 1);
+    request1.onsuccess = function() {
+        log(&quot;First put success&quot;);
+    }
+    request1.onerror = function() {
+        log(&quot;First put unexpected failure&quot;);
+        done();
+    }
+    
+    checkObjectStore();
+    checkIndex(i1, 1);
+    checkIndex(i2, 2);
+    
+    var request2 = objectStore.put({ bar: &quot;good&quot;, baz: &quot;bad&quot; }, 2);
+    request2.onsuccess = function() {
+        log(&quot;Second put unexpected success&quot;);
+        done();
+    }
+    request2.onerror = function(e) {
+        log(&quot;Second put failure&quot;);
+        e.stopPropagation();
+    }
+    
+    checkObjectStore();
+    checkIndex(i1, 1);
+    checkIndex(i2, 2);
+    
+    var request3 = objectStore.put({ bar: [ &quot;gnarly&quot;, &quot;great&quot;, &quot;good&quot; ]}, 3);
+    request3.onsuccess = function() {
+        log(&quot;Third put unexpected success&quot;);
+        done();
+    }
+    request3.onerror = function(e) {
+        log(&quot;Third put failure&quot;);
+        e.stopPropagation();
+    }
+    
+    checkObjectStore();
+    checkIndex(i1, 1);
+    checkIndex(i2, 2);
+    
+    versionTransaction.onabort = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected aborted&quot;);
+        done();
+    }
+
+    versionTransaction.oncomplete = function(event) {
+        log(&quot;Initial upgrade versionchange transaction complete&quot;);
+        done();
+    }
+
+    versionTransaction.onerror = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected error&quot; + event);
+        done();
+    }
+}
+
+&lt;/script&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindexgetcountbasicexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic-expected.txt (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic-expected.txt        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic-expected.txt        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -1,9 +1,10 @@
</span><del>-ALERT: Initial upgrade needed: Old version - 0 New version - 1
-ALERT: get result is: undefined
-ALERT: getKey result is: undefined
-ALERT: count result is: 0
-ALERT: Initial upgrade versionchange transaction complete
-ALERT: Done
</del><span class="cx"> This tests the most basic operation of the IDBIndex methods get(), getKey(), and count().
</span><del>-It doesn't actually do anything other than exercise the requests themselves because we don't actually index yet.
</del><ins>+Initial upgrade needed: Old version - 0 New version - 1
+get result is: [object Object]
+bar is good
+baz is bad
+getKey result is: foo
+count result is: 1
+Initial upgrade versionchange transaction complete
+Done
</ins><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindexgetcountbasichtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic.html (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic.html        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-get-count-basic.html        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -1,5 +1,4 @@
</span><span class="cx"> This tests the most basic operation of the IDBIndex methods get(), getKey(), and count().&lt;br&gt;
</span><del>-It doesn't actually do anything other than exercise the requests themselves because we don't actually index yet.&lt;br&gt;
</del><span class="cx"> &lt;div id=&quot;logger&quot;&gt;&lt;/div&gt;
</span><span class="cx"> &lt;script&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -10,12 +9,12 @@
</span><span class="cx"> 
</span><span class="cx"> function done()
</span><span class="cx"> {
</span><del>-    alert(&quot;Done&quot;);
</del><ins>+    log(&quot;Done&quot;);
</ins><span class="cx">     if (window.testRunner)
</span><span class="cx">         testRunner.notifyDone();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-function gol(message)
</del><ins>+function log(message)
</ins><span class="cx"> {
</span><span class="cx">     document.getElementById(&quot;logger&quot;).innerHTML += message + &quot;&lt;br&gt;&quot;;
</span><span class="cx"> }
</span><span class="lines">@@ -23,42 +22,44 @@
</span><span class="cx"> var createRequest = window.indexedDB.open(&quot;IndexGetCountBasicDatabase&quot;, 1);
</span><span class="cx"> 
</span><span class="cx"> createRequest.onupgradeneeded = function(event) {
</span><del>-    alert(&quot;Initial upgrade needed: Old version - &quot; + event.oldVersion + &quot; New version - &quot; + event.newVersion);
</del><ins>+    log(&quot;Initial upgrade needed: Old version - &quot; + event.oldVersion + &quot; New version - &quot; + event.newVersion);
</ins><span class="cx"> 
</span><span class="cx">     var versionTransaction = createRequest.transaction;
</span><span class="cx">     var database = event.target.result;
</span><span class="cx">     var objectStore = database.createObjectStore(&quot;TestObjectStore&quot;);
</span><del>-    var index = objectStore.createIndex(&quot;TestIndex&quot;, &quot;foo&quot;);
</del><ins>+    var index = objectStore.createIndex(&quot;TestIndex&quot;, &quot;bar&quot;);
</ins><span class="cx"> 
</span><del>-    objectStore.put(&quot;bar&quot;, &quot;foo&quot;);
</del><ins>+    objectStore.put({ bar: &quot;good&quot;, baz: &quot;bad&quot; }, &quot;foo&quot;);
</ins><span class="cx">     
</span><del>-    var request1 = index.get(&quot;bar&quot;);
</del><ins>+    var request1 = index.get(&quot;good&quot;);
</ins><span class="cx">     request1.onsuccess = function() {
</span><del>-        alert(&quot;get result is: &quot; + request1.result);
</del><ins>+        log(&quot;get result is: &quot; + request1.result);
+        for (n in request1.result)
+            log(n + &quot; is &quot; + request1.result[n]);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    request2 = index.getKey(&quot;bar&quot;);
</del><ins>+    request2 = index.getKey(&quot;good&quot;);
</ins><span class="cx">     request2.onsuccess = function() {
</span><del>-        alert(&quot;getKey result is: &quot; + request2.result);
</del><ins>+        log(&quot;getKey result is: &quot; + request2.result);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     var request3 = index.count();
</span><span class="cx">     request3.onsuccess = function() {
</span><del>-        alert(&quot;count result is: &quot; + request3.result);
</del><ins>+        log(&quot;count result is: &quot; + request3.result);
</ins><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     versionTransaction.onabort = function(event) {
</span><del>-        alert(&quot;Initial upgrade versionchange transaction unexpected aborted&quot;);
</del><ins>+        log(&quot;Initial upgrade versionchange transaction unexpected aborted&quot;);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     versionTransaction.oncomplete = function(event) {
</span><del>-        alert(&quot;Initial upgrade versionchange transaction complete&quot;);
</del><ins>+        log(&quot;Initial upgrade versionchange transaction complete&quot;);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     versionTransaction.onerror = function(event) {
</span><del>-        alert(&quot;Initial upgrade versionchange transaction unexpected error&quot; + event);
</del><ins>+        log(&quot;Initial upgrade versionchange transaction unexpected error&quot; + event);
</ins><span class="cx">         done();
</span><span class="cx">     }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/CMakeLists.txt (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/CMakeLists.txt        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/CMakeLists.txt        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -902,6 +902,8 @@
</span><span class="cx">     Modules/indexeddb/server/IDBConnectionToClient.cpp
</span><span class="cx">     Modules/indexeddb/server/IDBServer.cpp
</span><span class="cx">     Modules/indexeddb/server/IDBServerOperation.cpp
</span><ins>+    Modules/indexeddb/server/IndexValueEntry.cpp
+    Modules/indexeddb/server/IndexValueStore.cpp
</ins><span class="cx">     Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp
</span><span class="cx">     Modules/indexeddb/server/MemoryIDBBackingStore.cpp
</span><span class="cx">     Modules/indexeddb/server/MemoryIndex.cpp
</span><span class="lines">@@ -919,6 +921,7 @@
</span><span class="cx">     Modules/indexeddb/shared/IDBResultData.cpp
</span><span class="cx">     Modules/indexeddb/shared/IDBTransactionInfo.cpp
</span><span class="cx">     Modules/indexeddb/shared/InProcessIDBServer.cpp
</span><ins>+    Modules/indexeddb/shared/IndexKey.cpp
</ins><span class="cx"> 
</span><span class="cx">     Modules/mediacontrols/MediaControlsHost.cpp
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/ChangeLog        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -1,3 +1,97 @@
</span><ins>+2015-11-10  Brady Eidson  &lt;beidson@apple.com&gt;
+
+        Modern IDB: Make indexes actually index.
+        https://bugs.webkit.org/show_bug.cgi?id=150939
+
+        Reviewed by Alex Christensen.
+
+        Tests: storage/indexeddb/modern/index-1.html
+               storage/indexeddb/modern/index-2.html
+               storage/indexeddb/modern/index-3.html
+
+        * CMakeLists.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+
+        * Modules/indexeddb/IDBKeyData.h:
+        (WebCore::IDBKeyData::hash): Deleted.
+
+        * Modules/indexeddb/IDBKeyRangeData.cpp:
+        (WebCore::IDBKeyRangeData::isExactlyOneKey):
+
+        * Modules/indexeddb/client/IDBTransactionImpl.cpp:
+        (WebCore::IDBClient::IDBTransaction::didGetRecordOnServer):
+
+        * Modules/indexeddb/server/IndexValueEntry.cpp: Copied from Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp.
+        (WebCore::IDBServer::IndexValueEntry::IndexValueEntry):
+        (WebCore::IDBServer::IndexValueEntry::~IndexValueEntry):
+        (WebCore::IDBServer::IndexValueEntry::addKey):
+        (WebCore::IDBServer::IndexValueEntry::removeKey):
+        (WebCore::IDBServer::IndexValueEntry::getLowest):
+        (WebCore::IDBServer::IndexValueEntry::getCount):
+        * Modules/indexeddb/server/IndexValueEntry.h: Copied from Source/WebCore/Modules/indexeddb/server/MemoryIndex.h.
+
+        * Modules/indexeddb/server/IndexValueStore.cpp: Added.
+        (WebCore::IDBServer::IndexValueStore::IndexValueStore):
+        (WebCore::IDBServer::IndexValueStore::lowestValueForKey):
+        (WebCore::IDBServer::IndexValueStore::countForKey):
+        (WebCore::IDBServer::IndexValueStore::contains):
+        (WebCore::IDBServer::IndexValueStore::addRecord):
+        (WebCore::IDBServer::IndexValueStore::removeRecord):
+        (WebCore::IDBServer::IndexValueStore::removeEntriesWithValueKey):
+        (WebCore::IDBServer::IndexValueStore::lowestKeyWithRecordInRange):
+        * Modules/indexeddb/server/IndexValueStore.h: Copied from Source/WebCore/Modules/indexeddb/server/MemoryIndex.h.
+
+        * Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp:
+        (WebCore::IDBServer::MemoryBackingStoreTransaction::objectStoreCleared):
+        (WebCore::IDBServer::MemoryBackingStoreTransaction::indexCleared):
+        (WebCore::IDBServer::MemoryBackingStoreTransaction::abort):
+        * Modules/indexeddb/server/MemoryBackingStoreTransaction.h:
+
+        * Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
+        (WebCore::IDBServer::MemoryIDBBackingStore::addRecord):
+
+        * Modules/indexeddb/server/MemoryIndex.cpp:
+        (WebCore::IDBServer::MemoryIndex::create):
+        (WebCore::IDBServer::MemoryIndex::MemoryIndex):
+        (WebCore::IDBServer::MemoryIndex::objectStoreCleared):
+        (WebCore::IDBServer::MemoryIndex::replaceIndexValueStore):
+        (WebCore::IDBServer::MemoryIndex::getResultForKeyRange):
+        (WebCore::IDBServer::MemoryIndex::countForKeyRange):
+        (WebCore::IDBServer::MemoryIndex::putIndexKey):
+        (WebCore::IDBServer::MemoryIndex::removeRecord):
+        (WebCore::IDBServer::MemoryIndex::removeEntriesWithValueKey):
+        (WebCore::IDBServer::MemoryIndex::valueForKeyRange): Deleted.
+        * Modules/indexeddb/server/MemoryIndex.h:
+
+        * Modules/indexeddb/server/MemoryObjectStore.cpp:
+        (WebCore::IDBServer::MemoryObjectStore::createIndex):
+        (WebCore::IDBServer::MemoryObjectStore::clear):
+        (WebCore::IDBServer::MemoryObjectStore::deleteRecord):
+        (WebCore::IDBServer::MemoryObjectStore::addRecord):
+        (WebCore::IDBServer::indexVM):
+        (WebCore::IDBServer::indexGlobalExec):
+        (WebCore::IDBServer::MemoryObjectStore::updateIndexesForDeleteRecord):
+        (WebCore::IDBServer::MemoryObjectStore::updateIndexesForPutRecord):
+        (WebCore::IDBServer::MemoryObjectStore::indexValueForKeyRange):
+        * Modules/indexeddb/server/MemoryObjectStore.h:
+        (WebCore::IDBServer::MemoryObjectStore::writeTransaction):
+
+        * Modules/indexeddb/shared/IndexKey.cpp: Copied from Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp.
+        (WebCore::IndexKey::IndexKey):
+        (WebCore::IndexKey::isolatedCopy):
+        (WebCore::IndexKey::asOneKey):
+        (WebCore::IndexKey::multiEntry):
+        * Modules/indexeddb/shared/IndexKey.h: Added.
+        (WebCore::IndexKey::isNull):
+
+        * bindings/js/IDBBindingUtilities.cpp:
+        (WebCore::idbValueDataToJSValue):
+        (WebCore::deserializeIDBValueBuffer):
+        (WebCore::idbKeyDataToScriptValue):
+        (WebCore::createKeyPathArray):
+        (WebCore::generateIndexKeyForValue):
+        * bindings/js/IDBBindingUtilities.h:
+
</ins><span class="cx"> 2015-11-10  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Move locale information into FontDescription
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbIDBKeyDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/IDBKeyData.h (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/IDBKeyData.h        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBKeyData.h        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -122,9 +122,6 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        unsigned targetSize = WTF::roundUpToPowerOfTwo(hashCodes.size());
-        hashCodes.resize(targetSize);
-
</del><span class="cx">         return StringHasher::hashMemory(hashCodes.data(), hashCodes.size() * sizeof(unsigned));
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbIDBKeyRangeDatacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -73,7 +73,7 @@
</span><span class="cx"> 
</span><span class="cx"> bool IDBKeyRangeData::isExactlyOneKey() const
</span><span class="cx"> {
</span><del>-    if (isNull || lowerOpen || upperOpen)
</del><ins>+    if (isNull || lowerOpen || upperOpen || !upperKey.isValid() || !lowerKey.isValid())
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     return !lowerKey.compare(upperKey);
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbclientIDBTransactionImplcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBTransactionImpl.cpp        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -484,9 +484,11 @@
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;IDBTransaction::didGetRecordOnServer&quot;);
</span><span class="cx"> 
</span><ins>+    const IDBGetResult&amp; result = resultData.getResult();
+
</ins><span class="cx">     if (request.sourceIndexIdentifier() &amp;&amp; request.requestedIndexRecordType() == IndexedDB::IndexRecordType::Key) {
</span><del>-        if (resultData.resultKey())
-            request.setResult(resultData.resultKey());
</del><ins>+        if (!result.keyData.isNull())
+            request.setResult(&amp;result.keyData);
</ins><span class="cx">         else
</span><span class="cx">             request.setResultToUndefined();
</span><span class="cx">     } else {
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIndexValueEntrycppfromrev192293trunkSourceWebCoreModulesindexeddbserverMemoryIndexcpp"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.cpp (from rev 192293, trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp) (0 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.cpp                                (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.cpp        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -0,0 +1,96 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+#include &quot;IndexValueEntry.h&quot;
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+namespace IDBServer {
+
+IndexValueEntry::IndexValueEntry(bool unique)
+    : m_unique(unique)
+{
+    if (m_unique)
+        m_key = nullptr;
+    else
+        m_orderedKeys = new std::set&lt;IDBKeyData&gt;;
+}
+
+IndexValueEntry::~IndexValueEntry()
+{
+    if (m_unique)
+        delete m_key;
+    else
+        delete m_orderedKeys;
+}
+
+void IndexValueEntry::addKey(const IDBKeyData&amp; key)
+{
+    if (m_unique) {
+        delete m_key;
+        m_key = new IDBKeyData(key);
+        return;
+    }
+
+    m_orderedKeys-&gt;insert(key);
+}
+
+bool IndexValueEntry::removeKey(const IDBKeyData&amp; key)
+{
+    if (m_unique &amp;&amp; m_key &amp;&amp; *m_key == key) {
+        delete m_key;
+        m_key = nullptr;
+        return true;
+    }
+
+    m_orderedKeys-&gt;erase(key);
+    return m_orderedKeys-&gt;empty();
+}
+
+const IDBKeyData* IndexValueEntry::getLowest() const
+{
+    if (m_unique)
+        return m_key;
+
+    if (m_orderedKeys-&gt;empty())
+        return nullptr;
+
+    return &amp;(*m_orderedKeys-&gt;begin());
+}
+
+uint64_t IndexValueEntry::getCount() const
+{
+    if (m_unique)
+        return m_key ? 1 : 0;
+
+    return m_orderedKeys-&gt;size();
+}
+
+} // namespace IDBServer
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
</ins></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIndexValueEntryhfromrev192293trunkSourceWebCoreModulesindexeddbserverMemoryIndexh"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.h (from rev 192293, trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h) (0 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.h                                (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.h        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -0,0 +1,64 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IndexValueEntry_h
+#define IndexValueEntry_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include &quot;IDBKeyData.h&quot;
+#include &lt;set&gt;
+
+namespace WebCore {
+namespace IDBServer {
+
+class IndexValueEntry {
+public:
+    IndexValueEntry(bool unique);
+    ~IndexValueEntry();
+
+    void addKey(const IDBKeyData&amp;);
+
+    // Returns true if the IndexValueEntry is empty after removing the key;
+    bool removeKey(const IDBKeyData&amp;);
+
+    const IDBKeyData* getLowest() const;
+
+    uint64_t getCount() const;
+
+private:
+    union {
+        std::set&lt;IDBKeyData&gt;* m_orderedKeys;
+        IDBKeyData* m_key;
+    };
+
+    bool m_unique;
+};
+
+} // namespace IDBServer
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+#endif // IndexValueEntry_h
</ins></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIndexValueStorecpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.cpp (0 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.cpp                                (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.cpp        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -0,0 +1,141 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+#include &quot;IndexValueStore.h&quot;
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include &quot;IDBError.h&quot;
+#include &quot;IDBKeyRangeData.h&quot;
+
+namespace WebCore {
+namespace IDBServer {
+
+IndexValueStore::IndexValueStore(bool unique)
+    : m_unique(unique)
+{
+}
+
+const IDBKeyData* IndexValueStore::lowestValueForKey(const IDBKeyData&amp; key) const
+{
+    const auto&amp; entry = m_records.get(key);
+    if (!entry)
+        return nullptr;
+
+    return entry-&gt;getLowest();
+}
+
+uint64_t IndexValueStore::countForKey(const IDBKeyData&amp; key) const
+{
+    const auto&amp; entry = m_records.get(key);
+    if (!entry)
+        return 0;
+
+    return entry-&gt;getCount();
+}
+
+bool IndexValueStore::contains(const IDBKeyData&amp; key) const
+{
+    const auto&amp; entry = m_records.get(key);
+    if (!entry)
+        return false;
+
+    ASSERT(entry-&gt;getCount());
+
+    return true;
+}
+
+IDBError IndexValueStore::addRecord(const IDBKeyData&amp; indexKey, const IDBKeyData&amp; valueKey)
+{
+    auto result = m_records.add(indexKey, nullptr);
+
+    if (!result.isNewEntry &amp;&amp; m_unique)
+        return IDBError(IDBExceptionCode::ConstraintError);
+
+    if (result.isNewEntry)
+        result.iterator-&gt;value = std::make_unique&lt;IndexValueEntry&gt;(m_unique);
+
+    result.iterator-&gt;value-&gt;addKey(valueKey);
+    m_orderedKeys.insert(indexKey);
+
+    return { };
+}
+
+void IndexValueStore::removeRecord(const IDBKeyData&amp; indexKey, const IDBKeyData&amp; valueKey)
+{
+    auto iterator = m_records.find(indexKey);
+    if (!iterator-&gt;value)
+        return;
+
+    if (iterator-&gt;value-&gt;removeKey(valueKey))
+        m_records.remove(iterator);
+}
+
+void IndexValueStore::removeEntriesWithValueKey(const IDBKeyData&amp; valueKey)
+{
+    HashSet&lt;IDBKeyData*&gt; entryKeysToRemove;
+
+    for (auto&amp; entry : m_records) {
+        if (entry.value-&gt;removeKey(valueKey))
+            entryKeysToRemove.add(&amp;entry.key);
+    }
+
+    for (auto* entry : entryKeysToRemove) {
+        m_orderedKeys.erase(*entry);
+        m_records.remove(*entry);
+    }
+}
+
+IDBKeyData IndexValueStore::lowestKeyWithRecordInRange(const IDBKeyRangeData&amp; range) const
+{
+    if (range.isExactlyOneKey())
+        return m_records.contains(range.lowerKey) ? range.lowerKey : IDBKeyData();
+
+    auto lowestInRange = m_orderedKeys.lower_bound(range.lowerKey);
+
+    if (lowestInRange == m_orderedKeys.end())
+        return { };
+
+    if (range.lowerOpen &amp;&amp; *lowestInRange == range.lowerKey)
+        ++lowestInRange;
+
+    if (lowestInRange == m_orderedKeys.end())
+        return { };
+
+    if (!range.upperKey.isNull()) {
+        if (lowestInRange-&gt;compare(range.upperKey) &gt; 0)
+            return { };
+        if (range.upperOpen &amp;&amp; *lowestInRange == range.upperKey)
+            return { };
+    }
+
+    return *lowestInRange;
+}
+
+} // namespace IDBServer
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
</ins></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIndexValueStorehfromrev192293trunkSourceWebCoreModulesindexeddbserverMemoryIndexh"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.h (from rev 192293, trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h) (0 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.h                                (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.h        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -0,0 +1,71 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IndexValueStore_h
+#define IndexValueStore_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include &quot;IDBKeyData.h&quot;
+#include &quot;IndexValueEntry.h&quot;
+#include &lt;set&gt;
+#include &lt;wtf/HashMap.h&gt;
+
+namespace WebCore {
+
+class IDBError;
+
+struct IDBKeyRangeData;
+
+namespace IDBServer {
+
+typedef HashMap&lt;IDBKeyData, std::unique_ptr&lt;IndexValueEntry&gt;, IDBKeyDataHash, IDBKeyDataHashTraits&gt; IndexKeyValueMap;
+
+class IndexValueStore {
+public:
+    IndexValueStore(bool unique);
+
+    const IDBKeyData* lowestValueForKey(const IDBKeyData&amp;) const;
+    uint64_t countForKey(const IDBKeyData&amp;) const;
+    IDBKeyData lowestKeyWithRecordInRange(const IDBKeyRangeData&amp;) const;
+    bool contains(const IDBKeyData&amp;) const;
+
+    IDBError addRecord(const IDBKeyData&amp; indexKey, const IDBKeyData&amp; valueKey);
+    void removeRecord(const IDBKeyData&amp; indexKey, const IDBKeyData&amp; valueKey);
+
+    void removeEntriesWithValueKey(const IDBKeyData&amp; valueKey);
+
+private:
+    IndexKeyValueMap m_records;
+    std::set&lt;IDBKeyData&gt; m_orderedKeys;
+    
+    bool m_unique;
+};
+
+} // namespace IDBServer
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+#endif // IndexValueStore_h
</ins></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryBackingStoreTransactioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.cpp        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -117,21 +117,24 @@
</span><span class="cx"> 
</span><span class="cx">     auto addResult = m_clearedKeyValueMaps.add(&amp;objectStore, nullptr);
</span><span class="cx"> 
</span><del>-    // If this object store has already been cleared during this transaction, we don't need to remember this clearing.
</del><ins>+    // If this object store has already been cleared during this transaction, we shouldn't remember this clearing.
</ins><span class="cx">     if (!addResult.isNewEntry)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    // If values had previously been changed during this transaction, fold those changes back into the
-    // cleared key-value map now, so we have exactly the map that will need to be restored if the transaction is aborted.
-    auto originalValues = m_originalValues.take(&amp;objectStore);
-    if (originalValues) {
-        for (auto iterator : *originalValues)
-            keyValueMap-&gt;set(iterator.key, iterator.value);
-    }
-
</del><span class="cx">     addResult.iterator-&gt;value = WTF::move(keyValueMap);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void MemoryBackingStoreTransaction::indexCleared(MemoryIndex&amp; index, std::unique_ptr&lt;IndexValueStore&gt;&amp;&amp; valueStore)
+{
+    auto addResult = m_clearedIndexValueStores.add(&amp;index, nullptr);
+
+    // If this index has already been cleared during this transaction, we shouldn't remember this clearing.
+    if (!addResult.isNewEntry)
+        return;
+
+    addResult.iterator-&gt;value = WTF::move(valueStore);
+}
+
</ins><span class="cx"> void MemoryBackingStoreTransaction::recordValueChanged(MemoryObjectStore&amp; objectStore, const IDBKeyData&amp; key, ThreadSafeDataBuffer* value)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_objectStores.contains(&amp;objectStore));
</span><span class="lines">@@ -182,15 +185,19 @@
</span><span class="cx">         m_backingStore.setDatabaseInfo(*m_originalDatabaseInfo);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // Restore cleared index value stores before we re-insert values into object stores
+    // because inserting those values will regenerate the appropriate index values.
+    for (auto&amp; iterator : m_clearedIndexValueStores)
+        iterator.key-&gt;replaceIndexValueStore(WTF::move(iterator.value));
+    m_clearedIndexValueStores.clear();
+    
</ins><span class="cx">     for (auto objectStore : m_objectStores) {
</span><span class="cx">         ASSERT(m_originalKeyGenerators.contains(objectStore));
</span><span class="cx">         objectStore-&gt;setKeyGeneratorValue(m_originalKeyGenerators.get(objectStore));
</span><span class="cx"> 
</span><span class="cx">         auto clearedKeyValueMap = m_clearedKeyValueMaps.take(objectStore);
</span><del>-        if (clearedKeyValueMap) {
</del><ins>+        if (clearedKeyValueMap)
</ins><span class="cx">             objectStore-&gt;replaceKeyValueStore(WTF::move(clearedKeyValueMap));
</span><del>-            continue;
-        }
</del><span class="cx"> 
</span><span class="cx">         auto keyValueMap = m_originalValues.take(objectStore);
</span><span class="cx">         if (!keyValueMap)
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryBackingStoreTransactionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.h (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.h        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryBackingStoreTransaction.h        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &quot;IDBDatabaseInfo.h&quot;
</span><span class="cx"> #include &quot;IDBKeyData.h&quot;
</span><span class="cx"> #include &quot;IDBTransactionInfo.h&quot;
</span><ins>+#include &quot;IndexValueStore.h&quot;
</ins><span class="cx"> #include &quot;ThreadSafeDataBuffer.h&quot;
</span><span class="cx"> #include &lt;wtf/HashMap.h&gt;
</span><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><span class="lines">@@ -63,6 +64,7 @@
</span><span class="cx">     void recordValueChanged(MemoryObjectStore&amp;, const IDBKeyData&amp;, ThreadSafeDataBuffer*);
</span><span class="cx">     void objectStoreDeleted(std::unique_ptr&lt;MemoryObjectStore&gt;);
</span><span class="cx">     void objectStoreCleared(MemoryObjectStore&amp;, std::unique_ptr&lt;KeyValueMap&gt;&amp;&amp;);
</span><ins>+    void indexCleared(MemoryIndex&amp;, std::unique_ptr&lt;IndexValueStore&gt;&amp;&amp;);
</ins><span class="cx"> 
</span><span class="cx">     void addNewIndex(MemoryIndex&amp;);
</span><span class="cx">     void addExistingIndex(MemoryIndex&amp;);
</span><span class="lines">@@ -90,8 +92,10 @@
</span><span class="cx"> 
</span><span class="cx">     HashMap&lt;MemoryObjectStore*, uint64_t&gt; m_originalKeyGenerators;
</span><span class="cx">     HashMap&lt;String, std::unique_ptr&lt;MemoryObjectStore&gt;&gt; m_deletedObjectStores;
</span><ins>+    HashMap&lt;String, std::unique_ptr&lt;MemoryIndex&gt;&gt; m_deletedIndexes;
</ins><span class="cx">     HashMap&lt;MemoryObjectStore*, std::unique_ptr&lt;KeyValueMap&gt;&gt; m_originalValues;
</span><span class="cx">     HashMap&lt;MemoryObjectStore*, std::unique_ptr&lt;KeyValueMap&gt;&gt; m_clearedKeyValueMaps;
</span><ins>+    HashMap&lt;MemoryIndex*, std::unique_ptr&lt;IndexValueStore&gt;&gt; m_clearedIndexValueStores;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace IDBServer
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryIDBBackingStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -258,8 +258,7 @@
</span><span class="cx">     if (!objectStore)
</span><span class="cx">         return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral(&quot;No backing store object store found to put record&quot;));
</span><span class="cx"> 
</span><del>-    objectStore-&gt;addRecord(*transaction, keyData, value);
-    return IDBError();
</del><ins>+    return objectStore-&gt;addRecord(*transaction, keyData, value);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> IDBError MemoryIDBBackingStore::getRecord(const IDBResourceIdentifier&amp; transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData&amp; range, ThreadSafeDataBuffer&amp; outValue)
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryIndexcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -28,18 +28,26 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(INDEXED_DATABASE)
</span><span class="cx"> 
</span><ins>+#include &quot;IDBError.h&quot;
</ins><span class="cx"> #include &quot;IDBGetResult.h&quot;
</span><ins>+#include &quot;IDBKeyRangeData.h&quot;
+#include &quot;IndexKey.h&quot;
+#include &quot;Logging.h&quot;
+#include &quot;MemoryBackingStoreTransaction.h&quot;
+#include &quot;MemoryObjectStore.h&quot;
+#include &quot;ThreadSafeDataBuffer.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> namespace IDBServer {
</span><span class="cx"> 
</span><del>-std::unique_ptr&lt;MemoryIndex&gt; MemoryIndex::create(const IDBIndexInfo&amp; info)
</del><ins>+std::unique_ptr&lt;MemoryIndex&gt; MemoryIndex::create(const IDBIndexInfo&amp; info, MemoryObjectStore&amp; objectStore)
</ins><span class="cx"> {
</span><del>-    return std::make_unique&lt;MemoryIndex&gt;(info);
</del><ins>+    return std::make_unique&lt;MemoryIndex&gt;(info, objectStore);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-MemoryIndex::MemoryIndex(const IDBIndexInfo&amp; info)
</del><ins>+MemoryIndex::MemoryIndex(const IDBIndexInfo&amp; info, MemoryObjectStore&amp; objectStore)
</ins><span class="cx">     : m_info(info)
</span><ins>+    , m_objectStore(objectStore)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -47,20 +55,125 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-IDBGetResult MemoryIndex::valueForKeyRange(IndexedDB::IndexRecordType, const IDBKeyRangeData&amp;) const
</del><ins>+void MemoryIndex::objectStoreCleared()
</ins><span class="cx"> {
</span><del>-    // FIXME: Once indexes actually index, we'll return something real.
-    // https://bugs.webkit.org/show_bug.cgi?id=150939
</del><ins>+    auto transaction = m_objectStore.writeTransaction();
+    ASSERT(transaction);
+
+    transaction-&gt;indexCleared(*this, WTF::move(m_records));
+}
+
+void MemoryIndex::replaceIndexValueStore(std::unique_ptr&lt;IndexValueStore&gt;&amp;&amp; valueStore)
+{
+    ASSERT(m_objectStore.writeTransaction());
+    ASSERT(m_objectStore.writeTransaction()-&gt;isAborting());
+
+    m_records = WTF::move(valueStore);
+}
+
+IDBGetResult MemoryIndex::getResultForKeyRange(IndexedDB::IndexRecordType type, const IDBKeyRangeData&amp; range) const
+{
+    LOG(IndexedDB, &quot;MemoryIndex::getResultForKeyRange&quot;);
+
+    if (!m_records)
+        return { };
+
+    IDBKeyData keyToLookFor;
+    if (range.isExactlyOneKey())
+        keyToLookFor = range.lowerKey;
+    else
+        keyToLookFor = m_records-&gt;lowestKeyWithRecordInRange(range);
+
+    if (keyToLookFor.isNull())
+        return { };
+
+    const IDBKeyData* keyValue = m_records-&gt;lowestValueForKey(keyToLookFor);
+
+    if (!keyValue)
+        return { };
+
+    return type == IndexedDB::IndexRecordType::Key ? IDBGetResult(*keyValue) : IDBGetResult(m_objectStore.valueForKeyRange(*keyValue));
+}
+
+uint64_t MemoryIndex::countForKeyRange(const IDBKeyRangeData&amp; inRange)
+{
+    LOG(IndexedDB, &quot;MemoryIndex::countForKeyRange&quot;);
+
+    if (!m_records)
+        return 0;
+
+    uint64_t count = 0;
+    IDBKeyRangeData range = inRange;
+    while (true) {
+        auto key = m_records-&gt;lowestKeyWithRecordInRange(range);
+        if (key.isNull())
+            break;
+
+        count += m_records-&gt;countForKey(key);
+
+        range.lowerKey = key;
+        range.lowerOpen = true;
+    }
+
+    return count;
+}
+
+IDBError MemoryIndex::putIndexKey(const IDBKeyData&amp; valueKey, const IndexKey&amp; indexKey)
+{
+    LOG(IndexedDB, &quot;MemoryIndex::provisionalPutIndexKey&quot;);
+
+    if (!m_records)
+        m_records = std::make_unique&lt;IndexValueStore&gt;(m_info.unique());
+
+    if (!m_info.multiEntry()) {
+        IDBKeyData key = indexKey.asOneKey();
+        return m_records-&gt;addRecord(key, valueKey);
+    }
+
+    Vector&lt;IDBKeyData&gt; keys = indexKey.multiEntry();
+
+    if (m_info.unique()) {
+        for (auto&amp; key : keys) {
+            if (m_records-&gt;contains(key))
+                return IDBError(IDBExceptionCode::ConstraintError);
+        }
+    }
+
+    for (auto&amp; key : keys) {
+        auto error = m_records-&gt;addRecord(key, valueKey);
+        ASSERT_UNUSED(error, error.isNull());
+    }
+
</ins><span class="cx">     return { };
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-uint64_t MemoryIndex::countForKeyRange(const IDBKeyRangeData&amp;)
</del><ins>+void MemoryIndex::removeRecord(const IDBKeyData&amp; valueKey, const IndexKey&amp; indexKey)
</ins><span class="cx"> {
</span><del>-    // FIXME: Once indexes actually index, we'll return something real.
-    // https://bugs.webkit.org/show_bug.cgi?id=150939
-    return 0;
</del><ins>+    LOG(IndexedDB, &quot;MemoryIndex::removeRecord&quot;);
+
+    ASSERT(m_records);
+
+    if (!m_info.multiEntry()) {
+        IDBKeyData key = indexKey.asOneKey();
+        m_records-&gt;removeRecord(key, valueKey);
+        return;
+    }
+
+    Vector&lt;IDBKeyData&gt; keys = indexKey.multiEntry();
+    for (auto&amp; key : keys)
+        m_records-&gt;removeRecord(key, valueKey);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void MemoryIndex::removeEntriesWithValueKey(const IDBKeyData&amp; valueKey)
+{
+    LOG(IndexedDB, &quot;MemoryIndex::removeEntriesWithValueKey&quot;);
+
+    if (!m_records)
+        return;
+
+    m_records-&gt;removeEntriesWithValueKey(valueKey);
+}
+
</ins><span class="cx"> } // namespace IDBServer
</span><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryIndexh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -30,9 +30,15 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;IDBGetResult.h&quot;
</span><span class="cx"> #include &quot;IDBIndexInfo.h&quot;
</span><ins>+#include &quot;IDBKeyData.h&quot;
+#include &quot;IndexValueStore.h&quot;
+#include &lt;set&gt;
+#include &lt;wtf/HashMap.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><ins>+class IDBError;
+class IndexKey;
</ins><span class="cx"> class ThreadSafeDataBuffer;
</span><span class="cx"> 
</span><span class="cx"> struct IDBKeyRangeData;
</span><span class="lines">@@ -43,22 +49,38 @@
</span><span class="cx"> 
</span><span class="cx"> namespace IDBServer {
</span><span class="cx"> 
</span><ins>+class MemoryBackingStoreTransaction;
+class MemoryObjectStore;
+
</ins><span class="cx"> class MemoryIndex {
</span><del>-    friend std::unique_ptr&lt;MemoryIndex&gt; std::make_unique&lt;MemoryIndex&gt;(const WebCore::IDBIndexInfo&amp;);
</del><ins>+    friend std::unique_ptr&lt;MemoryIndex&gt; std::make_unique&lt;MemoryIndex&gt;(const WebCore::IDBIndexInfo&amp;, WebCore::IDBServer::MemoryObjectStore&amp;);
</ins><span class="cx"> public:
</span><del>-    static std::unique_ptr&lt;MemoryIndex&gt; create(const IDBIndexInfo&amp;);
</del><ins>+    static std::unique_ptr&lt;MemoryIndex&gt; create(const IDBIndexInfo&amp;, MemoryObjectStore&amp;);
</ins><span class="cx"> 
</span><span class="cx">     ~MemoryIndex();
</span><span class="cx"> 
</span><span class="cx">     const IDBIndexInfo&amp; info() const { return m_info; }
</span><span class="cx"> 
</span><del>-    IDBGetResult valueForKeyRange(IndexedDB::IndexRecordType, const IDBKeyRangeData&amp;) const;
</del><ins>+    IDBGetResult getResultForKeyRange(IndexedDB::IndexRecordType, const IDBKeyRangeData&amp;) const;
</ins><span class="cx">     uint64_t countForKeyRange(const IDBKeyRangeData&amp;);
</span><del>-    
</del><ins>+
+    IDBError putIndexKey(const IDBKeyData&amp;, const IndexKey&amp;);
+
+    void removeEntriesWithValueKey(const IDBKeyData&amp;);
+    void removeRecord(const IDBKeyData&amp;, const IndexKey&amp;);
+
+    void objectStoreCleared();
+    void replaceIndexValueStore(std::unique_ptr&lt;IndexValueStore&gt;&amp;&amp;);
+
</ins><span class="cx"> private:
</span><del>-    MemoryIndex(const IDBIndexInfo&amp;);
</del><ins>+    MemoryIndex(const IDBIndexInfo&amp;, MemoryObjectStore&amp;);
</ins><span class="cx"> 
</span><ins>+    uint64_t recordCountForKey(const IDBKeyData&amp;) const;
+    
</ins><span class="cx">     IDBIndexInfo m_info;
</span><ins>+    MemoryObjectStore&amp; m_objectStore;
+
+    std::unique_ptr&lt;IndexValueStore&gt; m_records;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace IDBServer
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryObjectStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -28,12 +28,18 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(INDEXED_DATABASE)
</span><span class="cx"> 
</span><ins>+#include &quot;IDBBindingUtilities.h&quot;
</ins><span class="cx"> #include &quot;IDBDatabaseException.h&quot;
</span><span class="cx"> #include &quot;IDBError.h&quot;
</span><span class="cx"> #include &quot;IDBKeyRangeData.h&quot;
</span><ins>+#include &quot;IndexKey.h&quot;
</ins><span class="cx"> #include &quot;Logging.h&quot;
</span><span class="cx"> #include &quot;MemoryBackingStoreTransaction.h&quot;
</span><span class="cx"> 
</span><ins>+#include &lt;wtf/NeverDestroyed.h&gt;
+
+using namespace JSC;
+
</ins><span class="cx"> namespace WebCore {
</span><span class="cx"> namespace IDBServer {
</span><span class="cx"> 
</span><span class="lines">@@ -76,7 +82,7 @@
</span><span class="cx">         return IDBError(IDBExceptionCode::ConstraintError);
</span><span class="cx"> 
</span><span class="cx">     ASSERT(!m_indexesByIdentifier.contains(info.identifier()));
</span><del>-    auto index = MemoryIndex::create(info);
</del><ins>+    auto index = MemoryIndex::create(info, *this);
</ins><span class="cx"> 
</span><span class="cx">     m_info.addExistingIndex(info);
</span><span class="cx"> 
</span><span class="lines">@@ -100,6 +106,8 @@
</span><span class="cx">     ASSERT(m_writeTransaction);
</span><span class="cx"> 
</span><span class="cx">     m_writeTransaction-&gt;objectStoreCleared(*this, WTF::move(m_keyValueStore));
</span><ins>+    for (auto&amp; index : m_indexesByIdentifier.values())
+        index-&gt;objectStoreCleared();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MemoryObjectStore::replaceKeyValueStore(std::unique_ptr&lt;KeyValueMap&gt;&amp;&amp; store)
</span><span class="lines">@@ -132,6 +140,8 @@
</span><span class="cx">     m_writeTransaction-&gt;recordValueChanged(*this, key, &amp;iterator-&gt;value);
</span><span class="cx">     m_keyValueStore-&gt;remove(iterator);
</span><span class="cx">     m_orderedKeys-&gt;erase(key);
</span><ins>+
+    updateIndexesForDeleteRecord(key);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MemoryObjectStore::deleteRange(const IDBKeyRangeData&amp; inputRange)
</span><span class="lines">@@ -158,7 +168,7 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MemoryObjectStore::addRecord(MemoryBackingStoreTransaction&amp; transaction, const IDBKeyData&amp; keyData, const ThreadSafeDataBuffer&amp; value)
</del><ins>+IDBError MemoryObjectStore::addRecord(MemoryBackingStoreTransaction&amp; transaction, const IDBKeyData&amp; keyData, const ThreadSafeDataBuffer&amp; value)
</ins><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;MemoryObjectStore::addRecord&quot;);
</span><span class="cx"> 
</span><span class="lines">@@ -173,11 +183,82 @@
</span><span class="cx">         m_orderedKeys = std::make_unique&lt;std::set&lt;IDBKeyData&gt;&gt;();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    auto result = m_keyValueStore-&gt;set(keyData, value);
-    if (result.isNewEntry)
-        m_orderedKeys-&gt;insert(keyData);
</del><ins>+    auto mapResult = m_keyValueStore-&gt;set(keyData, value);
+    ASSERT(mapResult.isNewEntry);
+    auto listResult = m_orderedKeys-&gt;insert(keyData);
+    ASSERT(listResult.second);
+
+    // If there was an error indexing this addition, then revert it.
+    auto error = updateIndexesForPutRecord(keyData, value);
+    if (!error.isNull()) {
+        m_keyValueStore-&gt;remove(mapResult.iterator);
+        m_orderedKeys-&gt;erase(listResult.first);
+    }
+
+    return error;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static VM&amp; indexVM()
+{
+    ASSERT(!isMainThread());
+    static NeverDestroyed&lt;RefPtr&lt;VM&gt;&gt; vm = VM::create();
+    return *vm.get();
+}
+
+static ExecState&amp; indexGlobalExec()
+{
+    ASSERT(!isMainThread());
+    static NeverDestroyed&lt;Strong&lt;JSGlobalObject&gt;&gt; globalObject;
+    static bool initialized = false;
+    if (!initialized) {
+        globalObject.get().set(indexVM(), JSGlobalObject::create(indexVM(), JSGlobalObject::createStructure(indexVM(), jsNull())));
+        initialized = true;
+    }
+
+    RELEASE_ASSERT(globalObject.get()-&gt;globalExec());
+    return *globalObject.get()-&gt;globalExec();
+}
+
+void MemoryObjectStore::updateIndexesForDeleteRecord(const IDBKeyData&amp; value)
+{
+    for (auto* index : m_indexesByName.values())
+        index-&gt;removeEntriesWithValueKey(value);
+}
+
+IDBError MemoryObjectStore::updateIndexesForPutRecord(const IDBKeyData&amp; key, const ThreadSafeDataBuffer&amp; value)
+{
+    JSLockHolder locker(indexVM());
+
+    auto jsValue = idbValueDataToJSValue(indexGlobalExec(), value);
+    if (jsValue.isUndefinedOrNull())
+        return { };
+
+    IDBError error;
+    Vector&lt;std::pair&lt;MemoryIndex*, IndexKey&gt;&gt; changedIndexRecords;
+
+    for (auto* index : m_indexesByName.values()) {
+        IndexKey indexKey;
+        generateIndexKeyForValue(indexGlobalExec(), index-&gt;info(), jsValue, indexKey);
+
+        if (indexKey.isNull())
+            continue;
+
+        error = index-&gt;putIndexKey(key, indexKey);
+        if (!error.isNull())
+            break;
+
+        changedIndexRecords.append(std::make_pair(index, indexKey));
+    }
+
+    // If any of the index puts failed, revert all of the ones that went through.
+    if (!error.isNull()) {
+        for (auto&amp; record : changedIndexRecords)
+            record.first-&gt;removeRecord(key, record.second);
+    }
+
+    return error;
+}
+
</ins><span class="cx"> uint64_t MemoryObjectStore::countForKeyRange(uint64_t indexIdentifier, const IDBKeyRangeData&amp; inRange) const
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;MemoryObjectStore::countForKeyRange&quot;);
</span><span class="lines">@@ -224,7 +305,7 @@
</span><span class="cx"> 
</span><span class="cx">     auto* index = m_indexesByIdentifier.get(indexIdentifier);
</span><span class="cx">     ASSERT(index);
</span><del>-    return index-&gt;valueForKeyRange(recordType, range);
</del><ins>+    return index-&gt;getResultForKeyRange(recordType, range);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> IDBKeyData MemoryObjectStore::lowestKeyWithRecordInRange(const IDBKeyRangeData&amp; keyRangeData) const
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryObjectStoreh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -61,13 +61,14 @@
</span><span class="cx"> 
</span><span class="cx">     void writeTransactionStarted(MemoryBackingStoreTransaction&amp;);
</span><span class="cx">     void writeTransactionFinished(MemoryBackingStoreTransaction&amp;);
</span><ins>+    MemoryBackingStoreTransaction* writeTransaction() { return m_writeTransaction; }
</ins><span class="cx"> 
</span><span class="cx">     IDBError createIndex(MemoryBackingStoreTransaction&amp;, const IDBIndexInfo&amp;);
</span><span class="cx"> 
</span><span class="cx">     bool containsRecord(const IDBKeyData&amp;);
</span><span class="cx">     void deleteRecord(const IDBKeyData&amp;);
</span><span class="cx">     void deleteRange(const IDBKeyRangeData&amp;);
</span><del>-    void addRecord(MemoryBackingStoreTransaction&amp;, const IDBKeyData&amp;, const ThreadSafeDataBuffer&amp; value);
</del><ins>+    IDBError addRecord(MemoryBackingStoreTransaction&amp;, const IDBKeyData&amp;, const ThreadSafeDataBuffer&amp; value);
</ins><span class="cx"> 
</span><span class="cx">     uint64_t currentKeyGeneratorValue() const { return m_keyGeneratorValue; }
</span><span class="cx">     void setKeyGeneratorValue(uint64_t value) { m_keyGeneratorValue = value; }
</span><span class="lines">@@ -86,6 +87,9 @@
</span><span class="cx"> 
</span><span class="cx">     IDBKeyData lowestKeyWithRecordInRange(const IDBKeyRangeData&amp;) const;
</span><span class="cx"> 
</span><ins>+    IDBError updateIndexesForPutRecord(const IDBKeyData&amp;, const ThreadSafeDataBuffer&amp; value);
+    void updateIndexesForDeleteRecord(const IDBKeyData&amp; value);
+
</ins><span class="cx">     IDBObjectStoreInfo m_info;
</span><span class="cx"> 
</span><span class="cx">     MemoryBackingStoreTransaction* m_writeTransaction { nullptr };
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbsharedIndexKeycppfromrev192293trunkSourceWebCoreModulesindexeddbIDBKeyRangeDatacpp"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.cpp (from rev 192293, trunk/Source/WebCore/Modules/indexeddb/IDBKeyRangeData.cpp) (0 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.cpp                                (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.cpp        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -0,0 +1,89 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+#include &quot;IndexKey.h&quot;
+
+#if ENABLE(INDEXED_DATABASE)
+
+namespace WebCore {
+
+IndexKey::IndexKey()
+{
+}
+
+IndexKey::IndexKey(Vector&lt;IDBKeyData&gt;&amp;&amp; keys)
+{
+    m_keys.swap(keys);
+}
+
+IndexKey IndexKey::isolatedCopy() const
+{
+    Vector&lt;IDBKeyData&gt; keys;
+    keys.reserveInitialCapacity(m_keys.size());
+    for (auto&amp; key : m_keys)
+        keys.uncheckedAppend(key.isolatedCopy());
+
+    return { WTF::move(keys) };
+}
+
+IDBKeyData IndexKey::asOneKey() const
+{
+    if (m_keys.isEmpty())
+        return { };
+
+    if (m_keys.size() == 1)
+        return m_keys[0];
+
+    IDBKeyData result;
+    result.setArrayValue(m_keys);
+    return result;
+}
+
+Vector&lt;IDBKeyData&gt; IndexKey::multiEntry() const
+{
+    Vector&lt;IDBKeyData&gt; multiEntry;
+    for (auto&amp; key : m_keys) {
+        if (!key.isValid())
+            continue;
+
+        bool skip = false;
+        for (auto&amp; otherKey : multiEntry) {
+            if (key == otherKey) {
+                skip = true;
+                break;
+            }
+        }
+
+        if (!skip)
+            multiEntry.append(key);
+    }
+
+    return multiEntry;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
</ins></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbsharedIndexKeyh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.h (0 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.h                                (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IndexKey.h        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IndexKey_h
+#define IndexKey_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include &quot;IDBKeyData.h&quot;
+#include &lt;wtf/HashMap.h&gt;
+#include &lt;wtf/Vector.h&gt;
+
+namespace WebCore {
+
+class IndexKey {
+public:
+    IndexKey();
+    IndexKey(Vector&lt;IDBKeyData&gt;&amp;&amp;);
+
+    IndexKey isolatedCopy() const;
+
+    IDBKeyData asOneKey() const;
+    Vector&lt;IDBKeyData&gt; multiEntry() const;
+
+    bool isNull() const { return m_keys.isEmpty(); }
+
+private:
+    Vector&lt;IDBKeyData&gt; m_keys;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+#endif // IndexKey_h
</ins></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -2047,6 +2047,10 @@
</span><span class="cx">                 516D7D701BB5F0BD00AF7C77 /* IDBConnectionToServerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5185FCBD1BB5CB770012898F /* IDBConnectionToServerDelegate.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 516D7D711BB5F0BD00AF7C77 /* IDBConnectionToClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 516D7D6D1BB5F06500AF7C77 /* IDBConnectionToClient.cpp */; };
</span><span class="cx">                 516D7D721BB5F0BD00AF7C77 /* IDBConnectionToClientDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 516D7D6E1BB5F06500AF7C77 /* IDBConnectionToClientDelegate.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                517138EF1BED1D1A000D5F01 /* IndexKey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 517138ED1BED1D17000D5F01 /* IndexKey.cpp */; };
+                517138F01BED1D1A000D5F01 /* IndexKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 517138EE1BED1D17000D5F01 /* IndexKey.h */; };
+                517138F71BF128BB000D5F01 /* IndexValueStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 517138F51BF12262000D5F01 /* IndexValueStore.cpp */; };
+                517138F81BF128BB000D5F01 /* IndexValueStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 517138F61BF12262000D5F01 /* IndexValueStore.h */; };
</ins><span class="cx">                 51741D0F0B07259A00ED442C /* BackForwardClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 51741D0B0B07259A00ED442C /* BackForwardClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 51741D110B07259A00ED442C /* HistoryItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 51741D0D0B07259A00ED442C /* HistoryItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 51741D120B07259A00ED442C /* HistoryItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51741D0E0B07259A00ED442C /* HistoryItem.cpp */; };
</span><span class="lines">@@ -2211,6 +2215,8 @@
</span><span class="cx">                 51EC92650CE90DD400F90308 /* JSCustomSQLStatementErrorCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51EC925D0CE90DD400F90308 /* JSCustomSQLStatementErrorCallback.cpp */; };
</span><span class="cx">                 51EE7B381AA50B0500F92B21 /* ResourceLoadInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 51EE7B371AA50B0500F92B21 /* ResourceLoadInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 51EE7B3A1AA5123100F92B21 /* ResourceLoadInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51EE7B391AA5123100F92B21 /* ResourceLoadInfo.cpp */; };
</span><ins>+                51EEAA731BEFFAB100218008 /* IndexValueEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51EEAA711BEFFA7900218008 /* IndexValueEntry.cpp */; };
+                51EEAA741BEFFAB100218008 /* IndexValueEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 51EEAA721BEFFA7900218008 /* IndexValueEntry.h */; };
</ins><span class="cx">                 51F41A681BA73B5B002E053B /* IDBCallbacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 51F41A481BA73B2C002E053B /* IDBCallbacks.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 51F41A691BA73B5B002E053B /* IDBCursorBackend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51F41A491BA73B2C002E053B /* IDBCursorBackend.cpp */; };
</span><span class="cx">                 51F41A6A1BA73B5B002E053B /* IDBCursorBackend.h in Headers */ = {isa = PBXBuildFile; fileRef = 51F41A4A1BA73B2C002E053B /* IDBCursorBackend.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -9497,6 +9503,10 @@
</span><span class="cx">                 516C62241950E2B900337E75 /* JSGamepadEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGamepadEvent.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 516D7D6D1BB5F06500AF7C77 /* IDBConnectionToClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IDBConnectionToClient.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 516D7D6E1BB5F06500AF7C77 /* IDBConnectionToClientDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBConnectionToClientDelegate.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                517138ED1BED1D17000D5F01 /* IndexKey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IndexKey.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                517138EE1BED1D17000D5F01 /* IndexKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexKey.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                517138F51BF12262000D5F01 /* IndexValueStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IndexValueStore.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                517138F61BF12262000D5F01 /* IndexValueStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexValueStore.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 51741D0B0B07259A00ED442C /* BackForwardClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BackForwardClient.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 51741D0D0B07259A00ED442C /* HistoryItem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HistoryItem.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 51741D0E0B07259A00ED442C /* HistoryItem.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = HistoryItem.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -9654,6 +9664,8 @@
</span><span class="cx">                 51EC925D0CE90DD400F90308 /* JSCustomSQLStatementErrorCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCustomSQLStatementErrorCallback.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 51EE7B371AA50B0500F92B21 /* ResourceLoadInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResourceLoadInfo.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 51EE7B391AA5123100F92B21 /* ResourceLoadInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ResourceLoadInfo.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                51EEAA711BEFFA7900218008 /* IndexValueEntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IndexValueEntry.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                51EEAA721BEFFA7900218008 /* IndexValueEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexValueEntry.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 51F41A481BA73B2C002E053B /* IDBCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBCallbacks.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 51F41A491BA73B2C002E053B /* IDBCursorBackend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IDBCursorBackend.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 51F41A4A1BA73B2C002E053B /* IDBCursorBackend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBCursorBackend.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -16878,6 +16890,8 @@
</span><span class="cx">                                 5198F7AB1BBDD3E300E2CC5F /* IDBTransactionInfo.h */,
</span><span class="cx">                                 510A58E21BAA40AE00C19282 /* InProcessIDBServer.cpp */,
</span><span class="cx">                                 510A58E31BAA40AE00C19282 /* InProcessIDBServer.h */,
</span><ins>+                                517138ED1BED1D17000D5F01 /* IndexKey.cpp */,
+                                517138EE1BED1D17000D5F01 /* IndexKey.h */,
</ins><span class="cx">                         );
</span><span class="cx">                         path = shared;
</span><span class="cx">                         sourceTree = &quot;&lt;group&gt;&quot;;
</span><span class="lines">@@ -16893,6 +16907,10 @@
</span><span class="cx">                                 510A58F01BAB720F00C19282 /* IDBServer.h */,
</span><span class="cx">                                 518864E41BBB4B7E00E540C9 /* IDBServerOperation.cpp */,
</span><span class="cx">                                 518864E51BBB4B7E00E540C9 /* IDBServerOperation.h */,
</span><ins>+                                51EEAA711BEFFA7900218008 /* IndexValueEntry.cpp */,
+                                51EEAA721BEFFA7900218008 /* IndexValueEntry.h */,
+                                517138F51BF12262000D5F01 /* IndexValueStore.cpp */,
+                                517138F61BF12262000D5F01 /* IndexValueStore.h */,
</ins><span class="cx">                                 51E1BAC01BD806470055D81F /* MemoryBackingStoreTransaction.cpp */,
</span><span class="cx">                                 51E1BAC11BD806470055D81F /* MemoryBackingStoreTransaction.h */,
</span><span class="cx">                                 51BA4AC81BBC5B9E00DF3D6D /* MemoryIDBBackingStore.cpp */,
</span><span class="lines">@@ -25682,6 +25700,7 @@
</span><span class="cx">                                 A871DE2D0A152AC800B12A68 /* HTMLHeadElement.h in Headers */,
</span><span class="cx">                                 A8EA7CB80A192B9C00A8EF5F /* HTMLHeadingElement.h in Headers */,
</span><span class="cx">                                 A8EA7CAF0A192B9C00A8EF5F /* HTMLHRElement.h in Headers */,
</span><ins>+                                517138F81BF128BB000D5F01 /* IndexValueStore.h in Headers */,
</ins><span class="cx">                                 A871DE270A152AC800B12A68 /* HTMLHtmlElement.h in Headers */,
</span><span class="cx">                                 A871DE2A0A152AC800B12A68 /* HTMLIFrameElement.h in Headers */,
</span><span class="cx">                                 A8EA7D2D0A19385500A8EF5F /* HTMLImageElement.h in Headers */,
</span><span class="lines">@@ -26960,6 +26979,7 @@
</span><span class="cx">                                 CE12523D1A1676CD00864480 /* QuartzCoreSPI.h in Headers */,
</span><span class="cx">                                 442AF7A9102CDDEA008FD4D3 /* QuickLook.h in Headers */,
</span><span class="cx">                                 A10DBF4718F92317000D70C6 /* QuickLookHandleClient.h in Headers */,
</span><ins>+                                51EEAA741BEFFAB100218008 /* IndexValueEntry.h in Headers */,
</ins><span class="cx">                                 937F4CCC1A2D48C100BB39F5 /* QuickLookMacSPI.h in Headers */,
</span><span class="cx">                                 443918001A91B2F8006E04F2 /* QuickLookSoftLink.h in Headers */,
</span><span class="cx">                                 CE1252391A166FA000864480 /* QuickLookSPI.h in Headers */,
</span><span class="lines">@@ -27321,6 +27341,7 @@
</span><span class="cx">                                 93309E10099E64920056E581 /* SetNodeAttributeCommand.h in Headers */,
</span><span class="cx">                                 B8DBDB4C130B0F8A00F5CDB1 /* SetSelectionCommand.h in Headers */,
</span><span class="cx">                                 93F1994F08245E59001E9ABC /* Settings.h in Headers */,
</span><ins>+                                517138F01BED1D1A000D5F01 /* IndexKey.h in Headers */,
</ins><span class="cx">                                 53EF766B16530A61004CBE49 /* SettingsMacros.h in Headers */,
</span><span class="cx">                                 0F3DD45012F5EA1B000D9190 /* ShadowBlur.h in Headers */,
</span><span class="cx">                                 BC5EB8C40E82031B00B25965 /* ShadowData.h in Headers */,
</span><span class="lines">@@ -28718,6 +28739,7 @@
</span><span class="cx">                                 31BC742D1AAFF45C006B4340 /* CSSAnimationTriggerScrollValue.cpp in Sources */,
</span><span class="cx">                                 CAE9F90F146441F000C245B0 /* CSSAspectRatioValue.cpp in Sources */,
</span><span class="cx">                                 FBD6AF8B15EF25E5008B7110 /* CSSBasicShapes.cpp in Sources */,
</span><ins>+                                51EEAA731BEFFAB100218008 /* IndexValueEntry.cpp in Sources */,
</ins><span class="cx">                                 E16A84F914C85CCC002977DF /* CSSBorderImage.cpp in Sources */,
</span><span class="cx">                                 BC274B31140EBED800EADFA6 /* CSSBorderImageSliceValue.cpp in Sources */,
</span><span class="cx">                                 49AE2D8E134EE50C0072920A /* CSSCalculationValue.cpp in Sources */,
</span><span class="lines">@@ -29789,6 +29811,7 @@
</span><span class="cx">                                 9752D38D1413104B003305BD /* JSHTMLSpanElement.cpp in Sources */,
</span><span class="cx">                                 A80E7B0F0A19D606007FB8C5 /* JSHTMLStyleElement.cpp in Sources */,
</span><span class="cx">                                 BCA169A20BFD55B40019CA76 /* JSHTMLTableCaptionElement.cpp in Sources */,
</span><ins>+                                517138F71BF128BB000D5F01 /* IndexValueStore.cpp in Sources */,
</ins><span class="cx">                                 BC06EDE30BFD6D0D00856E9D /* JSHTMLTableCellElement.cpp in Sources */,
</span><span class="cx">                                 BC06ED9D0BFD660600856E9D /* JSHTMLTableColElement.cpp in Sources */,
</span><span class="cx">                                 836CB1F91BD1E41800AF1591 /* JSHTMLTableDataCellElement.cpp in Sources */,
</span><span class="lines">@@ -29961,6 +29984,7 @@
</span><span class="cx">                                 AA7FEEA416A4E6F3004C0C33 /* JSSpeechSynthesis.cpp in Sources */,
</span><span class="cx">                                 AA2A5AD316A4860D00976A25 /* JSSpeechSynthesisEvent.cpp in Sources */,
</span><span class="cx">                                 AA7FEEA616A4E6F3004C0C33 /* JSSpeechSynthesisUtterance.cpp in Sources */,
</span><ins>+                                517138EF1BED1D1A000D5F01 /* IndexKey.cpp in Sources */,
</ins><span class="cx">                                 AA7FEEA816A4E6F3004C0C33 /* JSSpeechSynthesisVoice.cpp in Sources */,
</span><span class="cx">                                 514C76370CE9225E007EF3CD /* JSSQLError.cpp in Sources */,
</span><span class="cx">                                 B525A96611CA2340003A23A8 /* JSSQLException.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsjsIDBBindingUtilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/bindings/js/IDBBindingUtilities.cpp        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -30,10 +30,12 @@
</span><span class="cx"> #include &quot;IDBBindingUtilities.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #include &quot;DOMRequestState.h&quot;
</span><ins>+#include &quot;IDBIndexInfo.h&quot;
</ins><span class="cx"> #include &quot;IDBIndexMetadata.h&quot;
</span><span class="cx"> #include &quot;IDBKey.h&quot;
</span><span class="cx"> #include &quot;IDBKeyData.h&quot;
</span><span class="cx"> #include &quot;IDBKeyPath.h&quot;
</span><ins>+#include &quot;IndexKey.h&quot;
</ins><span class="cx"> #include &quot;JSDOMBinding.h&quot;
</span><span class="cx"> #include &quot;Logging.h&quot;
</span><span class="cx"> #include &quot;SharedBuffer.h&quot;
</span><span class="lines">@@ -398,8 +400,19 @@
</span><span class="cx">     return Deprecated::ScriptValue(requestState-&gt;exec()-&gt;vm(), jsNull());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static JSValue idbValueDataToJSValue(JSC::ExecState&amp; exec, const Vector&lt;uint8_t&gt;&amp; buffer)
+{
+    if (buffer.isEmpty())
+        return jsNull();
+
+    RefPtr&lt;SerializedScriptValue&gt; serializedValue = SerializedScriptValue::createFromWireBytes(buffer);
+    return serializedValue-&gt;deserialize(&amp;exec, exec.lexicalGlobalObject(), 0, NonThrowing);
+}
+
</ins><span class="cx"> Deprecated::ScriptValue deserializeIDBValueBuffer(JSC::ExecState* exec, const Vector&lt;uint8_t&gt;&amp; buffer, bool keyIsDefined)
</span><span class="cx"> {
</span><ins>+    ASSERT(exec);
+
</ins><span class="cx">     // If the key doesn't exist, then the value must be undefined (as opposed to null).
</span><span class="cx">     if (!keyIsDefined) {
</span><span class="cx">         // We either shouldn't have a buffer or it should be of size 0.
</span><span class="lines">@@ -407,16 +420,18 @@
</span><span class="cx">         return Deprecated::ScriptValue(exec-&gt;vm(), jsUndefined());
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    JSValue result;
-    if (buffer.size()) {
-        RefPtr&lt;SerializedScriptValue&gt; serializedValue = SerializedScriptValue::createFromWireBytes(buffer);
-        result = serializedValue-&gt;deserialize(exec, exec-&gt;lexicalGlobalObject(), 0, NonThrowing);
-    } else
-        result = jsNull();
-
</del><ins>+    JSValue result = idbValueDataToJSValue(*exec, buffer);
</ins><span class="cx">     return Deprecated::ScriptValue(exec-&gt;vm(), result);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+JSValue idbValueDataToJSValue(JSC::ExecState&amp; exec, const ThreadSafeDataBuffer&amp; valueData)
+{
+    if (!valueData.data())
+        return jsUndefined();
+
+    return idbValueDataToJSValue(exec, *valueData.data());
+}
+
</ins><span class="cx"> Deprecated::ScriptValue idbKeyToScriptValue(DOMRequestState* requestState, PassRefPtr&lt;IDBKey&gt; key)
</span><span class="cx"> {
</span><span class="cx">     ExecState* exec = requestState-&gt;exec();
</span><span class="lines">@@ -434,6 +449,13 @@
</span><span class="cx">     return createIDBKeyFromValue(&amp;exec, scriptValue);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Deprecated::ScriptValue idbKeyDataToScriptValue(ScriptExecutionContext* context, const IDBKeyData&amp; keyData)
+{
+    RefPtr&lt;IDBKey&gt; key = keyData.maybeCreateIDBKey();
+    DOMRequestState requestState(context);
+    return idbKeyToScriptValue(&amp;requestState, key.get());
+}
+
</ins><span class="cx"> void generateIndexKeysForValue(ExecState* exec, const IDBIndexMetadata&amp; indexMetadata, const Deprecated::ScriptValue&amp; objectValue, Vector&lt;IDBKeyData&gt;&amp; indexKeys)
</span><span class="cx"> {
</span><span class="cx">     RefPtr&lt;IDBKey&gt; indexKey = createIDBKeyFromScriptValueAndKeyPath(exec, objectValue, indexMetadata.keyPath);
</span><span class="lines">@@ -459,13 +481,49 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Deprecated::ScriptValue idbKeyDataToScriptValue(ScriptExecutionContext* context, const IDBKeyData&amp; keyData)
</del><ins>+static Vector&lt;IDBKeyData&gt; createKeyPathArray(ExecState&amp; exec, JSValue value, const IDBIndexInfo&amp; info)
</ins><span class="cx"> {
</span><del>-    RefPtr&lt;IDBKey&gt; key = keyData.maybeCreateIDBKey();
-    DOMRequestState requestState(context);
-    return idbKeyToScriptValue(&amp;requestState, key.get());
</del><ins>+    Vector&lt;IDBKeyData&gt; keys;
+
+    switch (info.keyPath().type()) {
+    case IndexedDB::KeyPathType::Array:
+        for (auto&amp; entry : info.keyPath().array()) {
+            auto key = internalCreateIDBKeyFromScriptValueAndKeyPath(&amp;exec, value, entry);
+            if (!key)
+                return { };
+            keys.append(key.get());
+        }
+        break;
+    case IndexedDB::KeyPathType::String: {
+        auto idbKey = internalCreateIDBKeyFromScriptValueAndKeyPath(&amp;exec, value, info.keyPath().string());
+        if (!idbKey)
+            return { };
+
+        if (info.multiEntry() &amp;&amp; idbKey-&gt;type() == IndexedDB::Array) {
+            for (auto&amp; key : idbKey-&gt;array())
+                keys.append(key.get());
+        } else
+            keys.append(idbKey.get());
+
+        break;
+    }
+    case IndexedDB::KeyPathType::Null:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+
+    return keys;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void generateIndexKeyForValue(ExecState&amp; exec, const IDBIndexInfo&amp; info, JSValue value, IndexKey&amp; outKey)
+{
+    auto keyDatas = createKeyPathArray(exec, value, info);
+
+    if (keyDatas.isEmpty())
+        return;
+
+    outKey = IndexKey(WTF::move(keyDatas));
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(INDEXED_DATABASE)
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsjsIDBBindingUtilitiesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h (192293 => 192294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h        2015-11-11 05:19:56 UTC (rev 192293)
+++ trunk/Source/WebCore/bindings/js/IDBBindingUtilities.h        2015-11-11 06:07:03 UTC (rev 192294)
</span><span class="lines">@@ -35,8 +35,10 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> class DOMRequestState;
</span><ins>+class IDBIndexInfo;
</ins><span class="cx"> class IDBKey;
</span><span class="cx"> class IDBKeyPath;
</span><ins>+class IndexKey;
</ins><span class="cx"> class SharedBuffer;
</span><span class="cx"> class ThreadSafeDataBuffer;
</span><span class="cx"> 
</span><span class="lines">@@ -58,12 +60,17 @@
</span><span class="cx"> Deprecated::ScriptValue deserializeIDBValueData(ScriptExecutionContext&amp;, const ThreadSafeDataBuffer&amp; valueData);
</span><span class="cx"> Deprecated::ScriptValue deserializeIDBValueBuffer(DOMRequestState*, PassRefPtr&lt;SharedBuffer&gt;, bool keyIsDefined);
</span><span class="cx"> WEBCORE_EXPORT Deprecated::ScriptValue deserializeIDBValueBuffer(JSC::ExecState*, const Vector&lt;uint8_t&gt;&amp;, bool keyIsDefined);
</span><ins>+
</ins><span class="cx"> Deprecated::ScriptValue idbKeyToScriptValue(DOMRequestState*, PassRefPtr&lt;IDBKey&gt;);
</span><span class="cx"> RefPtr&lt;IDBKey&gt; scriptValueToIDBKey(DOMRequestState*, const JSC::JSValue&amp;);
</span><span class="cx"> RefPtr&lt;IDBKey&gt; scriptValueToIDBKey(JSC::ExecState&amp;, const JSC::JSValue&amp;);
</span><span class="cx"> WEBCORE_EXPORT void generateIndexKeysForValue(JSC::ExecState*, const IDBIndexMetadata&amp;, const Deprecated::ScriptValue&amp; objectValue, Vector&lt;IDBKeyData&gt;&amp; indexKeys);
</span><span class="cx"> 
</span><span class="cx"> Deprecated::ScriptValue idbKeyDataToScriptValue(ScriptExecutionContext*, const IDBKeyData&amp;);
</span><ins>+
+JSC::JSValue idbValueDataToJSValue(JSC::ExecState&amp;, const ThreadSafeDataBuffer&amp; valueData);
+void generateIndexKeyForValue(JSC::ExecState&amp;, const IDBIndexInfo&amp;, JSC::JSValue, IndexKey&amp; outKey);
+
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(INDEXED_DATABASE)
</span></span></pre>
</div>
</div>

</body>
</html>