storage/StatementCache.h
author Samael Wang <freesamael@gmail.com>
Fri, 11 Aug 2017 14:49:09 +0800
changeset 413793 1f8a03070122f8c5fa92ebe76478dcd0b2b1a357
parent 305695 d5722e7de045a82cfbcb74b1c818e239ae63001a
child 450616 4bcb64fd8fa1aae1bdb7a2a019a283eacb7af4ca
permissions -rw-r--r--
Bug 1375833 - Part 2: Set mHistoryID to aSHEntry->DocshellID() in both reload and history navigation. r=smaug The root cause of bug 1326845 is that reloading would apply frame history entries without setting new child docshells' mHistoryID to the entrys' DocshellID. So SHistory can not find corresponding entries for subframes in a consequent GoBack(), and cause history navigation being broken (it would return NS_ERROR_FAILURE). MozReview-Commit-ID: 6syGYkoP1eZ

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
 * 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 mozilla_storage_StatementCache_h
#define mozilla_storage_StatementCache_h

#include "mozIStorageConnection.h"
#include "mozIStorageStatement.h"
#include "mozIStorageAsyncStatement.h"

#include "nsAutoPtr.h"
#include "nsHashKeys.h"
#include "nsInterfaceHashtable.h"

namespace mozilla {
namespace storage {

/**
 * Class used to cache statements (mozIStorageStatement or
 * mozIStorageAsyncStatement).
 */
template<typename StatementType>
class StatementCache {
public:
  /**
   * Constructor for the cache.
   *
   * @note a connection can have more than one cache.
   *
   * @param aConnection
   *        A reference to the nsCOMPtr for the connection this cache is to be
   *        used for.  This nsCOMPtr must at least live as long as this class,
   *        otherwise crashes will happen.
   */
  explicit StatementCache(nsCOMPtr<mozIStorageConnection>& aConnection)
  : mConnection(aConnection)
  {
  }

  /**
   * Obtains a cached statement.  If this statement is not yet created, it will
   * be created and stored for later use.
   *
   * @param aQuery
   *        The SQL string (either a const char [] or nsACString) to get a
   *        cached query for.
   * @return the cached statement, or null upon error.
   */
  inline
  already_AddRefed<StatementType>
  GetCachedStatement(const nsACString& aQuery)
  {
    nsCOMPtr<StatementType> stmt;
    if (!mCachedStatements.Get(aQuery, getter_AddRefs(stmt))) {
      stmt = CreateStatement(aQuery);
      NS_ENSURE_TRUE(stmt, nullptr);

      mCachedStatements.Put(aQuery, stmt);
    }
    return stmt.forget();
  }

  template<int N>
  MOZ_ALWAYS_INLINE already_AddRefed<StatementType>
  GetCachedStatement(const char (&aQuery)[N])
  {
    nsDependentCString query(aQuery, N - 1);
    return GetCachedStatement(query);
  }

  /**
   * Finalizes all cached statements so the database can be safely closed.  The
   * behavior of this cache is unspecified after this method is called.
   */
  inline
  void
  FinalizeStatements()
  {
    for (auto iter = mCachedStatements.Iter(); !iter.Done(); iter.Next()) {
      (void)iter.Data()->Finalize();
    }

    // Clear the cache at this time too!
    (void)mCachedStatements.Clear();
  }

private:
  inline
  already_AddRefed<StatementType>
  CreateStatement(const nsACString& aQuery);

  nsInterfaceHashtable<nsCStringHashKey, StatementType> mCachedStatements;
  nsCOMPtr<mozIStorageConnection>& mConnection;
};

template< >
inline
already_AddRefed<mozIStorageStatement>
StatementCache<mozIStorageStatement>::CreateStatement(const nsACString& aQuery)
{
  NS_ENSURE_TRUE(mConnection, nullptr);

  nsCOMPtr<mozIStorageStatement> stmt;
  nsresult rv = mConnection->CreateStatement(aQuery, getter_AddRefs(stmt));
  if (NS_FAILED(rv)) {
    nsCString error;
    error.AppendLiteral("The statement '");
    error.Append(aQuery);
    error.AppendLiteral("' failed to compile with the error message '");
    nsCString msg;
    (void)mConnection->GetLastErrorString(msg);
    error.Append(msg);
    error.AppendLiteral("'.");
    NS_ERROR(error.get());
  }
  NS_ENSURE_SUCCESS(rv, nullptr);

  return stmt.forget();
}

template< >
inline
already_AddRefed<mozIStorageAsyncStatement>
StatementCache<mozIStorageAsyncStatement>::CreateStatement(const nsACString& aQuery)
{
  NS_ENSURE_TRUE(mConnection, nullptr);

  nsCOMPtr<mozIStorageAsyncStatement> stmt;
  nsresult rv = mConnection->CreateAsyncStatement(aQuery, getter_AddRefs(stmt));
  NS_ENSURE_SUCCESS(rv, nullptr);

  return stmt.forget();
}

} // namespace storage
} // namespace mozilla

#endif // mozilla_storage_StatementCache_h