michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozStorageAsyncStatementExecution_h michael@0: #define mozStorageAsyncStatementExecution_h michael@0: michael@0: #include "nscore.h" michael@0: #include "nsTArray.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "mozilla/Mutex.h" michael@0: #include "mozilla/TimeStamp.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsIRunnable.h" michael@0: michael@0: #include "SQLiteMutex.h" michael@0: #include "mozIStoragePendingStatement.h" michael@0: #include "mozIStorageStatementCallback.h" michael@0: #include "mozStorageHelper.h" michael@0: michael@0: struct sqlite3_stmt; michael@0: michael@0: namespace mozilla { michael@0: namespace storage { michael@0: michael@0: class Connection; michael@0: class ResultSet; michael@0: class StatementData; michael@0: michael@0: class AsyncExecuteStatements MOZ_FINAL : public nsIRunnable michael@0: , public mozIStoragePendingStatement michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIRUNNABLE michael@0: NS_DECL_MOZISTORAGEPENDINGSTATEMENT michael@0: michael@0: /** michael@0: * Describes the state of execution. michael@0: */ michael@0: enum ExecutionState { michael@0: PENDING = -1, michael@0: COMPLETED = mozIStorageStatementCallback::REASON_FINISHED, michael@0: CANCELED = mozIStorageStatementCallback::REASON_CANCELED, michael@0: ERROR = mozIStorageStatementCallback::REASON_ERROR michael@0: }; michael@0: michael@0: typedef nsTArray StatementDataArray; michael@0: michael@0: /** michael@0: * Executes a statement in the background, and passes results back to the michael@0: * caller. michael@0: * michael@0: * @param aStatements michael@0: * The statements to execute and possibly bind in the background. michael@0: * Ownership is transfered from the caller. michael@0: * @param aConnection michael@0: * The connection that created the statements to execute. michael@0: * @param aNativeConnection michael@0: * The native Sqlite connection that created the statements to execute. michael@0: * @param aCallback michael@0: * The callback that is notified of results, completion, and errors. michael@0: * @param _stmt michael@0: * The handle to control the execution of the statements. michael@0: */ michael@0: static nsresult execute(StatementDataArray &aStatements, michael@0: Connection *aConnection, michael@0: sqlite3 *aNativeConnection, michael@0: mozIStorageStatementCallback *aCallback, michael@0: mozIStoragePendingStatement **_stmt); michael@0: michael@0: /** michael@0: * Indicates when events on the calling thread should run or not. Certain michael@0: * events posted back to the calling thread should call this see if they michael@0: * should run or not. michael@0: * michael@0: * @pre mMutex is not held michael@0: * michael@0: * @returns true if the event should notify still, false otherwise. michael@0: */ michael@0: bool shouldNotify(); michael@0: michael@0: private: michael@0: AsyncExecuteStatements(StatementDataArray &aStatements, michael@0: Connection *aConnection, michael@0: sqlite3 *aNativeConnection, michael@0: mozIStorageStatementCallback *aCallback); michael@0: ~AsyncExecuteStatements(); michael@0: michael@0: /** michael@0: * Binds and then executes a given statement until completion, an error michael@0: * occurs, or we are canceled. If aLastStatement is true, we should set michael@0: * mState accordingly. michael@0: * michael@0: * @pre mMutex is not held michael@0: * michael@0: * @param aData michael@0: * The StatementData to bind, execute, and then process. michael@0: * @param aLastStatement michael@0: * Indicates if this is the last statement or not. If it is, we have michael@0: * to set the proper state. michael@0: * @returns true if we should continue to process statements, false otherwise. michael@0: */ michael@0: bool bindExecuteAndProcessStatement(StatementData &aData, michael@0: bool aLastStatement); michael@0: michael@0: /** michael@0: * Executes a given statement until completion, an error occurs, or we are michael@0: * canceled. If aLastStatement is true, we should set mState accordingly. michael@0: * michael@0: * @pre mMutex is not held michael@0: * michael@0: * @param aStatement michael@0: * The statement to execute and then process. michael@0: * @param aLastStatement michael@0: * Indicates if this is the last statement or not. If it is, we have michael@0: * to set the proper state. michael@0: * @returns true if we should continue to process statements, false otherwise. michael@0: */ michael@0: bool executeAndProcessStatement(sqlite3_stmt *aStatement, michael@0: bool aLastStatement); michael@0: michael@0: /** michael@0: * Executes a statement to completion, properly handling any error conditions. michael@0: * michael@0: * @pre mMutex is not held michael@0: * michael@0: * @param aStatement michael@0: * The statement to execute to completion. michael@0: * @returns true if results were obtained, false otherwise. michael@0: */ michael@0: bool executeStatement(sqlite3_stmt *aStatement); michael@0: michael@0: /** michael@0: * Builds a result set up with a row from a given statement. If we meet the michael@0: * right criteria, go ahead and notify about this results too. michael@0: * michael@0: * @pre mMutex is not held michael@0: * michael@0: * @param aStatement michael@0: * The statement to get the row data from. michael@0: */ michael@0: nsresult buildAndNotifyResults(sqlite3_stmt *aStatement); michael@0: michael@0: /** michael@0: * Notifies callback about completion, and does any necessary cleanup. michael@0: * michael@0: * @pre mMutex is not held michael@0: */ michael@0: nsresult notifyComplete(); michael@0: michael@0: /** michael@0: * Notifies callback about an error. michael@0: * michael@0: * @pre mMutex is not held michael@0: * @pre mDBMutex is not held michael@0: * michael@0: * @param aErrorCode michael@0: * The error code defined in mozIStorageError for the error. michael@0: * @param aMessage michael@0: * The error string, if any. michael@0: * @param aError michael@0: * The error object to notify the caller with. michael@0: */ michael@0: nsresult notifyError(int32_t aErrorCode, const char *aMessage); michael@0: nsresult notifyError(mozIStorageError *aError); michael@0: michael@0: /** michael@0: * Notifies the callback about a result set. michael@0: * michael@0: * @pre mMutex is not held michael@0: */ michael@0: nsresult notifyResults(); michael@0: michael@0: /** michael@0: * Tests whether the current statements should be wrapped in an explicit michael@0: * transaction. michael@0: * michael@0: * @return true if an explicit transaction is needed, false otherwise. michael@0: */ michael@0: bool statementsNeedTransaction(); michael@0: michael@0: StatementDataArray mStatements; michael@0: nsRefPtr mConnection; michael@0: sqlite3 *mNativeConnection; michael@0: bool mHasTransaction; michael@0: mozIStorageStatementCallback *mCallback; michael@0: nsCOMPtr mCallingThread; michael@0: nsRefPtr mResultSet; michael@0: michael@0: /** michael@0: * The maximum amount of time we want to wait between results. Defined by michael@0: * MAX_MILLISECONDS_BETWEEN_RESULTS and set at construction. michael@0: */ michael@0: const TimeDuration mMaxWait; michael@0: michael@0: /** michael@0: * The start time since our last set of results. michael@0: */ michael@0: TimeStamp mIntervalStart; michael@0: michael@0: /** michael@0: * Indicates our state of execution. michael@0: */ michael@0: ExecutionState mState; michael@0: michael@0: /** michael@0: * Indicates if we should try to cancel at a cancelation point. michael@0: */ michael@0: bool mCancelRequested; michael@0: michael@0: /** michael@0: * This is the mutex that protects our state from changing between threads. michael@0: * This includes the following variables: michael@0: * - mCancelRequested is only set on the calling thread while the lock is michael@0: * held. It is always read from within the lock on the background thread, michael@0: * but not on the calling thread (see shouldNotify for why). michael@0: */ michael@0: Mutex &mMutex; michael@0: michael@0: /** michael@0: * The wrapped SQLite recursive connection mutex. We use it whenever we call michael@0: * sqlite3_step and care about having reliable error messages. By taking it michael@0: * prior to the call and holding it until the point where we no longer care michael@0: * about the error message, the user gets reliable error messages. michael@0: */ michael@0: SQLiteMutex &mDBMutex; michael@0: michael@0: /** michael@0: * The instant at which the request was started. michael@0: * michael@0: * Used by telemetry. michael@0: */ michael@0: TimeStamp mRequestStartDate; michael@0: }; michael@0: michael@0: } // namespace storage michael@0: } // namespace mozilla michael@0: michael@0: #endif // mozStorageAsyncStatementExecution_h