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 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 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 71 SQLTransaction::~SQLTransaction() 72 { 73 } 74 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 84 bool SQLTransaction::hasCallback() const 85 { 86 return m_callback; 87 } 88 89 bool SQLTransaction::hasSuccessCallback() const 90 { 91 return m_successCallback; 92 } 93 94 bool SQLTransaction::hasErrorCallback() const 95 { 96 return m_errorCallback; 97 } 98 99 void SQLTransaction::setBackend(SQLTransactionBackend* backend) 100 { 101 ASSERT(!m_backend); 102 m_backend = backend; 103 } 104 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. 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 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 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 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 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 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 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. 245 SQLTransactionState SQLTransaction::unreachableState() 246 { 247 ASSERT_NOT_REACHED(); 248 return SQLTransactionState::End; 249 } 250 251 SQLTransactionState SQLTransaction::sendToBackendState() 252 { 253 ASSERT(m_nextState != SQLTransactionState::Idle); 254 m_backend->requestTransitToState(m_nextState); 255 return SQLTransactionState::Idle; 256 } 257 258 void SQLTransaction::performPendingCallback() 259 { 260 computeNextStateAndCleanupIfNeeded(); 261 runStateMachine(); 262 } 263 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 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 309 void SQLTransaction::clearCallbacks() 310 { 311 m_callback.clear(); 312 m_successCallback.clear(); 313 m_errorCallback.clear(); 314 } 315 316 SQLTransactionErrorCallback* SQLTransaction::releaseErrorCallback() 317 { 318 return m_errorCallback.release(); 319 } 320 321 } // namespace blink 322