Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / Modules / webdatabase / SQLTransaction.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2013 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  *
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  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "SQLTransaction.h"
31
32 #include "Database.h"
33 #include "DatabaseAuthorizer.h"
34 #include "DatabaseContext.h"
35 #include "ExceptionCode.h"
36 #include "Logging.h"
37 #include "SQLError.h"
38 #include "SQLStatement.h"
39 #include "SQLStatementCallback.h"
40 #include "SQLStatementErrorCallback.h"
41 #include "SQLTransactionBackend.h"
42 #include "SQLTransactionCallback.h"
43 #include "SQLTransactionClient.h" // FIXME: Should be used in the backend only.
44 #include "SQLTransactionErrorCallback.h"
45 #include "VoidCallback.h"
46 #include <wtf/StdLibExtras.h>
47 #include <wtf/Vector.h>
48
49 namespace WebCore {
50
51 Ref<SQLTransaction> SQLTransaction::create(Ref<Database>&& database, RefPtr<SQLTransactionCallback>&& callback, RefPtr<VoidCallback>&& successCallback, RefPtr<SQLTransactionErrorCallback>&& errorCallback, bool readOnly)
52 {
53     return adoptRef(*new SQLTransaction(WTFMove(database), WTFMove(callback), WTFMove(successCallback), WTFMove(errorCallback), readOnly));
54 }
55
56 SQLTransaction::SQLTransaction(Ref<Database>&& database, RefPtr<SQLTransactionCallback>&& callback, RefPtr<VoidCallback>&& successCallback, RefPtr<SQLTransactionErrorCallback>&& errorCallback, bool readOnly)
57     : m_database(WTFMove(database))
58     , m_callbackWrapper(WTFMove(callback), m_database->scriptExecutionContext())
59     , m_successCallbackWrapper(WTFMove(successCallback), m_database->scriptExecutionContext())
60     , m_errorCallbackWrapper(WTFMove(errorCallback), m_database->scriptExecutionContext())
61     , m_executeSqlAllowed(false)
62     , m_readOnly(readOnly)
63 {
64 }
65
66 SQLTransaction::~SQLTransaction()
67 {
68 }
69
70 bool SQLTransaction::hasCallback() const
71 {
72     return m_callbackWrapper.hasCallback();
73 }
74
75 bool SQLTransaction::hasSuccessCallback() const
76 {
77     return m_successCallbackWrapper.hasCallback();
78 }
79
80 bool SQLTransaction::hasErrorCallback() const
81 {
82     return m_errorCallbackWrapper.hasCallback();
83 }
84
85 void SQLTransaction::setBackend(SQLTransactionBackend* backend)
86 {
87     ASSERT(!m_backend);
88     m_backend = backend;
89 }
90
91 SQLTransaction::StateFunction SQLTransaction::stateFunctionFor(SQLTransactionState state)
92 {
93     static const StateFunction stateFunctions[] = {
94         &SQLTransaction::unreachableState,                // 0. illegal
95         &SQLTransaction::unreachableState,                // 1. idle
96         &SQLTransaction::unreachableState,                // 2. acquireLock
97         &SQLTransaction::unreachableState,                // 3. openTransactionAndPreflight
98         &SQLTransaction::unreachableState,                // 4. runStatements
99         &SQLTransaction::unreachableState,                // 5. postflightAndCommit
100         &SQLTransaction::unreachableState,                // 6. cleanupAndTerminate
101         &SQLTransaction::unreachableState,                // 7. cleanupAfterTransactionErrorCallback
102         &SQLTransaction::deliverTransactionCallback,      // 8.
103         &SQLTransaction::deliverTransactionErrorCallback, // 9.
104         &SQLTransaction::deliverStatementCallback,        // 10.
105         &SQLTransaction::deliverQuotaIncreaseCallback,    // 11.
106         &SQLTransaction::deliverSuccessCallback           // 12.
107     };
108
109     ASSERT(WTF_ARRAY_LENGTH(stateFunctions) == static_cast<int>(SQLTransactionState::NumberOfStates));
110     ASSERT(state < SQLTransactionState::NumberOfStates);
111
112     return stateFunctions[static_cast<int>(state)];
113 }
114
115 // requestTransitToState() can be called from the backend. Hence, it should
116 // NOT be modifying SQLTransactionBackend in general. The only safe field to
117 // modify is m_requestedState which is meant for this purpose.
118 void SQLTransaction::requestTransitToState(SQLTransactionState nextState)
119 {
120     LOG(StorageAPI, "Scheduling %s for transaction %p\n", nameForSQLTransactionState(nextState), this);
121     m_requestedState = nextState;
122     m_database->scheduleTransactionCallback(this);
123 }
124
125 void SQLTransaction::deliverTransactionCallback()
126 {
127     bool shouldDeliverErrorCallback = false;
128
129     // Spec 4.3.2 4: Invoke the transaction callback with the new SQLTransaction object
130     RefPtr<SQLTransactionCallback> callback = m_callbackWrapper.unwrap();
131     if (callback) {
132         m_executeSqlAllowed = true;
133         shouldDeliverErrorCallback = !callback->handleEvent(this);
134         m_executeSqlAllowed = false;
135     }
136
137     // Spec 4.3.2 5: If the transaction callback was null or raised an exception, jump to the error callback
138     if (shouldDeliverErrorCallback) {
139         m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the SQLTransactionCallback was null or threw an exception");
140         return deliverTransactionErrorCallback();
141     }
142
143     m_backend->requestTransitToState(SQLTransactionState::RunStatements);
144 }
145
146 void SQLTransaction::deliverTransactionErrorCallback()
147 {
148     // Spec 4.3.2.10: If exists, invoke error callback with the last
149     // error to have occurred in this transaction.
150     RefPtr<SQLTransactionErrorCallback> errorCallback = m_errorCallbackWrapper.unwrap();
151     if (errorCallback) {
152         // If we get here with an empty m_transactionError, then the backend
153         // must be waiting in the idle state waiting for this state to finish.
154         // Hence, it's thread safe to fetch the backend transactionError without
155         // a lock.
156         if (!m_transactionError)
157             m_transactionError = m_backend->transactionError();
158
159         ASSERT(m_transactionError);
160         errorCallback->handleEvent(m_transactionError.get());
161
162         m_transactionError = nullptr;
163     }
164
165     clearCallbackWrappers();
166
167     // Spec 4.3.2.10: Rollback the transaction.
168     m_backend->requestTransitToState(SQLTransactionState::CleanupAfterTransactionErrorCallback);
169 }
170
171 void SQLTransaction::deliverStatementCallback()
172 {
173     // Spec 4.3.2.6.6 and 4.3.2.6.3: If the statement callback went wrong, jump to the transaction error callback
174     // Otherwise, continue to loop through the statement queue
175     m_executeSqlAllowed = true;
176
177     SQLStatement* currentStatement = m_backend->currentStatement();
178     ASSERT(currentStatement);
179
180     bool result = currentStatement->performCallback(this);
181
182     m_executeSqlAllowed = false;
183
184     if (result) {
185         m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the statement callback raised an exception or statement error callback did not return false");
186
187         if (m_errorCallbackWrapper.hasCallback())
188             return deliverTransactionErrorCallback();
189
190         // No error callback, so fast-forward to:
191         // Transaction Step 11 - Rollback the transaction.
192         m_backend->requestTransitToState(SQLTransactionState::CleanupAfterTransactionErrorCallback);
193         return;
194     }
195
196     m_backend->requestTransitToState(SQLTransactionState::RunStatements);
197 }
198
199 void SQLTransaction::deliverQuotaIncreaseCallback()
200 {
201     ASSERT(m_backend->currentStatement());
202
203     bool shouldRetryCurrentStatement = m_database->transactionClient()->didExceedQuota(&database());
204     m_backend->setShouldRetryCurrentStatement(shouldRetryCurrentStatement);
205
206     m_backend->requestTransitToState(SQLTransactionState::RunStatements);
207 }
208
209 void SQLTransaction::deliverSuccessCallback()
210 {
211     // Spec 4.3.2.8: Deliver success callback.
212     RefPtr<VoidCallback> successCallback = m_successCallbackWrapper.unwrap();
213     if (successCallback)
214         successCallback->handleEvent();
215
216     clearCallbackWrappers();
217
218     // Schedule a "post-success callback" step to return control to the database thread in case there
219     // are further transactions queued up for this Database
220     m_backend->requestTransitToState(SQLTransactionState::CleanupAndTerminate);
221 }
222
223 // This state function is used as a stub function to plug unimplemented states
224 // in the state dispatch table. They are unimplemented because they should
225 // never be reached in the course of correct execution.
226 void SQLTransaction::unreachableState()
227 {
228     ASSERT_NOT_REACHED();
229 }
230
231 void SQLTransaction::performPendingCallback()
232 {
233     computeNextStateAndCleanupIfNeeded();
234     runStateMachine();
235 }
236
237 void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, RefPtr<SQLStatementCallback>&& callback, RefPtr<SQLStatementErrorCallback>&& callbackError, ExceptionCode& ec)
238 {
239     if (!m_executeSqlAllowed || !m_database->opened()) {
240         ec = INVALID_STATE_ERR;
241         return;
242     }
243
244     int permissions = DatabaseAuthorizer::ReadWriteMask;
245     if (!m_database->databaseContext()->allowDatabaseAccess())
246         permissions |= DatabaseAuthorizer::NoAccessMask;
247     else if (m_readOnly)
248         permissions |= DatabaseAuthorizer::ReadOnlyMask;
249
250     auto statement = std::make_unique<SQLStatement>(m_database, sqlStatement, arguments, WTFMove(callback), WTFMove(callbackError), permissions);
251     m_backend->executeSQL(WTFMove(statement));
252 }
253
254 void SQLTransaction::computeNextStateAndCleanupIfNeeded()
255 {
256     // Only honor the requested state transition if we're not supposed to be
257     // cleaning up and shutting down:
258     if (m_database->opened()) {
259         setStateToRequestedState();
260         ASSERT(m_nextState == SQLTransactionState::End
261             || m_nextState == SQLTransactionState::DeliverTransactionCallback
262             || m_nextState == SQLTransactionState::DeliverTransactionErrorCallback
263             || m_nextState == SQLTransactionState::DeliverStatementCallback
264             || m_nextState == SQLTransactionState::DeliverQuotaIncreaseCallback
265             || m_nextState == SQLTransactionState::DeliverSuccessCallback);
266
267         LOG(StorageAPI, "Callback %s\n", nameForSQLTransactionState(m_nextState));
268         return;
269     }
270
271     clearCallbackWrappers();
272     m_backend->requestTransitToState(SQLTransactionState::CleanupAndTerminate);
273 }
274
275 void SQLTransaction::clearCallbackWrappers()
276 {
277     // Release the unneeded callbacks, to break reference cycles.
278     m_callbackWrapper.clear();
279     m_successCallbackWrapper.clear();
280     m_errorCallbackWrapper.clear();
281 }
282
283 } // namespace WebCore