/* -*- 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 "mozStorageBindingParamsArray.h" #include "mozStorageConnection.h" #include "StorageBaseStatementInternal.h" #include "mozStoragePrivateHelpers.h" struct sqlite3_stmt; namespace mozilla::storage { class StatementData { public: StatementData(sqlite3_stmt* aStatement, already_AddRefed 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) {} /** * 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; /** * It's safe to release this on any thread, as it holds `BindingParams` that * can only contain thread-safe derivates of `Variant_base`. */ RefPtr mParamsArray; bool mQueryStatusRecorded; /** * We hold onto a reference of the statement's owner so it doesn't get * destroyed out from under us. */ nsCOMPtr mStatementOwner; }; } // namespace mozilla::storage #endif // mozStorageStatementData_h