| Index: webkit/browser/appcache/appcache_database.cc
 | 
| diff --git a/webkit/browser/appcache/appcache_database.cc b/webkit/browser/appcache/appcache_database.cc
 | 
| deleted file mode 100644
 | 
| index a5349d8ca914bb3ed6d700cd67b65977a96b7529..0000000000000000000000000000000000000000
 | 
| --- a/webkit/browser/appcache/appcache_database.cc
 | 
| +++ /dev/null
 | 
| @@ -1,1226 +0,0 @@
 | 
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
 | 
| -// Use of this source code is governed by a BSD-style license that can be
 | 
| -// found in the LICENSE file.
 | 
| -
 | 
| -#include "webkit/browser/appcache/appcache_database.h"
 | 
| -
 | 
| -#include "base/auto_reset.h"
 | 
| -#include "base/bind.h"
 | 
| -#include "base/command_line.h"
 | 
| -#include "base/file_util.h"
 | 
| -#include "base/logging.h"
 | 
| -#include "base/strings/utf_string_conversions.h"
 | 
| -#include "sql/connection.h"
 | 
| -#include "sql/error_delegate_util.h"
 | 
| -#include "sql/meta_table.h"
 | 
| -#include "sql/statement.h"
 | 
| -#include "sql/transaction.h"
 | 
| -#include "webkit/browser/appcache/appcache_entry.h"
 | 
| -#include "webkit/browser/appcache/appcache_histograms.h"
 | 
| -
 | 
| -namespace appcache {
 | 
| -
 | 
| -// Schema -------------------------------------------------------------------
 | 
| -namespace {
 | 
| -
 | 
| -#if defined(APPCACHE_USE_SIMPLE_CACHE)
 | 
| -const int kCurrentVersion = 6;
 | 
| -const int kCompatibleVersion = 6;
 | 
| -#else
 | 
| -const int kCurrentVersion = 5;
 | 
| -const int kCompatibleVersion = 5;
 | 
| -#endif
 | 
| -
 | 
| -// A mechanism to run experiments that may affect in data being persisted
 | 
| -// in different ways such that when the experiment is toggled on/off via
 | 
| -// cmd line flags, the database gets reset. The active flags are stored at
 | 
| -// the time of database creation and compared when reopening. If different
 | 
| -// the database is reset.
 | 
| -const char kExperimentFlagsKey[] = "ExperimentFlags";
 | 
| -
 | 
| -const char kGroupsTable[] = "Groups";
 | 
| -const char kCachesTable[] = "Caches";
 | 
| -const char kEntriesTable[] = "Entries";
 | 
| -const char kNamespacesTable[] = "Namespaces";
 | 
| -const char kOnlineWhiteListsTable[] = "OnlineWhiteLists";
 | 
| -const char kDeletableResponseIdsTable[] = "DeletableResponseIds";
 | 
| -
 | 
| -struct TableInfo {
 | 
| -  const char* table_name;
 | 
| -  const char* columns;
 | 
| -};
 | 
| -
 | 
| -struct IndexInfo {
 | 
| -  const char* index_name;
 | 
| -  const char* table_name;
 | 
| -  const char* columns;
 | 
| -  bool unique;
 | 
| -};
 | 
| -
 | 
| -const TableInfo kTables[] = {
 | 
| -  { kGroupsTable,
 | 
| -    "(group_id INTEGER PRIMARY KEY,"
 | 
| -    " origin TEXT,"
 | 
| -    " manifest_url TEXT,"
 | 
| -    " creation_time INTEGER,"
 | 
| -    " last_access_time INTEGER)" },
 | 
| -
 | 
| -  { kCachesTable,
 | 
| -    "(cache_id INTEGER PRIMARY KEY,"
 | 
| -    " group_id INTEGER,"
 | 
| -    " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1)),"
 | 
| -    " update_time INTEGER,"
 | 
| -    " cache_size INTEGER)" },  // intentionally not normalized
 | 
| -
 | 
| -  { kEntriesTable,
 | 
| -    "(cache_id INTEGER,"
 | 
| -    " url TEXT,"
 | 
| -    " flags INTEGER,"
 | 
| -    " response_id INTEGER,"
 | 
| -    " response_size INTEGER)" },
 | 
| -
 | 
| -  { kNamespacesTable,
 | 
| -    "(cache_id INTEGER,"
 | 
| -    " origin TEXT,"  // intentionally not normalized
 | 
| -    " type INTEGER,"
 | 
| -    " namespace_url TEXT,"
 | 
| -    " target_url TEXT,"
 | 
| -    " is_pattern INTEGER CHECK(is_pattern IN (0, 1)))" },
 | 
| -
 | 
| -  { kOnlineWhiteListsTable,
 | 
| -    "(cache_id INTEGER,"
 | 
| -    " namespace_url TEXT,"
 | 
| -    " is_pattern INTEGER CHECK(is_pattern IN (0, 1)))" },
 | 
| -
 | 
| -  { kDeletableResponseIdsTable,
 | 
| -    "(response_id INTEGER NOT NULL)" },
 | 
| -};
 | 
| -
 | 
| -const IndexInfo kIndexes[] = {
 | 
| -  { "GroupsOriginIndex",
 | 
| -    kGroupsTable,
 | 
| -    "(origin)",
 | 
| -    false },
 | 
| -
 | 
| -  { "GroupsManifestIndex",
 | 
| -    kGroupsTable,
 | 
| -    "(manifest_url)",
 | 
| -    true },
 | 
| -
 | 
| -  { "CachesGroupIndex",
 | 
| -    kCachesTable,
 | 
| -    "(group_id)",
 | 
| -    false },
 | 
| -
 | 
| -  { "EntriesCacheIndex",
 | 
| -    kEntriesTable,
 | 
| -    "(cache_id)",
 | 
| -    false },
 | 
| -
 | 
| -  { "EntriesCacheAndUrlIndex",
 | 
| -    kEntriesTable,
 | 
| -    "(cache_id, url)",
 | 
| -    true },
 | 
| -
 | 
| -  { "EntriesResponseIdIndex",
 | 
| -    kEntriesTable,
 | 
| -    "(response_id)",
 | 
| -    true },
 | 
| -
 | 
| -  { "NamespacesCacheIndex",
 | 
| -    kNamespacesTable,
 | 
| -    "(cache_id)",
 | 
| -    false },
 | 
| -
 | 
| -  { "NamespacesOriginIndex",
 | 
| -    kNamespacesTable,
 | 
| -    "(origin)",
 | 
| -    false },
 | 
| -
 | 
| -  { "NamespacesCacheAndUrlIndex",
 | 
| -    kNamespacesTable,
 | 
| -    "(cache_id, namespace_url)",
 | 
| -    true },
 | 
| -
 | 
| -  { "OnlineWhiteListCacheIndex",
 | 
| -    kOnlineWhiteListsTable,
 | 
| -    "(cache_id)",
 | 
| -    false },
 | 
| -
 | 
| -  { "DeletableResponsesIdIndex",
 | 
| -    kDeletableResponseIdsTable,
 | 
| -    "(response_id)",
 | 
| -    true },
 | 
| -};
 | 
| -
 | 
| -const int kTableCount = ARRAYSIZE_UNSAFE(kTables);
 | 
| -const int kIndexCount = ARRAYSIZE_UNSAFE(kIndexes);
 | 
| -
 | 
| -bool CreateTable(sql::Connection* db, const TableInfo& info) {
 | 
| -  std::string sql("CREATE TABLE ");
 | 
| -  sql += info.table_name;
 | 
| -  sql += info.columns;
 | 
| -  return db->Execute(sql.c_str());
 | 
| -}
 | 
| -
 | 
| -bool CreateIndex(sql::Connection* db, const IndexInfo& info) {
 | 
| -  std::string sql;
 | 
| -  if (info.unique)
 | 
| -    sql += "CREATE UNIQUE INDEX ";
 | 
| -  else
 | 
| -    sql += "CREATE INDEX ";
 | 
| -  sql += info.index_name;
 | 
| -  sql += " ON ";
 | 
| -  sql += info.table_name;
 | 
| -  sql += info.columns;
 | 
| -  return db->Execute(sql.c_str());
 | 
| -}
 | 
| -
 | 
| -std::string GetActiveExperimentFlags() {
 | 
| -  if (CommandLine::ForCurrentProcess()->HasSwitch(kEnableExecutableHandlers))
 | 
| -    return std::string("executableHandlersEnabled");
 | 
| -  return std::string();
 | 
| -}
 | 
| -
 | 
| -}  // anon namespace
 | 
| -
 | 
| -// AppCacheDatabase ----------------------------------------------------------
 | 
| -
 | 
| -AppCacheDatabase::GroupRecord::GroupRecord()
 | 
| -    : group_id(0) {
 | 
| -}
 | 
| -
 | 
| -AppCacheDatabase::GroupRecord::~GroupRecord() {
 | 
| -}
 | 
| -
 | 
| -AppCacheDatabase::NamespaceRecord::NamespaceRecord()
 | 
| -    : cache_id(0) {
 | 
| -}
 | 
| -
 | 
| -AppCacheDatabase::NamespaceRecord::~NamespaceRecord() {
 | 
| -}
 | 
| -
 | 
| -
 | 
| -AppCacheDatabase::AppCacheDatabase(const base::FilePath& path)
 | 
| -    : db_file_path_(path),
 | 
| -      is_disabled_(false),
 | 
| -      is_recreating_(false),
 | 
| -      was_corruption_detected_(false) {
 | 
| -}
 | 
| -
 | 
| -AppCacheDatabase::~AppCacheDatabase() {
 | 
| -}
 | 
| -
 | 
| -void AppCacheDatabase::Disable() {
 | 
| -  VLOG(1) << "Disabling appcache database.";
 | 
| -  is_disabled_ = true;
 | 
| -  ResetConnectionAndTables();
 | 
| -}
 | 
| -
 | 
| -int64 AppCacheDatabase::GetOriginUsage(const GURL& origin) {
 | 
| -  std::vector<CacheRecord> records;
 | 
| -  if (!FindCachesForOrigin(origin, &records))
 | 
| -    return 0;
 | 
| -
 | 
| -  int64 origin_usage = 0;
 | 
| -  std::vector<CacheRecord>::const_iterator iter = records.begin();
 | 
| -  while (iter != records.end()) {
 | 
| -    origin_usage += iter->cache_size;
 | 
| -    ++iter;
 | 
| -  }
 | 
| -  return origin_usage;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::GetAllOriginUsage(std::map<GURL, int64>* usage_map) {
 | 
| -  std::set<GURL> origins;
 | 
| -  if (!FindOriginsWithGroups(&origins))
 | 
| -    return false;
 | 
| -  for (std::set<GURL>::const_iterator origin = origins.begin();
 | 
| -       origin != origins.end(); ++origin) {
 | 
| -    (*usage_map)[*origin] = GetOriginUsage(*origin);
 | 
| -  }
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindOriginsWithGroups(std::set<GURL>* origins) {
 | 
| -  DCHECK(origins && origins->empty());
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT DISTINCT(origin) FROM Groups";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetUniqueStatement(kSql));
 | 
| -
 | 
| -  while (statement.Step())
 | 
| -    origins->insert(GURL(statement.ColumnString(0)));
 | 
| -
 | 
| -  return statement.Succeeded();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindLastStorageIds(
 | 
| -    int64* last_group_id, int64* last_cache_id, int64* last_response_id,
 | 
| -    int64* last_deletable_response_rowid) {
 | 
| -  DCHECK(last_group_id && last_cache_id && last_response_id &&
 | 
| -         last_deletable_response_rowid);
 | 
| -
 | 
| -  *last_group_id = 0;
 | 
| -  *last_cache_id = 0;
 | 
| -  *last_response_id = 0;
 | 
| -  *last_deletable_response_rowid = 0;
 | 
| -
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kMaxGroupIdSql = "SELECT MAX(group_id) FROM Groups";
 | 
| -  const char* kMaxCacheIdSql = "SELECT MAX(cache_id) FROM Caches";
 | 
| -  const char* kMaxResponseIdFromEntriesSql =
 | 
| -      "SELECT MAX(response_id) FROM Entries";
 | 
| -  const char* kMaxResponseIdFromDeletablesSql =
 | 
| -      "SELECT MAX(response_id) FROM DeletableResponseIds";
 | 
| -  const char* kMaxDeletableResponseRowIdSql =
 | 
| -      "SELECT MAX(rowid) FROM DeletableResponseIds";
 | 
| -  int64 max_group_id;
 | 
| -  int64 max_cache_id;
 | 
| -  int64 max_response_id_from_entries;
 | 
| -  int64 max_response_id_from_deletables;
 | 
| -  int64 max_deletable_response_rowid;
 | 
| -  if (!RunUniqueStatementWithInt64Result(kMaxGroupIdSql, &max_group_id) ||
 | 
| -      !RunUniqueStatementWithInt64Result(kMaxCacheIdSql, &max_cache_id) ||
 | 
| -      !RunUniqueStatementWithInt64Result(kMaxResponseIdFromEntriesSql,
 | 
| -                                         &max_response_id_from_entries) ||
 | 
| -      !RunUniqueStatementWithInt64Result(kMaxResponseIdFromDeletablesSql,
 | 
| -                                         &max_response_id_from_deletables) ||
 | 
| -      !RunUniqueStatementWithInt64Result(kMaxDeletableResponseRowIdSql,
 | 
| -                                         &max_deletable_response_rowid)) {
 | 
| -    return false;
 | 
| -  }
 | 
| -
 | 
| -  *last_group_id = max_group_id;
 | 
| -  *last_cache_id = max_cache_id;
 | 
| -  *last_response_id = std::max(max_response_id_from_entries,
 | 
| -                               max_response_id_from_deletables);
 | 
| -  *last_deletable_response_rowid = max_deletable_response_rowid;
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindGroup(int64 group_id, GroupRecord* record) {
 | 
| -  DCHECK(record);
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT group_id, origin, manifest_url,"
 | 
| -      "       creation_time, last_access_time"
 | 
| -      "  FROM Groups WHERE group_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -
 | 
| -  statement.BindInt64(0, group_id);
 | 
| -  if (!statement.Step())
 | 
| -    return false;
 | 
| -
 | 
| -  ReadGroupRecord(statement, record);
 | 
| -  DCHECK(record->group_id == group_id);
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindGroupForManifestUrl(
 | 
| -    const GURL& manifest_url, GroupRecord* record) {
 | 
| -  DCHECK(record);
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT group_id, origin, manifest_url,"
 | 
| -      "       creation_time, last_access_time"
 | 
| -      "  FROM Groups WHERE manifest_url = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindString(0, manifest_url.spec());
 | 
| -
 | 
| -  if (!statement.Step())
 | 
| -    return false;
 | 
| -
 | 
| -  ReadGroupRecord(statement, record);
 | 
| -  DCHECK(record->manifest_url == manifest_url);
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindGroupsForOrigin(
 | 
| -    const GURL& origin, std::vector<GroupRecord>* records) {
 | 
| -  DCHECK(records && records->empty());
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT group_id, origin, manifest_url,"
 | 
| -      "       creation_time, last_access_time"
 | 
| -      "   FROM Groups WHERE origin = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindString(0, origin.spec());
 | 
| -
 | 
| -  while (statement.Step()) {
 | 
| -    records->push_back(GroupRecord());
 | 
| -    ReadGroupRecord(statement, &records->back());
 | 
| -    DCHECK(records->back().origin == origin);
 | 
| -  }
 | 
| -
 | 
| -  return statement.Succeeded();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindGroupForCache(int64 cache_id, GroupRecord* record) {
 | 
| -  DCHECK(record);
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT g.group_id, g.origin, g.manifest_url,"
 | 
| -      "       g.creation_time, g.last_access_time"
 | 
| -      "  FROM Groups g, Caches c"
 | 
| -      "  WHERE c.cache_id = ? AND c.group_id = g.group_id";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, cache_id);
 | 
| -
 | 
| -  if (!statement.Step())
 | 
| -    return false;
 | 
| -
 | 
| -  ReadGroupRecord(statement, record);
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::UpdateGroupLastAccessTime(
 | 
| -    int64 group_id, base::Time time) {
 | 
| -  if (!LazyOpen(true))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "UPDATE Groups SET last_access_time = ? WHERE group_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, time.ToInternalValue());
 | 
| -  statement.BindInt64(1, group_id);
 | 
| -
 | 
| -  return statement.Run() && db_->GetLastChangeCount();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::InsertGroup(const GroupRecord* record) {
 | 
| -  if (!LazyOpen(true))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "INSERT INTO Groups"
 | 
| -      "  (group_id, origin, manifest_url, creation_time, last_access_time)"
 | 
| -      "  VALUES(?, ?, ?, ?, ?)";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, record->group_id);
 | 
| -  statement.BindString(1, record->origin.spec());
 | 
| -  statement.BindString(2, record->manifest_url.spec());
 | 
| -  statement.BindInt64(3, record->creation_time.ToInternalValue());
 | 
| -  statement.BindInt64(4, record->last_access_time.ToInternalValue());
 | 
| -
 | 
| -  return statement.Run();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::DeleteGroup(int64 group_id) {
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "DELETE FROM Groups WHERE group_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, group_id);
 | 
| -
 | 
| -  return statement.Run();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindCache(int64 cache_id, CacheRecord* record) {
 | 
| -  DCHECK(record);
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT cache_id, group_id, online_wildcard, update_time, cache_size"
 | 
| -      " FROM Caches WHERE cache_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, cache_id);
 | 
| -
 | 
| -  if (!statement.Step())
 | 
| -    return false;
 | 
| -
 | 
| -  ReadCacheRecord(statement, record);
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindCacheForGroup(int64 group_id, CacheRecord* record) {
 | 
| -  DCHECK(record);
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT cache_id, group_id, online_wildcard, update_time, cache_size"
 | 
| -      "  FROM Caches WHERE group_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, group_id);
 | 
| -
 | 
| -  if (!statement.Step())
 | 
| -    return false;
 | 
| -
 | 
| -  ReadCacheRecord(statement, record);
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindCachesForOrigin(
 | 
| -    const GURL& origin, std::vector<CacheRecord>* records) {
 | 
| -  DCHECK(records);
 | 
| -  std::vector<GroupRecord> group_records;
 | 
| -  if (!FindGroupsForOrigin(origin, &group_records))
 | 
| -    return false;
 | 
| -
 | 
| -  CacheRecord cache_record;
 | 
| -  std::vector<GroupRecord>::const_iterator iter = group_records.begin();
 | 
| -  while (iter != group_records.end()) {
 | 
| -    if (FindCacheForGroup(iter->group_id, &cache_record))
 | 
| -      records->push_back(cache_record);
 | 
| -    ++iter;
 | 
| -  }
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::InsertCache(const CacheRecord* record) {
 | 
| -  if (!LazyOpen(true))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "INSERT INTO Caches (cache_id, group_id, online_wildcard,"
 | 
| -      "                    update_time, cache_size)"
 | 
| -      "  VALUES(?, ?, ?, ?, ?)";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, record->cache_id);
 | 
| -  statement.BindInt64(1, record->group_id);
 | 
| -  statement.BindBool(2, record->online_wildcard);
 | 
| -  statement.BindInt64(3, record->update_time.ToInternalValue());
 | 
| -  statement.BindInt64(4, record->cache_size);
 | 
| -
 | 
| -  return statement.Run();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::DeleteCache(int64 cache_id) {
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "DELETE FROM Caches WHERE cache_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, cache_id);
 | 
| -
 | 
| -  return statement.Run();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindEntriesForCache(
 | 
| -    int64 cache_id, std::vector<EntryRecord>* records) {
 | 
| -  DCHECK(records && records->empty());
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT cache_id, url, flags, response_id, response_size FROM Entries"
 | 
| -      "  WHERE cache_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, cache_id);
 | 
| -
 | 
| -  while (statement.Step()) {
 | 
| -    records->push_back(EntryRecord());
 | 
| -    ReadEntryRecord(statement, &records->back());
 | 
| -    DCHECK(records->back().cache_id == cache_id);
 | 
| -  }
 | 
| -
 | 
| -  return statement.Succeeded();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindEntriesForUrl(
 | 
| -    const GURL& url, std::vector<EntryRecord>* records) {
 | 
| -  DCHECK(records && records->empty());
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT cache_id, url, flags, response_id, response_size FROM Entries"
 | 
| -      "  WHERE url = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindString(0, url.spec());
 | 
| -
 | 
| -  while (statement.Step()) {
 | 
| -    records->push_back(EntryRecord());
 | 
| -    ReadEntryRecord(statement, &records->back());
 | 
| -    DCHECK(records->back().url == url);
 | 
| -  }
 | 
| -
 | 
| -  return statement.Succeeded();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindEntry(
 | 
| -    int64 cache_id, const GURL& url, EntryRecord* record) {
 | 
| -  DCHECK(record);
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT cache_id, url, flags, response_id, response_size FROM Entries"
 | 
| -      "  WHERE cache_id = ? AND url = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, cache_id);
 | 
| -  statement.BindString(1, url.spec());
 | 
| -
 | 
| -  if (!statement.Step())
 | 
| -    return false;
 | 
| -
 | 
| -  ReadEntryRecord(statement, record);
 | 
| -  DCHECK(record->cache_id == cache_id);
 | 
| -  DCHECK(record->url == url);
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::InsertEntry(const EntryRecord* record) {
 | 
| -  if (!LazyOpen(true))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "INSERT INTO Entries (cache_id, url, flags, response_id, response_size)"
 | 
| -      "  VALUES(?, ?, ?, ?, ?)";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, record->cache_id);
 | 
| -  statement.BindString(1, record->url.spec());
 | 
| -  statement.BindInt(2, record->flags);
 | 
| -  statement.BindInt64(3, record->response_id);
 | 
| -  statement.BindInt64(4, record->response_size);
 | 
| -
 | 
| -  return statement.Run();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::InsertEntryRecords(
 | 
| -    const std::vector<EntryRecord>& records) {
 | 
| -  if (records.empty())
 | 
| -    return true;
 | 
| -  sql::Transaction transaction(db_.get());
 | 
| -  if (!transaction.Begin())
 | 
| -    return false;
 | 
| -  std::vector<EntryRecord>::const_iterator iter = records.begin();
 | 
| -  while (iter != records.end()) {
 | 
| -    if (!InsertEntry(&(*iter)))
 | 
| -      return false;
 | 
| -    ++iter;
 | 
| -  }
 | 
| -  return transaction.Commit();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::DeleteEntriesForCache(int64 cache_id) {
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "DELETE FROM Entries WHERE cache_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, cache_id);
 | 
| -
 | 
| -  return statement.Run();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::AddEntryFlags(
 | 
| -    const GURL& entry_url, int64 cache_id, int additional_flags) {
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "UPDATE Entries SET flags = flags | ? WHERE cache_id = ? AND url = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt(0, additional_flags);
 | 
| -  statement.BindInt64(1, cache_id);
 | 
| -  statement.BindString(2, entry_url.spec());
 | 
| -
 | 
| -  return statement.Run() && db_->GetLastChangeCount();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindNamespacesForOrigin(
 | 
| -    const GURL& origin,
 | 
| -    std::vector<NamespaceRecord>* intercepts,
 | 
| -    std::vector<NamespaceRecord>* fallbacks) {
 | 
| -  DCHECK(intercepts && intercepts->empty());
 | 
| -  DCHECK(fallbacks && fallbacks->empty());
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT cache_id, origin, type, namespace_url, target_url, is_pattern"
 | 
| -      "  FROM Namespaces WHERE origin = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindString(0, origin.spec());
 | 
| -
 | 
| -  ReadNamespaceRecords(&statement, intercepts, fallbacks);
 | 
| -
 | 
| -  return statement.Succeeded();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindNamespacesForCache(
 | 
| -    int64 cache_id,
 | 
| -    std::vector<NamespaceRecord>* intercepts,
 | 
| -    std::vector<NamespaceRecord>* fallbacks) {
 | 
| -  DCHECK(intercepts && intercepts->empty());
 | 
| -  DCHECK(fallbacks && fallbacks->empty());
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT cache_id, origin, type, namespace_url, target_url, is_pattern"
 | 
| -      "  FROM Namespaces WHERE cache_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, cache_id);
 | 
| -
 | 
| -  ReadNamespaceRecords(&statement, intercepts, fallbacks);
 | 
| -
 | 
| -  return statement.Succeeded();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::InsertNamespace(
 | 
| -    const NamespaceRecord* record) {
 | 
| -  if (!LazyOpen(true))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "INSERT INTO Namespaces"
 | 
| -      "  (cache_id, origin, type, namespace_url, target_url, is_pattern)"
 | 
| -      "  VALUES (?, ?, ?, ?, ?, ?)";
 | 
| -
 | 
| -  // Note: quick and dirty storage for the 'executable' bit w/o changing
 | 
| -  // schemas, we use the high bit of 'type' field.
 | 
| -  int type_with_executable_bit = record->namespace_.type;
 | 
| -  if (record->namespace_.is_executable) {
 | 
| -    type_with_executable_bit |= 0x8000000;
 | 
| -    DCHECK(CommandLine::ForCurrentProcess()->HasSwitch(
 | 
| -        kEnableExecutableHandlers));
 | 
| -  }
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, record->cache_id);
 | 
| -  statement.BindString(1, record->origin.spec());
 | 
| -  statement.BindInt(2, type_with_executable_bit);
 | 
| -  statement.BindString(3, record->namespace_.namespace_url.spec());
 | 
| -  statement.BindString(4, record->namespace_.target_url.spec());
 | 
| -  statement.BindBool(5, record->namespace_.is_pattern);
 | 
| -  return statement.Run();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::InsertNamespaceRecords(
 | 
| -    const std::vector<NamespaceRecord>& records) {
 | 
| -  if (records.empty())
 | 
| -    return true;
 | 
| -  sql::Transaction transaction(db_.get());
 | 
| -  if (!transaction.Begin())
 | 
| -    return false;
 | 
| -  std::vector<NamespaceRecord>::const_iterator iter = records.begin();
 | 
| -  while (iter != records.end()) {
 | 
| -    if (!InsertNamespace(&(*iter)))
 | 
| -      return false;
 | 
| -    ++iter;
 | 
| -  }
 | 
| -  return transaction.Commit();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::DeleteNamespacesForCache(int64 cache_id) {
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "DELETE FROM Namespaces WHERE cache_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, cache_id);
 | 
| -
 | 
| -  return statement.Run();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindOnlineWhiteListForCache(
 | 
| -    int64 cache_id, std::vector<OnlineWhiteListRecord>* records) {
 | 
| -  DCHECK(records && records->empty());
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT cache_id, namespace_url, is_pattern FROM OnlineWhiteLists"
 | 
| -      "  WHERE cache_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, cache_id);
 | 
| -
 | 
| -  while (statement.Step()) {
 | 
| -    records->push_back(OnlineWhiteListRecord());
 | 
| -    this->ReadOnlineWhiteListRecord(statement, &records->back());
 | 
| -    DCHECK(records->back().cache_id == cache_id);
 | 
| -  }
 | 
| -  return statement.Succeeded();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::InsertOnlineWhiteList(
 | 
| -    const OnlineWhiteListRecord* record) {
 | 
| -  if (!LazyOpen(true))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "INSERT INTO OnlineWhiteLists (cache_id, namespace_url, is_pattern)"
 | 
| -      "  VALUES (?, ?, ?)";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, record->cache_id);
 | 
| -  statement.BindString(1, record->namespace_url.spec());
 | 
| -  statement.BindBool(2, record->is_pattern);
 | 
| -
 | 
| -  return statement.Run();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::InsertOnlineWhiteListRecords(
 | 
| -    const std::vector<OnlineWhiteListRecord>& records) {
 | 
| -  if (records.empty())
 | 
| -    return true;
 | 
| -  sql::Transaction transaction(db_.get());
 | 
| -  if (!transaction.Begin())
 | 
| -    return false;
 | 
| -  std::vector<OnlineWhiteListRecord>::const_iterator iter = records.begin();
 | 
| -  while (iter != records.end()) {
 | 
| -    if (!InsertOnlineWhiteList(&(*iter)))
 | 
| -      return false;
 | 
| -    ++iter;
 | 
| -  }
 | 
| -  return transaction.Commit();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::DeleteOnlineWhiteListForCache(int64 cache_id) {
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "DELETE FROM OnlineWhiteLists WHERE cache_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, cache_id);
 | 
| -
 | 
| -  return statement.Run();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::GetDeletableResponseIds(
 | 
| -    std::vector<int64>* response_ids, int64 max_rowid, int limit) {
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT response_id FROM DeletableResponseIds "
 | 
| -      "  WHERE rowid <= ?"
 | 
| -      "  LIMIT ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -  statement.BindInt64(0, max_rowid);
 | 
| -  statement.BindInt64(1, limit);
 | 
| -
 | 
| -  while (statement.Step())
 | 
| -    response_ids->push_back(statement.ColumnInt64(0));
 | 
| -  return statement.Succeeded();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::InsertDeletableResponseIds(
 | 
| -    const std::vector<int64>& response_ids) {
 | 
| -  const char* kSql =
 | 
| -      "INSERT INTO DeletableResponseIds (response_id) VALUES (?)";
 | 
| -  return RunCachedStatementWithIds(SQL_FROM_HERE, kSql, response_ids);
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::DeleteDeletableResponseIds(
 | 
| -    const std::vector<int64>& response_ids) {
 | 
| -  const char* kSql =
 | 
| -      "DELETE FROM DeletableResponseIds WHERE response_id = ?";
 | 
| -  return RunCachedStatementWithIds(SQL_FROM_HERE, kSql, response_ids);
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::RunCachedStatementWithIds(
 | 
| -    const sql::StatementID& statement_id, const char* sql,
 | 
| -    const std::vector<int64>& ids) {
 | 
| -  DCHECK(sql);
 | 
| -  if (!LazyOpen(true))
 | 
| -    return false;
 | 
| -
 | 
| -  sql::Transaction transaction(db_.get());
 | 
| -  if (!transaction.Begin())
 | 
| -    return false;
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(statement_id, sql));
 | 
| -
 | 
| -  std::vector<int64>::const_iterator iter = ids.begin();
 | 
| -  while (iter != ids.end()) {
 | 
| -    statement.BindInt64(0, *iter);
 | 
| -    if (!statement.Run())
 | 
| -      return false;
 | 
| -    statement.Reset(true);
 | 
| -    ++iter;
 | 
| -  }
 | 
| -
 | 
| -  return transaction.Commit();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::RunUniqueStatementWithInt64Result(
 | 
| -    const char* sql, int64* result) {
 | 
| -  DCHECK(sql);
 | 
| -  sql::Statement statement(db_->GetUniqueStatement(sql));
 | 
| -  if (!statement.Step()) {
 | 
| -    return false;
 | 
| -  }
 | 
| -  *result = statement.ColumnInt64(0);
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::FindResponseIdsForCacheHelper(
 | 
| -    int64 cache_id, std::vector<int64>* ids_vector,
 | 
| -    std::set<int64>* ids_set) {
 | 
| -  DCHECK(ids_vector || ids_set);
 | 
| -  DCHECK(!(ids_vector && ids_set));
 | 
| -  if (!LazyOpen(false))
 | 
| -    return false;
 | 
| -
 | 
| -  const char* kSql =
 | 
| -      "SELECT response_id FROM Entries WHERE cache_id = ?";
 | 
| -
 | 
| -  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
 | 
| -
 | 
| -  statement.BindInt64(0, cache_id);
 | 
| -  while (statement.Step()) {
 | 
| -    int64 id = statement.ColumnInt64(0);
 | 
| -    if (ids_set)
 | 
| -      ids_set->insert(id);
 | 
| -    else
 | 
| -      ids_vector->push_back(id);
 | 
| -  }
 | 
| -
 | 
| -  return statement.Succeeded();
 | 
| -}
 | 
| -
 | 
| -void AppCacheDatabase::ReadGroupRecord(
 | 
| -    const sql::Statement& statement, GroupRecord* record) {
 | 
| -  record->group_id = statement.ColumnInt64(0);
 | 
| -  record->origin = GURL(statement.ColumnString(1));
 | 
| -  record->manifest_url = GURL(statement.ColumnString(2));
 | 
| -  record->creation_time =
 | 
| -      base::Time::FromInternalValue(statement.ColumnInt64(3));
 | 
| -  record->last_access_time =
 | 
| -      base::Time::FromInternalValue(statement.ColumnInt64(4));
 | 
| -}
 | 
| -
 | 
| -void AppCacheDatabase::ReadCacheRecord(
 | 
| -    const sql::Statement& statement, CacheRecord* record) {
 | 
| -  record->cache_id = statement.ColumnInt64(0);
 | 
| -  record->group_id = statement.ColumnInt64(1);
 | 
| -  record->online_wildcard = statement.ColumnBool(2);
 | 
| -  record->update_time =
 | 
| -      base::Time::FromInternalValue(statement.ColumnInt64(3));
 | 
| -  record->cache_size = statement.ColumnInt64(4);
 | 
| -}
 | 
| -
 | 
| -void AppCacheDatabase::ReadEntryRecord(
 | 
| -    const sql::Statement& statement, EntryRecord* record) {
 | 
| -  record->cache_id = statement.ColumnInt64(0);
 | 
| -  record->url = GURL(statement.ColumnString(1));
 | 
| -  record->flags = statement.ColumnInt(2);
 | 
| -  record->response_id = statement.ColumnInt64(3);
 | 
| -  record->response_size = statement.ColumnInt64(4);
 | 
| -}
 | 
| -
 | 
| -void AppCacheDatabase::ReadNamespaceRecords(
 | 
| -      sql::Statement* statement,
 | 
| -      NamespaceRecordVector* intercepts,
 | 
| -      NamespaceRecordVector* fallbacks) {
 | 
| -  while (statement->Step()) {
 | 
| -    AppCacheNamespaceType type = static_cast<AppCacheNamespaceType>(
 | 
| -        statement->ColumnInt(2));
 | 
| -    NamespaceRecordVector* records =
 | 
| -        (type == APPCACHE_FALLBACK_NAMESPACE) ? fallbacks : intercepts;
 | 
| -    records->push_back(NamespaceRecord());
 | 
| -    ReadNamespaceRecord(statement, &records->back());
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -void AppCacheDatabase::ReadNamespaceRecord(
 | 
| -    const sql::Statement* statement, NamespaceRecord* record) {
 | 
| -  record->cache_id = statement->ColumnInt64(0);
 | 
| -  record->origin = GURL(statement->ColumnString(1));
 | 
| -  int type_with_executable_bit = statement->ColumnInt(2);
 | 
| -  record->namespace_.namespace_url = GURL(statement->ColumnString(3));
 | 
| -  record->namespace_.target_url = GURL(statement->ColumnString(4));
 | 
| -  record->namespace_.is_pattern = statement->ColumnBool(5);
 | 
| -
 | 
| -  // Note: quick and dirty storage for the 'executable' bit w/o changing
 | 
| -  // schemas, we use the high bit of 'type' field.
 | 
| -  record->namespace_.type = static_cast<AppCacheNamespaceType>
 | 
| -      (type_with_executable_bit & 0x7ffffff);
 | 
| -  record->namespace_.is_executable =
 | 
| -      (type_with_executable_bit & 0x80000000) != 0;
 | 
| -  DCHECK(!record->namespace_.is_executable ||
 | 
| -      CommandLine::ForCurrentProcess()->HasSwitch(kEnableExecutableHandlers));
 | 
| -}
 | 
| -
 | 
| -void AppCacheDatabase::ReadOnlineWhiteListRecord(
 | 
| -    const sql::Statement& statement, OnlineWhiteListRecord* record) {
 | 
| -  record->cache_id = statement.ColumnInt64(0);
 | 
| -  record->namespace_url = GURL(statement.ColumnString(1));
 | 
| -  record->is_pattern = statement.ColumnBool(2);
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::LazyOpen(bool create_if_needed) {
 | 
| -  if (db_)
 | 
| -    return true;
 | 
| -
 | 
| -  // If we tried and failed once, don't try again in the same session
 | 
| -  // to avoid creating an incoherent mess on disk.
 | 
| -  if (is_disabled_)
 | 
| -    return false;
 | 
| -
 | 
| -  // Avoid creating a database at all if we can.
 | 
| -  bool use_in_memory_db = db_file_path_.empty();
 | 
| -  if (!create_if_needed &&
 | 
| -      (use_in_memory_db || !base::PathExists(db_file_path_))) {
 | 
| -    return false;
 | 
| -  }
 | 
| -
 | 
| -  db_.reset(new sql::Connection);
 | 
| -  meta_table_.reset(new sql::MetaTable);
 | 
| -
 | 
| -  db_->set_histogram_tag("AppCache");
 | 
| -
 | 
| -  bool opened = false;
 | 
| -  if (use_in_memory_db) {
 | 
| -    opened = db_->OpenInMemory();
 | 
| -  } else if (!base::CreateDirectory(db_file_path_.DirName())) {
 | 
| -    LOG(ERROR) << "Failed to create appcache directory.";
 | 
| -  } else {
 | 
| -    opened = db_->Open(db_file_path_);
 | 
| -    if (opened)
 | 
| -      db_->Preload();
 | 
| -  }
 | 
| -
 | 
| -  if (!opened || !db_->QuickIntegrityCheck() || !EnsureDatabaseVersion()) {
 | 
| -    LOG(ERROR) << "Failed to open the appcache database.";
 | 
| -    AppCacheHistograms::CountInitResult(
 | 
| -        AppCacheHistograms::SQL_DATABASE_ERROR);
 | 
| -
 | 
| -    // We're unable to open the database. This is a fatal error
 | 
| -    // which we can't recover from. We try to handle it by deleting
 | 
| -    // the existing appcache data and starting with a clean slate in
 | 
| -    // this browser session.
 | 
| -    if (!use_in_memory_db && DeleteExistingAndCreateNewDatabase())
 | 
| -      return true;
 | 
| -
 | 
| -    Disable();
 | 
| -    return false;
 | 
| -  }
 | 
| -
 | 
| -  AppCacheHistograms::CountInitResult(AppCacheHistograms::INIT_OK);
 | 
| -  was_corruption_detected_ = false;
 | 
| -  db_->set_error_callback(
 | 
| -      base::Bind(&AppCacheDatabase::OnDatabaseError, base::Unretained(this)));
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::EnsureDatabaseVersion() {
 | 
| -  if (!sql::MetaTable::DoesTableExist(db_.get()))
 | 
| -    return CreateSchema();
 | 
| -
 | 
| -  if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion))
 | 
| -    return false;
 | 
| -
 | 
| -  if (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) {
 | 
| -    LOG(WARNING) << "AppCache database is too new.";
 | 
| -    return false;
 | 
| -  }
 | 
| -
 | 
| -  std::string stored_flags;
 | 
| -  meta_table_->GetValue(kExperimentFlagsKey, &stored_flags);
 | 
| -  if (stored_flags != GetActiveExperimentFlags())
 | 
| -    return false;
 | 
| -
 | 
| -  if (meta_table_->GetVersionNumber() < kCurrentVersion)
 | 
| -    return UpgradeSchema();
 | 
| -
 | 
| -#ifndef NDEBUG
 | 
| -  DCHECK(sql::MetaTable::DoesTableExist(db_.get()));
 | 
| -  for (int i = 0; i < kTableCount; ++i) {
 | 
| -    DCHECK(db_->DoesTableExist(kTables[i].table_name));
 | 
| -  }
 | 
| -  for (int i = 0; i < kIndexCount; ++i) {
 | 
| -    DCHECK(db_->DoesIndexExist(kIndexes[i].index_name));
 | 
| -  }
 | 
| -#endif
 | 
| -
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::CreateSchema() {
 | 
| -  sql::Transaction transaction(db_.get());
 | 
| -  if (!transaction.Begin())
 | 
| -    return false;
 | 
| -
 | 
| -  if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion))
 | 
| -    return false;
 | 
| -
 | 
| -  if (!meta_table_->SetValue(kExperimentFlagsKey,
 | 
| -                             GetActiveExperimentFlags())) {
 | 
| -    return false;
 | 
| -  }
 | 
| -
 | 
| -  for (int i = 0; i < kTableCount; ++i) {
 | 
| -    if (!CreateTable(db_.get(), kTables[i]))
 | 
| -      return false;
 | 
| -  }
 | 
| -
 | 
| -  for (int i = 0; i < kIndexCount; ++i) {
 | 
| -    if (!CreateIndex(db_.get(), kIndexes[i]))
 | 
| -      return false;
 | 
| -  }
 | 
| -
 | 
| -  return transaction.Commit();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::UpgradeSchema() {
 | 
| -#if defined(APPCACHE_USE_SIMPLE_CACHE)
 | 
| -  return DeleteExistingAndCreateNewDatabase();
 | 
| -#else
 | 
| -  if (meta_table_->GetVersionNumber() == 3) {
 | 
| -    // version 3 was pre 12/17/2011
 | 
| -    DCHECK_EQ(strcmp(kNamespacesTable, kTables[3].table_name), 0);
 | 
| -    DCHECK_EQ(strcmp(kNamespacesTable, kIndexes[6].table_name), 0);
 | 
| -    DCHECK_EQ(strcmp(kNamespacesTable, kIndexes[7].table_name), 0);
 | 
| -    DCHECK_EQ(strcmp(kNamespacesTable, kIndexes[8].table_name), 0);
 | 
| -
 | 
| -    const TableInfo kNamespaceTable_v4 = {
 | 
| -        kNamespacesTable,
 | 
| -        "(cache_id INTEGER,"
 | 
| -        " origin TEXT,"  // intentionally not normalized
 | 
| -        " type INTEGER,"
 | 
| -        " namespace_url TEXT,"
 | 
| -        " target_url TEXT)"
 | 
| -    };
 | 
| -
 | 
| -    // Migrate from the old FallbackNameSpaces to the newer Namespaces table,
 | 
| -    // but without the is_pattern column added in v5.
 | 
| -    sql::Transaction transaction(db_.get());
 | 
| -    if (!transaction.Begin() ||
 | 
| -        !CreateTable(db_.get(), kNamespaceTable_v4)) {
 | 
| -      return false;
 | 
| -    }
 | 
| -
 | 
| -    // Move data from the old table to the new table, setting the
 | 
| -    // 'type' for all current records to the value for
 | 
| -    // APPCACHE_FALLBACK_NAMESPACE.
 | 
| -    DCHECK_EQ(0, static_cast<int>(APPCACHE_FALLBACK_NAMESPACE));
 | 
| -    if (!db_->Execute(
 | 
| -            "INSERT INTO Namespaces"
 | 
| -            "  SELECT cache_id, origin, 0, namespace_url, fallback_entry_url"
 | 
| -            "  FROM FallbackNameSpaces")) {
 | 
| -      return false;
 | 
| -    }
 | 
| -
 | 
| -    // Drop the old table, indexes on that table are also removed by this.
 | 
| -    if (!db_->Execute("DROP TABLE FallbackNameSpaces"))
 | 
| -      return false;
 | 
| -
 | 
| -    // Create new indexes.
 | 
| -    if (!CreateIndex(db_.get(), kIndexes[6]) ||
 | 
| -        !CreateIndex(db_.get(), kIndexes[7]) ||
 | 
| -        !CreateIndex(db_.get(), kIndexes[8])) {
 | 
| -      return false;
 | 
| -    }
 | 
| -
 | 
| -    meta_table_->SetVersionNumber(4);
 | 
| -    meta_table_->SetCompatibleVersionNumber(4);
 | 
| -    if (!transaction.Commit())
 | 
| -      return false;
 | 
| -  }
 | 
| -
 | 
| -  if (meta_table_->GetVersionNumber() == 4) {
 | 
| -    // version 4 pre 3/30/2013
 | 
| -    // Add the is_pattern column to the Namespaces and OnlineWhitelists tables.
 | 
| -    DCHECK_EQ(strcmp(kNamespacesTable, "Namespaces"), 0);
 | 
| -    sql::Transaction transaction(db_.get());
 | 
| -    if (!transaction.Begin())
 | 
| -      return false;
 | 
| -    if (!db_->Execute(
 | 
| -            "ALTER TABLE Namespaces ADD COLUMN"
 | 
| -            "  is_pattern INTEGER CHECK(is_pattern IN (0, 1))")) {
 | 
| -      return false;
 | 
| -    }
 | 
| -    if (!db_->Execute(
 | 
| -            "ALTER TABLE OnlineWhitelists ADD COLUMN"
 | 
| -            "  is_pattern INTEGER CHECK(is_pattern IN (0, 1))")) {
 | 
| -      return false;
 | 
| -    }
 | 
| -    meta_table_->SetVersionNumber(5);
 | 
| -    meta_table_->SetCompatibleVersionNumber(5);
 | 
| -    return transaction.Commit();
 | 
| -  }
 | 
| -
 | 
| -  // If there is no upgrade path for the version on disk to the current
 | 
| -  // version, nuke everything and start over.
 | 
| -  return DeleteExistingAndCreateNewDatabase();
 | 
| -#endif
 | 
| -}
 | 
| -
 | 
| -void AppCacheDatabase::ResetConnectionAndTables() {
 | 
| -  meta_table_.reset();
 | 
| -  db_.reset();
 | 
| -}
 | 
| -
 | 
| -bool AppCacheDatabase::DeleteExistingAndCreateNewDatabase() {
 | 
| -  DCHECK(!db_file_path_.empty());
 | 
| -  DCHECK(base::PathExists(db_file_path_));
 | 
| -  VLOG(1) << "Deleting existing appcache data and starting over.";
 | 
| -
 | 
| -  ResetConnectionAndTables();
 | 
| -
 | 
| -  // This also deletes the disk cache data.
 | 
| -  base::FilePath directory = db_file_path_.DirName();
 | 
| -  if (!base::DeleteFile(directory, true))
 | 
| -    return false;
 | 
| -
 | 
| -  // Make sure the steps above actually deleted things.
 | 
| -  if (base::PathExists(directory))
 | 
| -    return false;
 | 
| -
 | 
| -  if (!base::CreateDirectory(directory))
 | 
| -    return false;
 | 
| -
 | 
| -  // So we can't go recursive.
 | 
| -  if (is_recreating_)
 | 
| -    return false;
 | 
| -
 | 
| -  base::AutoReset<bool> auto_reset(&is_recreating_, true);
 | 
| -  return LazyOpen(true);
 | 
| -}
 | 
| -
 | 
| -void AppCacheDatabase::OnDatabaseError(int err, sql::Statement* stmt) {
 | 
| -  was_corruption_detected_ |= sql::IsErrorCatastrophic(err);
 | 
| -  if (!db_->ShouldIgnoreSqliteError(err))
 | 
| -    DLOG(ERROR) << db_->GetErrorMessage();
 | 
| -  // TODO: Maybe use non-catostrophic errors to trigger a full integrity check?
 | 
| -}
 | 
| -
 | 
| -}  // namespace appcache
 | 
| 
 |