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