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