[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

jorlow at chromium.org jorlow at chromium.org
Wed Dec 22 13:27:37 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 5c509db17f0bd15168b2317fd6dfe6de81b26c22
Author: jorlow at chromium.org <jorlow at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Sep 16 10:23:58 2010 +0000

    2010-09-08  Jeremy Orlow  <jorlow at chromium.org>
    
            Reviewed by Steve Block.
    
            Complete index support for IndexedDB
            https://bugs.webkit.org/show_bug.cgi?id=45386
    
            * storage/indexeddb/index-basics-expected.txt: Added.
            * storage/indexeddb/index-basics.html: Added.
            * storage/indexeddb/index-cursor-expected.txt: Added.
            * storage/indexeddb/index-cursor.html: Added.
            * storage/indexeddb/objectstore-basics-expected.txt:
            * storage/indexeddb/objectstore-basics.html:
            * storage/indexeddb/script-tests/objectstore-basics.js: Removed.
    2010-09-08  Jeremy Orlow  <jorlow at chromium.org>
    
            Reviewed by Steve Block.
    
            Complete index support for IndexedDB
            https://bugs.webkit.org/show_bug.cgi?id=45386
    
            Add the rest of the index related API for IndexedDB.  This
            includes cursor suport.  A bunch of code was also refactored
            since it is shared between indexes and objectStores.
    
            Tests: storage/indexeddb/index-basics.html
                   storage/indexeddb/index-cursor.html
                   + additions to others.
    
            * storage/IDBAny.cpp:
            (WebCore::IDBAny::set):
            * storage/IDBCursor.cpp:
            (WebCore::IDBCursor::value):
            * storage/IDBCursorBackendImpl.cpp:
            (WebCore::IDBCursorBackendImpl::IDBCursorBackendImpl):
            (WebCore::IDBCursorBackendImpl::value):
            (WebCore::IDBCursorBackendImpl::update):
            (WebCore::IDBCursorBackendImpl::continueFunction):
            (WebCore::IDBCursorBackendImpl::remove):
            (WebCore::IDBCursorBackendImpl::loadCurrentRow):
            (WebCore::IDBCursorBackendImpl::database):
            * storage/IDBCursorBackendImpl.h:
            (WebCore::IDBCursorBackendImpl::create):
            * storage/IDBCursorBackendInterface.h:
            * storage/IDBFactoryBackendImpl.cpp:
            (WebCore::createTables):
            * storage/IDBIndex.cpp:
            (WebCore::IDBIndex::openObjectCursor):
            (WebCore::IDBIndex::openCursor):
            (WebCore::IDBIndex::getObject):
            (WebCore::IDBIndex::get):
            * storage/IDBIndex.h:
            (WebCore::IDBIndex::storeName):
            * storage/IDBIndex.idl:
            * storage/IDBIndexBackendImpl.cpp:
            (WebCore::IDBIndexBackendImpl::storeName):
            (WebCore::openCursorInternal):
            (WebCore::IDBIndexBackendImpl::openObjectCursor):
            (WebCore::IDBIndexBackendImpl::openCursor):
            (WebCore::getInternal):
            (WebCore::IDBIndexBackendImpl::getObject):
            (WebCore::IDBIndexBackendImpl::get):
            * storage/IDBIndexBackendImpl.h:
            (WebCore::IDBIndexBackendImpl::objectStore):
            * storage/IDBIndexBackendInterface.h:
            * storage/IDBKey.cpp:
            (WebCore::IDBKey::fromQuery):
            (WebCore::IDBKey::whereSyntax):
            (WebCore::IDBKey::leftCursorWhereFragment):
            (WebCore::IDBKey::rightCursorWhereFragment):
            * storage/IDBKey.h:
            * storage/IDBKeyRange.cpp:
            (WebCore::IDBKeyRange::leftWhereClauseComparisonOperator):
            (WebCore::IDBKeyRange::rightWhereClauseComparisonOperator):
            * storage/IDBKeyRange.h:
            * storage/IDBObjectStoreBackendImpl.cpp:
            (WebCore::IDBObjectStoreBackendImpl::openCursor):
            * storage/IDBRequest.cpp:
            (WebCore::IDBRequest::timerFired):
    2010-09-08  Jeremy Orlow  <jorlow at chromium.org>
    
            Reviewed by Steve Block.
    
            Complete index support for IndexedDB
            https://bugs.webkit.org/show_bug.cgi?id=45386
    
            * public/WebIDBCursor.h:
            (WebKit::WebIDBCursor::direction):
            (WebKit::WebIDBCursor::key):
            (WebKit::WebIDBCursor::value):
            (WebKit::WebIDBCursor::update):
            (WebKit::WebIDBCursor::continueFunction):
            (WebKit::WebIDBCursor::remove):
            * public/WebIDBIndex.h:
            (WebKit::WebIDBIndex::storeName):
            (WebKit::WebIDBIndex::openObjectCursor):
            (WebKit::WebIDBIndex::openCursor):
            (WebKit::WebIDBIndex::getObject):
            (WebKit::WebIDBIndex::get):
            * public/WebIDBKey.h:
            * src/IDBCursorBackendProxy.cpp:
            (WebCore::IDBCursorBackendProxy::value):
            * src/IDBCursorBackendProxy.h:
            * src/IDBIndexBackendProxy.cpp:
            (WebCore::IDBIndexBackendProxy::storeName):
            (WebCore::IDBIndexBackendProxy::openObjectCursor):
            (WebCore::IDBIndexBackendProxy::openCursor):
            (WebCore::IDBIndexBackendProxy::getObject):
            (WebCore::IDBIndexBackendProxy::get):
            * src/IDBIndexBackendProxy.h:
            * src/WebIDBCursorImpl.cpp:
            (WebKit::WebIDBCursorImpl::value):
            * src/WebIDBCursorImpl.h:
            * src/WebIDBIndexImpl.cpp:
            (WebKit::WebIDBIndexImpl::storeName):
            (WebKit::WebIDBIndexImpl::openCursor):
            (WebKit::WebIDBIndexImpl::openObjectCursor):
            (WebKit::WebIDBIndexImpl::getObject):
            (WebKit::WebIDBIndexImpl::get):
            * src/WebIDBIndexImpl.h:
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@67600 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index c5decbf..f678f1a 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,18 @@
+2010-09-08  Jeremy Orlow  <jorlow at chromium.org>
+
+        Reviewed by Steve Block.
+
+        Complete index support for IndexedDB
+        https://bugs.webkit.org/show_bug.cgi?id=45386
+
+        * storage/indexeddb/index-basics-expected.txt: Added.
+        * storage/indexeddb/index-basics.html: Added.
+        * storage/indexeddb/index-cursor-expected.txt: Added.
+        * storage/indexeddb/index-cursor.html: Added.
+        * storage/indexeddb/objectstore-basics-expected.txt:
+        * storage/indexeddb/objectstore-basics.html:
+        * storage/indexeddb/script-tests/objectstore-basics.js: Removed.
+
 2010-09-15  John Gregg  <johnnyg at google.com>
 
         Unreviewed, build fix after incomplete revert.
diff --git a/LayoutTests/storage/indexeddb/index-basics-expected.txt b/LayoutTests/storage/indexeddb/index-basics-expected.txt
new file mode 100644
index 0000000..a99bc86
--- /dev/null
+++ b/LayoutTests/storage/indexeddb/index-basics-expected.txt
@@ -0,0 +1,331 @@
+Test the basics of IndexedDB's IDBIndex.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB.open('name', 'description')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+db = event.result
+db.createObjectStore('storeName', null)
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+store = event.result
+event.result.createIndex('indexName', 'x')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.result === null is false
+indexObject = event.result
+PASS 'name' in indexObject is true
+PASS indexObject.name is "indexName"
+PASS 'storeName' in indexObject is true
+PASS indexObject.storeName is "storeName"
+PASS 'keyPath' in indexObject is true
+PASS indexObject.keyPath is "x"
+PASS 'unique' in indexObject is true
+PASS indexObject.unique is false
+PASS 'openObjectCursor' in indexObject is true
+PASS 'openCursor' in indexObject is true
+PASS 'getObject' in indexObject is true
+PASS 'get' in indexObject is true
+event.source.add({x: 'value', y: 'zzz'}, 'key')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+event.source.add({x: 'value2', y: 'zzz2'}, 'key2')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+indexObject.get('value')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.result is "key"
+indexObject.getObject('value')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.result.x is "value"
+PASS event.result.y is "zzz"
+indexObject.get('does not exist')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Error event fired:
+PASS 'result' in event is false
+PASS 'code' in event is true
+PASS 'message' in event is true
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.code is IDBDatabaseException.NOT_FOUND_ERR
+indexObject.getObject('does not exist')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Error event fired:
+PASS 'result' in event is false
+PASS 'code' in event is true
+PASS 'message' in event is true
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.code is IDBDatabaseException.NOT_FOUND_ERR
+indexObject.openCursor()
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.result === null is false
+PASS event.result.key is "value"
+PASS event.result.value is "key"
+event.result.continue()
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.result === null is false
+PASS event.result.key is "value2"
+PASS event.result.value is "key2"
+event.result.continue()
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.result === null is true
+indexObject.openObjectCursor()
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.result === null is false
+PASS event.result.key is "value"
+PASS event.result.value.x is "value"
+PASS event.result.value.y is "zzz"
+event.result.continue()
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.result === null is false
+PASS event.result.key is "value2"
+PASS event.result.value.x is "value2"
+PASS event.result.value.y is "zzz2"
+event.result.continue()
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.result === null is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/storage/indexeddb/index-basics.html b/LayoutTests/storage/indexeddb/index-basics.html
new file mode 100644
index 0000000..c23f141
--- /dev/null
+++ b/LayoutTests/storage/indexeddb/index-basics.html
@@ -0,0 +1,217 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+<script src="../../fast/js/resources/js-test-post-function.js"></script>
+<script src="resources/shared.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+
+description("Test the basics of IndexedDB's IDBIndex.");
+if (window.layoutTestController) 
+    layoutTestController.waitUntilDone();
+
+function test()
+{
+    result = evalAndLog("indexedDB.open('name', 'description')");
+    verifyResult(result);
+    result.onsuccess = createObjectStore;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function createObjectStore()
+{
+    verifySuccessEvent(event);
+    db = evalAndLog("db = event.result");
+
+    deleteAllObjectStores(db);
+
+    result = evalAndLog("db.createObjectStore('storeName', null)");
+    verifyResult(result);
+    result.onsuccess = createIndex;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function createIndex()
+{
+    verifySuccessEvent(event);
+    window.store = evalAndLog("store = event.result");
+
+    result = evalAndLog("event.result.createIndex('indexName', 'x')");
+    verifyResult(result);
+    result.onsuccess = addData;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function addData()
+{
+    verifySuccessEvent(event);
+    shouldBeFalse("event.result === null");
+    window.indexObject = evalAndLog("indexObject = event.result");
+    shouldBeTrue("'name' in indexObject");
+    shouldBeEqualToString("indexObject.name", "indexName");
+    shouldBeTrue("'storeName' in indexObject");
+    shouldBeEqualToString("indexObject.storeName", "storeName");
+    shouldBeTrue("'keyPath' in indexObject");
+    shouldBeEqualToString("indexObject.keyPath", "x");
+    shouldBeTrue("'unique' in indexObject");
+    shouldBeFalse("indexObject.unique");
+    shouldBeTrue("'openObjectCursor' in indexObject");
+    shouldBeTrue("'openCursor' in indexObject");
+    shouldBeTrue("'getObject' in indexObject");
+    shouldBeTrue("'get' in indexObject");
+
+    result = evalAndLog("event.source.add({x: 'value', y: 'zzz'}, 'key')");
+    verifyResult(result);
+    result.onsuccess = addMore;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function addMore()
+{
+    verifySuccessEvent(event);
+
+    result = evalAndLog("event.source.add({x: 'value2', y: 'zzz2'}, 'key2')");
+    verifyResult(result);
+    result.onsuccess = getData;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function getData()
+{
+    verifySuccessEvent(event);
+
+    result = evalAndLog("indexObject.get('value')");
+    verifyResult(result);
+    result.onsuccess = getObjectData;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function getObjectData()
+{
+    verifySuccessEvent(event);
+    shouldBeEqualToString("event.result", "key");
+
+    result = evalAndLog("indexObject.getObject('value')");
+    verifyResult(result);
+    result.onsuccess = getDataFail;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function getDataFail()
+{
+    verifySuccessEvent(event);
+    shouldBeEqualToString("event.result.x", "value");
+    shouldBeEqualToString("event.result.y", "zzz");
+
+    result = evalAndLog("indexObject.get('does not exist')");
+    verifyResult(result);
+    result.onsuccess = unexpectedSuccessCallback;
+    result.onerror = getObjectDataFail;
+}
+
+function getObjectDataFail()
+{
+    verifyErrorEvent(event);
+    shouldBe("event.code", "IDBDatabaseException.NOT_FOUND_ERR");
+
+    result = evalAndLog("indexObject.getObject('does not exist')");
+    verifyResult(result);
+    result.onsuccess = unexpectedSuccessCallback;
+    result.onerror = openCursor;
+}
+
+function openCursor()
+{
+    verifyErrorEvent(event);
+    shouldBe("event.code", "IDBDatabaseException.NOT_FOUND_ERR");
+
+    window.result = evalAndLog("indexObject.openCursor()");
+    verifyResult(result);
+    result.onsuccess = cursor1Continue;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function cursor1Continue()
+{
+    verifySuccessEvent(event);
+    shouldBeFalse("event.result === null");
+    shouldBeEqualToString("event.result.key", "value");
+    shouldBeEqualToString("event.result.value", "key");
+
+    // We re-use the last result object.
+    evalAndLog("event.result.continue()");
+    verifyResult(window.result);
+    window.result.onsuccess = cursor1Continue2;
+}
+
+function cursor1Continue2()
+{
+    verifySuccessEvent(event);
+    shouldBeFalse("event.result === null");
+    shouldBeEqualToString("event.result.key", "value2");
+    shouldBeEqualToString("event.result.value", "key2");
+
+    // We re-use the last result object.
+    evalAndLog("event.result.continue()");
+    verifyResult(window.result);
+    window.result.onsuccess = openObjectCursor;
+}
+
+function openObjectCursor()
+{
+    verifySuccessEvent(event);
+    shouldBeTrue("event.result === null");
+
+    window.result = evalAndLog("indexObject.openObjectCursor()");
+    verifyResult(result);
+    result.onsuccess = cursor2Continue;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function cursor2Continue()
+{
+    verifySuccessEvent(event);
+    shouldBeFalse("event.result === null");
+    shouldBeEqualToString("event.result.key", "value");
+    shouldBeEqualToString("event.result.value.x", "value");
+    shouldBeEqualToString("event.result.value.y", "zzz");
+
+    // We re-use the last result object.
+    evalAndLog("event.result.continue()");
+    verifyResult(window.result);
+    window.result.onsuccess = cursor2Continue2;
+}
+
+function cursor2Continue2()
+{
+    verifySuccessEvent(event);
+    shouldBeFalse("event.result === null");
+    shouldBeEqualToString("event.result.key", "value2");
+    shouldBeEqualToString("event.result.value.x", "value2");    
+    shouldBeEqualToString("event.result.value.y", "zzz2");
+
+    // We re-use the last result object.
+    evalAndLog("event.result.continue()");
+    verifyResult(window.result);
+    window.result.onsuccess = last;
+}
+
+function last()
+{
+    verifySuccessEvent(event);
+    shouldBeTrue("event.result === null");
+
+    done();
+}
+
+test();
+
+var successfullyParsed = true;
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/storage/indexeddb/index-cursor-expected.txt b/LayoutTests/storage/indexeddb/index-cursor-expected.txt
new file mode 100644
index 0000000..1442ad4
--- /dev/null
+++ b/LayoutTests/storage/indexeddb/index-cursor-expected.txt
@@ -0,0 +1,2111 @@
+Test IndexedDB's IDBIndex.openCursor + the cursor it produces in depth.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB.open('someDB', 'some description')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+db = event.result
+db.createObjectStore('someObjectStore')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+objectStore = event.result
+objectStore.createIndex('someIndex', 'x')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+indexObject = event.result
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+objectStore.add({'x': testData[nextToAdd]}, nextToAdd)
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+objectStore.add({'x': testData[nextToAdd]}, nextToAdd)
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+objectStore.add({'x': testData[nextToAdd]}, nextToAdd)
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+objectStore.add({'x': testData[nextToAdd]}, nextToAdd)
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+objectStore.add({'x': testData[nextToAdd]}, nextToAdd)
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+objectStore.add({'x': testData[nextToAdd]}, nextToAdd)
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+objectStore.add({'x': testData[nextToAdd]}, nextToAdd)
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+objectStore.add({'x': testData[nextToAdd]}, nextToAdd)
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Scheduling tests...
+Running tests...
+
+Next test: lower open bound is 0; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 0; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: upper open bound is 0; sorted ascending.
+PASS event.result is null
+
+Next test: upper bound is 0; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result is null
+
+Next test: lower open bound is 0; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower bound is 0; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: upper open bound is 0; sorted descending.
+PASS event.result is null
+
+Next test: upper bound is 0; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower open bound is 0; upper open bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 0; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 0; upper open bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 0; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 0; upper open bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower open bound is 0; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower bound is 0; upper open bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower bound is 0; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower open bound is 0; upper open bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 0; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 0; upper open bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 0; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 0; upper open bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower open bound is 0; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower bound is 0; upper open bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower bound is 0; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower open bound is 1; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 1; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: upper open bound is 1; sorted ascending.
+PASS event.result is null
+
+Next test: upper bound is 1; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result is null
+
+Next test: lower open bound is 1; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower bound is 1; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: upper open bound is 1; sorted descending.
+PASS event.result is null
+
+Next test: upper bound is 1; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower open bound is 1; upper open bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 1; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 1; upper open bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 1; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 1; upper open bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower open bound is 1; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower bound is 1; upper open bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower bound is 1; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower open bound is 1; upper open bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 1; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 1; upper open bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 1; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 1; upper open bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower open bound is 1; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower bound is 1; upper open bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower bound is 1; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower open bound is 2; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 2; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: upper open bound is 2; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result is null
+
+Next test: upper bound is 2; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result is null
+
+Next test: lower open bound is 2; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower bound is 2; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: upper open bound is 2; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: upper bound is 2; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower open bound is 2; upper open bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 2; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 2; upper open bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 2; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 2; upper open bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower open bound is 2; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower bound is 2; upper open bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower bound is 2; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower open bound is 2; upper open bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 2; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 2; upper open bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 2; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 2; upper open bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower open bound is 2; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower bound is 2; upper open bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower bound is 2; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower open bound is 3; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 3; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: upper open bound is 3; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result is null
+
+Next test: upper bound is 3; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result is null
+
+Next test: lower open bound is 3; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower bound is 3; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: upper open bound is 3; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: upper bound is 3; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower open bound is 3; upper open bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 3; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 3; upper open bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 3; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 3; upper open bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower open bound is 3; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower bound is 3; upper open bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower bound is 3; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower open bound is 3; upper open bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 3; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 3; upper open bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 3; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 3; upper open bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower open bound is 3; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower bound is 3; upper open bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower bound is 3; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result is null
+
+Next test: lower open bound is 4; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 4; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: upper open bound is 4; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result is null
+
+Next test: upper bound is 4; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower open bound is 4; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 4; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: upper open bound is 4; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: upper bound is 4; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower open bound is 4; upper open bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 4; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 4; upper open bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 4; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 4; upper open bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 4; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 4; upper open bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower bound is 4; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower open bound is 4; upper open bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 4; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 4; upper open bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 4; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 4; upper open bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 4; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 4; upper open bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower bound is 4; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: lower open bound is 5; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 5; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: upper open bound is 5; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result is null
+
+Next test: upper bound is 5; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 5; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result is null
+
+Next test: lower bound is 5; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: upper open bound is 5; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: upper bound is 5; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower open bound is 5; upper open bound is 6; sorted ascending.
+PASS event.result is null
+
+Next test: lower open bound is 5; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 5; upper open bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 5; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 5; upper open bound is 6; sorted descending.
+PASS event.result is null
+
+Next test: lower open bound is 5; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result is null
+
+Next test: lower bound is 5; upper open bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 5; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 5; upper open bound is 7; sorted ascending.
+PASS event.result is null
+
+Next test: lower open bound is 5; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower bound is 5; upper open bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 5; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 5; upper open bound is 7; sorted descending.
+PASS event.result is null
+
+Next test: lower open bound is 5; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result is null
+
+Next test: lower bound is 5; upper open bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower bound is 5; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: lower open bound is 6; sorted ascending.
+PASS event.result is null
+
+Next test: lower bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: upper open bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 6; sorted descending.
+PASS event.result is null
+
+Next test: lower bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result is null
+
+Next test: upper open bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower open bound is 6; upper open bound is 6; sorted ascending.
+PASS event.result is null
+
+Next test: lower open bound is 6; upper bound is 6; sorted ascending.
+PASS event.result is null
+
+Next test: lower bound is 6; upper open bound is 6; sorted ascending.
+PASS event.result is null
+
+Next test: lower bound is 6; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 6; upper open bound is 6; sorted descending.
+PASS event.result is null
+
+Next test: lower open bound is 6; upper bound is 6; sorted descending.
+PASS event.result is null
+
+Next test: lower bound is 6; upper open bound is 6; sorted descending.
+PASS event.result is null
+
+Next test: lower bound is 6; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result is null
+
+Next test: lower open bound is 6; upper open bound is 7; sorted ascending.
+PASS event.result is null
+
+Next test: lower open bound is 6; upper bound is 7; sorted ascending.
+PASS event.result is null
+
+Next test: lower bound is 6; upper open bound is 7; sorted ascending.
+PASS event.result is null
+
+Next test: lower bound is 6; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 6; upper open bound is 7; sorted descending.
+PASS event.result is null
+
+Next test: lower open bound is 6; upper bound is 7; sorted descending.
+PASS event.result is null
+
+Next test: lower bound is 6; upper open bound is 7; sorted descending.
+PASS event.result is null
+
+Next test: lower bound is 6; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result is null
+
+Next test: lower open bound is 7; sorted ascending.
+PASS event.result is null
+
+Next test: lower bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: upper open bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result is null
+
+Next test: upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 7; sorted descending.
+PASS event.result is null
+
+Next test: lower bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result is null
+
+Next test: upper open bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[5]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[4]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[3]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[2]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[1]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[0]
+PASS event.result is null
+
+Next test: lower open bound is 7; upper open bound is 6; sorted ascending.
+PASS event.result is null
+
+Next test: lower open bound is 7; upper bound is 6; sorted ascending.
+PASS event.result is null
+
+Next test: lower bound is 7; upper open bound is 6; sorted ascending.
+PASS event.result is null
+
+Next test: lower bound is 7; upper bound is 6; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 7; upper open bound is 6; sorted descending.
+PASS event.result is null
+
+Next test: lower open bound is 7; upper bound is 6; sorted descending.
+PASS event.result is null
+
+Next test: lower bound is 7; upper open bound is 6; sorted descending.
+PASS event.result is null
+
+Next test: lower bound is 7; upper bound is 6; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result is null
+
+Next test: lower open bound is 7; upper open bound is 7; sorted ascending.
+PASS event.result is null
+
+Next test: lower open bound is 7; upper bound is 7; sorted ascending.
+PASS event.result is null
+
+Next test: lower bound is 7; upper open bound is 7; sorted ascending.
+PASS event.result is null
+
+Next test: lower bound is 7; upper bound is 7; sorted ascending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result is null
+
+Next test: lower open bound is 7; upper open bound is 7; sorted descending.
+PASS event.result is null
+
+Next test: lower open bound is 7; upper bound is 7; sorted descending.
+PASS event.result is null
+
+Next test: lower bound is 7; upper open bound is 7; sorted descending.
+PASS event.result is null
+
+Next test: lower bound is 7; upper bound is 7; sorted descending.
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[7]
+PASS event.result.value is expectedIndex
+PASS event.result.key is testData[6]
+PASS event.result is null
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/storage/indexeddb/index-cursor.html b/LayoutTests/storage/indexeddb/index-cursor.html
new file mode 100644
index 0000000..9541d60
--- /dev/null
+++ b/LayoutTests/storage/indexeddb/index-cursor.html
@@ -0,0 +1,238 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+<script src="../../fast/js/resources/js-test-post-function.js"></script>
+<script src="resources/shared.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script> 
+
+description("Test IndexedDB's IDBIndex.openCursor + the cursor it produces in depth.");
+if (window.layoutTestController)
+    layoutTestController.waitUntilDone();
+ 
+// In order of how it should be sorted by IndexedDB.
+window.testData = [
+    null,
+    null,
+    2,
+    2,
+    10,
+    // FIXME: Dates.
+    "A big string",
+    "the BIGEST string",
+    "the BIGEST string"
+];
+ 
+function openDatabase()
+{
+    result = evalAndLog("indexedDB.open('someDB', 'some description')");
+    verifyResult(result);
+    result.onsuccess = openObjectStore;
+    result.onerror = unexpectedErrorCallback;
+}
+ 
+function openObjectStore()
+{
+    verifySuccessEvent(event);
+    window.db = evalAndLog("db = event.result");
+
+    deleteAllObjectStores(db);
+
+    result = evalAndLog("db.createObjectStore('someObjectStore')");
+    verifyResult(result);
+    result.onsuccess = openIndex;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function openIndex()
+{
+    verifySuccessEvent(event);
+    window.objectStore = evalAndLog("objectStore = event.result");
+
+    result = evalAndLog("objectStore.createIndex('someIndex', 'x')");
+    verifyResult(result);
+    result.onsuccess = startAddingData;
+    result.onerror = unexpectedErrorCallback;
+}
+ 
+function startAddingData()
+{
+    verifySuccessEvent(event);
+    window.indexObject = evalAndLog("indexObject = event.result");
+
+    window.nextToAdd = 0;
+    addData();
+}
+
+function addData()
+{
+    // We cheat when called for the first time; we're in the context of the objectStore success event.
+    verifySuccessEvent(event);
+
+    result = evalAndLog("objectStore.add({'x': testData[nextToAdd]}, nextToAdd)");
+    verifyResult(result);
+    result.onsuccess = ++window.nextToAdd < testData.length ? addData : scheduleTests;
+}
+
+function scheduleTests()
+{
+    debug("Scheduling tests...");
+    window.scheduledTests = [];
+    for (var i = 0; i < testData.length; ++i) {
+        /* left bound, is open, right bound, is open, ascending */
+        scheduledTests.unshift([i, true, null, null, true]);
+        scheduledTests.unshift([i, false, null, null, true]);
+        scheduledTests.unshift([null, null, i, true, true]);
+        scheduledTests.unshift([null, null, i, false, true]);
+        scheduledTests.unshift([i, true, null, null, false]);
+        scheduledTests.unshift([i, false, null, null, false]);
+        scheduledTests.unshift([null, null, i, true, false]);
+        scheduledTests.unshift([null, null, i, false, false]);
+        for (var j = 6; j < testData.length; ++j) {
+            scheduledTests.unshift([i, true, j, true, true]);
+            scheduledTests.unshift([i, true, j, false, true]);
+            scheduledTests.unshift([i, false, j, true, true]);
+            scheduledTests.unshift([i, false, j, false, true]);
+            scheduledTests.unshift([i, true, j, true, false]);
+            scheduledTests.unshift([i, true, j, false, false]);
+            scheduledTests.unshift([i, false, j, true, false]);
+            scheduledTests.unshift([i, false, j, false, false]);
+        }
+    }
+ 
+    debug("Running tests...");
+    setTimeout(runNextTest, 0);
+}
+ 
+function runNextTest()
+{
+    if (!scheduledTests.length) {
+        done();
+        return;
+    }
+ 
+    var test = scheduledTests.pop();
+    window.lower = test[0];
+    window.lowerIsOpen = test[1];
+    window.upper = test[2];
+    window.upperIsOpen = test[3];
+    window.ascending = test[4];
+
+    str = "Next test: ";
+    if (lower !== null) {
+        str += "lower ";
+        if (lowerIsOpen)
+            str += "open ";
+        str += "bound is " + lower + "; ";
+    }
+    if (upper !== null) {
+        str += "upper ";
+        if (upperIsOpen)
+            str += "open ";
+        str += "bound is " + upper + "; ";
+    }
+    if (ascending)
+        str += "sorted ascending.";
+    else
+        str += "sorted descending.";
+
+    debug("");
+    debug(str);
+
+    // Work around for duplicate values.
+    if (upper !== null) {
+        if (upperIsOpen) {
+            while (upper > 0 && testData[upper] === testData[upper - 1])
+                --window.upper;
+        } else {
+            while (upper < testData.length - 1 && testData[upper] === testData[upper + 1])
+                ++window.upper;
+        }
+    }
+    if (lower !== null) {
+        if (lowerIsOpen) {
+            while (lower < testData.length - 1 && testData[lower] === testData[lower + 1])
+                ++window.lower;
+        } else {
+            while (lower > 0 && testData[lower] === testData[lower - 1])
+                --window.lower;
+        }
+    }
+
+    if (ascending) {
+        if (lower !== null) {
+            if (!lowerIsOpen)
+                window.expectedIndex = lower;
+            else
+                window.expectedIndex = lower + 1;
+        } else
+            window.expectedIndex = 0;
+    } else {
+        if (upper !== null) {
+            if (!upperIsOpen)
+                window.expectedIndex = upper;
+            else
+                window.expectedIndex = upper - 1;
+        } else
+            window.expectedIndex = testData.length - 1;
+    }
+    testWithinBounds();
+ 
+    var keyRange;
+    if (lower !== null && upper !== null)
+        keyRange = IDBKeyRange.bound(testData[lower], testData[upper], lowerIsOpen, upperIsOpen);
+    else if (lower !== null)
+        keyRange = IDBKeyRange.leftBound(testData[lower], lowerIsOpen);
+    else
+        keyRange = IDBKeyRange.rightBound(testData[upper], upperIsOpen);
+ 
+    var request = indexObject.openCursor(keyRange, ascending ? IDBCursor.NEXT : IDBCursor.PREV);
+    request.onsuccess = cursorIteration;
+    request.onerror = unexpectedErrorCallback;
+}
+
+function testWithinBounds()
+{
+    if (expectedIndex < 0 || testData.length <= expectedIndex)
+        window.expectedIndex = null;
+    if (lower !== null && expectedIndex < lower)
+        window.expectedIndex = null;
+    if (upper !== null && upper < expectedIndex)
+        window.expectedIndex = null;
+    if (lower !== null && lowerIsOpen && expectedIndex <= lower)
+        window.expectedIndex = null;
+    if (upper !== null && upperIsOpen && upper <= expectedIndex)
+        window.expectedIndex = null;
+}
+ 
+function cursorIteration()
+{
+    if (expectedIndex === null) {
+        shouldBeNull("event.result");
+        setTimeout(runNextTest, 0);
+        return;
+    }
+    if (event.result === null) {
+        testFailed("Event.result should not be null.")
+        setTimeout(runNextTest, 0);
+        return;
+    }
+ 
+    shouldBe("event.result.value", "expectedIndex");
+    shouldBe("event.result.key", "testData[" + expectedIndex + "]");
+    window.expectedIndex = ascending ? expectedIndex + 1 : expectedIndex - 1;
+    testWithinBounds();
+
+    event.result.continue();
+}
+ 
+openDatabase(); // The first step.
+var successfullyParsed = true;
+ 
+</script>
+</body>
+</html>
diff --git a/LayoutTests/storage/indexeddb/objectstore-basics-expected.txt b/LayoutTests/storage/indexeddb/objectstore-basics-expected.txt
index a60e857..890c00f 100644
--- a/LayoutTests/storage/indexeddb/objectstore-basics-expected.txt
+++ b/LayoutTests/storage/indexeddb/objectstore-basics-expected.txt
@@ -50,7 +50,7 @@ PASS store.name is "storeName"
 PASS store.keyPath is null
 PASS storeNames.contains('storeName') is true
 PASS storeNames.length is 1
-event.result.createIndex('indexName', 'x')
+event.result.createIndex('indexName', 'x', true)
 PASS 'onsuccess' in result is true
 PASS 'onerror' in result is true
 PASS 'abort' in result is true
@@ -92,6 +92,27 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.result is "key"
+event.source.add({x: 'value'}, 'zzz')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'abort' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+addAgainFailure():
+Error event fired:
+PASS 'result' in event is false
+PASS 'code' in event is true
+PASS 'message' in event is true
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'abort' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+PASS event.code is IDBDatabaseException.UNKNOWN_ERR
 store = event.source
 store.get('key')
 PASS 'onsuccess' in result is true
diff --git a/LayoutTests/storage/indexeddb/objectstore-basics.html b/LayoutTests/storage/indexeddb/objectstore-basics.html
index 8b696c4..731d421 100644
--- a/LayoutTests/storage/indexeddb/objectstore-basics.html
+++ b/LayoutTests/storage/indexeddb/objectstore-basics.html
@@ -49,7 +49,7 @@ function createSuccess()
     shouldBe("storeNames.length", "1");
     // FIXME: test all of object store's methods.
 
-    result = evalAndLog("event.result.createIndex('indexName', 'x')");
+    result = evalAndLog("event.result.createIndex('indexName', 'x', true)"); // true == unique requirement.
     verifyResult(result);
     result.onsuccess = addIndexSuccess;
     result.onerror = unexpectedErrorCallback;
@@ -72,6 +72,19 @@ function addSuccess()
     debug("addSuccess():");
     verifySuccessEvent(event);
     shouldBeEqualToString("event.result", "key");
+
+    result = evalAndLog("event.source.add({x: 'value'}, 'zzz')");
+    verifyResult(result);
+    result.onsuccess = unexpectedSuccessCallback;
+    result.onerror = addAgainFailure;
+}
+
+function addAgainFailure()
+{
+    debug("addAgainFailure():");
+    verifyErrorEvent(event);
+    // FIXME: This error code needs to be specced.
+    shouldBe("event.code", "IDBDatabaseException.UNKNOWN_ERR");
     var store = evalAndLog("store = event.source");
 
     result = evalAndLog("store.get('key')");
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index d2b4f0b..d8c055d 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,69 @@
+2010-09-08  Jeremy Orlow  <jorlow at chromium.org>
+
+        Reviewed by Steve Block.
+
+        Complete index support for IndexedDB
+        https://bugs.webkit.org/show_bug.cgi?id=45386
+
+        Add the rest of the index related API for IndexedDB.  This
+        includes cursor suport.  A bunch of code was also refactored
+        since it is shared between indexes and objectStores.
+
+        Tests: storage/indexeddb/index-basics.html
+               storage/indexeddb/index-cursor.html
+               + additions to others.
+
+        * storage/IDBAny.cpp:
+        (WebCore::IDBAny::set):
+        * storage/IDBCursor.cpp:
+        (WebCore::IDBCursor::value):
+        * storage/IDBCursorBackendImpl.cpp:
+        (WebCore::IDBCursorBackendImpl::IDBCursorBackendImpl):
+        (WebCore::IDBCursorBackendImpl::value):
+        (WebCore::IDBCursorBackendImpl::update):
+        (WebCore::IDBCursorBackendImpl::continueFunction):
+        (WebCore::IDBCursorBackendImpl::remove):
+        (WebCore::IDBCursorBackendImpl::loadCurrentRow):
+        (WebCore::IDBCursorBackendImpl::database):
+        * storage/IDBCursorBackendImpl.h:
+        (WebCore::IDBCursorBackendImpl::create):
+        * storage/IDBCursorBackendInterface.h:
+        * storage/IDBFactoryBackendImpl.cpp:
+        (WebCore::createTables):
+        * storage/IDBIndex.cpp:
+        (WebCore::IDBIndex::openObjectCursor):
+        (WebCore::IDBIndex::openCursor):
+        (WebCore::IDBIndex::getObject):
+        (WebCore::IDBIndex::get):
+        * storage/IDBIndex.h:
+        (WebCore::IDBIndex::storeName):
+        * storage/IDBIndex.idl:
+        * storage/IDBIndexBackendImpl.cpp:
+        (WebCore::IDBIndexBackendImpl::storeName):
+        (WebCore::openCursorInternal):
+        (WebCore::IDBIndexBackendImpl::openObjectCursor):
+        (WebCore::IDBIndexBackendImpl::openCursor):
+        (WebCore::getInternal):
+        (WebCore::IDBIndexBackendImpl::getObject):
+        (WebCore::IDBIndexBackendImpl::get):
+        * storage/IDBIndexBackendImpl.h:
+        (WebCore::IDBIndexBackendImpl::objectStore):
+        * storage/IDBIndexBackendInterface.h:
+        * storage/IDBKey.cpp:
+        (WebCore::IDBKey::fromQuery):
+        (WebCore::IDBKey::whereSyntax):
+        (WebCore::IDBKey::leftCursorWhereFragment):
+        (WebCore::IDBKey::rightCursorWhereFragment):
+        * storage/IDBKey.h:
+        * storage/IDBKeyRange.cpp:
+        (WebCore::IDBKeyRange::leftWhereClauseComparisonOperator):
+        (WebCore::IDBKeyRange::rightWhereClauseComparisonOperator):
+        * storage/IDBKeyRange.h:
+        * storage/IDBObjectStoreBackendImpl.cpp:
+        (WebCore::IDBObjectStoreBackendImpl::openCursor):
+        * storage/IDBRequest.cpp:
+        (WebCore::IDBRequest::timerFired):
+
 2010-09-15  Simon Fraser  <simon.fraser at apple.com>
 
         Fix chromium build.
diff --git a/WebCore/storage/IDBAny.cpp b/WebCore/storage/IDBAny.cpp
index 7303fd6..45b166d 100644
--- a/WebCore/storage/IDBAny.cpp
+++ b/WebCore/storage/IDBAny.cpp
@@ -123,7 +123,7 @@ void IDBAny::set(PassRefPtr<IDBDatabase> value)
 void IDBAny::set(PassRefPtr<IDBIndex> value)
 {
     ASSERT(m_type == UndefinedType);
-    m_type = IDBDatabaseType;
+    m_type = IDBIndexType;
     m_idbIndex = value;
 }
 
diff --git a/WebCore/storage/IDBCursor.cpp b/WebCore/storage/IDBCursor.cpp
index 52945f8..c1c077b 100644
--- a/WebCore/storage/IDBCursor.cpp
+++ b/WebCore/storage/IDBCursor.cpp
@@ -60,7 +60,7 @@ PassRefPtr<IDBKey> IDBCursor::key() const
 
 PassRefPtr<IDBAny> IDBCursor::value() const
 {
-    return IDBAny::create(m_backend->value().get());
+    return m_backend->value();
 }
 
 PassRefPtr<IDBRequest> IDBCursor::update(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value)
diff --git a/WebCore/storage/IDBCursorBackendImpl.cpp b/WebCore/storage/IDBCursorBackendImpl.cpp
index 4cbac0e..3a4dd67 100644
--- a/WebCore/storage/IDBCursorBackendImpl.cpp
+++ b/WebCore/storage/IDBCursorBackendImpl.cpp
@@ -32,6 +32,7 @@
 #include "IDBDatabaseBackendImpl.h"
 #include "IDBDatabaseError.h"
 #include "IDBDatabaseException.h"
+#include "IDBIndexBackendImpl.h"
 #include "IDBKeyRange.h"
 #include "IDBObjectStoreBackendImpl.h"
 #include "IDBRequest.h"
@@ -46,6 +47,17 @@ IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBObjectStoreBackendImpl>
     , m_keyRange(keyRange)
     , m_direction(direction)
     , m_query(query)
+    , m_isSerializedScriptValueCursor(true)
+{
+    loadCurrentRow();
+}
+
+IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBIndexBackendImpl> idbIndex, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor)
+    : m_idbIndex(idbIndex)
+    , m_keyRange(keyRange)
+    , m_direction(direction)
+    , m_query(query)
+    , m_isSerializedScriptValueCursor(isSerializedScriptValueCursor)
 {
     loadCurrentRow();
 }
@@ -65,13 +77,19 @@ PassRefPtr<IDBKey> IDBCursorBackendImpl::key() const
     return m_currentKey;
 }
 
-PassRefPtr<SerializedScriptValue> IDBCursorBackendImpl::value() const
+PassRefPtr<IDBAny> IDBCursorBackendImpl::value() const
 {
-    return m_currentValue;
+    if (m_isSerializedScriptValueCursor)
+        return IDBAny::create(m_currentSerializedScriptValue.get());
+    return IDBAny::create(m_currentIDBKeyValue.get());
 }
 
 void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBCallbacks> callbacks)
 {
+    // FIXME: This method doesn't update indexes. It's dangerous to call in its current state.
+    callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Not implemented."));
+    return;
+
     RefPtr<SerializedScriptValue> value = prpValue;
 
     if (!m_query || m_currentId == InvalidId) {
@@ -81,7 +99,7 @@ void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> prpValue, Pa
     }
 
     String sql = "UPDATE ObjectStoreData SET value = ? WHERE id = ?";
-    SQLiteStatement updateQuery(m_idbObjectStore->database()->sqliteDatabase(), sql);
+    SQLiteStatement updateQuery(database()->sqliteDatabase(), sql);
     
     bool ok = updateQuery.prepare() == SQLResultOk;
     ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
@@ -90,7 +108,8 @@ void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> prpValue, Pa
     ok = updateQuery.step() == SQLResultDone;
     ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
 
-    m_currentValue = value.release();
+    if (m_isSerializedScriptValueCursor)
+        m_currentSerializedScriptValue = value.release();
     callbacks->onSuccess();
 }
 
@@ -102,7 +121,8 @@ void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey> prpKey, PassRefPt
             m_query = 0;
             m_currentId = InvalidId;
             m_currentKey = 0;
-            m_currentValue = 0;
+            m_currentSerializedScriptValue = 0;
+            m_currentIDBKeyValue = 0;
             callbacks->onSuccess();
             return;
         }
@@ -126,6 +146,10 @@ void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey> prpKey, PassRefPt
 
 void IDBCursorBackendImpl::remove(PassRefPtr<IDBCallbacks> callbacks)
 {
+    // FIXME: This method doesn't update indexes. It's dangerous to call in its current state.
+    callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Not implemented."));
+    return;
+
     if (!m_query || m_currentId == InvalidId) {
         // FIXME: Use the proper error code when it's specced.
         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Operation not possible."));
@@ -133,7 +157,7 @@ void IDBCursorBackendImpl::remove(PassRefPtr<IDBCallbacks> callbacks)
     }
 
     String sql = "DELETE FROM ObjectStoreData WHERE id = ?";
-    SQLiteStatement deleteQuery(m_idbObjectStore->database()->sqliteDatabase(), sql);
+    SQLiteStatement deleteQuery(database()->sqliteDatabase(), sql);
     
     bool ok = deleteQuery.prepare() == SQLResultOk;
     ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
@@ -142,8 +166,8 @@ void IDBCursorBackendImpl::remove(PassRefPtr<IDBCallbacks> callbacks)
     ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
 
     m_currentId = InvalidId;
-    m_currentKey = 0;
-    m_currentValue = 0;
+    m_currentSerializedScriptValue = 0;
+    m_currentIDBKeyValue = 0;
     callbacks->onSuccess();
 }
 
@@ -151,16 +175,18 @@ void IDBCursorBackendImpl::loadCurrentRow()
 {
     // The column numbers depend on the query in IDBObjectStoreBackendImpl::openCursor.
     m_currentId = m_query->getColumnInt64(0);
-    if (!m_query->isColumnNull(1))
-        m_currentKey = IDBKey::create(m_query->getColumnText(1));
-    else if (!m_query->isColumnNull(2)) {
-        ASSERT_NOT_REACHED(); // FIXME: Implement date.
-        m_currentKey = IDBKey::create();
-    } else if (!m_query->isColumnNull(3))
-        m_currentKey = IDBKey::create(m_query->getColumnInt(3));
+    m_currentKey = IDBKey::fromQuery(*m_query, 1);
+    if (m_isSerializedScriptValueCursor)
+        m_currentSerializedScriptValue = SerializedScriptValue::createFromWire(m_query->getColumnText(4));
     else
-        m_currentKey = IDBKey::create();
-    m_currentValue = SerializedScriptValue::createFromWire(m_query->getColumnText(4));
+        m_currentIDBKeyValue = IDBKey::fromQuery(*m_query, 4);
+}
+
+IDBDatabaseBackendImpl* IDBCursorBackendImpl::database() const
+{
+    if (m_idbObjectStore)
+        return m_idbObjectStore->database();
+    return m_idbIndex->objectStore()->database();
 }
 
 } // namespace WebCore
diff --git a/WebCore/storage/IDBCursorBackendImpl.h b/WebCore/storage/IDBCursorBackendImpl.h
index 3f7c4aa..b67ec70 100644
--- a/WebCore/storage/IDBCursorBackendImpl.h
+++ b/WebCore/storage/IDBCursorBackendImpl.h
@@ -37,6 +37,8 @@
 
 namespace WebCore {
 
+class IDBDatabaseBackendImpl;
+class IDBIndexBackendImpl;
 class IDBKeyRange;
 class IDBObjectStoreBackendImpl;
 class SQLiteStatement;
@@ -48,29 +50,42 @@ public:
     {
         return adoptRef(new IDBCursorBackendImpl(objectStore, keyRange, direction, query));
     }
+    static PassRefPtr<IDBCursorBackendImpl> create(PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor)
+    {
+        return adoptRef(new IDBCursorBackendImpl(index, keyRange, direction, query, isSerializedScriptValueCursor));
+    }
     virtual ~IDBCursorBackendImpl();
 
     virtual unsigned short direction() const;
     virtual PassRefPtr<IDBKey> key() const;
-    virtual PassRefPtr<SerializedScriptValue> value() const;
+    virtual PassRefPtr<IDBAny> value() const;
     virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>);
     virtual void continueFunction(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>);
     virtual void remove(PassRefPtr<IDBCallbacks>);
 
 private:
     IDBCursorBackendImpl(PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassOwnPtr<SQLiteStatement> query);
+    IDBCursorBackendImpl(PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor);
 
     void loadCurrentRow();
+    IDBDatabaseBackendImpl* database() const;
 
     static const int64_t InvalidId = -1;
 
+    // Only one or the other should be used.
     RefPtr<IDBObjectStoreBackendImpl> m_idbObjectStore;
+    RefPtr<IDBIndexBackendImpl> m_idbIndex;
+
     RefPtr<IDBKeyRange> m_keyRange;
     IDBCursor::Direction m_direction;
     OwnPtr<SQLiteStatement> m_query;
+    bool m_isSerializedScriptValueCursor;
     int64_t m_currentId;
     RefPtr<IDBKey> m_currentKey;
-    RefPtr<SerializedScriptValue> m_currentValue;
+
+    // Only one of these will ever be used for each instance. Which depends on m_isSerializedScriptValueCursor.
+    RefPtr<SerializedScriptValue> m_currentSerializedScriptValue;
+    RefPtr<IDBKey> m_currentIDBKeyValue;
 };
 
 } // namespace WebCore
diff --git a/WebCore/storage/IDBCursorBackendInterface.h b/WebCore/storage/IDBCursorBackendInterface.h
index acea955..4b209c4 100644
--- a/WebCore/storage/IDBCursorBackendInterface.h
+++ b/WebCore/storage/IDBCursorBackendInterface.h
@@ -46,7 +46,7 @@ public:
 
     virtual unsigned short direction() const = 0;
     virtual PassRefPtr<IDBKey> key() const = 0;
-    virtual PassRefPtr<SerializedScriptValue> value() const = 0;
+    virtual PassRefPtr<IDBAny> value() const = 0;
 
     virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>) = 0;
     virtual void continueFunction(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>) = 0;
diff --git a/WebCore/storage/IDBFactoryBackendImpl.cpp b/WebCore/storage/IDBFactoryBackendImpl.cpp
index 50cf778..76ce617 100644
--- a/WebCore/storage/IDBFactoryBackendImpl.cpp
+++ b/WebCore/storage/IDBFactoryBackendImpl.cpp
@@ -100,11 +100,11 @@ static bool createTables(SQLiteDatabase* sqliteDatabase)
         "DROP TABLE IF EXISTS IndexData",
         "CREATE TABLE IF NOT EXISTS IndexData (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexs(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, objectStoreDataId INTEGER NOT NULL UNIQUE REFERENCES ObjectStoreData(id))",
         "DROP INDEX IF EXISTS IndexData_composit",
-        "CREATE UNIQUE INDEX IF NOT EXISTS IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)",
+        "CREATE INDEX IF NOT EXISTS IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)",
         "DROP INDEX IF EXISTS IndexData_objectStoreDataId",
-        "CREATE UNIQUE INDEX IF NOT EXISTS IndexData_objectStoreDataId ON IndexData(objectStoreDataId)",
+        "CREATE INDEX IF NOT EXISTS IndexData_objectStoreDataId ON IndexData(objectStoreDataId)",
         "DROP INDEX IF EXISTS IndexData_indexId",
-        "CREATE UNIQUE INDEX IF NOT EXISTS IndexData_indexId ON IndexData(indexId)"
+        "CREATE INDEX IF NOT EXISTS IndexData_indexId ON IndexData(indexId)"
         };
 
     for (size_t i = 0; i < arraysize(commands); ++i) {
diff --git a/WebCore/storage/IDBIndex.cpp b/WebCore/storage/IDBIndex.cpp
index 62c1da8..5cd12dd 100644
--- a/WebCore/storage/IDBIndex.cpp
+++ b/WebCore/storage/IDBIndex.cpp
@@ -28,6 +28,12 @@
 
 #if ENABLE(INDEXED_DATABASE)
 
+#include "IDBCursorBackendInterface.h"
+#include "IDBIndexBackendInterface.h"
+#include "IDBKey.h"
+#include "IDBKeyRange.h"
+#include "IDBRequest.h"
+
 namespace WebCore {
 
 IDBIndex::IDBIndex(PassRefPtr<IDBIndexBackendInterface> backend)
@@ -39,6 +45,34 @@ IDBIndex::~IDBIndex()
 {
 }
 
+PassRefPtr<IDBRequest> IDBIndex::openObjectCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction)
+{
+    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
+    m_backend->openObjectCursor(keyRange, direction, request);
+    return request;
+}
+
+PassRefPtr<IDBRequest> IDBIndex::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction)
+{
+    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
+    m_backend->openCursor(keyRange, direction, request);
+    return request;
+}
+
+PassRefPtr<IDBRequest> IDBIndex::getObject(ScriptExecutionContext* context, PassRefPtr<IDBKey> key)
+{
+    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
+    m_backend->getObject(key, request);
+    return request;
+}
+
+PassRefPtr<IDBRequest> IDBIndex::get(ScriptExecutionContext* context, PassRefPtr<IDBKey> key)
+{
+    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
+    m_backend->get(key, request);
+    return request;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBIndex.h b/WebCore/storage/IDBIndex.h
index 5e716b7..45fcfa1 100644
--- a/WebCore/storage/IDBIndex.h
+++ b/WebCore/storage/IDBIndex.h
@@ -26,6 +26,7 @@
 #ifndef IDBIndex_h
 #define IDBIndex_h
 
+#include "IDBCursor.h"
 #include "IDBIndexBackendInterface.h"
 #include "PlatformString.h"
 #include <wtf/Forward.h>
@@ -44,9 +45,15 @@ public:
 
     // Implement the IDL
     String name() const { return m_backend->name(); }
+    String storeName() const { return m_backend->storeName(); }
     String keyPath() const { return m_backend->keyPath(); }
     bool unique() const { return m_backend->unique(); }
 
+    PassRefPtr<IDBRequest> openObjectCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange> = 0, unsigned short direction = IDBCursor::NEXT);
+    PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange> = 0, unsigned short direction = IDBCursor::NEXT);
+    PassRefPtr<IDBRequest> getObject(ScriptExecutionContext*, PassRefPtr<IDBKey>);
+    PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKey>);
+
 private:
     IDBIndex(PassRefPtr<IDBIndexBackendInterface>);
 
diff --git a/WebCore/storage/IDBIndex.idl b/WebCore/storage/IDBIndex.idl
index 629481e..ba3ecea 100644
--- a/WebCore/storage/IDBIndex.idl
+++ b/WebCore/storage/IDBIndex.idl
@@ -29,15 +29,15 @@ module storage {
         Conditional=INDEXED_DATABASE
     ] IDBIndex {
         readonly attribute DOMString name;
-        // FIXME: Add "storeName".
+        readonly attribute DOMString storeName;
         readonly attribute DOMString keyPath;
         readonly attribute boolean unique;
 
-        // FIXME: Implement.
-        //IDBRequest openObjectCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction) raises (DOMException);
-        //IDBRequest openCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction) raises (DOMException);
-        //IDBRequest getObject(in IDBKey key) raises (DOMException);
-        //IDBRequest get(in IDBKey key) raises (DOMException);
+        // FIXME: All of these should raise on certain errors.
+        [CallWith=ScriptExecutionContext] IDBRequest openObjectCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction);
+        [CallWith=ScriptExecutionContext] IDBRequest openCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction);
+        [CallWith=ScriptExecutionContext] IDBRequest getObject(in IDBKey key);
+        [CallWith=ScriptExecutionContext] IDBRequest get(in IDBKey key);
     };
 
 }
diff --git a/WebCore/storage/IDBIndexBackendImpl.cpp b/WebCore/storage/IDBIndexBackendImpl.cpp
index 42aa62b..6f698c6 100644
--- a/WebCore/storage/IDBIndexBackendImpl.cpp
+++ b/WebCore/storage/IDBIndexBackendImpl.cpp
@@ -28,8 +28,14 @@
 
 #if ENABLE(INDEXED_DATABASE)
 
+#include "IDBCallbacks.h"
+#include "IDBCursorBackendImpl.h"
 #include "IDBDatabaseBackendImpl.h"
+#include "IDBDatabaseException.h"
+#include "IDBKey.h"
+#include "IDBKeyRange.h"
 #include "IDBObjectStoreBackendImpl.h"
+#include "SQLiteDatabase.h"
 #include "SQLiteStatement.h"
 
 namespace WebCore {
@@ -47,6 +53,98 @@ IDBIndexBackendImpl::~IDBIndexBackendImpl()
 {
 }
 
+String IDBIndexBackendImpl::storeName()
+{
+    return m_objectStore->name();
+}
+
+static void openCursorInternal(SQLiteDatabase& database, IDBIndexBackendImpl* index, IDBKeyRange* range, unsigned short untypedDirection, bool objectCursor, IDBCallbacks* callbacks)
+{
+    // Several files depend on this order of selects.
+    String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ")
+                 + (objectCursor ? "ObjectStoreData.value " : "ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ")
+                 + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id WHERE ";
+
+    bool leftBound = range && (range->flags() & IDBKeyRange::LEFT_BOUND || range->flags() == IDBKeyRange::SINGLE);
+    bool rightBound = range && (range->flags() & IDBKeyRange::RIGHT_BOUND || range->flags() == IDBKeyRange::SINGLE);
+    
+    if (leftBound)
+        sql += range->left()->leftCursorWhereFragment(range->leftWhereClauseComparisonOperator(), "IndexData.");
+    if (rightBound)
+        sql += range->right()->rightCursorWhereFragment(range->rightWhereClauseComparisonOperator(), "IndexData.");
+    sql += "IndexData.indexId = ? ORDER BY ";
+
+    IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(untypedDirection);
+    if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE)
+        sql += "IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, IndexData.id";
+    else
+        sql += "IndexData.keyString DESC, IndexData.keyDate DESC, IndexData.keyNumber DESC, IndexData.id DESC";
+
+    OwnPtr<SQLiteStatement> query = adoptPtr(new SQLiteStatement(database, sql));
+    bool ok = query->prepare() == SQLResultOk;
+    ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+
+    int indexColumn = 1;
+    if (leftBound)
+        indexColumn += range->left()->bind(*query, indexColumn);
+    if (rightBound)
+        indexColumn += range->right()->bind(*query, indexColumn);
+    query->bindInt64(indexColumn, index->id());
+
+    if (query->step() != SQLResultRow) {
+        callbacks->onSuccess();
+        return;
+    }
+
+    RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(index, range, direction, query.release(), objectCursor);
+    callbacks->onSuccess(cursor.release());
+}
+
+void IDBIndexBackendImpl::openObjectCursor(PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, PassRefPtr<IDBCallbacks> callbacks)
+{
+    openCursorInternal(sqliteDatabase(), this, keyRange.get(), direction, true, callbacks.get());
+}
+
+void IDBIndexBackendImpl::openCursor(PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, PassRefPtr<IDBCallbacks> callbacks)
+{
+    openCursorInternal(sqliteDatabase(), this, keyRange.get(), direction, false, callbacks.get());
+}
+
+static void getInternal(SQLiteDatabase& database, int64 id, IDBKey* key, bool getObject, IDBCallbacks* callbacks)
+{
+    String sql = String("SELECT ")
+                 + (getObject ? "ObjectStoreData.value " : "ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ")
+                 + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id "
+                 + "WHERE IndexData.indexId = ?  AND  " + key->whereSyntax("IndexData.")
+                 + "ORDER BY IndexData.id LIMIT 1"; // Order by insertion order when all else fails.
+    SQLiteStatement query(database, sql);
+    bool ok = query.prepare() == SQLResultOk;
+    ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+
+    query.bindInt64(1, id);
+    key->bind(query, 2);
+    if (query.step() != SQLResultRow) {
+        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index."));
+        return;
+    }
+
+    if (getObject)
+        callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnText(0)));
+    else
+        callbacks->onSuccess(IDBKey::fromQuery(query, 0));
+    ASSERT(query.step() != SQLResultRow);
+}
+
+void IDBIndexBackendImpl::getObject(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
+{
+    getInternal(sqliteDatabase(), m_id, key.get(), true, callbacks.get());
+}
+
+void IDBIndexBackendImpl::get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
+{
+    getInternal(sqliteDatabase(), m_id, key.get(), false, callbacks.get());
+}
+
 static String whereClause(IDBKey* key)
 {
     return "WHERE indexId = ?  AND  " + key->whereSyntax();
diff --git a/WebCore/storage/IDBIndexBackendImpl.h b/WebCore/storage/IDBIndexBackendImpl.h
index 97c65f9..a98ed2a 100644
--- a/WebCore/storage/IDBIndexBackendImpl.h
+++ b/WebCore/storage/IDBIndexBackendImpl.h
@@ -49,9 +49,17 @@ public:
 
     // Implements IDBIndexBackendInterface.
     virtual String name() { return m_name; }
+    virtual String storeName();
     virtual String keyPath() { return m_keyPath; }
     virtual bool unique() { return m_unique; }
 
+    virtual void openObjectCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>);
+    virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>);
+    virtual void getObject(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>);
+    virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>);
+
+    IDBObjectStoreBackendImpl* objectStore() const { return m_objectStore.get(); }
+
 private:
     IDBIndexBackendImpl(IDBObjectStoreBackendImpl*, int64_t id, const String& name, const String& keyPath, bool unique);
 
diff --git a/WebCore/storage/IDBIndexBackendInterface.h b/WebCore/storage/IDBIndexBackendInterface.h
index 0d1ea34..ff2316f 100644
--- a/WebCore/storage/IDBIndexBackendInterface.h
+++ b/WebCore/storage/IDBIndexBackendInterface.h
@@ -33,13 +33,23 @@
 
 namespace WebCore {
 
+class IDBCallbacks;
+class IDBKey;
+class IDBKeyRange;
+
 class IDBIndexBackendInterface : public ThreadSafeShared<IDBIndexBackendInterface> {
 public:
     virtual ~IDBIndexBackendInterface() { }
 
     virtual String name() = 0;
+    virtual String storeName() = 0;
     virtual String keyPath() = 0;
     virtual bool unique() = 0;
+
+    virtual void openObjectCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>) = 0;
+    virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>) = 0;
+    virtual void getObject(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>) = 0;
+    virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>) = 0;
 };
 
 } // namespace WebCore
diff --git a/WebCore/storage/IDBKey.cpp b/WebCore/storage/IDBKey.cpp
index 6ae79ba..3eec36c 100644
--- a/WebCore/storage/IDBKey.cpp
+++ b/WebCore/storage/IDBKey.cpp
@@ -54,6 +54,22 @@ IDBKey::~IDBKey()
 {
 }
 
+PassRefPtr<IDBKey> IDBKey::fromQuery(SQLiteStatement& query, int baseColumn)
+{
+    if (!query.isColumnNull(baseColumn))
+        return IDBKey::create(query.getColumnText(baseColumn));
+
+    if (!query.isColumnNull(baseColumn + 1)) {
+        ASSERT_NOT_REACHED(); // FIXME: Implement date.
+        return IDBKey::create();
+    }
+
+    if (!query.isColumnNull(baseColumn + 2))
+        return IDBKey::create(query.getColumnInt(baseColumn + 2));
+
+    return IDBKey::create(); // Null.
+}
+
 bool IDBKey::isEqual(IDBKey* other)
 {
     if (!other || other->m_type != m_type)
@@ -73,22 +89,56 @@ bool IDBKey::isEqual(IDBKey* other)
     return false;
 }
 
-String IDBKey::whereSyntax() const
+String IDBKey::whereSyntax(String qualifiedTableName) const
 {
     switch (m_type) {
     case IDBKey::StringType:
-        return "keyString = ?";
+        return qualifiedTableName + "keyString = ?  ";
     case IDBKey::NumberType:
-        return "keyNumber = ?";
+        return qualifiedTableName + "keyNumber = ?  ";
     // FIXME: Implement date.
     case IDBKey::NullType:
-        return "keyString IS NULL  AND  keyDate IS NULL  AND  keyNumber IS NULL";
+        return qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate IS NULL  AND  " + qualifiedTableName + "keyNumber IS NULL  ";
     }
 
     ASSERT_NOT_REACHED();
     return "";
 }
 
+String IDBKey::leftCursorWhereFragment(String comparisonOperator, String qualifiedTableName)
+{
+    switch (m_type) {
+    case StringType:
+        return "? " + comparisonOperator + " " + qualifiedTableName + "keyString  AND  ";
+    // FIXME: Implement date.
+    case NumberType:
+        return "(? " + comparisonOperator + " " + qualifiedTableName + "keyNumber  OR  NOT " + qualifiedTableName + "keyString IS NULL  OR  NOT " + qualifiedTableName + "keyDate IS NULL)  AND  ";
+    case NullType:
+        if (comparisonOperator == "<")
+            return "NOT(" + qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate IS NULL  AND  " + qualifiedTableName + "keyNumber IS NULL)  AND  ";
+        return ""; // If it's =, the upper bound half will do the constraining. If it's <=, then that's a no-op.
+    }
+    ASSERT_NOT_REACHED();
+    return "";
+}
+
+String IDBKey::rightCursorWhereFragment(String comparisonOperator, String qualifiedTableName)
+{
+    switch (m_type) {
+    case StringType:
+        return "(" + qualifiedTableName + "keyString " + comparisonOperator + " ?  OR  " + qualifiedTableName + "keyString IS NULL)  AND  ";
+    // FIXME: Implement date.
+    case NumberType:
+        return "(" + qualifiedTableName + "keyNumber " + comparisonOperator + " ? OR " + qualifiedTableName + "keyNumber IS NULL)  AND  " + qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate IS NULL  AND  ";
+    case NullType:
+        if (comparisonOperator == "<")
+            return "0 != 0  AND  ";
+        return qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate IS NULL  AND  " + qualifiedTableName + "keyNumber IS NULL  AND  ";
+    }
+    ASSERT_NOT_REACHED();
+    return "";
+}
+
 // Returns the number of items bound.
 int IDBKey::bind(SQLiteStatement& query, int column) const
 {
diff --git a/WebCore/storage/IDBKey.h b/WebCore/storage/IDBKey.h
index b9a0be7..3175e7e 100644
--- a/WebCore/storage/IDBKey.h
+++ b/WebCore/storage/IDBKey.h
@@ -73,8 +73,12 @@ public:
         return m_number;
     }
 
+    static PassRefPtr<IDBKey> fromQuery(SQLiteStatement& query, int baseColumn);
+
     bool isEqual(IDBKey* other);
-    String whereSyntax() const;
+    String whereSyntax(String qualifiedTableName = "") const;
+    String leftCursorWhereFragment(String comparisonOperator, String qualifiedTableName = "");
+    String rightCursorWhereFragment(String comparisonOperator, String qualifiedTableName = "");
     int bind(SQLiteStatement& query, int column) const;
     void bindWithNulls(SQLiteStatement& query, int baseColumn) const;
 
diff --git a/WebCore/storage/IDBKeyRange.cpp b/WebCore/storage/IDBKeyRange.cpp
index 4088b34..6c612cc 100644
--- a/WebCore/storage/IDBKeyRange.cpp
+++ b/WebCore/storage/IDBKeyRange.cpp
@@ -71,6 +71,36 @@ PassRefPtr<IDBKeyRange> IDBKeyRange::bound(PassRefPtr<IDBKey> left, PassRefPtr<I
     return IDBKeyRange::create(left, right, flags);
 }
 
+String IDBKeyRange::leftWhereClauseComparisonOperator() const
+{
+    if (m_flags & LEFT_OPEN)
+        return "<";
+
+    if (m_flags & LEFT_BOUND)
+        return "<=";
+
+    if (m_flags == SINGLE)
+        return "=";
+
+    ASSERT_NOT_REACHED();
+    return "";
+}
+
+String IDBKeyRange::rightWhereClauseComparisonOperator() const
+{
+    if (m_flags & RIGHT_OPEN)
+        return "<";
+
+    if (m_flags & RIGHT_BOUND)
+        return "<=";
+
+    if (m_flags == SINGLE)
+        return "=";
+
+    ASSERT_NOT_REACHED();
+    return "";
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBKeyRange.h b/WebCore/storage/IDBKeyRange.h
index 5a426b7..4621a50 100644
--- a/WebCore/storage/IDBKeyRange.h
+++ b/WebCore/storage/IDBKeyRange.h
@@ -57,6 +57,9 @@ public:
     PassRefPtr<IDBKey> right() const { return m_right; }
     unsigned short flags() const { return m_flags; }
 
+    String leftWhereClauseComparisonOperator() const;
+    String rightWhereClauseComparisonOperator() const;
+
     static PassRefPtr<IDBKeyRange> only(PassRefPtr<IDBKey> value);
     static PassRefPtr<IDBKeyRange> leftBound(PassRefPtr<IDBKey> bound, bool open = false);
     static PassRefPtr<IDBKeyRange> rightBound(PassRefPtr<IDBKey> bound, bool open = false);
diff --git a/WebCore/storage/IDBObjectStoreBackendImpl.cpp b/WebCore/storage/IDBObjectStoreBackendImpl.cpp
index 86237de..e5f81ab 100644
--- a/WebCore/storage/IDBObjectStoreBackendImpl.cpp
+++ b/WebCore/storage/IDBObjectStoreBackendImpl.cpp
@@ -279,64 +279,14 @@ void IDBObjectStoreBackendImpl::removeIndex(const String& name, PassRefPtr<IDBCa
     callbacks->onSuccess();
 }
 
-static String leftCursorWhereFragment(IDBKey::Type type, String comparisonOperator)
-{
-    switch (type) {
-    case IDBKey::StringType:
-        return "? " + comparisonOperator + " keyString  AND  ";
-    // FIXME: Implement date.
-    case IDBKey::NumberType:
-        return "(? " + comparisonOperator + " keyNumber  OR  NOT keyString IS NULL  OR  NOT keyDate IS NULL)  AND  ";
-    case IDBKey::NullType:
-        if (comparisonOperator == "<")
-            return "NOT(keyString IS NULL  AND  keyDate IS NULL  AND  keyNumber IS NULL)  AND  ";
-        return ""; // If it's =, the upper bound half will do the constraining. If it's <=, then that's a no-op.
-    }
-    ASSERT_NOT_REACHED();
-    return "";
-}
-
-static String rightCursorWhereFragment(IDBKey::Type type, String comparisonOperator)
-{
-    switch (type) {
-    case IDBKey::StringType:
-        return "(keyString " + comparisonOperator + " ?  OR  keyString IS NULL)  AND  ";
-    // FIXME: Implement date.
-    case IDBKey::NumberType:
-        return "(keyNumber " + comparisonOperator + " ? OR keyNumber IS NULL)  AND  keyString IS NULL  AND  keyDate IS NULL  AND  ";
-    case IDBKey::NullType:
-        if (comparisonOperator == "<")
-            return "0 != 0  AND  ";
-        return "keyString IS NULL  AND  keyDate IS NULL  AND  keyNumber IS NULL  AND  ";
-    }
-    ASSERT_NOT_REACHED();
-    return "";
-}
-
 void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks)
 {
-    String lowerEquality;
-    if (range->flags() & IDBKeyRange::LEFT_OPEN)
-        lowerEquality = "<";
-    else if (range->flags() & IDBKeyRange::LEFT_BOUND)
-        lowerEquality = "<=";
-    else
-        lowerEquality = "=";
-
-    String upperEquality;
-    if (range->flags() & IDBKeyRange::RIGHT_OPEN)
-        upperEquality = "<";
-    else if (range->flags() & IDBKeyRange::RIGHT_BOUND)
-        upperEquality = "<=";
-    else
-        upperEquality = "=";
-
-    // If you change the order of this select, you'll need to change it in IDBCursorBackendImpl.cpp as well.
+    // Several files depend on this order of selects.
     String sql = "SELECT id, keyString, keyDate, keyNumber, value FROM ObjectStoreData WHERE ";
     if (range->flags() & IDBKeyRange::LEFT_BOUND || range->flags() == IDBKeyRange::SINGLE)
-        sql += leftCursorWhereFragment(range->left()->type(), lowerEquality);
+        sql += range->left()->leftCursorWhereFragment(range->leftWhereClauseComparisonOperator());
     if (range->flags() & IDBKeyRange::RIGHT_BOUND || range->flags() == IDBKeyRange::SINGLE)
-        sql += rightCursorWhereFragment(range->right()->type(), upperEquality);
+        sql += range->right()->rightCursorWhereFragment(range->rightWhereClauseComparisonOperator());
     sql += "objectStoreId = ? ORDER BY ";
 
     IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection);
diff --git a/WebCore/storage/IDBRequest.cpp b/WebCore/storage/IDBRequest.cpp
index 3513c17..6fbda0e 100644
--- a/WebCore/storage/IDBRequest.cpp
+++ b/WebCore/storage/IDBRequest.cpp
@@ -153,13 +153,12 @@ void IDBRequest::timerFired(Timer<IDBRequest>*)
     Vector<PendingEvent> pendingEvents;
     pendingEvents.swap(m_pendingEvents);
     for (size_t i = 0; i < pendingEvents.size(); ++i) {
-        PendingEvent pendingEvent = pendingEvents[i];
-        if (pendingEvent.m_error) {
-            ASSERT(!pendingEvent.m_result);
-            dispatchEvent(IDBErrorEvent::create(m_source, *pendingEvent.m_error));
+        if (pendingEvents[i].m_error) {
+            ASSERT(!pendingEvents[i].m_result);
+            dispatchEvent(IDBErrorEvent::create(m_source, *pendingEvents[i].m_error));
         } else {
-            ASSERT(pendingEvent.m_result->type() != IDBAny::UndefinedType);
-            dispatchEvent(IDBSuccessEvent::create(m_source, pendingEvent.m_result));
+            ASSERT(pendingEvents[i].m_result->type() != IDBAny::UndefinedType);
+            dispatchEvent(IDBSuccessEvent::create(m_source, pendingEvents[i].m_result));
         }
     }
 }
diff --git a/WebKit/chromium/ChangeLog b/WebKit/chromium/ChangeLog
index 73ee03b..aabe225 100644
--- a/WebKit/chromium/ChangeLog
+++ b/WebKit/chromium/ChangeLog
@@ -1,3 +1,45 @@
+2010-09-08  Jeremy Orlow  <jorlow at chromium.org>
+
+        Reviewed by Steve Block.
+
+        Complete index support for IndexedDB
+        https://bugs.webkit.org/show_bug.cgi?id=45386
+
+        * public/WebIDBCursor.h:
+        (WebKit::WebIDBCursor::direction):
+        (WebKit::WebIDBCursor::key):
+        (WebKit::WebIDBCursor::value):
+        (WebKit::WebIDBCursor::update):
+        (WebKit::WebIDBCursor::continueFunction):
+        (WebKit::WebIDBCursor::remove):
+        * public/WebIDBIndex.h:
+        (WebKit::WebIDBIndex::storeName):
+        (WebKit::WebIDBIndex::openObjectCursor):
+        (WebKit::WebIDBIndex::openCursor):
+        (WebKit::WebIDBIndex::getObject):
+        (WebKit::WebIDBIndex::get):
+        * public/WebIDBKey.h:
+        * src/IDBCursorBackendProxy.cpp:
+        (WebCore::IDBCursorBackendProxy::value):
+        * src/IDBCursorBackendProxy.h:
+        * src/IDBIndexBackendProxy.cpp:
+        (WebCore::IDBIndexBackendProxy::storeName):
+        (WebCore::IDBIndexBackendProxy::openObjectCursor):
+        (WebCore::IDBIndexBackendProxy::openCursor):
+        (WebCore::IDBIndexBackendProxy::getObject):
+        (WebCore::IDBIndexBackendProxy::get):
+        * src/IDBIndexBackendProxy.h:
+        * src/WebIDBCursorImpl.cpp:
+        (WebKit::WebIDBCursorImpl::value):
+        * src/WebIDBCursorImpl.h:
+        * src/WebIDBIndexImpl.cpp:
+        (WebKit::WebIDBIndexImpl::storeName):
+        (WebKit::WebIDBIndexImpl::openCursor):
+        (WebKit::WebIDBIndexImpl::openObjectCursor):
+        (WebKit::WebIDBIndexImpl::getObject):
+        (WebKit::WebIDBIndexImpl::get):
+        * src/WebIDBIndexImpl.h:
+
 2010-09-15  Dumitru Daniliuc  <dumi at chromium.org>
 
         Reviewed by Darin Fisher.
diff --git a/WebKit/chromium/public/WebIDBCursor.h b/WebKit/chromium/public/WebIDBCursor.h
index 27eb924..f47a44c 100644
--- a/WebKit/chromium/public/WebIDBCursor.h
+++ b/WebKit/chromium/public/WebIDBCursor.h
@@ -44,33 +44,30 @@ public:
         WEBKIT_ASSERT_NOT_REACHED();
         return 0;
     }
-
     virtual WebIDBKey key() const
     {
         WEBKIT_ASSERT_NOT_REACHED();
-        return WebIDBKey("");
+        return WebIDBKey::createInvalid();
     }
-
+    // FIXME: Remove the legacy version of value() (the first version) as soon as a WebKit roll happens.
     virtual WebSerializedScriptValue value() const
     {
-        WEBKIT_ASSERT_NOT_REACHED();
-        return WebSerializedScriptValue();
-    }
-
-    virtual void update(const WebSerializedScriptValue&, WebIDBCallbacks*)
-    {
-        WEBKIT_ASSERT_NOT_REACHED();
+        WebSerializedScriptValue serializedScriptValue;
+        WebIDBKey idbKey;
+        value(serializedScriptValue, idbKey);
+        WEBKIT_ASSERT(!serializedScriptValue.isNull());
+        WEBKIT_ASSERT(idbKey.type() == WebIDBKey::InvalidType);
+        return serializedScriptValue;
     }
-
-    virtual void continueFunction(const WebIDBKey&, WebIDBCallbacks*)
+    // One or the other will set, depending on what type of cursor this is.
+    virtual void value(WebSerializedScriptValue& serializedScriptValue, WebIDBKey& idbKey) const
     {
-        WEBKIT_ASSERT_NOT_REACHED();
+        serializedScriptValue = value();
     }
 
-    virtual void remove(WebIDBCallbacks*)
-    {
-        WEBKIT_ASSERT_NOT_REACHED();
-    }
+    virtual void update(const WebSerializedScriptValue&, WebIDBCallbacks*) { WEBKIT_ASSERT_NOT_REACHED(); }
+    virtual void continueFunction(const WebIDBKey&, WebIDBCallbacks*) { WEBKIT_ASSERT_NOT_REACHED(); }
+    virtual void remove(WebIDBCallbacks*) { WEBKIT_ASSERT_NOT_REACHED(); }
 };
 
 } // namespace WebKit
diff --git a/WebKit/chromium/public/WebIDBIndex.h b/WebKit/chromium/public/WebIDBIndex.h
index dafea0e..e03fc58 100644
--- a/WebKit/chromium/public/WebIDBIndex.h
+++ b/WebKit/chromium/public/WebIDBIndex.h
@@ -30,6 +30,10 @@
 
 namespace WebKit {
 
+class WebIDBCallbacks;
+class WebIDBKey;
+class WebIDBKeyRange;
+
 // See comment in WebIndexedDatabase for a high level overview of these classes.
 class WebIDBIndex {
 public:
@@ -40,6 +44,11 @@ public:
         WEBKIT_ASSERT_NOT_REACHED();
         return WebString();
     }
+    virtual WebString storeName() const
+    {
+        WEBKIT_ASSERT_NOT_REACHED();
+        return WebString();
+    }
     virtual WebString keyPath() const
     {
         WEBKIT_ASSERT_NOT_REACHED();
@@ -50,6 +59,11 @@ public:
         WEBKIT_ASSERT_NOT_REACHED();
         return false;
     }
+
+    virtual void openObjectCursor(const WebIDBKeyRange&, unsigned short direction, WebIDBCallbacks*) { WEBKIT_ASSERT_NOT_REACHED(); }
+    virtual void openCursor(const WebIDBKeyRange&, unsigned short direction, WebIDBCallbacks*) { WEBKIT_ASSERT_NOT_REACHED(); }
+    virtual void getObject(const WebIDBKey&, WebIDBCallbacks*) { WEBKIT_ASSERT_NOT_REACHED(); }
+    virtual void get(const WebIDBKey&, WebIDBCallbacks*) { WEBKIT_ASSERT_NOT_REACHED(); }
 };
 
 } // namespace WebKit
diff --git a/WebKit/chromium/public/WebIDBKey.h b/WebKit/chromium/public/WebIDBKey.h
index 6aef332..60d3325 100644
--- a/WebKit/chromium/public/WebIDBKey.h
+++ b/WebKit/chromium/public/WebIDBKey.h
@@ -42,7 +42,7 @@ public:
     // Please use one of the factory methods. This is public only to allow WebVector.
     WebIDBKey() { }
     ~WebIDBKey() { reset(); }
-  
+
     WEBKIT_API static WebIDBKey createNull();
     WEBKIT_API static WebIDBKey createInvalid();
     WEBKIT_API static WebIDBKey createFromValueAndKeyPath(const WebSerializedScriptValue&, const WebIDBKeyPath&);
diff --git a/WebKit/chromium/src/IDBCursorBackendProxy.cpp b/WebKit/chromium/src/IDBCursorBackendProxy.cpp
index b4711eb..cf18917 100644
--- a/WebKit/chromium/src/IDBCursorBackendProxy.cpp
+++ b/WebKit/chromium/src/IDBCursorBackendProxy.cpp
@@ -30,9 +30,11 @@
 
 #include "IDBAny.h"
 #include "IDBCallbacks.h"
+#include "IDBKey.h"
 #include "SerializedScriptValue.h"
 #include "WebIDBCallbacksImpl.h"
 #include "WebIDBKey.h"
+#include "WebSerializedScriptValue.h"
 
 namespace WebCore {
 
@@ -60,9 +62,17 @@ PassRefPtr<IDBKey> IDBCursorBackendProxy::key() const
     return m_idbCursor->key();
 }
 
-PassRefPtr<SerializedScriptValue> IDBCursorBackendProxy::value() const
+PassRefPtr<IDBAny> IDBCursorBackendProxy::value() const
 {
-    return m_idbCursor->value();
+    WebKit::WebSerializedScriptValue webScriptValue;
+    WebKit::WebIDBKey webKey;
+    m_idbCursor->value(webScriptValue, webKey);
+    if (!webScriptValue.isNull()) {
+        ASSERT(webKey.type() == WebKit::WebIDBKey::InvalidType);
+        return IDBAny::create<SerializedScriptValue>(webScriptValue);
+    }
+    ASSERT(webKey.type() != WebKit::WebIDBKey::InvalidType);
+    return IDBAny::create<IDBKey>(webKey);
 }
 
 void IDBCursorBackendProxy::update(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBCallbacks> callbacks)
diff --git a/WebKit/chromium/src/IDBCursorBackendProxy.h b/WebKit/chromium/src/IDBCursorBackendProxy.h
index 8af27cf..d8b621a 100644
--- a/WebKit/chromium/src/IDBCursorBackendProxy.h
+++ b/WebKit/chromium/src/IDBCursorBackendProxy.h
@@ -44,7 +44,7 @@ public:
 
     virtual unsigned short direction() const;
     virtual PassRefPtr<IDBKey> key() const;
-    virtual PassRefPtr<SerializedScriptValue> value() const;
+    virtual PassRefPtr<IDBAny> value() const;
     virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>);
     virtual void continueFunction(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>);
     virtual void remove(PassRefPtr<IDBCallbacks>);
diff --git a/WebKit/chromium/src/IDBIndexBackendProxy.cpp b/WebKit/chromium/src/IDBIndexBackendProxy.cpp
index 5f1b9d9..05097f2 100644
--- a/WebKit/chromium/src/IDBIndexBackendProxy.cpp
+++ b/WebKit/chromium/src/IDBIndexBackendProxy.cpp
@@ -26,10 +26,14 @@
 #include "config.h"
 #include "IDBIndexBackendProxy.h"
 
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBCallbacks.h"
+#include "WebIDBCallbacksImpl.h"
 #include "WebIDBDatabaseError.h"
 #include "WebIDBIndex.h"
-
-#if ENABLE(INDEXED_DATABASE)
+#include "WebIDBKey.h"
+#include "WebIDBKeyRange.h"
 
 namespace WebCore {
 
@@ -52,6 +56,11 @@ String IDBIndexBackendProxy::name()
     return m_webIDBIndex->name();
 }
 
+String IDBIndexBackendProxy::storeName()
+{
+    return m_webIDBIndex->storeName();
+}
+
 String IDBIndexBackendProxy::keyPath()
 {
     return m_webIDBIndex->keyPath();
@@ -62,6 +71,26 @@ bool IDBIndexBackendProxy::unique()
     return m_webIDBIndex->unique();
 }
 
+void IDBIndexBackendProxy::openObjectCursor(PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, PassRefPtr<IDBCallbacks> callbacks)
+{
+    m_webIDBIndex->openObjectCursor(keyRange, direction, new WebIDBCallbacksImpl(callbacks));
+}
+
+void IDBIndexBackendProxy::openCursor(PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, PassRefPtr<IDBCallbacks> callbacks)
+{
+    m_webIDBIndex->openCursor(keyRange, direction, new WebIDBCallbacksImpl(callbacks));
+}
+
+void IDBIndexBackendProxy::getObject(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
+{
+    m_webIDBIndex->getObject(key, new WebIDBCallbacksImpl(callbacks));
+}
+
+void IDBIndexBackendProxy::get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
+{
+    m_webIDBIndex->get(key, new WebIDBCallbacksImpl(callbacks));
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebKit/chromium/src/IDBIndexBackendProxy.h b/WebKit/chromium/src/IDBIndexBackendProxy.h
index 1b378dd..6aafdfa 100644
--- a/WebKit/chromium/src/IDBIndexBackendProxy.h
+++ b/WebKit/chromium/src/IDBIndexBackendProxy.h
@@ -42,10 +42,14 @@ public:
     virtual ~IDBIndexBackendProxy();
 
     virtual String name();
+    virtual String storeName();
     virtual String keyPath();
     virtual bool unique();
 
-    // FIXME: Add other methods.
+    virtual void openObjectCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>);
+    virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>);
+    virtual void getObject(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>);
+    virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>);
 
 private:
     IDBIndexBackendProxy(PassOwnPtr<WebKit::WebIDBIndex>);
diff --git a/WebKit/chromium/src/WebIDBCursorImpl.cpp b/WebKit/chromium/src/WebIDBCursorImpl.cpp
index b74d680..6a1053e 100644
--- a/WebKit/chromium/src/WebIDBCursorImpl.cpp
+++ b/WebKit/chromium/src/WebIDBCursorImpl.cpp
@@ -55,9 +55,19 @@ WebIDBKey WebIDBCursorImpl::key() const
     return WebIDBKey(m_idbCursorBackend->key());
 }
 
-WebSerializedScriptValue WebIDBCursorImpl::value() const
+void WebIDBCursorImpl::value(WebSerializedScriptValue& serializedScriptValue, WebIDBKey& idbKey) const
 {
-    return m_idbCursorBackend->value();
+    // Verify we're starting off with blank slates.
+    ASSERT(serializedScriptValue.isNull());
+    ASSERT(idbKey.type() == WebIDBKey::InvalidType);
+
+    RefPtr<IDBAny> any = m_idbCursorBackend->value();
+    if (any->type() == IDBAny::SerializedScriptValueType)
+        serializedScriptValue.assign(any->serializedScriptValue());
+    else if (any->type() == IDBAny::IDBKeyType)
+        idbKey.assign(any->idbKey());
+    else
+        ASSERT_NOT_REACHED();
 }
 
 void WebIDBCursorImpl::update(const WebSerializedScriptValue& value, WebIDBCallbacks* callbacks)
diff --git a/WebKit/chromium/src/WebIDBCursorImpl.h b/WebKit/chromium/src/WebIDBCursorImpl.h
index 565e86a..5fb9e1c 100644
--- a/WebKit/chromium/src/WebIDBCursorImpl.h
+++ b/WebKit/chromium/src/WebIDBCursorImpl.h
@@ -43,7 +43,7 @@ public:
 
     virtual unsigned short direction() const;
     virtual WebIDBKey key() const;
-    virtual WebSerializedScriptValue value() const;
+    virtual void value(WebSerializedScriptValue&, WebIDBKey&) const;
     virtual void update(const WebSerializedScriptValue&, WebIDBCallbacks*);
     virtual void continueFunction(const WebIDBKey&, WebIDBCallbacks*);
     virtual void remove(WebIDBCallbacks*);
diff --git a/WebKit/chromium/src/WebIDBIndexImpl.cpp b/WebKit/chromium/src/WebIDBIndexImpl.cpp
index 777ec32..c049aac 100644
--- a/WebKit/chromium/src/WebIDBIndexImpl.cpp
+++ b/WebKit/chromium/src/WebIDBIndexImpl.cpp
@@ -26,7 +26,12 @@
 #include "config.h"
 #include "WebIDBIndexImpl.h"
 
+#include "IDBCallbacksProxy.h"
 #include "IDBIndex.h"
+#include "IDBKeyRange.h"
+#include "WebIDBCallbacks.h"
+#include "WebIDBKey.h"
+#include "WebIDBKeyRange.h"
 
 #if ENABLE(INDEXED_DATABASE)
 
@@ -48,6 +53,11 @@ WebString WebIDBIndexImpl::name() const
     return m_backend->name();
 }
 
+WebString WebIDBIndexImpl::storeName() const
+{
+    return m_backend->storeName();
+}
+
 WebString WebIDBIndexImpl::keyPath() const
 {
     return m_backend->keyPath();
@@ -58,6 +68,26 @@ bool WebIDBIndexImpl::unique() const
     return m_backend->unique();
 }
 
+void WebIDBIndexImpl::openCursor(const WebIDBKeyRange& keyRange, unsigned short direction, WebIDBCallbacks* callbacks)
+{
+    m_backend->openCursor(keyRange, direction, IDBCallbacksProxy::create(callbacks));
+}
+
+void WebIDBIndexImpl::openObjectCursor(const WebIDBKeyRange& keyRange, unsigned short direction, WebIDBCallbacks* callbacks)
+{
+    m_backend->openObjectCursor(keyRange, direction, IDBCallbacksProxy::create(callbacks));
+}
+
+void WebIDBIndexImpl::getObject(const WebIDBKey& keyRange, WebIDBCallbacks* callbacks)
+{
+    m_backend->getObject(keyRange, IDBCallbacksProxy::create(callbacks));
+}
+
+void WebIDBIndexImpl::get(const WebIDBKey& keyRange, WebIDBCallbacks* callbacks)
+{
+    m_backend->get(keyRange, IDBCallbacksProxy::create(callbacks));
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebKit/chromium/src/WebIDBIndexImpl.h b/WebKit/chromium/src/WebIDBIndexImpl.h
index 73f3819..2108001 100644
--- a/WebKit/chromium/src/WebIDBIndexImpl.h
+++ b/WebKit/chromium/src/WebIDBIndexImpl.h
@@ -42,9 +42,15 @@ public:
     virtual ~WebIDBIndexImpl();
 
     virtual WebString name() const;
+    virtual WebString storeName() const;
     virtual WebString keyPath() const;
     virtual bool unique() const;
 
+    virtual void openObjectCursor(const WebIDBKeyRange&, unsigned short direction, WebIDBCallbacks*); 
+    virtual void openCursor(const WebIDBKeyRange&, unsigned short direction, WebIDBCallbacks*);
+    virtual void getObject(const WebIDBKey&, WebIDBCallbacks*);
+    virtual void get(const WebIDBKey&, WebIDBCallbacks*);
+
 private:
     WTF::RefPtr<WebCore::IDBIndexBackendInterface> m_backend;
 };

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list