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 mozilla_storage_StatementCache_h michael@0: #define mozilla_storage_StatementCache_h michael@0: michael@0: #include "mozIStorageConnection.h" michael@0: #include "mozIStorageStatement.h" michael@0: #include "mozIStorageAsyncStatement.h" michael@0: michael@0: #include "nsAutoPtr.h" michael@0: #include "nsHashKeys.h" michael@0: #include "nsInterfaceHashtable.h" michael@0: michael@0: namespace mozilla { michael@0: namespace storage { michael@0: michael@0: /** michael@0: * Class used to cache statements (mozIStorageStatement or michael@0: * mozIStorageAsyncStatement). michael@0: */ michael@0: template michael@0: class StatementCache { michael@0: public: michael@0: /** michael@0: * Constructor for the cache. michael@0: * michael@0: * @note a connection can have more than one cache. michael@0: * michael@0: * @param aConnection michael@0: * A reference to the nsCOMPtr for the connection this cache is to be michael@0: * used for. This nsCOMPtr must at least live as long as this class, michael@0: * otherwise crashes will happen. michael@0: */ michael@0: StatementCache(nsCOMPtr& aConnection) michael@0: : mConnection(aConnection) michael@0: { michael@0: } michael@0: michael@0: /** michael@0: * Obtains a cached statement. If this statement is not yet created, it will michael@0: * be created and stored for later use. michael@0: * michael@0: * @param aQuery michael@0: * The SQL string (either a const char [] or nsACString) to get a michael@0: * cached query for. michael@0: * @return the cached statement, or null upon error. michael@0: */ michael@0: inline michael@0: already_AddRefed michael@0: GetCachedStatement(const nsACString& aQuery) michael@0: { michael@0: nsCOMPtr stmt; michael@0: if (!mCachedStatements.Get(aQuery, getter_AddRefs(stmt))) { michael@0: stmt = CreateStatement(aQuery); michael@0: NS_ENSURE_TRUE(stmt, nullptr); michael@0: michael@0: mCachedStatements.Put(aQuery, stmt); michael@0: } michael@0: return stmt.forget(); michael@0: } michael@0: michael@0: template michael@0: MOZ_ALWAYS_INLINE already_AddRefed michael@0: GetCachedStatement(const char (&aQuery)[N]) michael@0: { michael@0: nsDependentCString query(aQuery, N - 1); michael@0: return GetCachedStatement(query); michael@0: } michael@0: michael@0: /** michael@0: * Finalizes all cached statements so the database can be safely closed. The michael@0: * behavior of this cache is unspecified after this method is called. michael@0: */ michael@0: inline michael@0: void michael@0: FinalizeStatements() michael@0: { michael@0: (void)mCachedStatements.Enumerate(FinalizeCachedStatements, nullptr); michael@0: michael@0: // Clear the cache at this time too! michael@0: (void)mCachedStatements.Clear(); michael@0: } michael@0: michael@0: private: michael@0: inline michael@0: already_AddRefed michael@0: CreateStatement(const nsACString& aQuery); michael@0: static michael@0: PLDHashOperator michael@0: FinalizeCachedStatements(const nsACString& aKey, michael@0: nsCOMPtr& aStatement, michael@0: void*) michael@0: { michael@0: (void)aStatement->Finalize(); michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: nsInterfaceHashtable mCachedStatements; michael@0: nsCOMPtr& mConnection; michael@0: }; michael@0: michael@0: template< > michael@0: inline michael@0: already_AddRefed michael@0: StatementCache::CreateStatement(const nsACString& aQuery) michael@0: { michael@0: NS_ENSURE_TRUE(mConnection, nullptr); michael@0: michael@0: nsCOMPtr stmt; michael@0: nsresult rv = mConnection->CreateStatement(aQuery, getter_AddRefs(stmt)); michael@0: if (NS_FAILED(rv)) { michael@0: nsCString error; michael@0: error.AppendLiteral("The statement '"); michael@0: error.Append(aQuery); michael@0: error.AppendLiteral("' failed to compile with the error message '"); michael@0: nsCString msg; michael@0: (void)mConnection->GetLastErrorString(msg); michael@0: error.Append(msg); michael@0: error.AppendLiteral("'."); michael@0: NS_ERROR(error.get()); michael@0: } michael@0: NS_ENSURE_SUCCESS(rv, nullptr); michael@0: michael@0: return stmt.forget(); michael@0: } michael@0: michael@0: template< > michael@0: inline michael@0: already_AddRefed michael@0: StatementCache::CreateStatement(const nsACString& aQuery) michael@0: { michael@0: NS_ENSURE_TRUE(mConnection, nullptr); michael@0: michael@0: nsCOMPtr stmt; michael@0: nsresult rv = mConnection->CreateAsyncStatement(aQuery, getter_AddRefs(stmt)); michael@0: NS_ENSURE_SUCCESS(rv, nullptr); michael@0: michael@0: return stmt.forget(); michael@0: } michael@0: michael@0: } // namespace storage michael@0: } // namespace mozilla michael@0: michael@0: #endif // mozilla_storage_StatementCache_h