259319684c6c73ad95129b53aa68010645b260ec
[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 #if ENABLE(SQL_DATABASE)
33
34 #include "AbstractSQLTransactionBackend.h"
35 #include "Database.h"
36 #include "DatabaseAuthorizer.h"
37 #include "DatabaseContext.h"
38 #include "ExceptionCode.h"
39 #include "Logging.h"
40 #include "SQLError.h"
41 #include "SQLStatementCallback.h"
42 #include "SQLStatementErrorCallback.h"
43 #include "SQLTransactionCallback.h"
44 #include "SQLTransactionClient.h" // FIXME: Should be used in the backend only.
45 #include "SQLTransactionErrorCallback.h"
46 #include "VoidCallback.h"
47 #include <wtf/StdLibExtras.h>
48 #include <wtf/Vector.h>
49
50 namespace WebCore {
51
52 PassRefPtr<SQLTransaction> SQLTransaction::create(Database* db, PassRefPtr<SQLTransactionCallback> callback,
53     PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
54     bool readOnly)
55 {
56     return adoptRef(new SQLTransaction(db, callback, successCallback, errorCallback, readOnly));
57 }
58
59 SQLTransaction::SQLTransaction(Database* db, PassRefPtr<SQLTransactionCallback> callback,
60     PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
61     bool readOnly)
62     : m_database(db)
63     , m_callbackWrapper(callback, db->scriptExecutionContext())
64     , m_successCallbackWrapper(successCallback, db->scriptExecutionContext())
65     , m_errorCallbackWrapper(errorCallback, db->scriptExecutionContext())
66     , m_executeSqlAllowed(false)
67     , m_readOnly(readOnly)
68 {
69     ASSERT(m_database);
70 }
71
72 bool SQLTransaction::hasCallback() const
73 {
74     return m_callbackWrapper.hasCallback();
75 }
76
77 bool SQLTransaction::hasSuccessCallback() const
78 {
79     return m_successCallbackWrapper.hasCallback();
80 }
81
82 bool SQLTransaction::hasErrorCallback() const
83 {
84     return m_errorCallbackWrapper.hasCallback();
85 }
86
87 void SQLTransaction::setBackend(AbstractSQLTransactionBackend* backend)
88 {
89     ASSERT(!m_backend);
90     m_backend = backend;
91 }
92
93 SQLTransaction::StateFunction SQLTransaction::stateFunctionFor(SQLTransactionState state)
94 {
95     static const StateFunction stateFunctions[] = {
96         &SQLTransaction::unreachableState,                // 0. illegal
97         &SQLTransaction::unreachableState,                // 1. idle
98         &SQLTransaction::unreachableState,                // 2. acquireLock
99         &SQLTransaction::unreachableState,                // 3. openTransactionAndPreflight
100         &SQLTransaction::sendToBackendState,              // 4. runStatements
101         &SQLTransaction::unreachableState,                // 5. postflightAndCommit
102         &SQLTransaction::sendToBackendState,              // 6. cleanupAndTerminate
103         &SQLTransaction::sendToBackendState,              // 7. cleanupAfterTransactionErrorCallback
104         &SQLTransaction::deliverTransactionCallback,      // 8.
105         &SQLTransaction::deliverTransactionErrorCallback, // 9.
106         &SQLTransaction::deliverStatementCallback,        // 10.
107         &SQLTransaction::deliverQuotaIncreaseCallback,    // 11.
108         &SQLTransaction::deliverSuccessCallback           // 12.
109     };
110
111     ASSERT(WTF_ARRAY_LENGTH(stateFunctions) == static_cast<int>(SQLTransactionState::NumberOfStates));
112     ASSERT(state < SQLTransactionState::NumberOfStates);
113
114     return stateFunctions[static_cast<int>(state)];
115 }
116
117 // requestTransitToState() can be called from the backend. Hence, it should
118 // NOT be modifying SQLTransactionBackend in general. The only safe field to
119 // modify is m_requestedState which is meant for this purpose.
120 void SQLTransaction::requestTransitToState(SQLTransactionState nextState)
121 {
122     LOG(StorageAPI, "Scheduling %s for transaction %p\n", nameForSQLTransactionState(nextState), this);
123     m_requestedState = nextState;
124     m_database->scheduleTransactionCallback(this);
125 }
126
127 SQLTransactionState SQLTransaction::nextStateForTransactionError()
128 {
129     ASSERT(m_transactionError);
130     if (m_errorCallbackWrapper.hasCallback())
131         return SQLTransactionState::DeliverTransactionErrorCallback;
132
133     // No error callback, so fast-forward to:
134     // Transaction Step 11 - Rollback the transaction.
135     return SQLTransactionState::CleanupAfterTransactionErrorCallback;
136 }
137
138 SQLTransactionState SQLTransaction::deliverTransactionCallback()
139 {
140     bool shouldDeliverErrorCallback = false;
141
142     // Spec 4.3.2 4: Invoke the transaction callback with the new SQLTransaction object
143     RefPtr<SQLTransactionCallback> callback = m_callbackWrapper.unwrap();
144     if (callback) {
145         m_executeSqlAllowed = true;
146         shouldDeliverErrorCallback = !callback->handleEvent(this);
147         m_executeSqlAllowed = false;
148     }
149
150     // Spec 4.3.2 5: If the transaction callback was null or raised an exception, jump to the error callback
151     SQLTransactionState nextState = SQLTransactionState::RunStatements;
152     if (shouldDeliverErrorCallback) {
153         m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the SQLTransactionCallback was null or threw an exception");
154         nextState = SQLTransactionState::DeliverTransactionErrorCallback;
155     }
156     return nextState;
157 }
158
159 SQLTransactionState SQLTransaction::deliverTransactionErrorCallback()
160 {
161     // Spec 4.3.2.10: If exists, invoke error callback with the last
162     // error to have occurred in this transaction.
163     RefPtr<SQLTransactionErrorCallback> errorCallback = m_errorCallbackWrapper.unwrap();
164     if (errorCallback) {
165         // If we get here with an empty m_transactionError, then the backend
166         // must be waiting in the idle state waiting for this state to finish.
167         // Hence, it's thread safe to fetch the backend transactionError without
168         // a lock.
169         if (!m_transactionError)
170             m_transactionError = m_backend->transactionError();
171
172         ASSERT(m_transactionError);
173         errorCallback->handleEvent(m_transactionError.get());
174
175         m_transactionError = 0;
176     }
177
178     clearCallbackWrappers();
179
180     // Spec 4.3.2.10: Rollback the transaction.
181     return SQLTransactionState::CleanupAfterTransactionErrorCallback;
182 }
183
184 SQLTransactionState SQLTransaction::deliverStatementCallback()
185 {
186     // Spec 4.3.2.6.6 and 4.3.2.6.3: If the statement callback went wrong, jump to the transaction error callback
187     // Otherwise, continue to loop through the statement queue
188     m_executeSqlAllowed = true;
189
190     AbstractSQLStatement* currentAbstractStatement = m_backend->currentStatement();
191     SQLStatement* currentStatement = static_cast<SQLStatement*>(currentAbstractStatement);
192     ASSERT(currentStatement);
193
194     bool result = currentStatement->performCallback(this);
195
196     m_executeSqlAllowed = false;
197
198     if (result) {
199         m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the statement callback raised an exception or statement error callback did not return false");
200         return nextStateForTransactionError();
201     }
202     return SQLTransactionState::RunStatements;
203 }
204
205 SQLTransactionState SQLTransaction::deliverQuotaIncreaseCallback()
206 {
207     ASSERT(m_backend->currentStatement());
208
209     bool shouldRetryCurrentStatement = m_database->transactionClient()->didExceedQuota(database());
210     m_backend->setShouldRetryCurrentStatement(shouldRetryCurrentStatement);
211
212     return SQLTransactionState::RunStatements;
213 }
214
215 SQLTransactionState SQLTransaction::deliverSuccessCallback()
216 {
217     // Spec 4.3.2.8: Deliver success callback.
218     RefPtr<VoidCallback> successCallback = m_successCallbackWrapper.unwrap();
219     if (successCallback)
220         successCallback->handleEvent();
221
222     clearCallbackWrappers();
223
224     // Schedule a "post-success callback" step to return control to the database thread in case there
225     // are further transactions queued up for this Database
226     return SQLTransactionState::CleanupAndTerminate;
227 }
228
229 // This state function is used as a stub function to plug unimplemented states
230 // in the state dispatch table. They are unimplemented because they should
231 // never be reached in the course of correct execution.
232 SQLTransactionState SQLTransaction::unreachableState()
233 {
234     ASSERT_NOT_REACHED();
235     return SQLTransactionState::End;
236 }
237
238 SQLTransactionState SQLTransaction::sendToBackendState()
239 {
240     ASSERT(m_nextState != SQLTransactionState::Idle);
241     m_backend->requestTransitToState(m_nextState);
242     return SQLTransactionState::Idle;
243 }
244
245 void SQLTransaction::performPendingCallback()
246 {
247     computeNextStateAndCleanupIfNeeded();
248     runStateMachine();
249 }
250
251 void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> callbackError, ExceptionCode& e)
252 {
253     if (!m_executeSqlAllowed || !m_database->opened()) {
254         e = INVALID_STATE_ERR;
255         return;
256     }
257
258     int permissions = DatabaseAuthorizer::ReadWriteMask;
259     if (!m_database->databaseContext()->allowDatabaseAccess())
260         permissions |= DatabaseAuthorizer::NoAccessMask;
261     else if (m_readOnly)
262         permissions |= DatabaseAuthorizer::ReadOnlyMask;
263
264     auto statement = std::make_unique<SQLStatement>(m_database.get(), callback, callbackError);
265     m_backend->executeSQL(std::move(statement), sqlStatement, arguments, permissions);
266 }
267
268 bool SQLTransaction::computeNextStateAndCleanupIfNeeded()
269 {
270     // Only honor the requested state transition if we're not supposed to be
271     // cleaning up and shutting down:
272     if (m_database->opened() && !m_database->isInterrupted()) {
273         setStateToRequestedState();
274         ASSERT(m_nextState == SQLTransactionState::End
275             || m_nextState == SQLTransactionState::DeliverTransactionCallback
276             || m_nextState == SQLTransactionState::DeliverTransactionErrorCallback
277             || m_nextState == SQLTransactionState::DeliverStatementCallback
278             || m_nextState == SQLTransactionState::DeliverQuotaIncreaseCallback
279             || m_nextState == SQLTransactionState::DeliverSuccessCallback);
280
281         LOG(StorageAPI, "Callback %s\n", nameForSQLTransactionState(m_nextState));
282         return false;
283     }
284
285     clearCallbackWrappers();
286     m_nextState = SQLTransactionState::CleanupAndTerminate;
287
288     return true;
289 }
290
291 void SQLTransaction::clearCallbackWrappers()
292 {
293     // Release the unneeded callbacks, to break reference cycles.
294     m_callbackWrapper.clear();
295     m_successCallbackWrapper.clear();
296     m_errorCallbackWrapper.clear();
297 }
298
299 } // namespace WebCore
300
301 #endif // ENABLE(SQL_DATABASE)