📄 sqltransaction.cpp
字号:
/* * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "SQLTransaction.h"#include "ChromeClient.h"#include "Database.h"#include "DatabaseAuthorizer.h"#include "DatabaseDetails.h"#include "DatabaseTracker.h"#include "Document.h"#include "ExceptionCode.h"#include "Logging.h"#include "OriginQuotaManager.h"#include "Page.h"#include "PlatformString.h"#include "SecurityOrigin.h"#include "SQLError.h"#include "SQLiteTransaction.h"#include "SQLResultSet.h"#include "SQLStatement.h"#include "SQLStatementCallback.h"#include "SQLStatementErrorCallback.h"#include "SQLValue.h"// There's no way of knowing exactly how much more space will be required when a statement hits the quota limit. // For now, we'll arbitrarily choose currentQuota + 1mb.// In the future we decide to track if a size increase wasn't enough, and ask for larger-and-larger increases until its enough.static const int DefaultQuotaSizeIncrease = 1048576;namespace WebCore {PassRefPtr<SQLTransaction> SQLTransaction::create(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper> wrapper){ return adoptRef(new SQLTransaction(db, callback, errorCallback, successCallback, wrapper));}SQLTransaction::SQLTransaction(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper> wrapper) : m_nextStep(&SQLTransaction::openTransactionAndPreflight) , m_executeSqlAllowed(false) , m_database(db) , m_wrapper(wrapper) , m_callback(callback) , m_successCallback(successCallback) , m_errorCallback(errorCallback) , m_shouldRetryCurrentStatement(false) , m_shouldCommitAfterErrorCallback(true) , m_modifiedDatabase(false){ ASSERT(m_database);}SQLTransaction::~SQLTransaction(){}void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> callbackError, ExceptionCode& e){ if (!m_executeSqlAllowed || m_database->stopped()) { e = INVALID_STATE_ERR; return; } RefPtr<SQLStatement> statement = SQLStatement::create(sqlStatement.copy(), arguments, callback, callbackError); if (m_database->deleted()) statement->setDatabaseDeletedError(); if (!m_database->versionMatchesExpected()) statement->setVersionMismatchedError(); enqueueStatement(statement);}void SQLTransaction::enqueueStatement(PassRefPtr<SQLStatement> statement){ MutexLocker locker(m_statementMutex); m_statementQueue.append(statement);}#ifndef NDEBUGconst char* SQLTransaction::debugStepName(SQLTransaction::TransactionStepMethod step){ if (step == &SQLTransaction::openTransactionAndPreflight) return "openTransactionAndPreflight"; else if (step == &SQLTransaction::runStatements) return "runStatements"; else if (step == &SQLTransaction::postflightAndCommit) return "postflightAndCommit"; else if (step == &SQLTransaction::cleanupAfterTransactionErrorCallback) return "cleanupAfterTransactionErrorCallback"; else if (step == &SQLTransaction::deliverTransactionCallback) return "deliverTransactionCallback"; else if (step == &SQLTransaction::deliverTransactionErrorCallback) return "deliverTransactionErrorCallback"; else if (step == &SQLTransaction::deliverStatementCallback) return "deliverStatementCallback"; else if (step == &SQLTransaction::deliverQuotaIncreaseCallback) return "deliverQuotaIncreaseCallback"; else if (step == &SQLTransaction::deliverSuccessCallback) return "deliverSuccessCallback"; else if (step == &SQLTransaction::cleanupAfterSuccessCallback) return "cleanupAfterSuccessCallback"; else return "UNKNOWN";}#endifvoid SQLTransaction::checkAndHandleClosedDatabase(){ if (!m_database->stopped()) return; // If the database was stopped, don't do anything and cancel queued work LOG(StorageAPI, "Database was stopped - cancelling work for this transaction"); MutexLocker locker(m_statementMutex); m_statementQueue.clear(); m_nextStep = 0; // The current SQLite transaction should be stopped, as well if (m_sqliteTransaction) { m_sqliteTransaction->stop(); m_sqliteTransaction.clear(); }}bool SQLTransaction::performNextStep(){ LOG(StorageAPI, "Step %s\n", debugStepName(m_nextStep)); ASSERT(m_nextStep == &SQLTransaction::openTransactionAndPreflight || m_nextStep == &SQLTransaction::runStatements || m_nextStep == &SQLTransaction::postflightAndCommit || m_nextStep == &SQLTransaction::cleanupAfterSuccessCallback || m_nextStep == &SQLTransaction::cleanupAfterTransactionErrorCallback); checkAndHandleClosedDatabase(); if (m_nextStep) (this->*m_nextStep)(); // If there is no nextStep after performing the above step, the transaction is complete return !m_nextStep;}void SQLTransaction::performPendingCallback(){ LOG(StorageAPI, "Callback %s\n", debugStepName(m_nextStep)); ASSERT(m_nextStep == &SQLTransaction::deliverTransactionCallback || m_nextStep == &SQLTransaction::deliverTransactionErrorCallback || m_nextStep == &SQLTransaction::deliverStatementCallback || m_nextStep == &SQLTransaction::deliverQuotaIncreaseCallback || m_nextStep == &SQLTransaction::deliverSuccessCallback); checkAndHandleClosedDatabase(); if (m_nextStep) (this->*m_nextStep)();}void SQLTransaction::openTransactionAndPreflight(){ ASSERT(!m_database->m_sqliteDatabase.transactionInProgress()); LOG(StorageAPI, "Opening and preflighting transaction %p", this); // If the database was deleted, jump to the error callback if (m_database->deleted()) { m_transactionError = SQLError::create(0, "unable to open a transaction, because the user deleted the database"); handleTransactionError(false); return; } // Set the maximum usage for this transaction m_database->m_sqliteDatabase.setMaximumSize(m_database->maximumSize()); ASSERT(!m_sqliteTransaction); m_sqliteTransaction.set(new SQLiteTransaction(m_database->m_sqliteDatabase)); m_database->m_databaseAuthorizer->disable(); m_sqliteTransaction->begin(); m_database->m_databaseAuthorizer->enable(); // Transaction Steps 1+2 - Open a transaction to the database, jumping to the error callback if that fails if (!m_sqliteTransaction->inProgress()) { ASSERT(!m_database->m_sqliteDatabase.transactionInProgress()); m_sqliteTransaction.clear(); m_transactionError = SQLError::create(0, "unable to open a transaction to the database"); handleTransactionError(false); return; } // Transaction Steps 3 - Peform preflight steps, jumping to the error callback if they fail if (m_wrapper && !m_wrapper->performPreflight(this)) { ASSERT(!m_database->m_sqliteDatabase.transactionInProgress()); m_sqliteTransaction.clear(); m_transactionError = m_wrapper->sqlError(); if (!m_transactionError) m_transactionError = SQLError::create(0, "unknown error occured setting up transaction"); handleTransactionError(false); return; } // Transaction Step 4 - Invoke the transaction callback with the new SQLTransaction object m_nextStep = &SQLTransaction::deliverTransactionCallback; LOG(StorageAPI, "Scheduling deliverTransactionCallback for transaction %p\n", this); m_database->scheduleTransactionCallback(this);}void SQLTransaction::deliverTransactionCallback(){ bool shouldDeliverErrorCallback = false; if (m_callback) { m_executeSqlAllowed = true; m_callback->handleEvent(this, shouldDeliverErrorCallback); m_executeSqlAllowed = false; } else shouldDeliverErrorCallback = true; // Transaction Step 5 - If the transaction callback was null or raised an exception, jump to the error callback if (shouldDeliverErrorCallback) { m_transactionError = SQLError::create(0, "the SQLTransactionCallback was null or threw an exception"); deliverTransactionErrorCallback(); } else scheduleToRunStatements();}void SQLTransaction::scheduleToRunStatements(){ m_nextStep = &SQLTransaction::runStatements; LOG(StorageAPI, "Scheduling runStatements for transaction %p\n", this); m_database->scheduleTransactionStep(this);}void SQLTransaction::runStatements(){ // If there is a series of statements queued up that are all successful and have no associated // SQLStatementCallback objects, then we can burn through the queue do { if (m_shouldRetryCurrentStatement) { m_shouldRetryCurrentStatement = false; // FIXME - Another place that needs fixing up after <rdar://problem/5628468> is addressed. // See ::openTransactionAndPreflight() for discussion
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -