This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.
jsbell and I have been discussing a possible ambiguity in the IndexedDB spec w.r.t. error handling around createIndex calls. In particular, createIndex() is supposed to behave somewhat synchronously in that calling: the implementation must create a newindex and return an IDBIndex object representing it. so that this is reasonable: objectStore.createIndex('foo',...) objectStore.put(...) objectStore.index('foo').get(...) But at the same time createIndex() behaves somewhat asynchrnously - while the metadata for the index needs to be there immediately, the actual indexing data doesn't have to: > In some implementations it's possible for the implementation to asynchronously run into problems creating the index after the createIndex function has returned. For example in implementations where metadata about the newly created index is queued up to be inserted into the database asynchronously, or where the implementation might need to ask the user for permission for quota reasons. Such implementations must still create and return an IDBIndex object. Instead, once the implementation realizes that creating the index has failed, it must abort the transaction using thesteps for aborting a transaction using the appropriate error as error parameter. The issue in question is how to handle this: objectStore.put({"foo": 1, "message": "hello"}); req = objectStore.put({"foo": 1, "message": "goodbye"}); objectStore.createIndex("foo", "foo", {unique: true}); // will fail asynchronously The question is, should req's onerror fire or not? From discussion on the list, I think most folks agree that both put()'s should succeed, but the spec needs to be clear on this. A suggested clarification, but I'm sure it could be worded better. In some implementations it's possible for the implementation to asynchronously run into problems creating the index [data] after the createIndex function has returned. For example in implementations where [indexing data about existing objects in the database] is queued up to be inserted into the database asynchronously, or where the implementation might need to ask the user for permission for quota reasons. Instead, once the implementation realizes that creating the objectStore has failed, it must abort the transaction using the steps for aborting a transaction using the appropriate error as error parameter. [If asynchronous write operations within the same transaction precede the createIndex, and they are the cause of the failure to create the index, they should not fail for this reason.] For example if creating the index failed due to quota reasons, QuotaError must be used as error and if the index can't be created due to unique constraints, ConstraintError must be used as error [and preceding requests which created these constraint violations should not fail.]
How precise do we need to be in terms of when the constraint enforcement will begin? Just to throw out one more example: request1 = store.put({name: 'carol'}, 1); store.createIndex('index', 'name', {unique: true}); request2 = store.put({name: 'carol'}, 2); If the timing of the index population/constraint enforcement is not defined, what happens here remains ambiguous: index metadata updated process request1 -> success index population here?? -> no abort process request2 -> constraint error?? or index population here?? -> abort Depending on when the index is populated / constraint is enforced, the second request could succeed or fail. It sounds like at least some implementations (WebKit, Gecko) treat the index population like a request internally, and therefore in the third example the second request would indeed be processed after the population and fail with a (preventable) constraint error. We probably need to be precise, e.g. reference the "steps for asynchronously executing a request" so that the "Wait until all previously added requests in transaction have their done flag set to true" clause is invoked. ... The timing of deleteIndex() may also need to be clarified. E.g. what is the behavior of: store.createIndex('index', 'name', {unique: true}); request1 = store.put({name: 'bob'}, 1); request2 = store.put({name: 'bob'}, 2); store.deleteIndex('index'); One possible interpretation: index metadata added index metadata removed index population (skipped) process request1 -> success process request2 -> success
I think both createIndex and deleteIndex should be treated as "asynchronous requests". From a web developers point of view it means that things happen in the order that their function calls run. So I think the ending example should result in: store.createIndex('index', 'name', {unique: true}); request1 = store.put({name: 'bob'}, 1); request2 = store.put({name: 'bob'}, 2); store.deleteIndex('index'); My interpretation: index metadata added process request1 -> success process request2 -> fail index metadata removed As you can see, it makes the actions line up exactly with the order of the function calls of the webpage.
I agree with Jonas, and what I seem to be picking up is the preferred way by Joshua and Alec too(?). I forgot a bit about this thread, but I made some tests exhibiting what I think it should work like. They might contain errors, but Firefox actually passed them when I was pleased with them anyway. So Gecko and the tests have to share the bug if so. http://w3c-test.org/webapps/IndexedDB/tests/submissions/Opera/idbobjectstore_createIndex6-event_order.htm http://w3c-test.org/webapps/IndexedDB/tests/submissions/Opera/idbobjectstore_createIndex7-event_order.htm http://w3c-test.org/webapps/IndexedDB/tests/submissions/Opera/idbobjectstore_createIndex8-deleteIndex-event_order.htm There is need for even more of tests like that. I also think this should apply to createObjectStore, deleteObjectStore as well as createIndex and deleteIndex for symmetry.
I took as stab at this - as minimally as possible - in https://dvcs.w3.org/hg/IndexedDB/rev/eeb7e443b582 I added an example to the createIndex case; a corresponding example for the deleteIndex case seemed too contrived.