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 49 IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl() 50 { 51 } 52 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 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 76 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 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 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 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 116 static PassRefPtr<SerializedScriptValue> injectKeyIntoKeyPath(PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value, const String& keyPath) 117 { 118 return IDBKeyPathBackendImpl::injectIDBKeyIntoSerializedValue(key, value, keyPath); 119 } 120 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 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 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 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 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 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 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: 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 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 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 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 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 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 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 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 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 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 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 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 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 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