Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / client / IDBTransactionImpl.cpp
1 /*
2  * Copyright (C) 2015 Apple 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "IDBTransactionImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "DOMError.h"
32 #include "EventQueue.h"
33 #include "IDBCursorWithValueImpl.h"
34 #include "IDBDatabaseException.h"
35 #include "IDBDatabaseImpl.h"
36 #include "IDBError.h"
37 #include "IDBEventDispatcher.h"
38 #include "IDBKeyData.h"
39 #include "IDBKeyRangeData.h"
40 #include "IDBObjectStore.h"
41 #include "IDBOpenDBRequestImpl.h"
42 #include "IDBRequestImpl.h"
43 #include "IDBResultData.h"
44 #include "JSDOMWindowBase.h"
45 #include "Logging.h"
46 #include "ScriptExecutionContext.h"
47 #include "TransactionOperation.h"
48
49 namespace WebCore {
50 namespace IDBClient {
51
52 Ref<IDBTransaction> IDBTransaction::create(IDBDatabase& database, const IDBTransactionInfo& info)
53 {
54     return adoptRef(*new IDBTransaction(database, info, nullptr));
55 }
56
57 Ref<IDBTransaction> IDBTransaction::create(IDBDatabase& database, const IDBTransactionInfo& info, IDBOpenDBRequest& request)
58 {
59     return adoptRef(*new IDBTransaction(database, info, &request));
60 }
61
62 IDBTransaction::IDBTransaction(IDBDatabase& database, const IDBTransactionInfo& info, IDBOpenDBRequest* request)
63     : WebCore::IDBTransaction(database.scriptExecutionContext())
64     , m_database(database)
65     , m_info(info)
66     , m_operationTimer(*this, &IDBTransaction::operationTimerFired)
67     , m_openDBRequest(request)
68
69 {
70     relaxAdoptionRequirement();
71
72     if (m_info.mode() == IndexedDB::TransactionMode::VersionChange) {
73         ASSERT(m_openDBRequest);
74         m_openDBRequest->setVersionChangeTransaction(*this);
75         m_startedOnServer = true;
76     } else {
77         activate();
78
79         RefPtr<IDBTransaction> self;
80         JSC::VM& vm = JSDOMWindowBase::commonVM();
81         vm.whenIdle([self, this]() {
82             deactivate();
83         });
84
85         establishOnServer();
86     }
87
88     suspendIfNeeded();
89 }
90
91 IDBTransaction::~IDBTransaction()
92 {
93 }
94
95 const String& IDBTransaction::mode() const
96 {
97     switch (m_info.mode()) {
98     case IndexedDB::TransactionMode::ReadOnly:
99         return IDBTransaction::modeReadOnly();
100     case IndexedDB::TransactionMode::ReadWrite:
101         return IDBTransaction::modeReadWrite();
102     case IndexedDB::TransactionMode::VersionChange:
103         return IDBTransaction::modeVersionChange();
104     }
105
106     RELEASE_ASSERT_NOT_REACHED();
107 }
108
109 WebCore::IDBDatabase* IDBTransaction::db()
110 {
111     return &m_database.get();
112 }
113
114 IDBConnectionToServer& IDBTransaction::serverConnection()
115 {
116     return m_database->serverConnection();
117 }
118
119 RefPtr<DOMError> IDBTransaction::error() const
120 {
121     return m_domError;
122 }
123
124 RefPtr<WebCore::IDBObjectStore> IDBTransaction::objectStore(const String& objectStoreName, ExceptionCodeWithMessage& ec)
125 {
126     LOG(IndexedDB, "IDBTransaction::objectStore");
127
128     if (isFinishedOrFinishing()) {
129         ec.code = IDBDatabaseException::InvalidStateError;
130         ec.message = ASCIILiteral("Failed to execute 'objectStore' on 'IDBTransaction': The transaction finished.");
131         return nullptr;
132     }
133
134     auto iterator = m_referencedObjectStores.find(objectStoreName);
135     if (iterator != m_referencedObjectStores.end())
136         return iterator->value;
137
138     bool found = false;
139     for (auto& objectStore : m_info.objectStores()) {
140         if (objectStore == objectStoreName) {
141             found = true;
142             break;
143         }
144     }
145
146     auto* info = m_database->info().infoForExistingObjectStore(objectStoreName);
147     if (!info) {
148         ec.code = IDBDatabaseException::NotFoundError;
149         ec.message = ASCIILiteral("Failed to execute 'objectStore' on 'IDBTransaction': The specified object store was not found.");
150         return nullptr;
151     }
152
153     // Version change transactions are scoped to every object store in the database.
154     if (!info || (!found && !isVersionChange())) {
155         ec.code = IDBDatabaseException::NotFoundError;
156         ec.message = ASCIILiteral("Failed to execute 'objectStore' on 'IDBTransaction': The specified object store was not found.");
157         return nullptr;
158     }
159
160     auto objectStore = IDBObjectStore::create(*info, *this);
161     m_referencedObjectStores.set(objectStoreName, &objectStore.get());
162
163     return adoptRef(&objectStore.leakRef());
164 }
165
166
167 void IDBTransaction::abortDueToFailedRequest(DOMError& error)
168 {
169     LOG(IndexedDB, "IDBTransaction::abortDueToFailedRequest");
170     if (isFinishedOrFinishing())
171         return;
172
173     m_domError = &error;
174     ExceptionCodeWithMessage ec;
175     abort(ec);
176 }
177
178 void IDBTransaction::abort(ExceptionCodeWithMessage& ec)
179 {
180     LOG(IndexedDB, "IDBTransaction::abort");
181
182     if (isFinishedOrFinishing()) {
183         ec.code = IDBDatabaseException::InvalidStateError;
184         ec.message = ASCIILiteral("Failed to execute 'abort' on 'IDBTransaction': The transaction is inactive or finished.");
185         return;
186     }
187
188     m_state = IndexedDB::TransactionState::Aborting;
189     m_database->willAbortTransaction(*this);
190
191     if (isVersionChange()) {
192         for (auto& objectStore : m_referencedObjectStores.values())
193             objectStore->rollbackInfoForVersionChangeAbort();
194     }
195     
196     m_abortQueue.swap(m_transactionOperationQueue);
197
198     auto operation = createTransactionOperation(*this, nullptr, &IDBTransaction::abortOnServerAndCancelRequests);
199     scheduleOperation(WTFMove(operation));
200 }
201
202 void IDBTransaction::abortOnServerAndCancelRequests(TransactionOperation&)
203 {
204     LOG(IndexedDB, "IDBTransaction::abortOnServerAndCancelRequests");
205
206     ASSERT(m_transactionOperationQueue.isEmpty());
207
208     serverConnection().abortTransaction(*this);
209
210     IDBError error(IDBDatabaseException::AbortError);
211     for (auto& operation : m_abortQueue)
212         operation->completed(IDBResultData::error(operation->identifier(), error));
213
214     // Since we're aborting, this abortOnServerAndCancelRequests() operation should be the only
215     // in-progress operation, and it should be impossible to have queued any further operations.
216     ASSERT(m_transactionOperationMap.size() == 1);
217     ASSERT(m_transactionOperationQueue.isEmpty());
218 }
219
220 const char* IDBTransaction::activeDOMObjectName() const
221 {
222     return "IDBTransaction";
223 }
224
225 bool IDBTransaction::canSuspendForDocumentSuspension() const
226 {
227     return false;
228 }
229
230 bool IDBTransaction::hasPendingActivity() const
231 {
232     return !m_contextStopped && m_state != IndexedDB::TransactionState::Finished;
233 }
234
235 void IDBTransaction::stop()
236 {
237     ASSERT(!m_contextStopped);
238     m_contextStopped = true;
239 }
240
241 bool IDBTransaction::isActive() const
242 {
243     return m_state == IndexedDB::TransactionState::Active;
244 }
245
246 bool IDBTransaction::isFinishedOrFinishing() const
247 {
248     return m_state == IndexedDB::TransactionState::Committing
249         || m_state == IndexedDB::TransactionState::Aborting
250         || m_state == IndexedDB::TransactionState::Finished;
251 }
252
253 void IDBTransaction::addRequest(IDBRequest& request)
254 {
255     m_openRequests.add(&request);
256 }
257
258 void IDBTransaction::removeRequest(IDBRequest& request)
259 {
260     ASSERT(m_openRequests.contains(&request));
261     m_openRequests.remove(&request);
262 }
263
264 void IDBTransaction::scheduleOperation(RefPtr<TransactionOperation>&& operation)
265 {
266     ASSERT(!m_transactionOperationMap.contains(operation->identifier()));
267
268     m_transactionOperationQueue.append(operation);
269     m_transactionOperationMap.set(operation->identifier(), WTFMove(operation));
270
271     scheduleOperationTimer();
272 }
273
274 void IDBTransaction::scheduleOperationTimer()
275 {
276     if (!m_operationTimer.isActive())
277         m_operationTimer.startOneShot(0);
278 }
279
280 void IDBTransaction::operationTimerFired()
281 {
282     LOG(IndexedDB, "IDBTransaction::operationTimerFired (%p)", this);
283
284     if (!m_startedOnServer)
285         return;
286
287     if (!m_transactionOperationQueue.isEmpty()) {
288         auto operation = m_transactionOperationQueue.takeFirst();
289         operation->perform();
290
291         return;
292     }
293
294     if (!m_transactionOperationMap.isEmpty() || !m_openRequests.isEmpty())
295         return;
296
297     if (!isFinishedOrFinishing())
298         commit();
299 }
300
301 void IDBTransaction::commit()
302 {
303     LOG(IndexedDB, "IDBTransaction::commit");
304
305     ASSERT(!isFinishedOrFinishing());
306
307     m_state = IndexedDB::TransactionState::Committing;
308     m_database->willCommitTransaction(*this);
309
310     auto operation = createTransactionOperation(*this, nullptr, &IDBTransaction::commitOnServer);
311     scheduleOperation(WTFMove(operation));
312 }
313
314 void IDBTransaction::commitOnServer(TransactionOperation&)
315 {
316     LOG(IndexedDB, "IDBTransaction::commitOnServer");
317     serverConnection().commitTransaction(*this);
318 }
319
320 void IDBTransaction::finishAbortOrCommit()
321 {
322     ASSERT(m_state != IndexedDB::TransactionState::Finished);
323     m_state = IndexedDB::TransactionState::Finished;
324 }
325
326 void IDBTransaction::didStart(const IDBError& error)
327 {
328     LOG(IndexedDB, "IDBTransaction::didStart");
329
330     m_database->didStartTransaction(*this);
331
332     m_startedOnServer = true;
333
334     // It's possible the transaction failed to start on the server.
335     // That equates to an abort.
336     if (!error.isNull()) {
337         didAbort(error);
338         return;
339     }
340
341     scheduleOperationTimer();
342 }
343
344 void IDBTransaction::notifyDidAbort(const IDBError& error)
345 {
346     m_database->didAbortTransaction(*this);
347     m_idbError = error;
348     fireOnAbort();
349
350     if (isVersionChange()) {
351         ASSERT(m_openDBRequest);
352         m_openDBRequest->fireErrorAfterVersionChangeCompletion();
353     }
354 }
355
356 void IDBTransaction::didAbort(const IDBError& error)
357 {
358     LOG(IndexedDB, "IDBTransaction::didAbort");
359
360     if (m_state == IndexedDB::TransactionState::Finished)
361         return;
362
363     notifyDidAbort(error);
364
365     finishAbortOrCommit();
366 }
367
368 void IDBTransaction::didCommit(const IDBError& error)
369 {
370     LOG(IndexedDB, "IDBTransaction::didCommit");
371
372     ASSERT(m_state == IndexedDB::TransactionState::Committing);
373
374     if (error.isNull()) {
375         m_database->didCommitTransaction(*this);
376         fireOnComplete();
377     } else
378         notifyDidAbort(error);
379
380     finishAbortOrCommit();
381 }
382
383 void IDBTransaction::fireOnComplete()
384 {
385     LOG(IndexedDB, "IDBTransaction::fireOnComplete");
386     enqueueEvent(Event::create(eventNames().completeEvent, false, false));
387 }
388
389 void IDBTransaction::fireOnAbort()
390 {
391     LOG(IndexedDB, "IDBTransaction::fireOnAbort");
392     enqueueEvent(Event::create(eventNames().abortEvent, true, false));
393 }
394
395 void IDBTransaction::enqueueEvent(Ref<Event>&& event)
396 {
397     ASSERT(m_state != IndexedDB::TransactionState::Finished);
398
399     if (!scriptExecutionContext() || m_contextStopped)
400         return;
401
402     event->setTarget(this);
403     scriptExecutionContext()->eventQueue().enqueueEvent(WTFMove(event));
404 }
405
406 bool IDBTransaction::dispatchEvent(Event& event)
407 {
408     LOG(IndexedDB, "IDBTransaction::dispatchEvent");
409
410     ASSERT(scriptExecutionContext());
411     ASSERT(!m_contextStopped);
412     ASSERT(event.target() == this);
413     ASSERT(event.type() == eventNames().completeEvent || event.type() == eventNames().abortEvent);
414
415     Vector<RefPtr<EventTarget>> targets;
416     targets.append(this);
417     targets.append(db());
418
419     bool result = IDBEventDispatcher::dispatch(event, targets);
420
421     if (isVersionChange()) {
422         ASSERT(m_openDBRequest);
423         m_openDBRequest->versionChangeTransactionDidFinish();
424
425         if (event.type() == eventNames().completeEvent) {
426             if (m_database->isClosingOrClosed())
427                 m_openDBRequest->fireErrorAfterVersionChangeCompletion();
428             else
429                 m_openDBRequest->fireSuccessAfterVersionChangeCommit();
430         }
431     }
432
433     return result;
434 }
435
436 Ref<IDBObjectStore> IDBTransaction::createObjectStore(const IDBObjectStoreInfo& info)
437 {
438     LOG(IndexedDB, "IDBTransaction::createObjectStore");
439     ASSERT(isVersionChange());
440
441     Ref<IDBObjectStore> objectStore = IDBObjectStore::create(info, *this);
442     m_referencedObjectStores.set(info.name(), &objectStore.get());
443
444     auto operation = createTransactionOperation(*this, &IDBTransaction::didCreateObjectStoreOnServer, &IDBTransaction::createObjectStoreOnServer, info);
445     scheduleOperation(WTFMove(operation));
446
447     return objectStore;
448 }
449
450 void IDBTransaction::createObjectStoreOnServer(TransactionOperation& operation, const IDBObjectStoreInfo& info)
451 {
452     LOG(IndexedDB, "IDBTransaction::createObjectStoreOnServer");
453
454     ASSERT(isVersionChange());
455
456     m_database->serverConnection().createObjectStore(operation, info);
457 }
458
459 void IDBTransaction::didCreateObjectStoreOnServer(const IDBResultData& resultData)
460 {
461     LOG(IndexedDB, "IDBTransaction::didCreateObjectStoreOnServer");
462
463     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::CreateObjectStoreSuccess || resultData.type() == IDBResultType::Error);
464 }
465
466 Ref<IDBIndex> IDBTransaction::createIndex(IDBObjectStore& objectStore, const IDBIndexInfo& info)
467 {
468     LOG(IndexedDB, "IDBTransaction::createIndex");
469     ASSERT(isVersionChange());
470
471     Ref<IDBIndex> index = IDBIndex::create(info, objectStore);
472
473     auto operation = createTransactionOperation(*this, &IDBTransaction::didCreateIndexOnServer, &IDBTransaction::createIndexOnServer, info);
474     scheduleOperation(WTFMove(operation));
475
476     return index;
477 }
478
479 void IDBTransaction::createIndexOnServer(TransactionOperation& operation, const IDBIndexInfo& info)
480 {
481     LOG(IndexedDB, "IDBTransaction::createIndexOnServer");
482
483     ASSERT(isVersionChange());
484
485     m_database->serverConnection().createIndex(operation, info);
486 }
487
488 void IDBTransaction::didCreateIndexOnServer(const IDBResultData& resultData)
489 {
490     LOG(IndexedDB, "IDBTransaction::didCreateIndexOnServer");
491
492     if (resultData.type() == IDBResultType::CreateIndexSuccess)
493         return;
494
495     ASSERT(resultData.type() == IDBResultType::Error);
496
497     // This operation might have failed because the transaction is already aborting.
498     if (m_state == IndexedDB::TransactionState::Aborting)
499         return;
500
501     // Otherwise, failure to create an index forced abortion of the transaction.
502     abortDueToFailedRequest(DOMError::create(IDBDatabaseException::getErrorName(resultData.error().code())));
503 }
504
505 Ref<IDBRequest> IDBTransaction::requestOpenCursor(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBCursorInfo& info)
506 {
507     LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
508
509     return doRequestOpenCursor(context, IDBCursorWithValue::create(*this, objectStore, info));
510 }
511
512 Ref<IDBRequest> IDBTransaction::requestOpenCursor(ScriptExecutionContext& context, IDBIndex& index, const IDBCursorInfo& info)
513 {
514     LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
515
516     if (info.cursorType() == IndexedDB::CursorType::KeyOnly)
517         return doRequestOpenCursor(context, IDBCursor::create(*this, index, info));
518
519     return doRequestOpenCursor(context, IDBCursorWithValue::create(*this, index, info));
520 }
521
522 Ref<IDBRequest> IDBTransaction::doRequestOpenCursor(ScriptExecutionContext& context, Ref<IDBCursor>&& cursor)
523 {
524     ASSERT(isActive());
525
526     Ref<IDBRequest> request = IDBRequest::create(context, cursor.get(), *this);
527     addRequest(request.get());
528
529     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didOpenCursorOnServer, &IDBTransaction::openCursorOnServer, cursor->info());
530     scheduleOperation(WTFMove(operation));
531
532     return request;
533 }
534
535 void IDBTransaction::openCursorOnServer(TransactionOperation& operation, const IDBCursorInfo& info)
536 {
537     LOG(IndexedDB, "IDBTransaction::openCursorOnServer");
538
539     m_database->serverConnection().openCursor(operation, info);
540 }
541
542 void IDBTransaction::didOpenCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
543 {
544     LOG(IndexedDB, "IDBTransaction::didOpenCursorOnServer");
545
546     request.didOpenOrIterateCursor(resultData);
547 }
548
549 void IDBTransaction::iterateCursor(IDBCursor& cursor, const IDBKeyData& key, unsigned long count)
550 {
551     LOG(IndexedDB, "IDBTransaction::iterateCursor");
552     ASSERT(isActive());
553     ASSERT(cursor.request());
554
555     addRequest(*cursor.request());
556
557     auto operation = createTransactionOperation(*this, *cursor.request(), &IDBTransaction::didIterateCursorOnServer, &IDBTransaction::iterateCursorOnServer, key, count);
558     scheduleOperation(WTFMove(operation));
559 }
560
561 void IDBTransaction::iterateCursorOnServer(TransactionOperation& operation, const IDBKeyData& key, const unsigned long& count)
562 {
563     LOG(IndexedDB, "IDBTransaction::iterateCursorOnServer");
564
565     serverConnection().iterateCursor(operation, key, count);
566 }
567
568 void IDBTransaction::didIterateCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
569 {
570     LOG(IndexedDB, "IDBTransaction::didIterateCursorOnServer");
571
572     request.didOpenOrIterateCursor(resultData);
573 }
574
575 Ref<IDBRequest> IDBTransaction::requestGetRecord(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& keyRangeData)
576 {
577     LOG(IndexedDB, "IDBTransaction::requestGetRecord");
578     ASSERT(isActive());
579     ASSERT(!keyRangeData.isNull);
580
581     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
582     addRequest(request.get());
583
584     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, keyRangeData);
585     scheduleOperation(WTFMove(operation));
586
587     return request;
588 }
589
590 Ref<IDBRequest> IDBTransaction::requestGetValue(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
591 {
592     LOG(IndexedDB, "IDBTransaction::requestGetValue");
593     return requestIndexRecord(context, index, IndexedDB::IndexRecordType::Value, range);
594 }
595
596 Ref<IDBRequest> IDBTransaction::requestGetKey(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
597 {
598     LOG(IndexedDB, "IDBTransaction::requestGetValue");
599     return requestIndexRecord(context, index, IndexedDB::IndexRecordType::Key, range);
600 }
601
602 Ref<IDBRequest> IDBTransaction::requestIndexRecord(ScriptExecutionContext& context, IDBIndex& index, IndexedDB::IndexRecordType type, const IDBKeyRangeData&range)
603 {
604     LOG(IndexedDB, "IDBTransaction::requestGetValue");
605     ASSERT(isActive());
606     ASSERT(!range.isNull);
607
608     Ref<IDBRequest> request = IDBRequest::createGet(context, index, type, *this);
609     addRequest(request.get());
610
611     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, range);
612     scheduleOperation(WTFMove(operation));
613
614     return request;
615 }
616
617 void IDBTransaction::getRecordOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
618 {
619     LOG(IndexedDB, "IDBTransaction::getRecordOnServer");
620
621     serverConnection().getRecord(operation, keyRange);
622 }
623
624 void IDBTransaction::didGetRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
625 {
626     LOG(IndexedDB, "IDBTransaction::didGetRecordOnServer");
627
628     if (resultData.type() == IDBResultType::Error) {
629         request.requestCompleted(resultData);
630         return;
631     }
632
633     ASSERT(resultData.type() == IDBResultType::GetRecordSuccess);
634
635     const IDBGetResult& result = resultData.getResult();
636
637     if (request.sourceIndexIdentifier() && request.requestedIndexRecordType() == IndexedDB::IndexRecordType::Key) {
638         if (!result.keyData().isNull())
639             request.setResult(&result.keyData());
640         else
641             request.setResultToUndefined();
642     } else {
643         if (resultData.getResult().valueBuffer().data())
644             request.setResultToStructuredClone(resultData.getResult().valueBuffer());
645         else
646             request.setResultToUndefined();
647     }
648
649     request.requestCompleted(resultData);
650 }
651
652 Ref<IDBRequest> IDBTransaction::requestCount(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& range)
653 {
654     LOG(IndexedDB, "IDBTransaction::requestCount (IDBObjectStore)");
655     ASSERT(isActive());
656     ASSERT(!range.isNull);
657
658     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
659     addRequest(request.get());
660
661     scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didGetCountOnServer, &IDBTransaction::getCountOnServer, range));
662
663     return request;
664 }
665
666 Ref<IDBRequest> IDBTransaction::requestCount(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
667 {
668     LOG(IndexedDB, "IDBTransaction::requestCount (IDBIndex)");
669     ASSERT(isActive());
670     ASSERT(!range.isNull);
671
672     Ref<IDBRequest> request = IDBRequest::createCount(context, index, *this);
673     addRequest(request.get());
674
675     scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didGetCountOnServer, &IDBTransaction::getCountOnServer, range));
676
677     return request;
678 }
679
680 void IDBTransaction::getCountOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
681 {
682     LOG(IndexedDB, "IDBTransaction::getCountOnServer");
683
684     serverConnection().getCount(operation, keyRange);
685 }
686
687 void IDBTransaction::didGetCountOnServer(IDBRequest& request, const IDBResultData& resultData)
688 {
689     LOG(IndexedDB, "IDBTransaction::didGetCountOnServer");
690
691     request.setResult(resultData.resultInteger());
692     request.requestCompleted(resultData);
693 }
694
695 Ref<IDBRequest> IDBTransaction::requestDeleteRecord(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& range)
696 {
697     LOG(IndexedDB, "IDBTransaction::requestDeleteRecord");
698     ASSERT(isActive());
699     ASSERT(!range.isNull);
700
701     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
702     addRequest(request.get());
703
704     scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didDeleteRecordOnServer, &IDBTransaction::deleteRecordOnServer, range));
705     return request;
706 }
707
708 void IDBTransaction::deleteRecordOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
709 {
710     LOG(IndexedDB, "IDBTransaction::deleteRecordOnServer");
711
712     serverConnection().deleteRecord(operation, keyRange);
713 }
714
715 void IDBTransaction::didDeleteRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
716 {
717     LOG(IndexedDB, "IDBTransaction::didDeleteRecordOnServer");
718
719     request.setResultToUndefined();
720     request.requestCompleted(resultData);
721 }
722
723 Ref<IDBRequest> IDBTransaction::requestClearObjectStore(ScriptExecutionContext& context, IDBObjectStore& objectStore)
724 {
725     LOG(IndexedDB, "IDBTransaction::requestClearObjectStore");
726     ASSERT(isActive());
727
728     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
729     addRequest(request.get());
730
731     uint64_t objectStoreIdentifier = objectStore.info().identifier();
732     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didClearObjectStoreOnServer, &IDBTransaction::clearObjectStoreOnServer, objectStoreIdentifier);
733     scheduleOperation(WTFMove(operation));
734
735     return request;
736 }
737
738 void IDBTransaction::clearObjectStoreOnServer(TransactionOperation& operation, const uint64_t& objectStoreIdentifier)
739 {
740     LOG(IndexedDB, "IDBTransaction::clearObjectStoreOnServer");
741
742     serverConnection().clearObjectStore(operation, objectStoreIdentifier);
743 }
744
745 void IDBTransaction::didClearObjectStoreOnServer(IDBRequest& request, const IDBResultData& resultData)
746 {
747     LOG(IndexedDB, "IDBTransaction::didClearObjectStoreOnServer");
748
749     request.setResultToUndefined();
750     request.requestCompleted(resultData);
751 }
752
753 Ref<IDBRequest> IDBTransaction::requestPutOrAdd(ScriptExecutionContext& context, IDBObjectStore& objectStore, IDBKey* key, SerializedScriptValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
754 {
755     LOG(IndexedDB, "IDBTransaction::requestPutOrAdd");
756     ASSERT(isActive());
757     ASSERT(!isReadOnly());
758     ASSERT(objectStore.info().autoIncrement() || key);
759
760     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
761     addRequest(request.get());
762
763     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didPutOrAddOnServer, &IDBTransaction::putOrAddOnServer, key, &value, overwriteMode);
764     scheduleOperation(WTFMove(operation));
765
766     return request;
767 }
768
769 void IDBTransaction::putOrAddOnServer(TransactionOperation& operation, RefPtr<IDBKey> key, RefPtr<SerializedScriptValue> value, const IndexedDB::ObjectStoreOverwriteMode& overwriteMode)
770 {
771     LOG(IndexedDB, "IDBTransaction::putOrAddOnServer");
772
773     ASSERT(!isReadOnly());
774
775     serverConnection().putOrAdd(operation, key, value, overwriteMode);
776 }
777
778 void IDBTransaction::didPutOrAddOnServer(IDBRequest& request, const IDBResultData& resultData)
779 {
780     LOG(IndexedDB, "IDBTransaction::didPutOrAddOnServer");
781
782     request.setResult(resultData.resultKey());
783     request.requestCompleted(resultData);
784 }
785
786 void IDBTransaction::deleteObjectStore(const String& objectStoreName)
787 {
788     LOG(IndexedDB, "IDBTransaction::deleteObjectStore");
789
790     ASSERT(isVersionChange());
791
792     if (auto objectStore = m_referencedObjectStores.take(objectStoreName))
793         objectStore->markAsDeleted();
794
795     auto operation = createTransactionOperation(*this, &IDBTransaction::didDeleteObjectStoreOnServer, &IDBTransaction::deleteObjectStoreOnServer, objectStoreName);
796     scheduleOperation(WTFMove(operation));
797 }
798
799 void IDBTransaction::deleteObjectStoreOnServer(TransactionOperation& operation, const String& objectStoreName)
800 {
801     LOG(IndexedDB, "IDBTransaction::deleteObjectStoreOnServer");
802     ASSERT(isVersionChange());
803
804     serverConnection().deleteObjectStore(operation, objectStoreName);
805 }
806
807 void IDBTransaction::didDeleteObjectStoreOnServer(const IDBResultData& resultData)
808 {
809     LOG(IndexedDB, "IDBTransaction::didDeleteObjectStoreOnServer");
810     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteObjectStoreSuccess || resultData.type() == IDBResultType::Error);
811 }
812
813 void IDBTransaction::deleteIndex(uint64_t objectStoreIdentifier, const String& indexName)
814 {
815     LOG(IndexedDB, "IDBTransaction::deleteIndex");
816
817     ASSERT(isVersionChange());
818
819     auto operation = createTransactionOperation(*this, &IDBTransaction::didDeleteIndexOnServer, &IDBTransaction::deleteIndexOnServer, objectStoreIdentifier, indexName);
820     scheduleOperation(WTFMove(operation));
821 }
822
823 void IDBTransaction::deleteIndexOnServer(TransactionOperation& operation, const uint64_t& objectStoreIdentifier, const String& indexName)
824 {
825     LOG(IndexedDB, "IDBTransaction::deleteIndexOnServer");
826     ASSERT(isVersionChange());
827
828     serverConnection().deleteIndex(operation, objectStoreIdentifier, indexName);
829 }
830
831 void IDBTransaction::didDeleteIndexOnServer(const IDBResultData& resultData)
832 {
833     LOG(IndexedDB, "IDBTransaction::didDeleteIndexOnServer");
834     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteIndexSuccess || resultData.type() == IDBResultType::Error);
835 }
836
837 void IDBTransaction::operationDidComplete(TransactionOperation& operation)
838 {
839     ASSERT(m_transactionOperationMap.get(operation.identifier()) == &operation);
840     m_transactionOperationMap.remove(operation.identifier());
841
842     scheduleOperationTimer();
843 }
844
845 void IDBTransaction::establishOnServer()
846 {
847     LOG(IndexedDB, "IDBTransaction::establishOnServer");
848
849     serverConnection().establishTransaction(*this);
850 }
851
852 void IDBTransaction::activate()
853 {
854     if (isFinishedOrFinishing())
855         return;
856
857     m_state = IndexedDB::TransactionState::Active;
858 }
859
860 void IDBTransaction::deactivate()
861 {
862     if (m_state == IndexedDB::TransactionState::Active)
863         m_state = IndexedDB::TransactionState::Inactive;
864
865     scheduleOperationTimer();
866 }
867
868 } // namespace IDBClient
869 } // namespace WebCore
870
871 #endif // ENABLE(INDEXED_DATABASE)