15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/thumbnail_database.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/bind.h"
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/debug/alias.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/debug/dump_without_crashing.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/format_macros.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted_memory.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/metrics/histogram.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/rand_util.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/history/core/browser/history_client.h"
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/history/core/browser/url_database.h"
2368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "sql/recovery.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/statement.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/transaction.h"
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "third_party/sqlite/sqlite3.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/mac_util.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Description of database tables:
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// icon_mapping
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   id               Unique ID.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   page_url         Page URL which has one or more associated favicons.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   icon_id          The ID of favicon that this mapping maps to.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// favicons           This table associates a row to each favicon for a
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    |page_url| in the |icon_mapping| table. This is the
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    default favicon |page_url|/favicon.ico plus any favicons
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    associated via <link rel="icon_type" href="url">.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    The |id| matches the |icon_id| field in the appropriate
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    row in the icon_mapping table.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   id               Unique ID.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   url              The URL at which the favicon file is located.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   icon_type        The type of the favicon specified in the rel attribute of
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    the link tag. The FAVICON type is used for the default
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    favicon.ico favicon.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// favicon_bitmaps    This table contains the PNG encoded bitmap data of the
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    favicons. There is a separate row for every size in a
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    multi resolution bitmap. The bitmap data is associated
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    to the favicon via the |icon_id| field which matches
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    the |id| field in the appropriate row in the |favicons|
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch//                    table.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  id                Unique ID.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  icon_id           The ID of the favicon that the bitmap is associated to.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  last_updated      The time at which this favicon was inserted into the
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    table. This is used to determine if it needs to be
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                    redownloaded from the web.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  image_data        PNG encoded data of the favicon.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  width             Pixel width of |image_data|.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  height            Pixel height of |image_data|.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// For this database, schema migrations are deprecated after two
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// years.  This means that the oldest non-deprecated version should be
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// two years old or greater (thus the migrations to get there are
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// older).  Databases containing deprecated versions will be cleared
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// at startup.  Since this database is a cache, losing old data is not
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// fatal (in fact, very old data may be expired immediately at startup
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// anyhow).
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Version 7: 911a634d/r209424 by qsr@chromium.org on 2013-07-01
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Version 6: 610f923b/r152367 by pkotwicz@chromium.org on 2012-08-20
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Version 5: e2ee8ae9/r105004 by groby@chromium.org on 2011-10-12
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Version 4: 5f104d76/r77288 by sky@chromium.org on 2011-03-08 (deprecated)
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Version 3: 09911bf3/r15 by initial.commit on 2008-07-26 (deprecated)
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Version number of the database.
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// NOTE(shess): When changing the version, add a new golden file for
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// the new version and a test to verify that Init() works with it.
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const int kCurrentVersionNumber = 7;
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const int kCompatibleVersionNumber = 7;
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const int kDeprecatedVersionNumber = 4;  // and earlier.
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void FillIconMapping(const sql::Statement& statement,
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     const GURL& page_url,
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     history::IconMapping* icon_mapping) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_mapping->mapping_id = statement.ColumnInt64(0);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_mapping->icon_id = statement.ColumnInt64(1);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_mapping->icon_type =
970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      static_cast<favicon_base::IconType>(statement.ColumnInt(2));
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_mapping->icon_url = GURL(statement.ColumnString(3));
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_mapping->page_url = page_url;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)enum InvalidStructureType {
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // NOTE(shess): Intentionally skip bucket 0 to account for
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // conversion from a boolean histogram.
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  STRUCTURE_EVENT_FAVICON = 1,
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  STRUCTURE_EVENT_VERSION4,
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  STRUCTURE_EVENT_VERSION5,
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Always keep this at the end.
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  STRUCTURE_EVENT_MAX,
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void RecordInvalidStructure(InvalidStructureType invalid_type) {
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("History.InvalidFaviconsDBStructure",
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                            invalid_type, STRUCTURE_EVENT_MAX);
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Attempt to pass 2000 bytes of |debug_info| into a crash dump.
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void DumpWithoutCrashing2000(const std::string& debug_info) {
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  char debug_buf[2000];
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::strlcpy(debug_buf, debug_info.c_str(), arraysize(debug_buf));
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::debug::Alias(&debug_buf);
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::debug::DumpWithoutCrashing();
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ReportCorrupt(sql::Connection* db, size_t startup_kb) {
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Buffer for accumulating debugging info about the error.  Place
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // more-relevant information earlier, in case things overflow the
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // fixed-size buffer.
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string debug_info;
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::StringAppendF(&debug_info, "SQLITE_CORRUPT, integrity_check:\n");
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Check files up to 8M to keep things from blocking too long.
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const size_t kMaxIntegrityCheckSize = 8192;
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (startup_kb > kMaxIntegrityCheckSize) {
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::StringAppendF(&debug_info, "too big %" PRIuS "\n", startup_kb);
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::vector<std::string> messages;
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::TimeTicks before = base::TimeTicks::Now();
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    db->FullIntegrityCheck(&messages);
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::StringAppendF(&debug_info, "# %" PRIx64 " ms, %" PRIuS " records\n",
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        (base::TimeTicks::Now() - before).InMilliseconds(),
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        messages.size());
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // SQLite returns up to 100 messages by default, trim deeper to
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // keep close to the 2000-character size limit for dumping.
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    //
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // TODO(shess): If the first 20 tend to be actionable, test if
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // passing the count to integrity_check makes it exit earlier.  In
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // that case it may be possible to greatly ease the size
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // restriction.
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const size_t kMaxMessages = 20;
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (size_t i = 0; i < kMaxMessages && i < messages.size(); ++i) {
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::StringAppendF(&debug_info, "%s\n", messages[i].c_str());
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DumpWithoutCrashing2000(debug_info);
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ReportError(sql::Connection* db, int error) {
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Buffer for accumulating debugging info about the error.  Place
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // more-relevant information earlier, in case things overflow the
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // fixed-size buffer.
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string debug_info;
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The error message from the failed operation.
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::StringAppendF(&debug_info, "db error: %d/%s\n",
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                      db->GetErrorCode(), db->GetErrorMessage());
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // System errno information.
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::StringAppendF(&debug_info, "errno: %d\n", db->GetLastErrno());
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // SQLITE_ERROR reports seem to be attempts to upgrade invalid
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // schema, try to log that info.
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (error == SQLITE_ERROR) {
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const char* kVersionSql = "SELECT value FROM meta WHERE key = 'version'";
181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (db->IsSQLValid(kVersionSql)) {
182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      sql::Statement statement(db->GetUniqueStatement(kVersionSql));
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (statement.Step()) {
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        debug_info += "version: ";
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        debug_info += statement.ColumnString(0);
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        debug_info += '\n';
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      } else if (statement.Succeeded()) {
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        debug_info += "version: none\n";
189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      } else {
190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        debug_info += "version: error\n";
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    } else {
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      debug_info += "version: invalid\n";
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    debug_info += "schema:\n";
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // sqlite_master has columns:
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    //   type - "index" or "table".
200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    //   name - name of created element.
201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    //   tbl_name - name of element, or target table in case of index.
202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    //   rootpage - root page of the element in database file.
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    //   sql - SQL to create the element.
204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // In general, the |sql| column is sufficient to derive the other
205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // columns.  |rootpage| is not interesting for debugging, without
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // the contents of the database.  The COALESCE is because certain
207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // automatic elements will have a |name| but no |sql|,
208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const char* kSchemaSql = "SELECT COALESCE(sql, name) FROM sqlite_master";
209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    sql::Statement statement(db->GetUniqueStatement(kSchemaSql));
210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    while (statement.Step()) {
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      debug_info += statement.ColumnString(0);
212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      debug_info += '\n';
213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!statement.Succeeded())
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      debug_info += "error\n";
216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // TODO(shess): Think of other things to log.  Not logging the
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // statement text because the backtrace should suffice in most
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // cases.  The database schema is a possibility, but the
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // likelihood of recursive error callbacks makes that risky (same
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // reasoning applies to other data fetched from the database).
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DumpWithoutCrashing2000(debug_info);
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
22690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// TODO(shess): If this proves out, perhaps lift the code out to
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// chrome/browser/diagnostics/sqlite_diagnostics.{h,cc}.
22968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void GenerateDiagnostics(sql::Connection* db,
23068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                         size_t startup_kb,
23168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                         int extended_error) {
23268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int error = (extended_error & 0xFF);
23368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
23468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Infrequently report information about the error up to the crash
23568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // server.
23668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  static const uint64 kReportsPerMillion = 50000;
23768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
23868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Since some/most errors will not resolve themselves, only report
23968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // once per Chrome run.
24068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  static bool reported = false;
24168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (reported)
24268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return;
24368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
24468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  uint64 rand = base::RandGenerator(1000000);
24568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == SQLITE_CORRUPT) {
24668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Once the database is known to be corrupt, it will generate a
24768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // stream of errors until someone fixes it, so give one chance.
24868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Set first in case of errors in generating the report.
24968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    reported = true;
25068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
25168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Corrupt cases currently dominate, report them very infrequently.
25268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    static const uint64 kCorruptReportsPerMillion = 10000;
25368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (rand < kCorruptReportsPerMillion)
25468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ReportCorrupt(db, startup_kb);
25568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else if (error == SQLITE_READONLY) {
25668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // SQLITE_READONLY appears similar to SQLITE_CORRUPT - once it
25768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // is seen, it is almost guaranteed to be seen again.
25868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    reported = true;
25968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
26068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (rand < kReportsPerMillion)
26168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ReportError(db, extended_error);
26268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else {
26368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Only set the flag when making a report.  This should allow
26468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // later (potentially different) errors in a stream of errors to
26568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // be reported.
26668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    //
26768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // TODO(shess): Would it be worthwile to audit for which cases
26868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // want once-only handling?  Sqlite.Error.Thumbnail shows
26968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // CORRUPT and READONLY as almost 95% of all reports on these
27068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // channels, so probably easier to just harvest from the field.
27168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (rand < kReportsPerMillion) {
27268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      reported = true;
27368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ReportError(db, extended_error);
27468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
27568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
27668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
27768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// NOTE(shess): Schema modifications must consider initial creation in
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// |InitImpl()|, recovery in |RecoverDatabaseOrRaze()|, and history pruning in
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// |RetainDataForPageUrls()|.
28168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool InitTables(sql::Connection* db) {
28268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kIconMappingSql[] =
28368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "CREATE TABLE IF NOT EXISTS icon_mapping"
28468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "("
28568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "id INTEGER PRIMARY KEY,"
28668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "page_url LONGVARCHAR NOT NULL,"
28768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "icon_id INTEGER"
28868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ")";
28968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!db->Execute(kIconMappingSql))
29068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
29168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
29268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kFaviconsSql[] =
29368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "CREATE TABLE IF NOT EXISTS favicons"
29468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "("
29568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "id INTEGER PRIMARY KEY,"
29668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "url LONGVARCHAR NOT NULL,"
2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // default icon_type FAVICON to be consistent with past migration.
29868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "icon_type INTEGER DEFAULT 1"
29968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ")";
30068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!db->Execute(kFaviconsSql))
30168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
30268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
30368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kFaviconBitmapsSql[] =
30468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "CREATE TABLE IF NOT EXISTS favicon_bitmaps"
30568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "("
30668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "id INTEGER PRIMARY KEY,"
30768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "icon_id INTEGER NOT NULL,"
30868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "last_updated INTEGER DEFAULT 0,"
30968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "image_data BLOB,"
31068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "width INTEGER DEFAULT 0,"
31168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "height INTEGER DEFAULT 0"
31268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ")";
31368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!db->Execute(kFaviconBitmapsSql))
31468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
31568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
31668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return true;
31768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
31868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// NOTE(shess): Schema modifications must consider initial creation in
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// |InitImpl()|, recovery in |RecoverDatabaseOrRaze()|, and history pruning in
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// |RetainDataForPageUrls()|.
32268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool InitIndices(sql::Connection* db) {
32368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kIconMappingUrlIndexSql[] =
32468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "CREATE INDEX IF NOT EXISTS icon_mapping_page_url_idx"
32568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      " ON icon_mapping(page_url)";
32668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kIconMappingIdIndexSql[] =
32768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "CREATE INDEX IF NOT EXISTS icon_mapping_icon_id_idx"
32868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      " ON icon_mapping(icon_id)";
32968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!db->Execute(kIconMappingUrlIndexSql) ||
33068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      !db->Execute(kIconMappingIdIndexSql)) {
33168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
33268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
33368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
33468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kFaviconsIndexSql[] =
33568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "CREATE INDEX IF NOT EXISTS favicons_url ON favicons(url)";
33668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!db->Execute(kFaviconsIndexSql))
33768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
33868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
33968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kFaviconBitmapsIndexSql[] =
34068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "CREATE INDEX IF NOT EXISTS favicon_bitmaps_icon_id ON "
34168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "favicon_bitmaps(icon_id)";
34268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!db->Execute(kFaviconBitmapsIndexSql))
34368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
34468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
34568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return true;
34668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
34768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
34868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)enum RecoveryEventType {
34968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RECOVERY_EVENT_RECOVERED = 0,
35068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RECOVERY_EVENT_FAILED_SCOPER,
351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_META_VERSION_ERROR,  // obsolete
352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_META_VERSION_NONE,  // obsolete
3534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  RECOVERY_EVENT_FAILED_META_WRONG_VERSION6,  // obsolete
354f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_META_WRONG_VERSION5,  // obsolete
35568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RECOVERY_EVENT_FAILED_META_WRONG_VERSION,
356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_RECOVER_META,  // obsolete
3574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  RECOVERY_EVENT_FAILED_META_INSERT,  // obsolete
35868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RECOVERY_EVENT_FAILED_INIT,
359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_RECOVER_FAVICONS,  // obsolete
360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_FAVICONS_INSERT,  // obsolete
361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_RECOVER_FAVICON_BITMAPS,  // obsolete
362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_FAVICON_BITMAPS_INSERT,  // obsolete
363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_RECOVER_ICON_MAPPING,  // obsolete
364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_ICON_MAPPING_INSERT,  // obsolete
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RECOVERY_EVENT_RECOVERED_VERSION6,  // obsolete
3664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  RECOVERY_EVENT_FAILED_META_INIT,
367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_META_VERSION,
368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_DEPRECATED,
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RECOVERY_EVENT_FAILED_V5_INITSCHEMA,  // obsolete
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RECOVERY_EVENT_FAILED_V5_AUTORECOVER_FAVICONS,  // obsolete
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RECOVERY_EVENT_FAILED_V5_AUTORECOVER_ICON_MAPPING,  // obsolete
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RECOVERY_EVENT_RECOVERED_VERSION5,  // obsolete
373f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICONS,
374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICON_BITMAPS,
375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_AUTORECOVER_ICON_MAPPING,
376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECOVERY_EVENT_FAILED_COMMIT,
37768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
37868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Always keep this at the end.
37968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RECOVERY_EVENT_MAX,
38068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)};
38168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
38268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void RecordRecoveryEvent(RecoveryEventType recovery_event) {
38368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("History.FaviconsRecovery",
38468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                            recovery_event, RECOVERY_EVENT_MAX);
38568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
38668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
38768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Recover the database to the extent possible, razing it if recovery
38868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// is not possible.
38968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// TODO(shess): This is mostly just a safe proof of concept.  In the
39068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// real world, this database is probably not worthwhile recovering, as
39168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// opposed to just razing it and starting over whenever corruption is
39268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// detected.  So this database is a good test subject.
39368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void RecoverDatabaseOrRaze(sql::Connection* db, const base::FilePath& db_path) {
3944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // NOTE(shess): This code is currently specific to the version
3954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // number.  I am working on simplifying things to loosen the
3964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // dependency, meanwhile contact me if you need to bump the version.
3974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_EQ(7, kCurrentVersionNumber);
3984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
39968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // TODO(shess): Reset back after?
40068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  db->reset_error_callback();
40168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
4020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // For histogram purposes.
4030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  size_t favicons_rows_recovered = 0;
4040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  size_t favicon_bitmaps_rows_recovered = 0;
4050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  size_t icon_mapping_rows_recovered = 0;
4060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  int64 original_size = 0;
407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::GetFileSize(db_path, &original_size);
4080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
40968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path);
41068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!recovery) {
41168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // TODO(shess): Unable to create recovery connection.  This
41268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // implies something substantial is wrong.  At this point |db| has
41368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // been poisoned so there is nothing really to do.
41468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    //
41568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Possible responses are unclear.  If the failure relates to a
41668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // problem somehow specific to the temporary file used to back the
41768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // database, then an in-memory database could possibly be used.
41868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // This could potentially allow recovering the main database, and
41968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // might be simple to implement w/in Begin().
42068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_SCOPER);
42168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return;
42268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
42368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
424f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Setup the meta recovery table and fetch the version number from
425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // the corrupt database.
426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int version = 0;
427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!recovery->SetupMeta() || !recovery->GetMetaVersionNumber(&version)) {
428f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // TODO(shess): Prior histograms indicate all failures are in
429f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // creating the recover virtual table for corrupt.meta.  The table
430f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // may not exist, or the database may be too far gone.  Either
431f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // way, unclear how to resolve.
432f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    sql::Recovery::Rollback(recovery.Pass());
433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_VERSION);
434f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This code may be able to fetch version information that the regular
438f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // deprecation path cannot.
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // NOTE(shess): v5 and v6 are currently not deprecated in the normal Init()
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // path, but are deprecated in the recovery path in the interest of keeping
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the code simple.  http://crbug.com/327485 for numbers.
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_LE(kDeprecatedVersionNumber, 6);
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (version <= 6) {
444f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    sql::Recovery::Unrecoverable(recovery.Pass());
445f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    RecordRecoveryEvent(RECOVERY_EVENT_DEPRECATED);
446f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
447f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
448f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Earlier versions have been handled or deprecated, later versions should be
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // impossible.
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (version != 7) {
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    sql::Recovery::Unrecoverable(recovery.Pass());
453f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_WRONG_VERSION);
454f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
455f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
456f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Recover to current schema version.
458f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  sql::MetaTable recover_meta_table;
459f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!recover_meta_table.Init(recovery->db(), kCurrentVersionNumber,
460f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                               kCompatibleVersionNumber)) {
461f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    sql::Recovery::Rollback(recovery.Pass());
462f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_INIT);
463f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
46468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
46568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
46668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Create a fresh version of the database.  The recovery code uses
46768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // conflict-resolution to handle duplicates, so the indices are
46868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // necessary.
46968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!InitTables(recovery->db()) || !InitIndices(recovery->db())) {
47068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // TODO(shess): Unable to create the new schema in the new
47168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // database.  The new database should be a temporary file, so
47268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // being unable to work with it is pretty unclear.
47368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    //
47468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // What are the potential responses, even?  The recovery database
47568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // could be opened as in-memory.  If the temp database had a
47668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // filesystem problem and the temp filesystem differs from the
47768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // main database, then that could fix it.
47868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    sql::Recovery::Rollback(recovery.Pass());
47968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_INIT);
48068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return;
48168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
48268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!recovery->AutoRecoverTable("favicons", 0, &favicons_rows_recovered)) {
484f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    sql::Recovery::Rollback(recovery.Pass());
485f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICONS);
486f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
48768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
488f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!recovery->AutoRecoverTable("favicon_bitmaps", 0,
489f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                  &favicon_bitmaps_rows_recovered)) {
490f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    sql::Recovery::Rollback(recovery.Pass());
491f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICON_BITMAPS);
492f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
49368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
494f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!recovery->AutoRecoverTable("icon_mapping", 0,
495f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                  &icon_mapping_rows_recovered)) {
496f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    sql::Recovery::Rollback(recovery.Pass());
497f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_ICON_MAPPING);
498f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
49968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
50068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
50168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // TODO(shess): Is it possible/likely to have broken foreign-key
50268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // issues with the tables?
50368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // - icon_mapping.icon_id maps to no favicons.id
50468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // - favicon_bitmaps.icon_id maps to no favicons.id
50568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // - favicons.id is referenced by no icon_mapping.icon_id
50668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // - favicons.id is referenced by no favicon_bitmaps.icon_id
50768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // This step is possibly not worth the effort necessary to develop
50868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // and sequence the statements, as it is basically a form of garbage
50968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // collection.
51068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
511f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!sql::Recovery::Recovered(recovery.Pass())) {
512f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_COMMIT);
513f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
514f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
5150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Track the size of the recovered database relative to the size of
5170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // the input database.  The size should almost always be smaller,
5180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // unless the input database was empty to start with.  If the
5190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // percentage results are very low, something is awry.
5200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  int64 final_size = 0;
5210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (original_size > 0 &&
522a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::GetFileSize(db_path, &final_size) &&
5230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      final_size > 0) {
5240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    int percentage = static_cast<int>(original_size * 100 / final_size);
5250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    UMA_HISTOGRAM_PERCENTAGE("History.FaviconsRecoveredPercentage",
5260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                             std::max(100, percentage));
5270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
5280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Using 10,000 because these cases mostly care about "none
5300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // recovered" and "lots recovered".  More than 10,000 rows recovered
5310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // probably means there's something wrong with the profile.
5320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS_10000("History.FaviconsRecoveredRowsFavicons",
5330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                             favicons_rows_recovered);
5340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS_10000("History.FaviconsRecoveredRowsFaviconBitmaps",
5350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                             favicon_bitmaps_rows_recovered);
5360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS_10000("History.FaviconsRecoveredRowsIconMapping",
5370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                             icon_mapping_rows_recovered);
5380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RecordRecoveryEvent(RECOVERY_EVENT_RECOVERED);
54068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
54168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
54290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void DatabaseErrorCallback(sql::Connection* db,
54368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                           const base::FilePath& db_path,
54490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           size_t startup_kb,
545116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           history::HistoryClient* history_client,
54668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                           int extended_error,
54790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           sql::Statement* stmt) {
54890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // TODO(shess): Assert that this is running on a safe thread.
54990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // AFAICT, should be the history thread, but at this level I can't
55090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // see how to reach that.
55190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
552116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (history_client && history_client->ShouldReportDatabaseError()) {
55368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    GenerateDiagnostics(db, startup_kb, extended_error);
55468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
555868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
55668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Attempt to recover corrupt databases.
5570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  int error = (extended_error & 0xFF);
5580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (error == SQLITE_CORRUPT ||
5590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      error == SQLITE_CANTOPEN ||
5600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      error == SQLITE_NOTADB) {
5610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    RecoverDatabaseOrRaze(db, db_path);
56290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
56390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
56490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The default handling is to assert on debug and to ignore on release.
56568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!sql::Connection::ShouldIgnoreSqliteError(extended_error))
56668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    DLOG(FATAL) << db->GetErrorMessage();
56790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
56890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
56990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
57090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace history {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThumbnailDatabase::IconMappingEnumerator::IconMappingEnumerator() {
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThumbnailDatabase::IconMappingEnumerator::~IconMappingEnumerator() {
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::IconMappingEnumerator::GetNextIconMapping(
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IconMapping* icon_mapping) {
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement_.Step())
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillIconMapping(statement_, GURL(statement_.ColumnString(4)), icon_mapping);
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
587116680a4aac90f2aa7413d9095a592090648e557Ben MurdochThumbnailDatabase::ThumbnailDatabase(HistoryClient* history_client)
588116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : history_client_(history_client) {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ThumbnailDatabase::~ThumbnailDatabase() {
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The DBCloseScoper will delete the DB and the cache.
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)sql::InitStatus ThumbnailDatabase::Init(const base::FilePath& db_name) {
5961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // TODO(shess): Consider separating database open from schema setup.
5971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // With that change, this code could Raze() from outside the
5981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // transaction, rather than needing RazeAndClose() in InitImpl().
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Retry failed setup in case the recovery system fixed things.
6011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const size_t kAttempts = 2;
6024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  sql::InitStatus status = sql::INIT_FAILURE;
6041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for (size_t i = 0; i < kAttempts; ++i) {
6051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    status = InitImpl(db_name);
6061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (status == sql::INIT_OK)
6071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return status;
6084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    meta_table_.Reset();
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    db_.Close();
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return status;
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ThumbnailDatabase::ComputeDatabaseMetrics() {
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sql::Statement favicon_count(
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      db_.GetCachedStatement(SQL_FROM_HERE, "SELECT COUNT(*) FROM favicons"));
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_COUNTS_10000(
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "History.NumFaviconsInDB",
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_count.Step() ? favicon_count.ColumnInt(0) : 0);
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThumbnailDatabase::BeginTransaction() {
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.BeginTransaction();
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThumbnailDatabase::CommitTransaction() {
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.CommitTransaction();
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThumbnailDatabase::RollbackTransaction() {
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.RollbackTransaction();
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ThumbnailDatabase::Vacuum() {
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(db_.transaction_nesting() == 0) <<
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Can not have a transaction when vacuuming.";
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ignore_result(db_.Execute("VACUUM"));
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
641ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid ThumbnailDatabase::TrimMemory(bool aggressively) {
642ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  db_.TrimMemory(aggressively);
643ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
644ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::GetFaviconBitmapIDSizes(
6460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID icon_id,
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<FaviconBitmapIDSize>* bitmap_id_sizes) {
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(icon_id);
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT id, width, height FROM favicon_bitmaps WHERE icon_id=?"));
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, icon_id);
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = false;
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (statement.Step()) {
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = true;
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!bitmap_id_sizes)
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return result;
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FaviconBitmapIDSize bitmap_id_size;
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_id_size.bitmap_id = statement.ColumnInt64(0);
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_id_size.pixel_size = gfx::Size(statement.ColumnInt(1),
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          statement.ColumnInt(2));
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_id_sizes->push_back(bitmap_id_size);
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::GetFaviconBitmaps(
6690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID icon_id,
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<FaviconBitmap>* favicon_bitmaps) {
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(icon_id);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT id, last_updated, image_data, width, height FROM favicon_bitmaps "
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE icon_id=?"));
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, icon_id);
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = false;
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (statement.Step()) {
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = true;
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!favicon_bitmaps)
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return result;
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FaviconBitmap favicon_bitmap;
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_bitmap.bitmap_id = statement.ColumnInt64(0);
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_bitmap.icon_id = icon_id;
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_bitmap.last_updated =
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Time::FromInternalValue(statement.ColumnInt64(1));
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (statement.ColumnByteLength(2) > 0) {
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes());
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      statement.ColumnBlobAsVector(2, &data->data());
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_bitmap.bitmap_data = data;
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_bitmap.pixel_size = gfx::Size(statement.ColumnInt(3),
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          statement.ColumnInt(4));
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_bitmaps->push_back(favicon_bitmap);
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::GetFaviconBitmap(
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FaviconBitmapID bitmap_id,
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time* last_updated,
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedMemory>* png_icon_data,
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Size* pixel_size) {
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bitmap_id);
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT last_updated, image_data, width, height FROM favicon_bitmaps "
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE id=?"));
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, bitmap_id);
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Step())
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (last_updated)
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *last_updated = base::Time::FromInternalValue(statement.ColumnInt64(0));
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (png_icon_data && statement.ColumnByteLength(1) > 0) {
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes());
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.ColumnBlobAsVector(1, &data->data());
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *png_icon_data = data;
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pixel_size) {
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *pixel_size = gfx::Size(statement.ColumnInt(2),
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            statement.ColumnInt(3));
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconBitmapID ThumbnailDatabase::AddFaviconBitmap(
7310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID icon_id,
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const scoped_refptr<base::RefCountedMemory>& icon_data,
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time time,
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Size& pixel_size) {
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(icon_id);
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "INSERT INTO favicon_bitmaps (icon_id, image_data, last_updated, width, "
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "height) VALUES (?, ?, ?, ?, ?)"));
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, icon_id);
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (icon_data.get() && icon_data->size()) {
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.BindBlob(1, icon_data->front(),
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       static_cast<int>(icon_data->size()));
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.BindNull(1);
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(2, time.ToInternalValue());
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(3, pixel_size.width());
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(4, pixel_size.height());
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Run())
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return db_.GetLastInsertRowId();
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::SetFaviconBitmap(
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FaviconBitmapID bitmap_id,
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedMemory> bitmap_data,
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time time) {
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bitmap_id);
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "UPDATE favicon_bitmaps SET image_data=?, last_updated=? WHERE id=?"));
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bitmap_data.get() && bitmap_data->size()) {
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.BindBlob(0, bitmap_data->front(),
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       static_cast<int>(bitmap_data->size()));
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.BindNull(0);
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(1, time.ToInternalValue());
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(2, bitmap_id);
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Run();
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ThumbnailDatabase::SetFaviconBitmapLastUpdateTime(
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FaviconBitmapID bitmap_id,
7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Time time) {
7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(bitmap_id);
7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "UPDATE favicon_bitmaps SET last_updated=? WHERE id=?"));
7802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement.BindInt64(0, time.ToInternalValue());
7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement.BindInt64(1, bitmap_id);
7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return statement.Run();
7832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::DeleteFaviconBitmap(FaviconBitmapID bitmap_id) {
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "DELETE FROM favicon_bitmaps WHERE id=?"));
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, bitmap_id);
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Run();
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool ThumbnailDatabase::SetFaviconOutOfDate(favicon_base::FaviconID icon_id) {
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "UPDATE favicon_bitmaps SET last_updated=? WHERE icon_id=?"));
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, 0);
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(1, icon_id);
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Run();
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochfavicon_base::FaviconID ThumbnailDatabase::GetFaviconIDForFaviconURL(
80290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const GURL& icon_url,
80390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int required_icon_type,
8040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType* icon_type) {
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT id, icon_type FROM favicons WHERE url=? AND (icon_type & ? > 0) "
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ORDER BY icon_type DESC"));
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindString(0, URLDatabase::GURLToDatabaseURL(icon_url));
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(1, required_icon_type);
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Step())
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;  // not cached
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (icon_type)
8150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    *icon_type = static_cast<favicon_base::IconType>(statement.ColumnInt(1));
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.ColumnInt64(0);
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool ThumbnailDatabase::GetFaviconHeader(favicon_base::FaviconID icon_id,
82090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         GURL* icon_url,
8210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                         favicon_base::IconType* icon_type) {
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(icon_id);
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
825eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      "SELECT url, icon_type FROM favicons WHERE id=?"));
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, icon_id);
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Step())
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No entry for the id.
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (icon_url)
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *icon_url = GURL(statement.ColumnString(0));
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (icon_type)
8340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    *icon_type = static_cast<favicon_base::IconType>(statement.ColumnInt(1));
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochfavicon_base::FaviconID ThumbnailDatabase::AddFavicon(
84090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const GURL& icon_url,
8410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type) {
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
844eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      "INSERT INTO favicons (url, icon_type) VALUES (?, ?)"));
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindString(0, URLDatabase::GURLToDatabaseURL(icon_url));
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(1, icon_type);
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Run())
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return db_.GetLastInsertRowId();
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochfavicon_base::FaviconID ThumbnailDatabase::AddFavicon(
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url,
8550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const scoped_refptr<base::RefCountedMemory>& icon_data,
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time time,
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Size& pixel_size) {
8590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  favicon_base::FaviconID icon_id = AddFavicon(icon_url, icon_type);
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!icon_id || !AddFaviconBitmap(icon_id, icon_data, time, pixel_size))
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return icon_id;
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool ThumbnailDatabase::DeleteFavicon(favicon_base::FaviconID id) {
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement;
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.Assign(db_.GetCachedStatement(SQL_FROM_HERE,
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "DELETE FROM favicons WHERE id = ?"));
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, id);
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Run())
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.Assign(db_.GetCachedStatement(SQL_FROM_HERE,
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "DELETE FROM favicon_bitmaps WHERE icon_id = ?"));
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, id);
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Run();
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::GetIconMappingsForPageURL(
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int required_icon_types,
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<IconMapping>* filtered_mapping_data) {
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<IconMapping> mapping_data;
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetIconMappingsForPageURL(page_url, &mapping_data))
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = false;
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<IconMapping>::iterator m = mapping_data.begin();
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       m != mapping_data.end(); ++m) {
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (m->icon_type & required_icon_types) {
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = true;
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!filtered_mapping_data)
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return result;
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Restrict icon type of subsequent matches to |m->icon_type|.
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // |m->icon_type| is the largest IconType in |mapping_data| because
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // |mapping_data| is sorted in descending order of IconType.
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      required_icon_types = m->icon_type;
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      filtered_mapping_data->push_back(*m);
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::GetIconMappingsForPageURL(
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<IconMapping>* mapping_data) {
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT icon_mapping.id, icon_mapping.icon_id, favicons.icon_type, "
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "favicons.url "
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "FROM icon_mapping "
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "INNER JOIN favicons "
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ON icon_mapping.icon_id = favicons.id "
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE icon_mapping.page_url=? "
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ORDER BY favicons.icon_type DESC"));
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindString(0, URLDatabase::GURLToDatabaseURL(page_url));
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = false;
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (statement.Step()) {
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = true;
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!mapping_data)
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return result;
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IconMapping icon_mapping;
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FillIconMapping(statement, page_url, &icon_mapping);
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mapping_data->push_back(icon_mapping);
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9330529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochIconMappingID ThumbnailDatabase::AddIconMapping(
9340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const GURL& page_url,
9350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconID icon_id) {
9361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const char kSql[] =
9371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      "INSERT INTO icon_mapping (page_url, icon_id) VALUES (?, ?)";
9381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSql));
9391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  statement.BindString(0, URLDatabase::GURLToDatabaseURL(page_url));
9401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  statement.BindInt64(1, icon_id);
9411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
9421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!statement.Run())
9431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return 0;
9441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
9451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return db_.GetLastInsertRowId();
9461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
9471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::UpdateIconMapping(IconMappingID mapping_id,
9490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                          favicon_base::FaviconID icon_id) {
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "UPDATE icon_mapping SET icon_id=? WHERE id=?"));
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, icon_id);
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(1, mapping_id);
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Run();
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::DeleteIconMappings(const GURL& page_url) {
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "DELETE FROM icon_mapping WHERE page_url = ?"));
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindString(0, URLDatabase::GURLToDatabaseURL(page_url));
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Run();
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::DeleteIconMapping(IconMappingID mapping_id) {
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "DELETE FROM icon_mapping WHERE id=?"));
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, mapping_id);
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Run();
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool ThumbnailDatabase::HasMappingFor(favicon_base::FaviconID id) {
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT id FROM icon_mapping "
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE icon_id=?"));
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, id);
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Step();
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::CloneIconMappings(const GURL& old_page_url,
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          const GURL& new_page_url) {
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT icon_id FROM icon_mapping "
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE page_url=?"));
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.is_valid())
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do nothing if there are existing bindings
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindString(0, URLDatabase::GURLToDatabaseURL(new_page_url));
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (statement.Step())
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.Assign(db_.GetCachedStatement(SQL_FROM_HERE,
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "INSERT INTO icon_mapping (page_url, icon_id) "
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "SELECT ?, icon_id FROM icon_mapping "
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "WHERE page_url = ?"));
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindString(0, URLDatabase::GURLToDatabaseURL(new_page_url));
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindString(1, URLDatabase::GURLToDatabaseURL(old_page_url));
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Run();
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::InitIconMappingEnumerator(
10070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType type,
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IconMappingEnumerator* enumerator) {
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!enumerator->statement_.is_valid());
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enumerator->statement_.Assign(db_.GetCachedStatement(
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SQL_FROM_HERE,
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT icon_mapping.id, icon_mapping.icon_id, favicons.icon_type, "
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             "favicons.url, icon_mapping.page_url "
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         "FROM icon_mapping JOIN favicons ON ("
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              "icon_mapping.icon_id = favicons.id) "
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         "WHERE favicons.icon_type = ?"));
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enumerator->statement_.BindInt(0, type);
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return enumerator->statement_.is_valid();
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool ThumbnailDatabase::RetainDataForPageUrls(
10223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::vector<GURL>& urls_to_keep) {
10233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  sql::Transaction transaction(&db_);
10243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!transaction.Begin())
10253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // temp.icon_id_mapping generates new icon ids as consecutive
10283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // integers starting from 1, and maps them to the old icon ids.
10293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  {
10303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const char kIconMappingCreate[] =
10313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        "CREATE TEMP TABLE icon_id_mapping "
10323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        "("
10333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        "new_icon_id INTEGER PRIMARY KEY,"
10343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        "old_icon_id INTEGER NOT NULL UNIQUE"
10353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ")";
10363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!db_.Execute(kIconMappingCreate))
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Insert the icon ids for retained urls, skipping duplicates.
10403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const char kIconMappingSql[] =
10413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        "INSERT OR IGNORE INTO temp.icon_id_mapping (old_icon_id) "
10423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        "SELECT icon_id FROM icon_mapping WHERE page_url = ?";
10433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    sql::Statement statement(db_.GetUniqueStatement(kIconMappingSql));
10443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    for (std::vector<GURL>::const_iterator
10453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)             i = urls_to_keep.begin(); i != urls_to_keep.end(); ++i) {
10463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      statement.BindString(0, URLDatabase::GURLToDatabaseURL(*i));
10473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (!statement.Run())
10483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return false;
10491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      statement.Reset(true);
10503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kRenameIconMappingTable[] =
105468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "ALTER TABLE icon_mapping RENAME TO old_icon_mapping";
105568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kCopyIconMapping[] =
105668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "INSERT INTO icon_mapping (page_url, icon_id) "
105768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "SELECT old.page_url, mapping.new_icon_id "
105868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "FROM old_icon_mapping AS old "
105968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "JOIN temp.icon_id_mapping AS mapping "
106068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "ON (old.icon_id = mapping.old_icon_id)";
106168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kDropOldIconMappingTable[] = "DROP TABLE old_icon_mapping";
106268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
106368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kRenameFaviconsTable[] =
106468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "ALTER TABLE favicons RENAME TO old_favicons";
106568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kCopyFavicons[] =
106668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "INSERT INTO favicons (id, url, icon_type) "
106768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "SELECT mapping.new_icon_id, old.url, old.icon_type "
106868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "FROM old_favicons AS old "
106968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "JOIN temp.icon_id_mapping AS mapping "
107068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "ON (old.id = mapping.old_icon_id)";
107168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kDropOldFaviconsTable[] = "DROP TABLE old_favicons";
107268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
107368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kRenameFaviconBitmapsTable[] =
107468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "ALTER TABLE favicon_bitmaps RENAME TO old_favicon_bitmaps";
107568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kCopyFaviconBitmaps[] =
107668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "INSERT INTO favicon_bitmaps "
107768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "  (icon_id, last_updated, image_data, width, height) "
107868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "SELECT mapping.new_icon_id, old.last_updated, "
107968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "    old.image_data, old.width, old.height "
108068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "FROM old_favicon_bitmaps AS old "
108168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "JOIN temp.icon_id_mapping AS mapping "
108268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "ON (old.icon_id = mapping.old_icon_id)";
108368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const char kDropOldFaviconBitmapsTable[] =
108468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "DROP TABLE old_favicon_bitmaps";
108568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
108668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Rename existing tables to new location.
108768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!db_.Execute(kRenameIconMappingTable) ||
108868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      !db_.Execute(kRenameFaviconsTable) ||
108968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      !db_.Execute(kRenameFaviconBitmapsTable)) {
109068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
10913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
109368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Initialize the replacement tables.  At this point the old indices
109468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // still exist (pointing to the old_* tables), so do not initialize
109568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // the indices.
109668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!InitTables(&db_))
109768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
109968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Copy all of the data over.
110068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!db_.Execute(kCopyIconMapping) ||
110168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      !db_.Execute(kCopyFavicons) ||
110268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      !db_.Execute(kCopyFaviconBitmaps)) {
110368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
110668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Drop the old_* tables, which also drops the indices.
110768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!db_.Execute(kDropOldIconMappingTable) ||
110868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      !db_.Execute(kDropOldFaviconsTable) ||
110968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      !db_.Execute(kDropOldFaviconBitmapsTable)) {
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
111368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Recreate the indices.
111468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // TODO(shess): UNIQUE indices could fail due to duplication.  This
111568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // could happen in case of corruption.
111668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!InitIndices(&db_))
111768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return false;
111868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
11193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const char kIconMappingDrop[] = "DROP TABLE temp.icon_id_mapping";
11203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!db_.Execute(kIconMappingDrop))
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return transaction.Commit();
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)sql::InitStatus ThumbnailDatabase::OpenDatabase(sql::Connection* db,
11271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                                const base::FilePath& db_name) {
11281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  size_t startup_kb = 0;
11291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int64 size_64;
1130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (base::GetFileSize(db_name, &size_64))
11311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    startup_kb = static_cast<size_t>(size_64 / 1024);
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  db->set_histogram_tag("Thumbnail");
11341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  db->set_error_callback(base::Bind(&DatabaseErrorCallback,
1135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                    db, db_name, startup_kb, history_client_));
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Thumbnails db now only stores favicons, so we don't need that big a page
11381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // size or cache.
11391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  db->set_page_size(2048);
11401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  db->set_cache_size(32);
11411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Run the database in exclusive mode. Nobody else should be accessing the
11431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // database while we're running, and this will give somewhat improved perf.
11441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  db->set_exclusive_locking();
11451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!db->Open(db_name))
11471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return sql::INIT_FAILURE;
11481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return sql::INIT_OK;
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)sql::InitStatus ThumbnailDatabase::InitImpl(const base::FilePath& db_name) {
11531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  sql::InitStatus status = OpenDatabase(&db_, db_name);
11541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (status != sql::INIT_OK)
11551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return status;
11561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Clear databases which are too old to process.
11581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK_LT(kDeprecatedVersionNumber, kCurrentVersionNumber);
11591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  sql::MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersionNumber);
11601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // TODO(shess): Sqlite.Version.Thumbnail shows versions 22, 23, and
11621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // 25.  Future versions are not destroyed because that could lead to
11631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // data loss if the profile is opened by a later channel, but
11641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // perhaps a heuristic like >kCurrentVersionNumber+3 could be used.
11651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Scope initialization in a transaction so we can't be partially initialized.
11671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  sql::Transaction transaction(&db_);
11681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!transaction.Begin())
11691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return sql::INIT_FAILURE;
11701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // TODO(shess): Failing Begin() implies that something serious is
11721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // wrong with the database.  Raze() may be in order.
11731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#if defined(OS_MACOSX)
11751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Exclude the thumbnails file from backups.
11761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::mac::SetFileBackupExclusion(db_name);
11771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#endif
11781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // thumbnails table has been obsolete for a long time, remove any
11801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // detrious.
11811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ignore_result(db_.Execute("DROP TABLE IF EXISTS thumbnails"));
11821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // At some point, operations involving temporary tables weren't done
11841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // atomically and users have been stranded.  Drop those tables and
11851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // move on.
11861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // TODO(shess): Prove it?  Audit all cases and see if it's possible
11871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // that this implies non-atomic update, and should thus be handled
11881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // via the corruption handler.
11891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ignore_result(db_.Execute("DROP TABLE IF EXISTS temp_favicons"));
11901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ignore_result(db_.Execute("DROP TABLE IF EXISTS temp_favicon_bitmaps"));
11911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ignore_result(db_.Execute("DROP TABLE IF EXISTS temp_icon_mapping"));
11921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Create the tables.
11941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!meta_table_.Init(&db_, kCurrentVersionNumber,
11951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                        kCompatibleVersionNumber) ||
11961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      !InitTables(&db_) ||
11971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      !InitIndices(&db_)) {
11981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return sql::INIT_FAILURE;
11991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
12001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Version check. We should not encounter a database too old for us to handle
12021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // in the wild, so we try to continue in that case.
12031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
12041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    LOG(WARNING) << "Thumbnail database is too new.";
12051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return sql::INIT_TOO_NEW;
12061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
12071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int cur_version = meta_table_.GetVersionNumber();
12091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!db_.DoesColumnExist("favicons", "icon_type")) {
12111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    LOG(ERROR) << "Raze because of missing favicon.icon_type";
12121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    RecordInvalidStructure(STRUCTURE_EVENT_VERSION4);
12131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    db_.RazeAndClose();
12151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return sql::INIT_FAILURE;
12161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
12171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (cur_version < 7 && !db_.DoesColumnExist("favicons", "sizes")) {
12191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    LOG(ERROR) << "Raze because of missing favicon.sizes";
12201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    RecordInvalidStructure(STRUCTURE_EVENT_VERSION5);
12211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    db_.RazeAndClose();
12231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return sql::INIT_FAILURE;
12241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
12251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (cur_version == 5) {
12271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    ++cur_version;
12281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (!UpgradeToVersion6())
12291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return CantUpgradeToVersion(cur_version);
12301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
12311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (cur_version == 6) {
12331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    ++cur_version;
12341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (!UpgradeToVersion7())
12351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return CantUpgradeToVersion(cur_version);
12361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
12371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  LOG_IF(WARNING, cur_version < kCurrentVersionNumber) <<
12391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      "Thumbnail database version " << cur_version << " is too old to handle.";
12401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Initialization is complete.
12421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!transaction.Commit())
12431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return sql::INIT_FAILURE;
12441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Raze the database if the structure of the favicons database is not what
12461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // it should be. This error cannot be detected via the SQL error code because
12471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // the error code for running SQL statements against a database with missing
12481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // columns is SQLITE_ERROR which is not unique enough to act upon.
12491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // TODO(pkotwicz): Revisit this in M27 and see if the razing can be removed.
12501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // (crbug.com/166453)
12511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (IsFaviconDBStructureIncorrect()) {
12521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    LOG(ERROR) << "Raze because of invalid favicon db structure.";
12531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    RecordInvalidStructure(STRUCTURE_EVENT_FAVICON);
12541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    db_.RazeAndClose();
12561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return sql::INIT_FAILURE;
12571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
12581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return sql::INIT_OK;
12601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
12611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
12621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)sql::InitStatus ThumbnailDatabase::CantUpgradeToVersion(int cur_version) {
12631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  LOG(WARNING) << "Unable to update to thumbnail database to version " <<
12641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)               cur_version << ".";
12651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  db_.Close();
12661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return sql::INIT_FAILURE;
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ThumbnailDatabase::UpgradeToVersion6() {
12704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Move bitmap data from favicons to favicon_bitmaps.
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success =
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.Execute("INSERT INTO favicon_bitmaps (icon_id, last_updated, "
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "image_data, width, height)"
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "SELECT id, last_updated, image_data, 0, 0 FROM favicons") &&
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.Execute("CREATE TABLE temp_favicons ("
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "id INTEGER PRIMARY KEY,"
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "url LONGVARCHAR NOT NULL,"
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "icon_type INTEGER DEFAULT 1,"
12794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                  // default icon_type FAVICON to be consistent with
12804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                  // past migration.
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "sizes LONGVARCHAR)") &&
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.Execute("INSERT INTO temp_favicons (id, url, icon_type) "
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "SELECT id, url, icon_type FROM favicons") &&
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.Execute("DROP TABLE favicons") &&
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_.Execute("ALTER TABLE temp_favicons RENAME TO favicons");
12861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // NOTE(shess): v7 will re-create the index.
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!success)
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  meta_table_.SetVersionNumber(6);
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  meta_table_.SetCompatibleVersionNumber(std::min(6, kCompatibleVersionNumber));
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ThumbnailDatabase::UpgradeToVersion7() {
12964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Sizes column was never used, remove it.
1297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool success =
1298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      db_.Execute("CREATE TABLE temp_favicons ("
1299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  "id INTEGER PRIMARY KEY,"
1300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  "url LONGVARCHAR NOT NULL,"
13014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                  // default icon_type FAVICON to be consistent with
13024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                  // past migration.
1303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  "icon_type INTEGER DEFAULT 1)") &&
1304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      db_.Execute("INSERT INTO temp_favicons (id, url, icon_type) "
1305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  "SELECT id, url, icon_type FROM favicons") &&
1306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      db_.Execute("DROP TABLE favicons") &&
1307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      db_.Execute("ALTER TABLE temp_favicons RENAME TO favicons") &&
1308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      db_.Execute("CREATE INDEX IF NOT EXISTS favicons_url ON favicons(url)");
1309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!success)
1311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  meta_table_.SetVersionNumber(7);
1314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  meta_table_.SetCompatibleVersionNumber(std::min(7, kCompatibleVersionNumber));
1315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool ThumbnailDatabase::IsFaviconDBStructureIncorrect() {
13191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return !db_.IsSQLValid("SELECT id, url, icon_type FROM favicons");
13201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
13211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace history
1323