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 "third_party/blink/renderer/modules/indexeddb/idb_database.h"
27
28 #include <limits>
29 #include <memory>
30
31 #include "base/atomic_sequence_num.h"
32 #include "base/optional.h"
33 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
34 #include "third_party/blink/public/common/indexeddb/web_idb_types.h"
35 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
36 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
37 #include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
38 #include "third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_callback.h"
39 #include "third_party/blink/renderer/core/dom/events/event_queue.h"
40 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
41 #include "third_party/blink/renderer/modules/indexed_db_names.h"
42 #include "third_party/blink/renderer/modules/indexeddb/idb_any.h"
43 #include "third_party/blink/renderer/modules/indexeddb/idb_event_dispatcher.h"
44 #include "third_party/blink/renderer/modules/indexeddb/idb_index.h"
45 #include "third_party/blink/renderer/modules/indexeddb/idb_key_path.h"
46 #include "third_party/blink/renderer/modules/indexeddb/idb_observer.h"
47 #include "third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h"
48 #include "third_party/blink/renderer/modules/indexeddb/idb_tracing.h"
49 #include "third_party/blink/renderer/modules/indexeddb/idb_version_change_event.h"
50 #include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
51 #include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h"
52 #include "third_party/blink/renderer/modules/indexeddb/web_idb_transaction_impl.h"
53 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
54 #include "third_party/blink/renderer/platform/heap/heap.h"
55 #include "third_party/blink/renderer/platform/wtf/assertions.h"
56 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
57
58 namespace blink {
59
60 const char IDBDatabase::kCannotObserveVersionChangeTransaction[] =
61 "An observer cannot target a version change transaction.";
62 const char IDBDatabase::kIndexDeletedErrorMessage[] =
63 "The index or its object store has been deleted.";
64 const char IDBDatabase::kIndexNameTakenErrorMessage[] =
65 "An index with the specified name already exists.";
66 const char IDBDatabase::kIsKeyCursorErrorMessage[] =
67 "The cursor is a key cursor.";
68 const char IDBDatabase::kNoKeyOrKeyRangeErrorMessage[] =
69 "No key or key range specified.";
70 const char IDBDatabase::kNoSuchIndexErrorMessage[] =
71 "The specified index was not found.";
72 const char IDBDatabase::kNoSuchObjectStoreErrorMessage[] =
73 "The specified object store was not found.";
74 const char IDBDatabase::kNoValueErrorMessage[] =
75 "The cursor is being iterated or has iterated past its end.";
76 const char IDBDatabase::kNotValidKeyErrorMessage[] =
77 "The parameter is not a valid key.";
78 const char IDBDatabase::kNotVersionChangeTransactionErrorMessage[] =
79 "The database is not running a version change transaction.";
80 const char IDBDatabase::kObjectStoreDeletedErrorMessage[] =
81 "The object store has been deleted.";
82 const char IDBDatabase::kObjectStoreNameTakenErrorMessage[] =
83 "An object store with the specified name already exists.";
84 const char IDBDatabase::kRequestNotFinishedErrorMessage[] =
85 "The request has not finished.";
86 const char IDBDatabase::kSourceDeletedErrorMessage[] =
87 "The cursor's source or effective object store has been deleted.";
88 const char IDBDatabase::kTransactionInactiveErrorMessage[] =
89 "The transaction is not active.";
90 const char IDBDatabase::kTransactionFinishedErrorMessage[] =
91 "The transaction has finished.";
92 const char IDBDatabase::kTransactionReadOnlyErrorMessage[] =
93 "The transaction is read-only.";
94 const char IDBDatabase::kDatabaseClosedErrorMessage[] =
95 "The database connection is closed.";
96
IDBDatabase(ExecutionContext * context,std::unique_ptr<WebIDBDatabase> backend,IDBDatabaseCallbacks * callbacks,v8::Isolate * isolate,mojo::PendingRemote<mojom::blink::ObservedFeature> connection_lifetime)97 IDBDatabase::IDBDatabase(
98 ExecutionContext* context,
99 std::unique_ptr<WebIDBDatabase> backend,
100 IDBDatabaseCallbacks* callbacks,
101 v8::Isolate* isolate,
102 mojo::PendingRemote<mojom::blink::ObservedFeature> connection_lifetime)
103 : ExecutionContextLifecycleObserver(context),
104 backend_(std::move(backend)),
105 connection_lifetime_(std::move(connection_lifetime)),
106 event_queue_(
107 MakeGarbageCollected<EventQueue>(context, TaskType::kDatabaseAccess)),
108 database_callbacks_(callbacks),
109 isolate_(isolate),
110 feature_handle_for_scheduler_(
111 context
112 ? context->GetScheduler()->RegisterFeature(
113 SchedulingPolicy::Feature::kIndexedDBConnection,
114 {SchedulingPolicy::RecordMetricsForBackForwardCache()})
115 : FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle()) {
116 database_callbacks_->Connect(this);
117 }
118
~IDBDatabase()119 IDBDatabase::~IDBDatabase() {
120 if (!close_pending_ && backend_)
121 backend_->Close();
122 }
123
Trace(Visitor * visitor) const124 void IDBDatabase::Trace(Visitor* visitor) const {
125 visitor->Trace(version_change_transaction_);
126 visitor->Trace(transactions_);
127 visitor->Trace(observers_);
128 visitor->Trace(event_queue_);
129 visitor->Trace(database_callbacks_);
130 EventTargetWithInlineData::Trace(visitor);
131 ExecutionContextLifecycleObserver::Trace(visitor);
132 }
133
NextTransactionId()134 int64_t IDBDatabase::NextTransactionId() {
135 // Starts at 1, unlike AtomicSequenceNumber.
136 // Only keep a 32-bit counter to allow ports to use the other 32
137 // bits of the id.
138 static base::AtomicSequenceNumber current_transaction_id;
139 return current_transaction_id.GetNext() + 1;
140 }
141
NextObserverId()142 int32_t IDBDatabase::NextObserverId() {
143 // Starts at 1, unlike AtomicSequenceNumber.
144 static base::AtomicSequenceNumber current_observer_id;
145 return current_observer_id.GetNext() + 1;
146 }
147
SetMetadata(const IDBDatabaseMetadata & metadata)148 void IDBDatabase::SetMetadata(const IDBDatabaseMetadata& metadata) {
149 metadata_ = metadata;
150 }
151
SetDatabaseMetadata(const IDBDatabaseMetadata & metadata)152 void IDBDatabase::SetDatabaseMetadata(const IDBDatabaseMetadata& metadata) {
153 metadata_.CopyFrom(metadata);
154 }
155
TransactionCreated(IDBTransaction * transaction)156 void IDBDatabase::TransactionCreated(IDBTransaction* transaction) {
157 DCHECK(transaction);
158 DCHECK(!transactions_.Contains(transaction->Id()));
159 transactions_.insert(transaction->Id(), transaction);
160
161 if (transaction->IsVersionChange()) {
162 DCHECK(!version_change_transaction_);
163 version_change_transaction_ = transaction;
164 }
165 }
166
TransactionFinished(const IDBTransaction * transaction)167 void IDBDatabase::TransactionFinished(const IDBTransaction* transaction) {
168 DCHECK(transaction);
169 DCHECK(transactions_.Contains(transaction->Id()));
170 DCHECK_EQ(transactions_.at(transaction->Id()), transaction);
171 transactions_.erase(transaction->Id());
172
173 if (transaction->IsVersionChange()) {
174 DCHECK_EQ(version_change_transaction_, transaction);
175 version_change_transaction_ = nullptr;
176 }
177
178 if (close_pending_ && transactions_.IsEmpty())
179 CloseConnection();
180 }
181
OnAbort(int64_t transaction_id,DOMException * error)182 void IDBDatabase::OnAbort(int64_t transaction_id, DOMException* error) {
183 DCHECK(transactions_.Contains(transaction_id));
184 transactions_.at(transaction_id)->OnAbort(error);
185 }
186
OnComplete(int64_t transaction_id)187 void IDBDatabase::OnComplete(int64_t transaction_id) {
188 DCHECK(transactions_.Contains(transaction_id));
189 transactions_.at(transaction_id)->OnComplete();
190 }
191
OnChanges(const WebIDBDatabaseCallbacks::ObservationIndexMap & observation_index_map,Vector<Persistent<IDBObservation>> observations,const WebIDBDatabaseCallbacks::TransactionMap & transactions)192 void IDBDatabase::OnChanges(
193 const WebIDBDatabaseCallbacks::ObservationIndexMap& observation_index_map,
194 Vector<Persistent<IDBObservation>> observations,
195 const WebIDBDatabaseCallbacks::TransactionMap& transactions) {
196 for (const auto& observation : observations) {
197 observation->SetIsolate(isolate_);
198 }
199
200 for (const auto& map_entry : observation_index_map) {
201 auto observer_lookup_result = observers_.find(map_entry.key);
202 if (observer_lookup_result != observers_.end()) {
203 IDBObserver* observer = observer_lookup_result->value;
204
205 auto transactions_lookup_result = transactions.find(map_entry.key);
206 if (transactions_lookup_result != transactions.end()) {
207 const std::pair<int64_t, Vector<int64_t>>& obs_txn =
208 transactions_lookup_result->value;
209 HashSet<String> stores;
210 for (int64_t store_id : obs_txn.second) {
211 stores.insert(metadata_.object_stores.at(store_id)->name);
212 }
213 }
214
215 observer->Callback()->InvokeAndReportException(
216 observer, MakeGarbageCollected<IDBObserverChanges>(
217 this, nullptr, observations, map_entry.value));
218 }
219 }
220 }
221
objectStoreNames() const222 DOMStringList* IDBDatabase::objectStoreNames() const {
223 auto* object_store_names = MakeGarbageCollected<DOMStringList>();
224 for (const auto& it : metadata_.object_stores)
225 object_store_names->Append(it.value->name);
226 object_store_names->Sort();
227 return object_store_names;
228 }
229
GetObjectStoreName(int64_t object_store_id) const230 const String& IDBDatabase::GetObjectStoreName(int64_t object_store_id) const {
231 const auto& it = metadata_.object_stores.find(object_store_id);
232 DCHECK(it != metadata_.object_stores.end());
233 return it->value->name;
234 }
235
AddObserver(IDBObserver * observer,int64_t transaction_id,bool include_transaction,bool no_records,bool values,std::bitset<blink::kIDBOperationTypeCount> operation_types)236 int32_t IDBDatabase::AddObserver(
237 IDBObserver* observer,
238 int64_t transaction_id,
239 bool include_transaction,
240 bool no_records,
241 bool values,
242 std::bitset<blink::kIDBOperationTypeCount> operation_types) {
243 int32_t observer_id = NextObserverId();
244 observers_.Set(observer_id, observer);
245 Backend()->AddObserver(transaction_id, observer_id, include_transaction,
246 no_records, values, operation_types);
247 return observer_id;
248 }
249
RemoveObservers(const Vector<int32_t> & observer_ids)250 void IDBDatabase::RemoveObservers(const Vector<int32_t>& observer_ids) {
251 observers_.RemoveAll(observer_ids);
252 Backend()->RemoveObservers(observer_ids);
253 }
254
createObjectStore(const String & name,const IDBKeyPath & key_path,bool auto_increment,ExceptionState & exception_state)255 IDBObjectStore* IDBDatabase::createObjectStore(
256 const String& name,
257 const IDBKeyPath& key_path,
258 bool auto_increment,
259 ExceptionState& exception_state) {
260 IDB_TRACE("IDBDatabase::createObjectStore");
261
262 if (!version_change_transaction_) {
263 exception_state.ThrowDOMException(
264 DOMExceptionCode::kInvalidStateError,
265 IDBDatabase::kNotVersionChangeTransactionErrorMessage);
266 return nullptr;
267 }
268 if (!version_change_transaction_->IsActive()) {
269 exception_state.ThrowDOMException(
270 DOMExceptionCode::kTransactionInactiveError,
271 version_change_transaction_->InactiveErrorMessage());
272 return nullptr;
273 }
274
275 if (!key_path.IsNull() && !key_path.IsValid()) {
276 exception_state.ThrowDOMException(
277 DOMExceptionCode::kSyntaxError,
278 "The keyPath option is not a valid key path.");
279 return nullptr;
280 }
281
282 if (ContainsObjectStore(name)) {
283 exception_state.ThrowDOMException(
284 DOMExceptionCode::kConstraintError,
285 IDBDatabase::kObjectStoreNameTakenErrorMessage);
286 return nullptr;
287 }
288
289 if (auto_increment && ((key_path.GetType() == mojom::IDBKeyPathType::String &&
290 key_path.GetString().IsEmpty()) ||
291 key_path.GetType() == mojom::IDBKeyPathType::Array)) {
292 exception_state.ThrowDOMException(
293 DOMExceptionCode::kInvalidAccessError,
294 "The autoIncrement option was set but the "
295 "keyPath option was empty or an array.");
296 return nullptr;
297 }
298
299 if (!backend_) {
300 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
301 IDBDatabase::kDatabaseClosedErrorMessage);
302 return nullptr;
303 }
304
305 int64_t object_store_id = metadata_.max_object_store_id + 1;
306 DCHECK_NE(object_store_id, IDBObjectStoreMetadata::kInvalidId);
307 version_change_transaction_->transaction_backend()->CreateObjectStore(
308 object_store_id, name, key_path, auto_increment);
309
310 scoped_refptr<IDBObjectStoreMetadata> store_metadata =
311 base::AdoptRef(new IDBObjectStoreMetadata(
312 name, object_store_id, key_path, auto_increment,
313 WebIDBDatabase::kMinimumIndexId));
314 auto* object_store = MakeGarbageCollected<IDBObjectStore>(
315 store_metadata, version_change_transaction_.Get());
316 version_change_transaction_->ObjectStoreCreated(name, object_store);
317 metadata_.object_stores.Set(object_store_id, std::move(store_metadata));
318 ++metadata_.max_object_store_id;
319
320 return object_store;
321 }
322
deleteObjectStore(const String & name,ExceptionState & exception_state)323 void IDBDatabase::deleteObjectStore(const String& name,
324 ExceptionState& exception_state) {
325 IDB_TRACE("IDBDatabase::deleteObjectStore");
326 if (!version_change_transaction_) {
327 exception_state.ThrowDOMException(
328 DOMExceptionCode::kInvalidStateError,
329 IDBDatabase::kNotVersionChangeTransactionErrorMessage);
330 return;
331 }
332 if (!version_change_transaction_->IsActive()) {
333 exception_state.ThrowDOMException(
334 DOMExceptionCode::kTransactionInactiveError,
335 version_change_transaction_->InactiveErrorMessage());
336 return;
337 }
338
339 int64_t object_store_id = FindObjectStoreId(name);
340 if (object_store_id == IDBObjectStoreMetadata::kInvalidId) {
341 exception_state.ThrowDOMException(
342 DOMExceptionCode::kNotFoundError,
343 "The specified object store was not found.");
344 return;
345 }
346
347 if (!backend_) {
348 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
349 IDBDatabase::kDatabaseClosedErrorMessage);
350 return;
351 }
352
353 version_change_transaction_->transaction_backend()->DeleteObjectStore(
354 object_store_id);
355 version_change_transaction_->ObjectStoreDeleted(object_store_id, name);
356 metadata_.object_stores.erase(object_store_id);
357 }
358
transaction(ScriptState * script_state,const StringOrStringSequence & store_names,const String & mode,ExceptionState & exception_state)359 IDBTransaction* IDBDatabase::transaction(
360 ScriptState* script_state,
361 const StringOrStringSequence& store_names,
362 const String& mode,
363 ExceptionState& exception_state) {
364 return transaction(script_state, store_names, mode, nullptr, exception_state);
365 }
366
transaction(ScriptState * script_state,const StringOrStringSequence & store_names,const String & mode_string,const IDBTransactionOptions * options,ExceptionState & exception_state)367 IDBTransaction* IDBDatabase::transaction(
368 ScriptState* script_state,
369 const StringOrStringSequence& store_names,
370 const String& mode_string,
371 const IDBTransactionOptions* options,
372 ExceptionState& exception_state) {
373 IDB_TRACE("IDBDatabase::transaction");
374
375 HashSet<String> scope;
376 if (store_names.IsString()) {
377 scope.insert(store_names.GetAsString());
378 } else if (store_names.IsStringSequence()) {
379 for (const String& name : store_names.GetAsStringSequence())
380 scope.insert(name);
381 } else {
382 NOTREACHED();
383 }
384
385 if (version_change_transaction_) {
386 exception_state.ThrowDOMException(
387 DOMExceptionCode::kInvalidStateError,
388 "A version change transaction is running.");
389 return nullptr;
390 }
391
392 if (close_pending_) {
393 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
394 "The database connection is closing.");
395 return nullptr;
396 }
397
398 if (!backend_) {
399 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
400 IDBDatabase::kDatabaseClosedErrorMessage);
401 return nullptr;
402 }
403
404 if (scope.IsEmpty()) {
405 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
406 "The storeNames parameter was empty.");
407 return nullptr;
408 }
409
410 Vector<int64_t> object_store_ids;
411 for (const String& name : scope) {
412 int64_t object_store_id = FindObjectStoreId(name);
413 if (object_store_id == IDBObjectStoreMetadata::kInvalidId) {
414 exception_state.ThrowDOMException(
415 DOMExceptionCode::kNotFoundError,
416 "One of the specified object stores was not found.");
417 return nullptr;
418 }
419 object_store_ids.push_back(object_store_id);
420 }
421
422 mojom::IDBTransactionMode mode = IDBTransaction::StringToMode(mode_string);
423 if (mode != mojom::IDBTransactionMode::ReadOnly &&
424 mode != mojom::IDBTransactionMode::ReadWrite) {
425 exception_state.ThrowTypeError(
426 "The mode provided ('" + mode_string +
427 "') is not one of 'readonly' or 'readwrite'.");
428 return nullptr;
429 }
430
431 // TODO(cmp): Delete |transaction_id| once all users are removed.
432 int64_t transaction_id = NextTransactionId();
433 auto transaction_backend = std::make_unique<WebIDBTransactionImpl>(
434 ExecutionContext::From(script_state)
435 ->GetTaskRunner(TaskType::kDatabaseAccess),
436 transaction_id);
437
438 mojom::IDBTransactionDurability durability =
439 mojom::IDBTransactionDurability::Default;
440 if (options) {
441 DCHECK(RuntimeEnabledFeatures::IDBRelaxedDurabilityEnabled());
442 if (options->durability() == indexed_db_names::kRelaxed) {
443 durability = mojom::IDBTransactionDurability::Relaxed;
444 } else if (options->durability() == indexed_db_names::kStrict) {
445 durability = mojom::IDBTransactionDurability::Strict;
446 }
447 }
448
449 backend_->CreateTransaction(transaction_backend->CreateReceiver(),
450 transaction_id, object_store_ids, mode,
451 durability);
452
453 return IDBTransaction::CreateNonVersionChange(
454 script_state, std::move(transaction_backend), transaction_id, scope, mode,
455 durability, this);
456 }
457
ForceClose()458 void IDBDatabase::ForceClose() {
459 for (const auto& it : transactions_)
460 it.value->abort(IGNORE_EXCEPTION_FOR_TESTING);
461 this->close();
462 EnqueueEvent(Event::Create(event_type_names::kClose));
463 }
464
close()465 void IDBDatabase::close() {
466 IDB_TRACE("IDBDatabase::close");
467 if (close_pending_)
468 return;
469
470 connection_lifetime_.reset();
471 close_pending_ = true;
472 feature_handle_for_scheduler_.reset();
473
474 if (transactions_.IsEmpty())
475 CloseConnection();
476 }
477
CloseConnection()478 void IDBDatabase::CloseConnection() {
479 DCHECK(close_pending_);
480 DCHECK(transactions_.IsEmpty());
481
482 if (backend_) {
483 backend_->Close();
484 backend_.reset();
485 }
486
487 if (database_callbacks_)
488 database_callbacks_->DetachWebCallbacks();
489
490 if (!GetExecutionContext())
491 return;
492
493 // Remove any pending versionchange events scheduled to fire on this
494 // connection. They would have been scheduled by the backend when another
495 // connection attempted an upgrade, but the frontend connection is being
496 // closed before they could fire.
497 event_queue_->CancelAllEvents();
498 }
499
OnVersionChange(int64_t old_version,int64_t new_version)500 void IDBDatabase::OnVersionChange(int64_t old_version, int64_t new_version) {
501 IDB_TRACE("IDBDatabase::onVersionChange");
502 if (!GetExecutionContext())
503 return;
504
505 if (close_pending_) {
506 // If we're pending, that means there's a busy transaction. We won't
507 // fire 'versionchange' but since we're not closing immediately the
508 // back-end should still send out 'blocked'.
509 backend_->VersionChangeIgnored();
510 return;
511 }
512
513 base::Optional<uint64_t> new_version_nullable;
514 if (new_version != IDBDatabaseMetadata::kNoVersion) {
515 new_version_nullable = new_version;
516 }
517 EnqueueEvent(MakeGarbageCollected<IDBVersionChangeEvent>(
518 event_type_names::kVersionchange, old_version, new_version_nullable));
519 }
520
EnqueueEvent(Event * event)521 void IDBDatabase::EnqueueEvent(Event* event) {
522 DCHECK(GetExecutionContext());
523 event->SetTarget(this);
524 event_queue_->EnqueueEvent(FROM_HERE, *event);
525 }
526
DispatchEventInternal(Event & event)527 DispatchEventResult IDBDatabase::DispatchEventInternal(Event& event) {
528 IDB_TRACE("IDBDatabase::dispatchEvent");
529
530 event.SetTarget(this);
531
532 // If this event originated from script, it should have no side effects.
533 if (!event.isTrusted())
534 return EventTarget::DispatchEventInternal(event);
535 DCHECK(event.type() == event_type_names::kVersionchange ||
536 event.type() == event_type_names::kClose);
537
538 if (!GetExecutionContext())
539 return DispatchEventResult::kCanceledBeforeDispatch;
540
541 DispatchEventResult dispatch_result =
542 EventTarget::DispatchEventInternal(event);
543 if (event.type() == event_type_names::kVersionchange && !close_pending_ &&
544 backend_)
545 backend_->VersionChangeIgnored();
546 return dispatch_result;
547 }
548
FindObjectStoreId(const String & name) const549 int64_t IDBDatabase::FindObjectStoreId(const String& name) const {
550 for (const auto& it : metadata_.object_stores) {
551 if (it.value->name == name) {
552 DCHECK_NE(it.key, IDBObjectStoreMetadata::kInvalidId);
553 return it.key;
554 }
555 }
556 return IDBObjectStoreMetadata::kInvalidId;
557 }
558
RenameObjectStore(int64_t object_store_id,const String & new_name)559 void IDBDatabase::RenameObjectStore(int64_t object_store_id,
560 const String& new_name) {
561 DCHECK(version_change_transaction_)
562 << "Object store renamed on database without a versionchange transaction";
563 DCHECK(version_change_transaction_->IsActive())
564 << "Object store renamed when versionchange transaction is not active";
565 DCHECK(backend_) << "Object store renamed after database connection closed";
566 DCHECK(metadata_.object_stores.Contains(object_store_id));
567
568 backend_->RenameObjectStore(version_change_transaction_->Id(),
569 object_store_id, new_name);
570
571 IDBObjectStoreMetadata* object_store_metadata =
572 metadata_.object_stores.at(object_store_id);
573 version_change_transaction_->ObjectStoreRenamed(object_store_metadata->name,
574 new_name);
575 object_store_metadata->name = new_name;
576 }
577
RevertObjectStoreCreation(int64_t object_store_id)578 void IDBDatabase::RevertObjectStoreCreation(int64_t object_store_id) {
579 DCHECK(version_change_transaction_) << "Object store metadata reverted on "
580 "database without a versionchange "
581 "transaction";
582 DCHECK(!version_change_transaction_->IsActive())
583 << "Object store metadata reverted when versionchange transaction is "
584 "still active";
585 DCHECK(metadata_.object_stores.Contains(object_store_id));
586 metadata_.object_stores.erase(object_store_id);
587 }
588
RevertObjectStoreMetadata(scoped_refptr<IDBObjectStoreMetadata> old_metadata)589 void IDBDatabase::RevertObjectStoreMetadata(
590 scoped_refptr<IDBObjectStoreMetadata> old_metadata) {
591 DCHECK(version_change_transaction_) << "Object store metadata reverted on "
592 "database without a versionchange "
593 "transaction";
594 DCHECK(!version_change_transaction_->IsActive())
595 << "Object store metadata reverted when versionchange transaction is "
596 "still active";
597 DCHECK(old_metadata.get());
598 metadata_.object_stores.Set(old_metadata->id, std::move(old_metadata));
599 }
600
HasPendingActivity() const601 bool IDBDatabase::HasPendingActivity() const {
602 // The script wrapper must not be collected before the object is closed or
603 // we can't fire a "versionchange" event to let script manually close the
604 // connection.
605 return !close_pending_ && GetExecutionContext() && HasEventListeners();
606 }
607
ContextDestroyed()608 void IDBDatabase::ContextDestroyed() {
609 // Immediately close the connection to the back end. Don't attempt a
610 // normal close() since that may wait on transactions which require a
611 // round trip to the back-end to abort.
612 if (backend_) {
613 backend_->Close();
614 backend_.reset();
615 }
616
617 connection_lifetime_.reset();
618
619 if (database_callbacks_)
620 database_callbacks_->DetachWebCallbacks();
621 }
622
InterfaceName() const623 const AtomicString& IDBDatabase::InterfaceName() const {
624 return event_target_names::kIDBDatabase;
625 }
626
GetExecutionContext() const627 ExecutionContext* IDBDatabase::GetExecutionContext() const {
628 return ExecutionContextLifecycleObserver::GetExecutionContext();
629 }
630
631 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kNoError,
632 DOMExceptionCode::kNoError);
633 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kUnknownError,
634 DOMExceptionCode::kUnknownError);
635 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kConstraintError,
636 DOMExceptionCode::kConstraintError);
637 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kDataError,
638 DOMExceptionCode::kDataError);
639 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kVersionError,
640 DOMExceptionCode::kVersionError);
641 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kAbortError,
642 DOMExceptionCode::kAbortError);
643 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kQuotaError,
644 DOMExceptionCode::kQuotaExceededError);
645 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kTimeoutError,
646 DOMExceptionCode::kTimeoutError);
647
648 } // namespace blink
649