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 49namespace WebCore { 50 51PassRefPtr<SQLTransaction> SQLTransaction::create(Database* db, PassOwnPtr<SQLTransactionCallback> callback, 52 PassOwnPtr<VoidCallback> successCallback, PassOwnPtr<SQLTransactionErrorCallback> errorCallback, 53 bool readOnly) 54{ 55 return adoptRef(new SQLTransaction(db, callback, successCallback, errorCallback, readOnly)); 56} 57 58SQLTransaction::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 72bool SQLTransaction::hasCallback() const 73{ 74 return m_callbackWrapper.hasCallback(); 75} 76 77bool SQLTransaction::hasSuccessCallback() const 78{ 79 return m_successCallbackWrapper.hasCallback(); 80} 81 82bool SQLTransaction::hasErrorCallback() const 83{ 84 return m_errorCallbackWrapper.hasCallback(); 85} 86 87void SQLTransaction::setBackend(AbstractSQLTransactionBackend* backend) 88{ 89 ASSERT(!m_backend); 90 m_backend = backend; 91} 92 93SQLTransaction::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. 120void SQLTransaction::requestTransitToState(SQLTransactionState nextState) 121{ 122 WTF_LOG(StorageAPI, "Scheduling %s for transaction %p\n", nameForSQLTransactionState(nextState), this); 123 m_requestedState = nextState; 124 m_database->scheduleTransactionCallback(this); 125} 126 127SQLTransactionState 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 138SQLTransactionState SQLTransaction::deliverTransactionCallback() 139{ 140 bool shouldDeliverErrorCallback = false; 141 142 // Spec 4.3.2 4: Invoke the transaction callback with the new SQLTransaction object 143 OwnPtr<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_database->reportStartTransactionResult(5, SQLError::UNKNOWN_ERR, 0); 154 m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the SQLTransactionCallback was null or threw an exception"); 155 nextState = SQLTransactionState::DeliverTransactionErrorCallback; 156 } 157 m_database->reportStartTransactionResult(0, -1, 0); // OK 158 return nextState; 159} 160 161SQLTransactionState SQLTransaction::deliverTransactionErrorCallback() 162{ 163 // Spec 4.3.2.10: If exists, invoke error callback with the last 164 // error to have occurred in this transaction. 165 OwnPtr<SQLTransactionErrorCallback> errorCallback = m_errorCallbackWrapper.unwrap(); 166 if (errorCallback) { 167 // If we get here with an empty m_transactionError, then the backend 168 // must be waiting in the idle state waiting for this state to finish. 169 // Hence, it's thread safe to fetch the backend transactionError without 170 // a lock. 171 if (!m_transactionError) 172 m_transactionError = m_backend->transactionError(); 173 174 ASSERT(m_transactionError); 175 errorCallback->handleEvent(m_transactionError.get()); 176 177 m_transactionError = 0; 178 } 179 180 clearCallbackWrappers(); 181 182 // Spec 4.3.2.10: Rollback the transaction. 183 return SQLTransactionState::CleanupAfterTransactionErrorCallback; 184} 185 186SQLTransactionState SQLTransaction::deliverStatementCallback() 187{ 188 // Spec 4.3.2.6.6 and 4.3.2.6.3: If the statement callback went wrong, jump to the transaction error callback 189 // Otherwise, continue to loop through the statement queue 190 m_executeSqlAllowed = true; 191 192 AbstractSQLStatement* currentAbstractStatement = m_backend->currentStatement(); 193 SQLStatement* currentStatement = static_cast<SQLStatement*>(currentAbstractStatement); 194 ASSERT(currentStatement); 195 196 bool result = currentStatement->performCallback(this); 197 198 m_executeSqlAllowed = false; 199 200 if (result) { 201 m_database->reportCommitTransactionResult(2, SQLError::UNKNOWN_ERR, 0); 202 m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the statement callback raised an exception or statement error callback did not return false"); 203 return nextStateForTransactionError(); 204 } 205 return SQLTransactionState::RunStatements; 206} 207 208SQLTransactionState SQLTransaction::deliverQuotaIncreaseCallback() 209{ 210 ASSERT(m_backend->currentStatement()); 211 212 bool shouldRetryCurrentStatement = m_database->transactionClient()->didExceedQuota(database()); 213 m_backend->setShouldRetryCurrentStatement(shouldRetryCurrentStatement); 214 215 return SQLTransactionState::RunStatements; 216} 217 218SQLTransactionState SQLTransaction::deliverSuccessCallback() 219{ 220 // Spec 4.3.2.8: Deliver success callback. 221 OwnPtr<VoidCallback> successCallback = m_successCallbackWrapper.unwrap(); 222 if (successCallback) 223 successCallback->handleEvent(); 224 225 clearCallbackWrappers(); 226 227 // Schedule a "post-success callback" step to return control to the database thread in case there 228 // are further transactions queued up for this Database 229 return SQLTransactionState::CleanupAndTerminate; 230} 231 232// This state function is used as a stub function to plug unimplemented states 233// in the state dispatch table. They are unimplemented because they should 234// never be reached in the course of correct execution. 235SQLTransactionState SQLTransaction::unreachableState() 236{ 237 ASSERT_NOT_REACHED(); 238 return SQLTransactionState::End; 239} 240 241SQLTransactionState SQLTransaction::sendToBackendState() 242{ 243 ASSERT(m_nextState != SQLTransactionState::Idle); 244 m_backend->requestTransitToState(m_nextState); 245 return SQLTransactionState::Idle; 246} 247 248void SQLTransaction::performPendingCallback() 249{ 250 computeNextStateAndCleanupIfNeeded(); 251 runStateMachine(); 252} 253 254void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, PassOwnPtr<SQLStatementCallback> callback, PassOwnPtr<SQLStatementErrorCallback> callbackError, ExceptionState& exceptionState) 255{ 256 if (!m_executeSqlAllowed || !m_database->opened()) { 257 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError); 258 return; 259 } 260 261 int permissions = DatabaseAuthorizer::ReadWriteMask; 262 if (!m_database->databaseContext()->allowDatabaseAccess()) 263 permissions |= DatabaseAuthorizer::NoAccessMask; 264 else if (m_readOnly) 265 permissions |= DatabaseAuthorizer::ReadOnlyMask; 266 267 OwnPtr<SQLStatement> statement = SQLStatement::create(m_database.get(), callback, callbackError); 268 m_backend->executeSQL(statement.release(), sqlStatement, arguments, permissions); 269} 270 271bool SQLTransaction::computeNextStateAndCleanupIfNeeded() 272{ 273 // Only honor the requested state transition if we're not supposed to be 274 // cleaning up and shutting down: 275 if (m_database->opened() && !m_database->isInterrupted()) { 276 setStateToRequestedState(); 277 ASSERT(m_nextState == SQLTransactionState::End 278 || m_nextState == SQLTransactionState::DeliverTransactionCallback 279 || m_nextState == SQLTransactionState::DeliverTransactionErrorCallback 280 || m_nextState == SQLTransactionState::DeliverStatementCallback 281 || m_nextState == SQLTransactionState::DeliverQuotaIncreaseCallback 282 || m_nextState == SQLTransactionState::DeliverSuccessCallback); 283 284 WTF_LOG(StorageAPI, "Callback %s\n", nameForSQLTransactionState(m_nextState)); 285 return false; 286 } 287 288 clearCallbackWrappers(); 289 m_nextState = SQLTransactionState::CleanupAndTerminate; 290 291 return true; 292} 293 294void SQLTransaction::clearCallbackWrappers() 295{ 296 // Release the unneeded callbacks, to break reference cycles. 297 m_callbackWrapper.clear(); 298 m_successCallbackWrapper.clear(); 299 m_errorCallbackWrapper.clear(); 300} 301 302PassOwnPtr<SQLTransactionErrorCallback> SQLTransaction::releaseErrorCallback() 303{ 304 return m_errorCallbackWrapper.unwrap(); 305} 306 307} // namespace WebCore 308