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