Blame storage/StatementCache.h

Packit f0b94e
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
Packit f0b94e
 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
Packit f0b94e
 * This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
#ifndef mozilla_storage_StatementCache_h
Packit f0b94e
#define mozilla_storage_StatementCache_h
Packit f0b94e
Packit f0b94e
#include "mozIStorageConnection.h"
Packit f0b94e
#include "mozIStorageStatement.h"
Packit f0b94e
#include "mozIStorageAsyncStatement.h"
Packit f0b94e
Packit f0b94e
#include "nsAutoPtr.h"
Packit f0b94e
#include "nsHashKeys.h"
Packit f0b94e
#include "nsInterfaceHashtable.h"
Packit f0b94e
Packit f0b94e
namespace mozilla {
Packit f0b94e
namespace storage {
Packit f0b94e
Packit f0b94e
/**
Packit f0b94e
 * Class used to cache statements (mozIStorageStatement or
Packit f0b94e
 * mozIStorageAsyncStatement).
Packit f0b94e
 */
Packit f0b94e
template <typename StatementType>
Packit f0b94e
class StatementCache {
Packit f0b94e
 public:
Packit f0b94e
  /**
Packit f0b94e
   * Constructor for the cache.
Packit f0b94e
   *
Packit f0b94e
   * @note a connection can have more than one cache.
Packit f0b94e
   *
Packit f0b94e
   * @param aConnection
Packit f0b94e
   *        A reference to the nsCOMPtr for the connection this cache is to be
Packit f0b94e
   *        used for.  This nsCOMPtr must at least live as long as this class,
Packit f0b94e
   *        otherwise crashes will happen.
Packit f0b94e
   */
Packit f0b94e
  explicit StatementCache(nsCOMPtr<mozIStorageConnection>& aConnection)
Packit f0b94e
      : mConnection(aConnection) {}
Packit f0b94e
Packit f0b94e
  /**
Packit f0b94e
   * Obtains a cached statement.  If this statement is not yet created, it will
Packit f0b94e
   * be created and stored for later use.
Packit f0b94e
   *
Packit f0b94e
   * @param aQuery
Packit f0b94e
   *        The SQL string (either a const char [] or nsACString) to get a
Packit f0b94e
   *        cached query for.
Packit f0b94e
   * @return the cached statement, or null upon error.
Packit f0b94e
   */
Packit f0b94e
  inline already_AddRefed<StatementType> GetCachedStatement(
Packit f0b94e
      const nsACString& aQuery) {
Packit f0b94e
    nsCOMPtr<StatementType> stmt;
Packit f0b94e
    if (!mCachedStatements.Get(aQuery, getter_AddRefs(stmt))) {
Packit f0b94e
      stmt = CreateStatement(aQuery);
Packit f0b94e
      NS_ENSURE_TRUE(stmt, nullptr);
Packit f0b94e
Packit f0b94e
      mCachedStatements.Put(aQuery, stmt);
Packit f0b94e
    }
Packit f0b94e
    return stmt.forget();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  template <int N>
Packit f0b94e
  MOZ_ALWAYS_INLINE already_AddRefed<StatementType> GetCachedStatement(
Packit f0b94e
      const char (&aQuery)[N]) {
Packit f0b94e
    nsDependentCString query(aQuery, N - 1);
Packit f0b94e
    return GetCachedStatement(query);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  /**
Packit f0b94e
   * Finalizes all cached statements so the database can be safely closed.  The
Packit f0b94e
   * behavior of this cache is unspecified after this method is called.
Packit f0b94e
   */
Packit f0b94e
  inline void FinalizeStatements() {
Packit f0b94e
    for (auto iter = mCachedStatements.Iter(); !iter.Done(); iter.Next()) {
Packit f0b94e
      (void)iter.Data()->Finalize();
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    // Clear the cache at this time too!
Packit f0b94e
    (void)mCachedStatements.Clear();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
 private:
Packit f0b94e
  inline already_AddRefed<StatementType> CreateStatement(
Packit f0b94e
      const nsACString& aQuery);
Packit f0b94e
Packit f0b94e
  nsInterfaceHashtable<nsCStringHashKey, StatementType> mCachedStatements;
Packit f0b94e
  nsCOMPtr<mozIStorageConnection>& mConnection;
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
template <>
Packit f0b94e
inline already_AddRefed<mozIStorageStatement>
Packit f0b94e
StatementCache<mozIStorageStatement>::CreateStatement(
Packit f0b94e
    const nsACString& aQuery) {
Packit f0b94e
  NS_ENSURE_TRUE(mConnection, nullptr);
Packit f0b94e
Packit f0b94e
  nsCOMPtr<mozIStorageStatement> stmt;
Packit f0b94e
  nsresult rv = mConnection->CreateStatement(aQuery, getter_AddRefs(stmt));
Packit f0b94e
  if (NS_FAILED(rv)) {
Packit f0b94e
    nsCString error;
Packit f0b94e
    error.AppendLiteral("The statement '");
Packit f0b94e
    error.Append(aQuery);
Packit f0b94e
    error.AppendLiteral("' failed to compile with the error message '");
Packit f0b94e
    nsCString msg;
Packit f0b94e
    (void)mConnection->GetLastErrorString(msg);
Packit f0b94e
    error.Append(msg);
Packit f0b94e
    error.AppendLiteral("'.");
Packit f0b94e
    NS_ERROR(error.get());
Packit f0b94e
  }
Packit f0b94e
  NS_ENSURE_SUCCESS(rv, nullptr);
Packit f0b94e
Packit f0b94e
  return stmt.forget();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
template <>
Packit f0b94e
inline already_AddRefed<mozIStorageAsyncStatement>
Packit f0b94e
StatementCache<mozIStorageAsyncStatement>::CreateStatement(
Packit f0b94e
    const nsACString& aQuery) {
Packit f0b94e
  NS_ENSURE_TRUE(mConnection, nullptr);
Packit f0b94e
Packit f0b94e
  nsCOMPtr<mozIStorageAsyncStatement> stmt;
Packit f0b94e
  nsresult rv = mConnection->CreateAsyncStatement(aQuery, getter_AddRefs(stmt));
Packit f0b94e
  NS_ENSURE_SUCCESS(rv, nullptr);
Packit f0b94e
Packit f0b94e
  return stmt.forget();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
}  // namespace storage
Packit f0b94e
}  // namespace mozilla
Packit f0b94e
Packit f0b94e
#endif  // mozilla_storage_StatementCache_h