Skip to content

Instantly share code, notes, and snippets.

@maximerety
Last active May 23, 2018 09:59
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 maximerety/2332ed4660652f57ef6e12e3194e28e4 to your computer and use it in GitHub Desktop.
Save maximerety/2332ed4660652f57ef6e12e3194e28e4 to your computer and use it in GitHub Desktop.
Safari issue when having an autoIncrement key and binary data in indexedDB

Bug filed: https://bugs.webkit.org/show_bug.cgi?id=185869

This gist demonstrates a bug in Safari when you try to add a record with binary data (Uint8Array) into an indexedDB store having an autoIncrement key.

Currently breaks on Safari Version 11.1 (13605.1.33.1.4) on macOS High Sierra 10.13.4.

Demo files:

  • ko-indexeddb-both.html: the add() call triggers an "UnknownError: An internal error was encountered in the Indexed Database server" error, then the whole database is broken and can't be reused.
  • ok-indexeddb-autoincrement.html: autoIncrement works (as long as you don't have binary values in your data)
  • ok-indexeddb-uint8array.html: binary data is ok (as long as you don't use autoIncrement)

Related reports:

Usage:

  • Download this gist as a zip
  • Start a local webserver (e.g. python3 -m http.server)
  • View the locally served .html files in Safari
Filed: https://bugs.webkit.org/show_bug.cgi?id=185869
<!DOCTYPE html>
<meta charset="utf-8">
<title>KO: add a record containing binary data in a store having an autoIncrement key.</title>
<!-- Logging -->
<style type="text/css">
textarea#log {
width: 100%;
height: 1000px;
}
</style>
<h3>Log</h3>
<textarea id="log"></textarea>
<script type="text/javascript">
const log = (...args) => {
console.log(...args);
document.getElementById('log').value += args.join(' ') + "\n";
};
</script>
<!-- Test script -->
<script type="text/javascript">
let db;
const record = {
// id: 1, <- automatically added due to autoIncrement
property: Uint8Array.from([42, 255])
};
const open_rq = window.indexedDB.open("TestBinaryAndAutoIncrement", 1);
open_rq.onupgradeneeded = function (e) {
db = e.target.result;
const objStore = db.createObjectStore("store", { keyPath: "id", autoIncrement: true });
const add_rq = objStore.add(record);
add_rq.onerror = function (e) {
log("failed to add record (see console)");
console.error(e);
}
add_rq.onsuccess = function (e) {
log("added record");
}
};
open_rq.onsuccess = function (e) {
if (!db) {
db = e.target.result;
}
const rq = db.transaction("store")
.objectStore("store")
.get(1);
rq.onsuccess = function (e) {
const result = e.target.result;
log("result.property instanceof Uint8Array:", result.property instanceof Uint8Array);
log("result.property.length === 2:", result.property.length === 2);
log("result.property[0] === 42:", result.property[0] === 42);
log("result.property[1] === 255:", result.property[1] === 255);
};
};
</script>
<!DOCTYPE html>
<meta charset="utf-8">
<title>OK: add a record with no binary data in a store having an autoIncrement key.</title>
<!-- Logging -->
<style type="text/css">
textarea#log {
width: 100%;
height: 1000px;
}
</style>
<h3>Log</h3>
<textarea id="log"></textarea>
<script type="text/javascript">
const log = (...args) => {
console.log(...args);
document.getElementById('log').value += args.join(' ') + "\n";
};
</script>
<!-- Test script -->
<script type="text/javascript">
let db;
const record = {
// id: 1, <- automatically added due to autoIncrement
property: "Non binary"
};
const open_rq = window.indexedDB.open("TestAutoIncrement", 1);
open_rq.onupgradeneeded = function (e) {
db = e.target.result;
const objStore = db.createObjectStore("store", { keyPath: "id", autoIncrement: true });
const add_rq = objStore.add(record);
add_rq.onerror = function (e) {
log("failed to add record (see console)");
console.error(e);
}
add_rq.onsuccess = function (e) {
log("added record");
}
};
open_rq.onsuccess = function (e) {
if (!db) {
db = e.target.result;
}
const rq = db.transaction("store")
.objectStore("store")
.get(1);
rq.onsuccess = function (e) {
const result = e.target.result;
log("result.property === 'Non binary':", result.property === 'Non binary');
};
};
</script>
<!DOCTYPE html>
<meta charset="utf-8">
<title>OK: add a record containing binary data in a store that does NOT have an autoIncrement key.</title>
<!-- Logging -->
<style type="text/css">
textarea#log {
width: 100%;
height: 1000px;
}
</style>
<h3>Log</h3>
<textarea id="log"></textarea>
<script type="text/javascript">
const log = (...args) => {
console.log(...args);
document.getElementById('log').value += args.join(' ') + "\n";
};
</script>
<!-- Test script -->
<script type="text/javascript">
let db;
const record = {
id: 1, // No autoIncrement
property: Uint8Array.from([42, 255])
};
const open_rq = window.indexedDB.open("TestBinary", 1);
open_rq.onupgradeneeded = function (e) {
db = e.target.result;
const objStore = db.createObjectStore("store", { keyPath: "id" }); // No autoIncrement
const add_rq = objStore.add(record);
add_rq.onerror = function (e) {
log("failed to add record (see console)");
console.error(e);
}
add_rq.onsuccess = function (e) {
log("added record");
}
};
open_rq.onsuccess = function (e) {
if (!db) {
db = e.target.result;
}
const rq = db.transaction("store")
.objectStore("store")
.get(1);
rq.onsuccess = function (e) {
const result = e.target.result;
log("result.property instanceof Uint8Array:", result.property instanceof Uint8Array);
log("result.property.length === 2:", result.property.length === 2);
log("result.property[0] === 42:", result.property[0] === 42);
log("result.property[1] === 255:", result.property[1] === 255);
};
};
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment