Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@dfahlander
Last active September 22, 2016 22:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dfahlander/a7a0608513d527742c5a09e3c95dd343 to your computer and use it in GitHub Desktop.
Save dfahlander/a7a0608513d527742c5a09e3c95dd343 to your computer and use it in GitHub Desktop.
Repro of IndexedDB bug in Safari10 (webkit bug #158833)

IndexedDB Safari10 bug (webkit bugzilla #158833)

IDBIndex is unreliable on Safari 10

Basically, if you have objectStores 'students' with an index 'name' and 'schools' with an index 'city', and you query the 'name' index on 'students' with no range specified (or WITH a range - it doesnt matter), you will get a cursor that iterates a mix of student names and cities. Each onsuccess callback from the cursor will have a key that sometimes is a student name and sometimes a city. The value though is always a student and some students are shown multiple times - one time with the name key and another time with a city key.

Bugzilla URL

https://bugs.webkit.org/show_bug.cgi?id=158833

<html>
<script>
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.");
})
});
});
});
}
}
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();
}
}
}
</script>
</html>
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.
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: Adam Anderson, primaryKey: 1, value: {"name":"Stockholm University","city":"Stockholm","id":1}
key: Bertil Bengtson, primaryKey: 2, value: {"name":"Uppsala University","city":"Uppsala","id":2}
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}
key: Stockholm, primaryKey: 1, value: {"name":"Adam Anderson","id":1}
key: Uppsala, primaryKey: 2, value: {"name":"Bertil Bengtson","id":2}
Done.
@dfahlander
Copy link
Author

Tested with Safari 10.0 (12602.1.38.2) on browserstack.com.

As you can see, on Safari 10, IDBIndex.openCursor() will iterate the mix of keys in the index itself and other indexes on other stores.

The diff's first unexpected output is at line 8, where a city was expected, but it is iterating a key from another store.

@dfahlander
Copy link
Author

@beidson @bradeeoh Please have a look at this issue with Safari 10 and its IndexedDB support.

@dfahlander
Copy link
Author

Update : bug was fixed today by Bradley Eidson at Apple. Thanks! :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment