/* -*- 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 "nsAutoPtr.h" #include "nsTArray.h" #include "nsIEventTarget.h" #include "MainThreadUtils.h" #include "mozStorageBindingParamsArray.h" #include "mozIStorageBaseStatement.h" #include "mozStorageConnection.h" #include "StorageBaseStatementInternal.h" struct sqlite3_stmt; namespace mozilla { namespace storage { class StatementData { public: StatementData(sqlite3_stmt *aStatement, already_AddRefed aParamsArray, StorageBaseStatementInternal *aStatementOwner) : mStatement(aStatement) , mParamsArray(aParamsArray) , mStatementOwner(aStatementOwner) { NS_PRECONDITION(mStatementOwner, "Must have a statement owner!"); } StatementData(const StatementData &aSource) : mStatement(aSource.mStatement) , mParamsArray(aSource.mParamsArray) , mStatementOwner(aSource.mStatementOwner) { NS_PRECONDITION(mStatementOwner, "Must have a statement owner!"); } StatementData() : mStatement(nullptr) { } ~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(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); 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() { NS_PRECONDITION(mStatementOwner, "Must have a statement owner!"); #ifdef DEBUG { nsCOMPtr asyncThread = mStatementOwner->getOwner()->getAsyncExecutionTarget(); // It's possible that we are shutting down the async thread, and this // method would return nullptr as a result. if (asyncThread) { bool onAsyncThread; NS_ASSERTION(NS_SUCCEEDED(asyncThread->IsOnCurrentThread(&onAsyncThread)) && onAsyncThread, "This should only be running on the async thread!"); } } #endif // 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; } } /** * 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; } private: sqlite3_stmt *mStatement; RefPtr mParamsArray; /** * We hold onto a reference of the statement's owner so it doesn't get * destroyed out from under us. */ nsCOMPtr mStatementOwner; }; } // namespace storage } // namespace mozilla #endif // mozStorageStatementData_h