diff options
Diffstat (limited to 'storage/mozStorageStatementData.h')
-rw-r--r-- | storage/mozStorageStatementData.h | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/storage/mozStorageStatementData.h b/storage/mozStorageStatementData.h new file mode 100644 index 0000000000..1008496671 --- /dev/null +++ b/storage/mozStorageStatementData.h @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 sts=2 et + * 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 mozStorageStatementData_h +#define mozStorageStatementData_h + +#include "sqlite3.h" + +#include "nsTArray.h" +#include "MainThreadUtils.h" + +#include "mozStorageBindingParamsArray.h" +#include "mozStorageConnection.h" +#include "StorageBaseStatementInternal.h" +#include "mozStoragePrivateHelpers.h" + +struct sqlite3_stmt; + +namespace mozilla { +namespace storage { + +class StatementData { + public: + StatementData(sqlite3_stmt* aStatement, + already_AddRefed<BindingParamsArray> aParamsArray, + StorageBaseStatementInternal* aStatementOwner) + : mStatement(aStatement), + mParamsArray(aParamsArray), + mQueryStatusRecorded(false), + mStatementOwner(aStatementOwner) { + MOZ_ASSERT(mStatementOwner, "Must have a statement owner!"); + } + StatementData(const StatementData& aSource) + : mStatement(aSource.mStatement), + mParamsArray(aSource.mParamsArray), + mQueryStatusRecorded(false), + mStatementOwner(aSource.mStatementOwner) { + MOZ_ASSERT(mStatementOwner, "Must have a statement owner!"); + } + StatementData() : mStatement(nullptr), mQueryStatusRecorded(false) {} + ~StatementData() { + // We need to ensure that mParamsArray is released on the main thread, + // as the binding arguments may be XPConnect values, which are safe + // to release only on the main thread. + NS_ReleaseOnMainThread("StatementData::mParamsArray", + mParamsArray.forget()); + } + + /** + * Return the sqlite statement, fetching it from the storage statement. In + * the case of AsyncStatements this may actually create the statement + */ + inline int getSqliteStatement(sqlite3_stmt** _stmt) { + if (!mStatement) { + int rc = mStatementOwner->getAsyncStatement(&mStatement); + MaybeRecordQueryStatus(rc); + NS_ENSURE_TRUE(rc == SQLITE_OK, rc); + } + *_stmt = mStatement; + return SQLITE_OK; + } + + operator BindingParamsArray*() const { return mParamsArray; } + + /** + * NULLs out our sqlite3_stmt (it is held by the owner) after reseting it and + * clear all bindings to it. This is expected to occur on the async thread. + */ + inline void reset() { + MOZ_ASSERT(mStatementOwner, "Must have a statement owner!"); + // In the AsyncStatement case we may never have populated mStatement if the + // AsyncExecuteStatements got canceled or a failure occurred in constructing + // the statement. + if (mStatement) { + (void)::sqlite3_reset(mStatement); + (void)::sqlite3_clear_bindings(mStatement); + mStatement = nullptr; + + if (!mQueryStatusRecorded) { + mStatementOwner->getOwner()->RecordQueryStatus(SQLITE_OK); + } + } + } + + /** + * Indicates if this statement has parameters to be bound before it is + * executed. + * + * @return true if the statement has parameters to bind against, false + * otherwise. + */ + inline bool hasParametersToBeBound() const { return !!mParamsArray; } + /** + * Indicates the number of implicit statements generated by this statement + * requiring a transaction for execution. For example a single statement + * with N BindingParams will execute N implicit staments. + * + * @return number of statements requiring a transaction for execution. + * + * @note In the case of AsyncStatements this may actually create the + * statement. + */ + inline uint32_t needsTransaction() { + MOZ_ASSERT(!NS_IsMainThread()); + // Be sure to use the getSqliteStatement helper, since sqlite3_stmt_readonly + // can only analyze prepared statements and AsyncStatements are prepared + // lazily. + sqlite3_stmt* stmt; + int rc = getSqliteStatement(&stmt); + if (SQLITE_OK != rc || ::sqlite3_stmt_readonly(stmt)) { + return 0; + } + return mParamsArray ? mParamsArray->length() : 1; + } + + void MaybeRecordQueryStatus(int srv) { + if (mQueryStatusRecorded || !isErrorCode(srv)) { + return; + } + + mStatementOwner->getOwner()->RecordQueryStatus(srv); + mQueryStatusRecorded = true; + } + + private: + sqlite3_stmt* mStatement; + RefPtr<BindingParamsArray> mParamsArray; + bool mQueryStatusRecorded; + + /** + * We hold onto a reference of the statement's owner so it doesn't get + * destroyed out from under us. + */ + nsCOMPtr<StorageBaseStatementInternal> mStatementOwner; +}; + +} // namespace storage +} // namespace mozilla + +#endif // mozStorageStatementData_h |