IDBIndex.openCursor() matches indices on multiple object stores.
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Sep 2016 22:34:02 +0000 (22:34 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Sep 2016 22:34:02 +0000 (22:34 +0000)
<rdar://problem/28434463> and https://bugs.webkit.org/show_bug.cgi?id=158833

Reviewed by Alex Christensen.

Source/WebCore:

Tests: storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-private.html
       storage/indexeddb/modern/multiple-objectstore-index-cursor-collision.html

* Modules/indexeddb/server/SQLiteIDBCursor.cpp:
(WebCore::IDBServer::buildIndexStatement): Need to include the object store id in the statement for
  index cursors, otherwise there will be collisions amongst multiple object stores that happen to
  share primary keys.
(WebCore::IDBServer::SQLiteIDBCursor::bindArguments):

LayoutTests:

* storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-expected.txt: Added.
* storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-private-expected.txt: Added.
* storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-private.html: Added.
* storage/indexeddb/modern/multiple-objectstore-index-cursor-collision.html: Added.
* storage/indexeddb/modern/resources/multiple-objectstore-index-cursor-collision.js: Added.

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

LayoutTests/ChangeLog
LayoutTests/storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-expected.txt [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-private-expected.txt [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-private.html [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/multiple-objectstore-index-cursor-collision.html [new file with mode: 0644]
LayoutTests/storage/indexeddb/modern/resources/multiple-objectstore-index-cursor-collision.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/server/SQLiteIDBCursor.cpp

index a0770ff..ab77597 100644 (file)
@@ -1,3 +1,16 @@
+2016-09-22  Brady Eidson  <beidson@apple.com>
+
+        IDBIndex.openCursor() matches indices on multiple object stores.
+        <rdar://problem/28434463> and https://bugs.webkit.org/show_bug.cgi?id=158833
+
+        Reviewed by Alex Christensen.
+
+        * storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-expected.txt: Added.
+        * storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-private-expected.txt: Added.
+        * storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-private.html: Added.
+        * storage/indexeddb/modern/multiple-objectstore-index-cursor-collision.html: Added.
+        * storage/indexeddb/modern/resources/multiple-objectstore-index-cursor-collision.js: Added.
+
 2016-09-22  Daniel Bates  <dabates@apple.com>
 
         [CSP] Violation report may be sent to wrong domain on frame-ancestors violation
diff --git a/LayoutTests/storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-expected.txt b/LayoutTests/storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-expected.txt
new file mode 100644 (file)
index 0000000..9de2f1e
--- /dev/null
@@ -0,0 +1,21 @@
+PASS successfullyParsed is true
+
+TEST COMPLETE
+db deleted
+Creating db
+Enumerating ObjectStore 'schools' by primary key
+key: 1, primaryKey: 1, value: {"name":"Stockholm University","city":"Stockholm","id":1}
+key: 2, primaryKey: 2, value: {"name":"Uppsala University","city":"Uppsala","id":2}
+key: 3, primaryKey: 3, value: {"name":"Chalmers","city":"Gothenburg","id":3}
+Enumerating index 'city' on 'schools'
+key: Gothenburg, primaryKey: 3, value: {"name":"Chalmers","city":"Gothenburg","id":3}
+key: Stockholm, primaryKey: 1, value: {"name":"Stockholm University","city":"Stockholm","id":1}
+key: Uppsala, primaryKey: 2, value: {"name":"Uppsala University","city":"Uppsala","id":2}
+Enumerating ObjectStore 'students' by primary key
+key: 1, primaryKey: 1, value: {"name":"Adam Anderson","id":1}
+key: 2, primaryKey: 2, value: {"name":"Bertil Bengtson","id":2}
+Enumerating index 'name' on 'students'
+key: Adam Anderson, primaryKey: 1, value: {"name":"Adam Anderson","id":1}
+key: Bertil Bengtson, primaryKey: 2, value: {"name":"Bertil Bengtson","id":2}
+Done.
+
diff --git a/LayoutTests/storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-private-expected.txt b/LayoutTests/storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-private-expected.txt
new file mode 100644 (file)
index 0000000..9de2f1e
--- /dev/null
@@ -0,0 +1,21 @@
+PASS successfullyParsed is true
+
+TEST COMPLETE
+db deleted
+Creating db
+Enumerating ObjectStore 'schools' by primary key
+key: 1, primaryKey: 1, value: {"name":"Stockholm University","city":"Stockholm","id":1}
+key: 2, primaryKey: 2, value: {"name":"Uppsala University","city":"Uppsala","id":2}
+key: 3, primaryKey: 3, value: {"name":"Chalmers","city":"Gothenburg","id":3}
+Enumerating index 'city' on 'schools'
+key: Gothenburg, primaryKey: 3, value: {"name":"Chalmers","city":"Gothenburg","id":3}
+key: Stockholm, primaryKey: 1, value: {"name":"Stockholm University","city":"Stockholm","id":1}
+key: Uppsala, primaryKey: 2, value: {"name":"Uppsala University","city":"Uppsala","id":2}
+Enumerating ObjectStore 'students' by primary key
+key: 1, primaryKey: 1, value: {"name":"Adam Anderson","id":1}
+key: 2, primaryKey: 2, value: {"name":"Bertil Bengtson","id":2}
+Enumerating index 'name' on 'students'
+key: Adam Anderson, primaryKey: 1, value: {"name":"Adam Anderson","id":1}
+key: Bertil Bengtson, primaryKey: 2, value: {"name":"Bertil Bengtson","id":2}
+Done.
+
diff --git a/LayoutTests/storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-private.html b/LayoutTests/storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-private.html
new file mode 100644 (file)
index 0000000..6c96c27
--- /dev/null
@@ -0,0 +1,12 @@
+<html>
+<head>
+<script>
+enablePrivateBrowsing = true;
+</script>
+<script src="../../../resources/js-test.js"></script>
+<script src="../resources/shared.js"></script>
+</head>
+<body>
+<script src="resources/multiple-objectstore-index-cursor-collision.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/storage/indexeddb/modern/multiple-objectstore-index-cursor-collision.html b/LayoutTests/storage/indexeddb/modern/multiple-objectstore-index-cursor-collision.html
new file mode 100644 (file)
index 0000000..487b003
--- /dev/null
@@ -0,0 +1,9 @@
+<html>
+<head>
+<script src="../../../resources/js-test.js"></script>
+<script src="../resources/shared.js"></script>
+</head>
+<body>
+<script src="resources/multiple-objectstore-index-cursor-collision.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/storage/indexeddb/modern/resources/multiple-objectstore-index-cursor-collision.js b/LayoutTests/storage/indexeddb/modern/resources/multiple-objectstore-index-cursor-collision.js
new file mode 100644 (file)
index 0000000..7cf0960
--- /dev/null
@@ -0,0 +1,48 @@
+const log = txt => document.writeln(`${txt}<br/>`);
+log("Deleting db");
+indexedDB.deleteDatabase("db").onsuccess = ()=> {
+    log("db deleted");
+    let req = indexedDB.open("db", 1);
+    req.onupgradeneeded = e => {
+        log ("Creating db");
+        let db = req.transaction.db;
+        let schools = db.createObjectStore('schools', { keyPath: 'id', autoIncrement: true });
+        schools.createIndex ('city', 'city');
+        schools.add({name: 'Stockholm University', city: 'Stockholm'});
+        schools.add({name: 'Uppsala University', city: 'Uppsala'});
+        schools.add({name: 'Chalmers', city: 'Gothenburg'});
+        let students = db.createObjectStore('students', { keyPath: 'id', autoIncrement: true });
+        students.createIndex ('name', 'name');
+        students.add({name: 'Adam Anderson'});
+        students.add({name: 'Bertil Bengtson'});
+    }
+    req.onsuccess = ()=> {
+        let db = req.result;
+        let tx = db.transaction(['schools', 'students'], 'readonly');
+        dump(tx.objectStore('schools'), ()=> {
+            dump(tx.objectStore('schools').index('city'), ()=> {
+                dump(tx.objectStore('students'), ()=>{
+                    dump(tx.objectStore('students').index('name'), ()=>{
+                        log("Done.");
+                                               finishJSTest();
+                    })
+                });
+            });
+        });
+    }
+}
+
+function dump (idx, done) {
+    log (idx instanceof IDBObjectStore ?
+        `Enumerating ObjectStore '${idx.name}' by primary key` :
+        `Enumerating index '${idx.name}' on '${idx.objectStore.name}'`);
+    idx.openCursor().onsuccess = e => {
+        let cursor = e.target.result; 
+        if (cursor) {
+            log(`key: ${cursor.key}, primaryKey: ${cursor.primaryKey}, value: ${JSON.stringify(cursor.value)}`);
+            cursor.continue();
+        } else {
+            done();
+        }
+    }
+}
index d3f873a..090dbbc 100644 (file)
@@ -1,3 +1,19 @@
+2016-09-22  Brady Eidson  <beidson@apple.com>
+
+        IDBIndex.openCursor() matches indices on multiple object stores.
+        <rdar://problem/28434463> and https://bugs.webkit.org/show_bug.cgi?id=158833
+
+        Reviewed by Alex Christensen.
+
+        Tests: storage/indexeddb/modern/multiple-objectstore-index-cursor-collision-private.html
+               storage/indexeddb/modern/multiple-objectstore-index-cursor-collision.html
+
+        * Modules/indexeddb/server/SQLiteIDBCursor.cpp:
+        (WebCore::IDBServer::buildIndexStatement): Need to include the object store id in the statement for
+          index cursors, otherwise there will be collisions amongst multiple object stores that happen to
+          share primary keys.
+        (WebCore::IDBServer::SQLiteIDBCursor::bindArguments):
+
 2016-09-22  Zalan Bujtas  <zalan@apple.com>
 
         ShowRenderTree: Shuffle letters to have better readability.
index bdad2a7..33212be 100644 (file)
@@ -112,7 +112,7 @@ static String buildIndexStatement(const IDBKeyRangeData& keyRange, IndexedDB::Cu
 {
     StringBuilder builder;
 
-    builder.appendLiteral("SELECT rowid, key, value FROM IndexRecords WHERE indexID = ? AND key ");
+    builder.appendLiteral("SELECT rowid, key, value FROM IndexRecords WHERE indexID = ? AND objectStoreID = ? AND key ");
     if (!keyRange.lowerKey.isNull() && !keyRange.lowerOpen)
         builder.appendLiteral(">=");
     else
@@ -260,19 +260,26 @@ bool SQLiteIDBCursor::bindArguments()
 {
     LOG(IndexedDB, "Cursor is binding lower key '%s' and upper key '%s'", m_currentLowerKey.loggingString().utf8().data(), m_currentUpperKey.loggingString().utf8().data());
 
-    if (m_statement->bindInt64(1, m_boundID) != SQLITE_OK) {
+    int currentBindArgument = 1;
+
+    if (m_statement->bindInt64(currentBindArgument++, m_boundID) != SQLITE_OK) {
         LOG_ERROR("Could not bind id argument (bound ID)");
         return false;
     }
 
+    if (m_indexID != IDBIndexInfo::InvalidId && m_statement->bindInt64(currentBindArgument++, m_objectStoreID) != SQLITE_OK) {
+        LOG_ERROR("Could not bind object store id argument for an index cursor");
+        return false;
+    }
+
     RefPtr<SharedBuffer> buffer = serializeIDBKeyData(m_currentLowerKey);
-    if (m_statement->bindBlob(2, buffer->data(), buffer->size()) != SQLITE_OK) {
+    if (m_statement->bindBlob(currentBindArgument++, buffer->data(), buffer->size()) != SQLITE_OK) {
         LOG_ERROR("Could not create cursor statement (lower key)");
         return false;
     }
 
     buffer = serializeIDBKeyData(m_currentUpperKey);
-    if (m_statement->bindBlob(3, buffer->data(), buffer->size()) != SQLITE_OK) {
+    if (m_statement->bindBlob(currentBindArgument++, buffer->data(), buffer->size()) != SQLITE_OK) {
         LOG_ERROR("Could not create cursor statement (upper key)");
         return false;
     }