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