• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "IDBObjectStoreBackendImpl.h"
28 
29 #if ENABLE(INDEXED_DATABASE)
30 
31 #include "CrossThreadTask.h"
32 #include "DOMStringList.h"
33 #include "IDBBackingStore.h"
34 #include "IDBBindingUtilities.h"
35 #include "IDBCallbacks.h"
36 #include "IDBCursorBackendImpl.h"
37 #include "IDBDatabaseBackendImpl.h"
38 #include "IDBDatabaseException.h"
39 #include "IDBIndexBackendImpl.h"
40 #include "IDBKey.h"
41 #include "IDBKeyPath.h"
42 #include "IDBKeyPathBackendImpl.h"
43 #include "IDBKeyRange.h"
44 #include "IDBTransactionBackendInterface.h"
45 #include "ScriptExecutionContext.h"
46 
47 namespace WebCore {
48 
~IDBObjectStoreBackendImpl()49 IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl()
50 {
51 }
52 
IDBObjectStoreBackendImpl(IDBBackingStore * backingStore,int64_t databaseId,int64_t id,const String & name,const String & keyPath,bool autoIncrement)53 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBBackingStore* backingStore, int64_t databaseId, int64_t id, const String& name, const String& keyPath, bool autoIncrement)
54     : m_backingStore(backingStore)
55     , m_databaseId(databaseId)
56     , m_id(id)
57     , m_name(name)
58     , m_keyPath(keyPath)
59     , m_autoIncrement(autoIncrement)
60     , m_autoIncrementNumber(-1)
61 {
62     loadIndexes();
63 }
64 
IDBObjectStoreBackendImpl(IDBBackingStore * backingStore,int64_t databaseId,const String & name,const String & keyPath,bool autoIncrement)65 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBBackingStore* backingStore, int64_t databaseId, const String& name, const String& keyPath, bool autoIncrement)
66     : m_backingStore(backingStore)
67     , m_databaseId(databaseId)
68     , m_id(InvalidId)
69     , m_name(name)
70     , m_keyPath(keyPath)
71     , m_autoIncrement(autoIncrement)
72     , m_autoIncrementNumber(-1)
73 {
74 }
75 
indexNames() const76 PassRefPtr<DOMStringList> IDBObjectStoreBackendImpl::indexNames() const
77 {
78     RefPtr<DOMStringList> indexNames = DOMStringList::create();
79     for (IndexMap::const_iterator it = m_indexes.begin(); it != m_indexes.end(); ++it)
80         indexNames->append(it->first);
81     return indexNames.release();
82 }
83 
get(PassRefPtr<IDBKey> prpKey,PassRefPtr<IDBCallbacks> prpCallbacks,IDBTransactionBackendInterface * transaction,ExceptionCode & ec)84 void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
85 {
86     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
87     RefPtr<IDBKey> key = prpKey;
88     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
89     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::getInternal, objectStore, key, callbacks)))
90         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
91 }
92 
getInternal(ScriptExecutionContext *,PassRefPtr<IDBObjectStoreBackendImpl> objectStore,PassRefPtr<IDBKey> key,PassRefPtr<IDBCallbacks> callbacks)93 void IDBObjectStoreBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
94 {
95     String wireData = objectStore->m_backingStore->getObjectStoreRecord(objectStore->m_databaseId, objectStore->id(), *key);
96     if (wireData.isNull()) {
97         callbacks->onSuccess(SerializedScriptValue::undefinedValue());
98         return;
99     }
100 
101     callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData));
102 }
103 
fetchKeyFromKeyPath(SerializedScriptValue * value,const String & keyPath)104 static PassRefPtr<IDBKey> fetchKeyFromKeyPath(SerializedScriptValue* value, const String& keyPath)
105 {
106     Vector<RefPtr<SerializedScriptValue> > values;
107     values.append(value);
108     Vector<RefPtr<IDBKey> > keys;
109     IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(values, keyPath, keys);
110     if (keys.isEmpty())
111         return 0;
112     ASSERT(keys.size() == 1);
113     return keys[0].release();
114 }
115 
injectKeyIntoKeyPath(PassRefPtr<IDBKey> key,PassRefPtr<SerializedScriptValue> value,const String & keyPath)116 static PassRefPtr<SerializedScriptValue> injectKeyIntoKeyPath(PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value, const String& keyPath)
117 {
118     return IDBKeyPathBackendImpl::injectIDBKeyIntoSerializedValue(key, value, keyPath);
119 }
120 
put(PassRefPtr<SerializedScriptValue> prpValue,PassRefPtr<IDBKey> prpKey,PutMode putMode,PassRefPtr<IDBCallbacks> prpCallbacks,IDBTransactionBackendInterface * transactionPtr,ExceptionCode & ec)121 void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
122 {
123     if (transactionPtr->mode() == IDBTransaction::READ_ONLY) {
124         ec = IDBDatabaseException::READ_ONLY_ERR;
125         return;
126     }
127 
128     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
129     RefPtr<SerializedScriptValue> value = prpValue;
130     RefPtr<IDBKey> key = prpKey;
131     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
132     RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
133     // FIXME: This should throw a SERIAL_ERR on structured clone problems.
134     // FIXME: This should throw a DATA_ERR when the wrong key/keyPath data is supplied.
135     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, putMode, callbacks, transaction)))
136         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
137 }
138 
selectKeyForPut(IDBObjectStoreBackendImpl * objectStore,IDBKey * key,PutMode putMode,IDBCallbacks * callbacks,RefPtr<SerializedScriptValue> & value)139 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::selectKeyForPut(IDBObjectStoreBackendImpl* objectStore, IDBKey* key, PutMode putMode, IDBCallbacks* callbacks, RefPtr<SerializedScriptValue>& value)
140 {
141     if (putMode == CursorUpdate)
142         ASSERT(key);
143 
144     const bool autoIncrement = objectStore->autoIncrement();
145     const bool hasKeyPath = !objectStore->m_keyPath.isNull();
146 
147     if (hasKeyPath && key && putMode != CursorUpdate) {
148         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "A key was supplied for an objectStore that has a keyPath."));
149         return 0;
150     }
151 
152     if (autoIncrement && key) {
153         objectStore->resetAutoIncrementKeyCache();
154         return key;
155     }
156 
157     if (autoIncrement) {
158         ASSERT(!key);
159         if (!hasKeyPath)
160             return objectStore->genAutoIncrementKey();
161 
162         RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
163         if (keyPathKey) {
164             objectStore->resetAutoIncrementKeyCache();
165             return keyPathKey;
166         }
167 
168         RefPtr<IDBKey> autoIncKey = objectStore->genAutoIncrementKey();
169         RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(autoIncKey, value, objectStore->m_keyPath);
170         if (!valueAfterInjection) {
171             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The generated key could not be inserted into the object using the keyPath."));
172             return 0;
173         }
174         value = valueAfterInjection;
175         return autoIncKey.release();
176     }
177 
178     if (hasKeyPath) {
179         RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
180 
181         if (!keyPathKey) {
182             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The key could not be fetched from the keyPath."));
183             return 0;
184         }
185 
186         if (putMode == CursorUpdate && !keyPathKey->isEqual(key)) {
187             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The key fetched from the keyPath does not match the key of the cursor."));
188             return 0;
189         }
190 
191         return keyPathKey.release();
192     }
193 
194     if (!key) {
195         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "No key supplied"));
196         return 0;
197     }
198 
199     return key;
200 }
201 
putInternal(ScriptExecutionContext *,PassRefPtr<IDBObjectStoreBackendImpl> objectStore,PassRefPtr<SerializedScriptValue> prpValue,PassRefPtr<IDBKey> prpKey,PutMode putMode,PassRefPtr<IDBCallbacks> callbacks,PassRefPtr<IDBTransactionBackendInterface> transaction)202 void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
203 {
204     RefPtr<SerializedScriptValue> value = prpValue;
205     RefPtr<IDBKey> key = selectKeyForPut(objectStore.get(), prpKey.get(), putMode, callbacks.get(), value);
206     if (!key)
207         return;
208 
209     if (key->type() == IDBKey::NullType) {
210         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "NULL key is not allowed."));
211         return;
212     }
213 
214     Vector<RefPtr<IDBKey> > indexKeys;
215     for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
216         RefPtr<IDBKey> key = fetchKeyFromKeyPath(value.get(), it->second->keyPath());
217         if (!key) {
218             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "The key could not be fetched from an index's keyPath."));
219             return;
220         }
221         if (key->type() == IDBKey::NullType) {
222             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "One of the derived (from a keyPath) keys for an index is NULL."));
223             return;
224         }
225         if (!it->second->addingKeyAllowed(key.get())) {
226             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "One of the derived (from a keyPath) keys for an index does not satisfy its uniqueness requirements."));
227             return;
228         }
229         indexKeys.append(key.release());
230     }
231 
232     RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->m_backingStore->createInvalidRecordIdentifier();
233     bool isExistingValue = objectStore->m_backingStore->keyExistsInObjectStore(objectStore->m_databaseId, objectStore->id(), *key, recordIdentifier.get());
234 
235     if (putMode == AddOnly && isExistingValue) {
236         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
237         return;
238     }
239 
240     // Before this point, don't do any mutation.  After this point, rollback the transaction in case of error.
241 
242     if (!objectStore->m_backingStore->putObjectStoreRecord(objectStore->m_databaseId, objectStore->id(), *key, value->toWireString(), recordIdentifier.get())) {
243         // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
244         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
245         transaction->abort();
246         return;
247     }
248 
249     int i = 0;
250     for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it, ++i) {
251         if (!it->second->hasValidId())
252             continue; // The index object has been created, but does not exist in the database yet.
253 
254         if (!objectStore->m_backingStore->deleteIndexDataForRecord(objectStore->m_databaseId, objectStore->id(), it->second->id(), recordIdentifier.get())) {
255             // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
256             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
257             transaction->abort();
258             return;
259         }
260 
261         if (!objectStore->m_backingStore->putIndexDataForRecord(objectStore->m_databaseId, objectStore->id(), it->second->id(), *indexKeys[i], recordIdentifier.get())) {
262             // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
263             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
264             transaction->abort();
265             return;
266         }
267     }
268 
269     callbacks->onSuccess(key.get());
270 }
271 
deleteFunction(PassRefPtr<IDBKey> prpKey,PassRefPtr<IDBCallbacks> prpCallbacks,IDBTransactionBackendInterface * transaction,ExceptionCode & ec)272 void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
273 {
274     if (transaction->mode() == IDBTransaction::READ_ONLY) {
275         ec = IDBDatabaseException::READ_ONLY_ERR;
276         return;
277     }
278 
279     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
280     RefPtr<IDBKey> key = prpKey;
281     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
282 
283     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::deleteInternal, objectStore, key, callbacks)))
284         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
285 }
286 
deleteInternal(ScriptExecutionContext *,PassRefPtr<IDBObjectStoreBackendImpl> objectStore,PassRefPtr<IDBKey> key,PassRefPtr<IDBCallbacks> callbacks)287 void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
288 {
289     RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->m_backingStore->createInvalidRecordIdentifier();
290     if (!objectStore->m_backingStore->keyExistsInObjectStore(objectStore->m_databaseId, objectStore->id(), *key, recordIdentifier.get())) {
291         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store."));
292         return;
293     }
294 
295     for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
296         if (!it->second->hasValidId())
297             continue; // The index object has been created, but does not exist in the database yet.
298 
299         if (!objectStore->m_backingStore->deleteIndexDataForRecord(objectStore->m_databaseId, objectStore->id(), it->second->id(), recordIdentifier.get()))
300             ASSERT_NOT_REACHED();
301     }
302 
303     objectStore->m_backingStore->deleteObjectStoreRecord(objectStore->m_databaseId, objectStore->id(), recordIdentifier.get());
304     callbacks->onSuccess(SerializedScriptValue::nullValue());
305 }
306 
clear(PassRefPtr<IDBCallbacks> prpCallbacks,IDBTransactionBackendInterface * transaction,ExceptionCode & ec)307 void IDBObjectStoreBackendImpl::clear(PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
308 {
309     if (transaction->mode() == IDBTransaction::READ_ONLY) {
310         ec = IDBDatabaseException::READ_ONLY_ERR;
311         return;
312     }
313 
314     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
315     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
316 
317     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::clearInternal, objectStore, callbacks)))
318         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
319 }
320 
clearInternal(ScriptExecutionContext *,PassRefPtr<IDBObjectStoreBackendImpl> objectStore,PassRefPtr<IDBCallbacks> callbacks)321 void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBCallbacks> callbacks)
322 {
323     objectStore->m_backingStore->clearObjectStore(objectStore->m_databaseId, objectStore->id());
324     callbacks->onSuccess(SerializedScriptValue::undefinedValue());
325 }
326 
327 namespace {
328 class PopulateIndexCallback : public IDBBackingStore::ObjectStoreRecordCallback {
329 public:
PopulateIndexCallback(IDBBackingStore & backingStore,const String & indexKeyPath,int64_t databaseId,int64_t objectStoreId,int64_t indexId)330     PopulateIndexCallback(IDBBackingStore& backingStore, const String& indexKeyPath, int64_t databaseId, int64_t objectStoreId, int64_t indexId)
331         : m_backingStore(backingStore)
332         , m_indexKeyPath(indexKeyPath)
333         , m_databaseId(databaseId)
334         , m_objectStoreId(objectStoreId)
335         , m_indexId(indexId)
336     {
337     }
338 
callback(const IDBBackingStore::ObjectStoreRecordIdentifier * recordIdentifier,const String & value)339     virtual bool callback(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, const String& value)
340     {
341         RefPtr<SerializedScriptValue> objectValue = SerializedScriptValue::createFromWire(value);
342         RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(objectValue.get(), m_indexKeyPath);
343 
344         if (!indexKey)
345             return true;
346         if (!m_backingStore.putIndexDataForRecord(m_databaseId, m_objectStoreId, m_indexId, *indexKey, recordIdentifier))
347             return false;
348 
349         return true;
350     }
351 
352 private:
353     IDBBackingStore& m_backingStore;
354     const String& m_indexKeyPath;
355     int64_t m_databaseId;
356     int64_t m_objectStoreId;
357     int64_t m_indexId;
358 };
359 }
360 
populateIndex(IDBBackingStore & backingStore,int64_t databaseId,int64_t objectStoreId,int64_t indexId,const String & indexKeyPath)361 static bool populateIndex(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const String& indexKeyPath)
362 {
363     PopulateIndexCallback callback(backingStore, indexKeyPath, databaseId, objectStoreId, indexId);
364     if (!backingStore.forEachObjectStoreRecord(databaseId, objectStoreId, callback))
365         return false;
366     return true;
367 }
368 
createIndex(const String & name,const String & keyPath,bool unique,IDBTransactionBackendInterface * transaction,ExceptionCode & ec)369 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(const String& name, const String& keyPath, bool unique, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
370 {
371     if (m_indexes.contains(name)) {
372         ec = IDBDatabaseException::CONSTRAINT_ERR;
373         return 0;
374     }
375     if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
376         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
377         return 0;
378     }
379 
380     RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(m_backingStore.get(), m_databaseId, this, name, m_name, keyPath, unique);
381     ASSERT(index->name() == name);
382 
383     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
384     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
385     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::createIndexInternal, objectStore, index, transaction),
386                                    createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexFromMap, objectStore, index))) {
387         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
388         return 0;
389     }
390 
391     m_indexes.set(name, index);
392     return index.release();
393 }
394 
createIndexInternal(ScriptExecutionContext *,PassRefPtr<IDBObjectStoreBackendImpl> objectStore,PassRefPtr<IDBIndexBackendImpl> index,PassRefPtr<IDBTransactionBackendInterface> transaction)395 void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
396 {
397     int64_t id;
398     if (!objectStore->m_backingStore->createIndex(objectStore->m_databaseId, objectStore->id(), index->name(), index->keyPath(), index->unique(), id)) {
399         transaction->abort();
400         return;
401     }
402 
403     index->setId(id);
404 
405     if (!populateIndex(*objectStore->m_backingStore, objectStore->m_databaseId, objectStore->m_id, id, index->keyPath())) {
406         transaction->abort();
407         return;
408     }
409 
410     transaction->didCompleteTaskEvents();
411 }
412 
index(const String & name,ExceptionCode & ec)413 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name, ExceptionCode& ec)
414 {
415     RefPtr<IDBIndexBackendInterface> index = m_indexes.get(name);
416     if (!index) {
417         ec = IDBDatabaseException::NOT_FOUND_ERR;
418         return 0;
419     }
420     return index.release();
421 }
422 
deleteIndex(const String & name,IDBTransactionBackendInterface * transaction,ExceptionCode & ec)423 void IDBObjectStoreBackendImpl::deleteIndex(const String& name, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
424 {
425     if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
426         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
427         return;
428     }
429 
430     RefPtr<IDBIndexBackendImpl> index = m_indexes.get(name);
431     if (!index) {
432         ec = IDBDatabaseException::NOT_FOUND_ERR;
433         return;
434     }
435 
436     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
437     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
438     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::deleteIndexInternal, objectStore, index, transactionPtr),
439                                    createCallbackTask(&IDBObjectStoreBackendImpl::addIndexToMap, objectStore, index))) {
440         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
441         return;
442     }
443     m_indexes.remove(name);
444 }
445 
deleteIndexInternal(ScriptExecutionContext *,PassRefPtr<IDBObjectStoreBackendImpl> objectStore,PassRefPtr<IDBIndexBackendImpl> index,PassRefPtr<IDBTransactionBackendInterface> transaction)446 void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
447 {
448     objectStore->m_backingStore->deleteIndex(objectStore->m_databaseId, objectStore->id(), index->id());
449     transaction->didCompleteTaskEvents();
450 }
451 
openCursor(PassRefPtr<IDBKeyRange> prpRange,unsigned short direction,PassRefPtr<IDBCallbacks> prpCallbacks,IDBTransactionBackendInterface * transactionPtr,ExceptionCode & ec)452 void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
453 {
454     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
455     RefPtr<IDBKeyRange> range = prpRange;
456     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
457     RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
458     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal, objectStore, range, direction, callbacks, transaction)))
459         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
460 }
461 
openCursorInternal(ScriptExecutionContext *,PassRefPtr<IDBObjectStoreBackendImpl> objectStore,PassRefPtr<IDBKeyRange> range,unsigned short tmpDirection,PassRefPtr<IDBCallbacks> callbacks,PassRefPtr<IDBTransactionBackendInterface> transaction)462 void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
463 {
464     IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection);
465 
466     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->m_backingStore->openObjectStoreCursor(objectStore->m_databaseId, objectStore->id(), range.get(), direction);
467     if (!backingStoreCursor) {
468         callbacks->onSuccess(SerializedScriptValue::nullValue());
469         return;
470     }
471 
472     RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), direction, IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get());
473     callbacks->onSuccess(cursor.release());
474 }
475 
loadIndexes()476 void IDBObjectStoreBackendImpl::loadIndexes()
477 {
478     Vector<int64_t> ids;
479     Vector<String> names;
480     Vector<String> keyPaths;
481     Vector<bool> uniqueFlags;
482     m_backingStore->getIndexes(m_databaseId, m_id, ids, names, keyPaths, uniqueFlags);
483 
484     ASSERT(names.size() == ids.size());
485     ASSERT(keyPaths.size() == ids.size());
486     ASSERT(uniqueFlags.size() == ids.size());
487 
488     for (size_t i = 0; i < ids.size(); i++)
489         m_indexes.set(names[i], IDBIndexBackendImpl::create(m_backingStore.get(), m_databaseId, this, ids[i], names[i], m_name, keyPaths[i], uniqueFlags[i]));
490 }
491 
removeIndexFromMap(ScriptExecutionContext *,PassRefPtr<IDBObjectStoreBackendImpl> objectStore,PassRefPtr<IDBIndexBackendImpl> index)492 void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
493 {
494     ASSERT(objectStore->m_indexes.contains(index->name()));
495     objectStore->m_indexes.remove(index->name());
496 }
497 
addIndexToMap(ScriptExecutionContext *,PassRefPtr<IDBObjectStoreBackendImpl> objectStore,PassRefPtr<IDBIndexBackendImpl> index)498 void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
499 {
500     RefPtr<IDBIndexBackendImpl> indexPtr = index;
501     ASSERT(!objectStore->m_indexes.contains(indexPtr->name()));
502     objectStore->m_indexes.set(indexPtr->name(), indexPtr);
503 }
504 
genAutoIncrementKey()505 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::genAutoIncrementKey()
506 {
507     if (m_autoIncrementNumber > 0)
508         return IDBKey::createNumber(m_autoIncrementNumber++);
509 
510     m_autoIncrementNumber = static_cast<int>(m_backingStore->nextAutoIncrementNumber(m_databaseId, id()));
511     return IDBKey::createNumber(m_autoIncrementNumber++);
512 }
513 
514 
515 } // namespace WebCore
516 
517 #endif
518