1 /* 2 * Copyright (C) 2010 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 "modules/indexeddb/IDBObjectStore.h" 28 29 #include "bindings/v8/ExceptionState.h" 30 #include "bindings/v8/ExceptionStatePlaceholder.h" 31 #include "bindings/v8/IDBBindingUtilities.h" 32 #include "bindings/v8/ScriptState.h" 33 #include "core/dom/DOMStringList.h" 34 #include "core/dom/ExceptionCode.h" 35 #include "core/dom/ExecutionContext.h" 36 #include "modules/indexeddb/IDBAny.h" 37 #include "modules/indexeddb/IDBCursorWithValue.h" 38 #include "modules/indexeddb/IDBDatabase.h" 39 #include "modules/indexeddb/IDBKeyPath.h" 40 #include "modules/indexeddb/IDBTracing.h" 41 #include "modules/indexeddb/WebIDBCallbacksImpl.h" 42 #include "platform/SharedBuffer.h" 43 #include "public/platform/WebBlobInfo.h" 44 #include "public/platform/WebData.h" 45 #include "public/platform/WebIDBKey.h" 46 #include "public/platform/WebIDBKeyRange.h" 47 #include "public/platform/WebVector.h" 48 #include <v8.h> 49 50 using blink::WebBlobInfo; 51 using blink::WebIDBCallbacks; 52 using blink::WebIDBCursor; 53 using blink::WebIDBDatabase; 54 using blink::WebVector; 55 56 namespace WebCore { 57 58 IDBObjectStore::IDBObjectStore(const IDBObjectStoreMetadata& metadata, IDBTransaction* transaction) 59 : m_metadata(metadata) 60 , m_transaction(transaction) 61 , m_deleted(false) 62 { 63 ASSERT(m_transaction); 64 ScriptWrappable::init(this); 65 } 66 67 void IDBObjectStore::trace(Visitor* visitor) 68 { 69 visitor->trace(m_transaction); 70 visitor->trace(m_indexMap); 71 } 72 73 ScriptValue IDBObjectStore::keyPath(ScriptState* scriptState) const 74 { 75 return idbAnyToScriptValue(scriptState, IDBAny::create(m_metadata.keyPath)); 76 } 77 78 PassRefPtrWillBeRawPtr<DOMStringList> IDBObjectStore::indexNames() const 79 { 80 IDB_TRACE("IDBObjectStore::indexNames"); 81 RefPtrWillBeRawPtr<DOMStringList> indexNames = DOMStringList::create(); 82 for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it) 83 indexNames->append(it->value.name); 84 indexNames->sort(); 85 return indexNames.release(); 86 } 87 88 IDBRequest* IDBObjectStore::get(ScriptState* scriptState, const ScriptValue& key, ExceptionState& exceptionState) 89 { 90 IDB_TRACE("IDBObjectStore::get"); 91 if (isDeleted()) { 92 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage); 93 return 0; 94 } 95 if (m_transaction->isFinished() || m_transaction->isFinishing()) { 96 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 97 return 0; 98 } 99 if (!m_transaction->isActive()) { 100 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 101 return 0; 102 } 103 IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), key, exceptionState); 104 if (exceptionState.hadException()) 105 return 0; 106 if (!keyRange) { 107 exceptionState.throwDOMException(DataError, IDBDatabase::noKeyOrKeyRangeErrorMessage); 108 return 0; 109 } 110 if (!backendDB()) { 111 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage); 112 return 0; 113 } 114 115 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get()); 116 backendDB()->get(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, keyRange, false, WebIDBCallbacksImpl::create(request).leakPtr()); 117 return request; 118 } 119 120 static void generateIndexKeysForValue(v8::Isolate* isolate, const IDBIndexMetadata& indexMetadata, const ScriptValue& objectValue, IDBObjectStore::IndexKeys* indexKeys) 121 { 122 ASSERT(indexKeys); 123 IDBKey* indexKey = createIDBKeyFromScriptValueAndKeyPath(isolate, objectValue, indexMetadata.keyPath); 124 125 if (!indexKey) 126 return; 127 128 if (!indexMetadata.multiEntry || indexKey->type() != IDBKey::ArrayType) { 129 if (!indexKey->isValid()) 130 return; 131 132 indexKeys->append(indexKey); 133 } else { 134 ASSERT(indexMetadata.multiEntry); 135 ASSERT(indexKey->type() == IDBKey::ArrayType); 136 indexKey = IDBKey::createMultiEntryArray(indexKey->array()); 137 138 for (size_t i = 0; i < indexKey->array().size(); ++i) 139 indexKeys->append(indexKey->array()[i]); 140 } 141 } 142 143 IDBRequest* IDBObjectStore::add(ScriptState* scriptState, ScriptValue& value, const ScriptValue& key, ExceptionState& exceptionState) 144 { 145 IDB_TRACE("IDBObjectStore::add"); 146 return put(scriptState, blink::WebIDBPutModeAddOnly, IDBAny::create(this), value, key, exceptionState); 147 } 148 149 IDBRequest* IDBObjectStore::put(ScriptState* scriptState, ScriptValue& value, const ScriptValue& key, ExceptionState& exceptionState) 150 { 151 IDB_TRACE("IDBObjectStore::put"); 152 return put(scriptState, blink::WebIDBPutModeAddOrUpdate, IDBAny::create(this), value, key, exceptionState); 153 } 154 155 IDBRequest* IDBObjectStore::put(ScriptState* scriptState, blink::WebIDBPutMode putMode, IDBAny* source, ScriptValue& value, const ScriptValue& keyValue, ExceptionState& exceptionState) 156 { 157 IDBKey* key = keyValue.isUndefined() ? nullptr : scriptValueToIDBKey(scriptState->isolate(), keyValue); 158 return put(scriptState, putMode, source, value, key, exceptionState); 159 } 160 161 IDBRequest* IDBObjectStore::put(ScriptState* scriptState, blink::WebIDBPutMode putMode, IDBAny* source, ScriptValue& value, IDBKey* key, ExceptionState& exceptionState) 162 { 163 if (isDeleted()) { 164 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage); 165 return 0; 166 } 167 if (m_transaction->isFinished() || m_transaction->isFinishing()) { 168 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 169 return 0; 170 } 171 if (!m_transaction->isActive()) { 172 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 173 return 0; 174 } 175 if (m_transaction->isReadOnly()) { 176 exceptionState.throwDOMException(ReadOnlyError, IDBDatabase::transactionReadOnlyErrorMessage); 177 return 0; 178 } 179 180 Vector<WebBlobInfo> blobInfo; 181 RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(value, &blobInfo, exceptionState, scriptState->isolate()); 182 if (exceptionState.hadException()) 183 return 0; 184 185 const IDBKeyPath& keyPath = m_metadata.keyPath; 186 const bool usesInLineKeys = !keyPath.isNull(); 187 const bool hasKeyGenerator = autoIncrement(); 188 189 if (putMode != blink::WebIDBPutModeCursorUpdate && usesInLineKeys && key) { 190 exceptionState.throwDOMException(DataError, "The object store uses in-line keys and the key parameter was provided."); 191 return 0; 192 } 193 if (!usesInLineKeys && !hasKeyGenerator && !key) { 194 exceptionState.throwDOMException(DataError, "The object store uses out-of-line keys and has no key generator and the key parameter was not provided."); 195 return 0; 196 } 197 if (usesInLineKeys) { 198 IDBKey* keyPathKey = createIDBKeyFromScriptValueAndKeyPath(scriptState->isolate(), value, keyPath); 199 if (keyPathKey && !keyPathKey->isValid()) { 200 exceptionState.throwDOMException(DataError, "Evaluating the object store's key path yielded a value that is not a valid key."); 201 return 0; 202 } 203 if (!hasKeyGenerator && !keyPathKey) { 204 exceptionState.throwDOMException(DataError, "Evaluating the object store's key path did not yield a value."); 205 return 0; 206 } 207 if (hasKeyGenerator && !keyPathKey) { 208 if (!canInjectIDBKeyIntoScriptValue(scriptState->isolate(), value, keyPath)) { 209 exceptionState.throwDOMException(DataError, "A generated key could not be inserted into the value."); 210 return 0; 211 } 212 } 213 if (keyPathKey) 214 key = keyPathKey; 215 } 216 if (key && !key->isValid()) { 217 exceptionState.throwDOMException(DataError, IDBDatabase::notValidKeyErrorMessage); 218 return 0; 219 } 220 221 if (!backendDB()) { 222 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage); 223 return 0; 224 } 225 226 Vector<int64_t> indexIds; 227 HeapVector<IndexKeys> indexKeys; 228 for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it) { 229 IndexKeys keys; 230 generateIndexKeysForValue(scriptState->isolate(), it->value, value, &keys); 231 indexIds.append(it->key); 232 indexKeys.append(keys); 233 } 234 235 IDBRequest* request = IDBRequest::create(scriptState, source, m_transaction.get()); 236 Vector<char> wireBytes; 237 serializedValue->toWireBytes(wireBytes); 238 RefPtr<SharedBuffer> valueBuffer = SharedBuffer::adoptVector(wireBytes); 239 240 backendDB()->put(m_transaction->id(), id(), blink::WebData(valueBuffer), blobInfo, key, static_cast<blink::WebIDBPutMode>(putMode), WebIDBCallbacksImpl::create(request).leakPtr(), indexIds, indexKeys); 241 return request; 242 } 243 244 IDBRequest* IDBObjectStore::deleteFunction(ScriptState* scriptState, const ScriptValue& key, ExceptionState& exceptionState) 245 { 246 IDB_TRACE("IDBObjectStore::delete"); 247 if (isDeleted()) { 248 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage); 249 return 0; 250 } 251 if (m_transaction->isFinished() || m_transaction->isFinishing()) { 252 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 253 return 0; 254 } 255 if (!m_transaction->isActive()) { 256 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 257 return 0; 258 } 259 if (m_transaction->isReadOnly()) { 260 exceptionState.throwDOMException(ReadOnlyError, IDBDatabase::transactionReadOnlyErrorMessage); 261 return 0; 262 } 263 264 IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), key, exceptionState); 265 if (exceptionState.hadException()) 266 return 0; 267 if (!keyRange) { 268 exceptionState.throwDOMException(DataError, IDBDatabase::noKeyOrKeyRangeErrorMessage); 269 return 0; 270 } 271 if (!backendDB()) { 272 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage); 273 return 0; 274 } 275 276 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get()); 277 backendDB()->deleteRange(m_transaction->id(), id(), keyRange, WebIDBCallbacksImpl::create(request).leakPtr()); 278 return request; 279 } 280 281 IDBRequest* IDBObjectStore::clear(ScriptState* scriptState, ExceptionState& exceptionState) 282 { 283 IDB_TRACE("IDBObjectStore::clear"); 284 if (isDeleted()) { 285 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage); 286 return 0; 287 } 288 if (m_transaction->isFinished() || m_transaction->isFinishing()) { 289 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 290 return 0; 291 } 292 if (!m_transaction->isActive()) { 293 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 294 return 0; 295 } 296 if (m_transaction->isReadOnly()) { 297 exceptionState.throwDOMException(ReadOnlyError, IDBDatabase::transactionReadOnlyErrorMessage); 298 return 0; 299 } 300 if (!backendDB()) { 301 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage); 302 return 0; 303 } 304 305 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get()); 306 backendDB()->clear(m_transaction->id(), id(), WebIDBCallbacksImpl::create(request).leakPtr()); 307 return request; 308 } 309 310 namespace { 311 // This class creates the index keys for a given index by extracting 312 // them from the SerializedScriptValue, for all the existing values in 313 // the objectStore. It only needs to be kept alive by virtue of being 314 // a listener on an IDBRequest object, in the same way that JavaScript 315 // cursor success handlers are kept alive. 316 class IndexPopulator FINAL : public EventListener { 317 public: 318 static PassRefPtr<IndexPopulator> create(ScriptState* scriptState, IDBDatabase* database, int64_t transactionId, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata) 319 { 320 return adoptRef(new IndexPopulator(scriptState, database, transactionId, objectStoreId, indexMetadata)); 321 } 322 323 virtual bool operator==(const EventListener& other) OVERRIDE 324 { 325 return this == &other; 326 } 327 328 private: 329 IndexPopulator(ScriptState* scriptState, IDBDatabase* database, int64_t transactionId, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata) 330 : EventListener(CPPEventListenerType) 331 , m_scriptState(scriptState) 332 , m_database(database) 333 , m_transactionId(transactionId) 334 , m_objectStoreId(objectStoreId) 335 , m_indexMetadata(indexMetadata) 336 { 337 } 338 339 virtual void handleEvent(ExecutionContext* executionContext, Event* event) OVERRIDE 340 { 341 ASSERT(m_scriptState->executionContext() == executionContext); 342 ASSERT(event->type() == EventTypeNames::success); 343 EventTarget* target = event->target(); 344 IDBRequest* request = static_cast<IDBRequest*>(target); 345 346 if (!m_database->backend()) // If database is stopped? 347 return; 348 349 IDBAny* cursorAny = request->resultAsAny(); 350 IDBCursorWithValue* cursor = 0; 351 if (cursorAny->type() == IDBAny::IDBCursorWithValueType) 352 cursor = cursorAny->idbCursorWithValue(); 353 354 Vector<int64_t> indexIds; 355 indexIds.append(m_indexMetadata.id); 356 if (cursor && !cursor->isDeleted()) { 357 cursor->continueFunction(static_cast<IDBKey*>(0), static_cast<IDBKey*>(0), ASSERT_NO_EXCEPTION); 358 359 IDBKey* primaryKey = cursor->idbPrimaryKey(); 360 ScriptValue value = cursor->value(m_scriptState.get()); 361 362 IDBObjectStore::IndexKeys indexKeys; 363 generateIndexKeysForValue(m_scriptState->isolate(), m_indexMetadata, value, &indexKeys); 364 365 HeapVector<IDBObjectStore::IndexKeys> indexKeysList; 366 indexKeysList.append(indexKeys); 367 368 m_database->backend()->setIndexKeys(m_transactionId, m_objectStoreId, primaryKey, indexIds, indexKeysList); 369 } else { 370 // Now that we are done indexing, tell the backend to go 371 // back to processing tasks of type NormalTask. 372 m_database->backend()->setIndexesReady(m_transactionId, m_objectStoreId, indexIds); 373 m_database.clear(); 374 } 375 376 } 377 378 RefPtr<ScriptState> m_scriptState; 379 Persistent<IDBDatabase> m_database; 380 const int64_t m_transactionId; 381 const int64_t m_objectStoreId; 382 const IDBIndexMetadata m_indexMetadata; 383 }; 384 } 385 386 IDBIndex* IDBObjectStore::createIndex(ScriptState* scriptState, const String& name, const IDBKeyPath& keyPath, const Dictionary& options, ExceptionState& exceptionState) 387 { 388 bool unique = false; 389 options.get("unique", unique); 390 391 bool multiEntry = false; 392 options.get("multiEntry", multiEntry); 393 394 return createIndex(scriptState, name, keyPath, unique, multiEntry, exceptionState); 395 } 396 397 IDBIndex* IDBObjectStore::createIndex(ScriptState* scriptState, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, ExceptionState& exceptionState) 398 { 399 IDB_TRACE("IDBObjectStore::createIndex"); 400 if (!m_transaction->isVersionChange()) { 401 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVersionChangeTransactionErrorMessage); 402 return 0; 403 } 404 if (isDeleted()) { 405 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage); 406 return 0; 407 } 408 if (m_transaction->isFinished() || m_transaction->isFinishing()) { 409 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 410 return 0; 411 } 412 if (!m_transaction->isActive()) { 413 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 414 return 0; 415 } 416 if (!keyPath.isValid()) { 417 exceptionState.throwDOMException(SyntaxError, "The keyPath argument contains an invalid key path."); 418 return 0; 419 } 420 if (name.isNull()) { 421 exceptionState.throwTypeError("The name provided is null."); 422 return 0; 423 } 424 if (containsIndex(name)) { 425 exceptionState.throwDOMException(ConstraintError, "An index with the specified name already exists."); 426 return 0; 427 } 428 429 if (keyPath.type() == IDBKeyPath::ArrayType && multiEntry) { 430 exceptionState.throwDOMException(InvalidAccessError, "The keyPath argument was an array and the multiEntry option is true."); 431 return 0; 432 } 433 if (!backendDB()) { 434 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage); 435 return 0; 436 } 437 438 int64_t indexId = m_metadata.maxIndexId + 1; 439 backendDB()->createIndex(m_transaction->id(), id(), indexId, name, keyPath, unique, multiEntry); 440 441 ++m_metadata.maxIndexId; 442 443 IDBIndexMetadata metadata(name, indexId, keyPath, unique, multiEntry); 444 IDBIndex* index = IDBIndex::create(metadata, this, m_transaction.get()); 445 m_indexMap.set(name, index); 446 m_metadata.indexes.set(indexId, metadata); 447 m_transaction->db()->indexCreated(id(), metadata); 448 449 ASSERT(!exceptionState.hadException()); 450 if (exceptionState.hadException()) 451 return 0; 452 453 IDBRequest* indexRequest = openCursor(scriptState, static_cast<IDBKeyRange*>(0), blink::WebIDBCursorDirectionNext, blink::WebIDBTaskTypePreemptive); 454 indexRequest->preventPropagation(); 455 456 // This is kept alive by being the success handler of the request, which is in turn kept alive by the owning transaction. 457 RefPtr<IndexPopulator> indexPopulator = IndexPopulator::create(scriptState, transaction()->db(), m_transaction->id(), id(), metadata); 458 indexRequest->setOnsuccess(indexPopulator); 459 return index; 460 } 461 462 IDBIndex* IDBObjectStore::index(const String& name, ExceptionState& exceptionState) 463 { 464 IDB_TRACE("IDBObjectStore::index"); 465 if (isDeleted()) { 466 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage); 467 return 0; 468 } 469 if (m_transaction->isFinished() || m_transaction->isFinishing()) { 470 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::transactionFinishedErrorMessage); 471 return 0; 472 } 473 474 IDBIndexMap::iterator it = m_indexMap.find(name); 475 if (it != m_indexMap.end()) 476 return it->value; 477 478 int64_t indexId = findIndexId(name); 479 if (indexId == IDBIndexMetadata::InvalidId) { 480 exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchIndexErrorMessage); 481 return 0; 482 } 483 484 const IDBIndexMetadata* indexMetadata(0); 485 for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it) { 486 if (it->value.name == name) { 487 indexMetadata = &it->value; 488 break; 489 } 490 } 491 ASSERT(indexMetadata); 492 ASSERT(indexMetadata->id != IDBIndexMetadata::InvalidId); 493 494 IDBIndex* index = IDBIndex::create(*indexMetadata, this, m_transaction.get()); 495 m_indexMap.set(name, index); 496 return index; 497 } 498 499 void IDBObjectStore::deleteIndex(const String& name, ExceptionState& exceptionState) 500 { 501 IDB_TRACE("IDBObjectStore::deleteIndex"); 502 if (!m_transaction->isVersionChange()) { 503 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVersionChangeTransactionErrorMessage); 504 return; 505 } 506 if (isDeleted()) { 507 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage); 508 return; 509 } 510 if (m_transaction->isFinished() || m_transaction->isFinishing()) { 511 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 512 return; 513 } 514 if (!m_transaction->isActive()) { 515 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 516 return; 517 } 518 int64_t indexId = findIndexId(name); 519 if (indexId == IDBIndexMetadata::InvalidId) { 520 exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchIndexErrorMessage); 521 return; 522 } 523 if (!backendDB()) { 524 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage); 525 return; 526 } 527 528 backendDB()->deleteIndex(m_transaction->id(), id(), indexId); 529 530 m_metadata.indexes.remove(indexId); 531 m_transaction->db()->indexDeleted(id(), indexId); 532 IDBIndexMap::iterator it = m_indexMap.find(name); 533 if (it != m_indexMap.end()) { 534 it->value->markDeleted(); 535 m_indexMap.remove(name); 536 } 537 } 538 539 IDBRequest* IDBObjectStore::openCursor(ScriptState* scriptState, const ScriptValue& range, const String& directionString, ExceptionState& exceptionState) 540 { 541 IDB_TRACE("IDBObjectStore::openCursor"); 542 if (isDeleted()) { 543 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage); 544 return 0; 545 } 546 if (m_transaction->isFinished() || m_transaction->isFinishing()) { 547 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 548 return 0; 549 } 550 if (!m_transaction->isActive()) { 551 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 552 return 0; 553 } 554 555 blink::WebIDBCursorDirection direction = IDBCursor::stringToDirection(directionString, exceptionState); 556 if (exceptionState.hadException()) 557 return 0; 558 559 IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), range, exceptionState); 560 if (exceptionState.hadException()) 561 return 0; 562 563 if (!backendDB()) { 564 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage); 565 return 0; 566 } 567 568 return openCursor(scriptState, keyRange, direction, blink::WebIDBTaskTypeNormal); 569 } 570 571 IDBRequest* IDBObjectStore::openCursor(ScriptState* scriptState, IDBKeyRange* range, blink::WebIDBCursorDirection direction, blink::WebIDBTaskType taskType) 572 { 573 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get()); 574 request->setCursorDetails(IndexedDB::CursorKeyAndValue, direction); 575 576 backendDB()->openCursor(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, range, direction, false, taskType, WebIDBCallbacksImpl::create(request).leakPtr()); 577 return request; 578 } 579 580 IDBRequest* IDBObjectStore::openKeyCursor(ScriptState* scriptState, const ScriptValue& range, const String& directionString, ExceptionState& exceptionState) 581 { 582 IDB_TRACE("IDBObjectStore::openKeyCursor"); 583 if (isDeleted()) { 584 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage); 585 return 0; 586 } 587 if (m_transaction->isFinished() || m_transaction->isFinishing()) { 588 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 589 return 0; 590 } 591 if (!m_transaction->isActive()) { 592 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 593 return 0; 594 } 595 596 blink::WebIDBCursorDirection direction = IDBCursor::stringToDirection(directionString, exceptionState); 597 if (exceptionState.hadException()) 598 return 0; 599 600 IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), range, exceptionState); 601 if (exceptionState.hadException()) 602 return 0; 603 604 if (!backendDB()) { 605 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage); 606 return 0; 607 } 608 609 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get()); 610 request->setCursorDetails(IndexedDB::CursorKeyOnly, direction); 611 612 backendDB()->openCursor(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, keyRange, direction, true, blink::WebIDBTaskTypeNormal, WebIDBCallbacksImpl::create(request).leakPtr()); 613 return request; 614 } 615 616 IDBRequest* IDBObjectStore::count(ScriptState* scriptState, const ScriptValue& range, ExceptionState& exceptionState) 617 { 618 IDB_TRACE("IDBObjectStore::count"); 619 if (isDeleted()) { 620 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage); 621 return 0; 622 } 623 if (m_transaction->isFinished() || m_transaction->isFinishing()) { 624 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 625 return 0; 626 } 627 if (!m_transaction->isActive()) { 628 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 629 return 0; 630 } 631 632 IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), range, exceptionState); 633 if (exceptionState.hadException()) 634 return 0; 635 636 if (!backendDB()) { 637 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage); 638 return 0; 639 } 640 641 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get()); 642 backendDB()->count(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, keyRange, WebIDBCallbacksImpl::create(request).leakPtr()); 643 return request; 644 } 645 646 void IDBObjectStore::transactionFinished() 647 { 648 ASSERT(m_transaction->isFinished()); 649 650 // Break reference cycles. 651 m_indexMap.clear(); 652 } 653 654 int64_t IDBObjectStore::findIndexId(const String& name) const 655 { 656 for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it) { 657 if (it->value.name == name) { 658 ASSERT(it->key != IDBIndexMetadata::InvalidId); 659 return it->key; 660 } 661 } 662 return IDBIndexMetadata::InvalidId; 663 } 664 665 WebIDBDatabase* IDBObjectStore::backendDB() const 666 { 667 return m_transaction->backendDB(); 668 } 669 670 } // namespace WebCore 671