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