summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-08 16:19:24 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-08 16:19:24 +0000
commit5f104d769c8c1302eaffec131d201eae8849570f (patch)
tree8775de80988147495a6dd8654fbdf0bb854daccd /chrome
parent59c50a33c4961750f3d47cce47f67f243527390d (diff)
downloadchromium_src-5f104d769c8c1302eaffec131d201eae8849570f.zip
chromium_src-5f104d769c8c1302eaffec131d201eae8849570f.tar.gz
chromium_src-5f104d769c8c1302eaffec131d201eae8849570f.tar.bz2
Lands http://code.google.com/p/chromium/issues/detail?id=71571 for
Moved the page and icon mapping from URLDatabase to ThumbnailDatabase. a. Created a new table icon_mappings in ThumbnailDatabase. b. Migrated the mapping data during the upgrade. c. Provided the new interface to access the icon_mapping data. d. Removed the API to access the faviconID field in url database. Support IconType. a. Added additional column icon_type in favicons table. b. Provided the APIs to access the icon_type field. c. Currently hard-code all icon_type as FAV_ICON in history backend. BUG=71571 TEST=new testcases in thumbnail_database_unittest.cc, and the existent tests in history_backend_unittest.cc, history_unitest.cc, bookmark_html_writer_unittest.cc etc. Review URL: http://codereview.chromium.org/6620001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77288 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/history/expire_history_backend.cc21
-rw-r--r--chrome/browser/history/expire_history_backend_unittest.cc62
-rw-r--r--chrome/browser/history/history.cc9
-rw-r--r--chrome/browser/history/history_backend.cc186
-rw-r--r--chrome/browser/history/history_backend.h40
-rw-r--r--chrome/browser/history/history_backend_unittest.cc181
-rw-r--r--chrome/browser/history/history_database.cc2
-rw-r--r--chrome/browser/history/history_database.h1
-rw-r--r--chrome/browser/history/history_types.cc13
-rw-r--r--chrome/browser/history/history_types.h37
-rw-r--r--chrome/browser/history/history_unittest_base.cc39
-rw-r--r--chrome/browser/history/history_unittest_base.h33
-rw-r--r--chrome/browser/history/thumbnail_database.cc250
-rw-r--r--chrome/browser/history/thumbnail_database.h105
-rw-r--r--chrome/browser/history/thumbnail_database_unittest.cc369
-rw-r--r--chrome/browser/history/top_sites_unittest.cc34
-rw-r--r--chrome/browser/history/url_database.cc72
-rw-r--r--chrome/browser/history/url_database.h52
-rw-r--r--chrome/browser/history/url_database_unittest.cc58
-rw-r--r--chrome/browser/history/visit_database_unittest.cc1
-rw-r--r--chrome/browser/importer/importer_messages.h4
-rw-r--r--chrome/chrome_tests.gypi2
-rw-r--r--chrome/test/data/History/history.20.sql11
-rw-r--r--chrome/test/data/History/thumbnails.3.sql9
-rw-r--r--chrome/test/data/profiles/typical_history/Default/Faviconsbin20480 -> 10240 bytes
-rw-r--r--chrome/test/data/profiles/typical_history/Default/Historybin13725696 -> 13869056 bytes
26 files changed, 1347 insertions, 244 deletions
diff --git a/chrome/browser/history/expire_history_backend.cc b/chrome/browser/history/expire_history_backend.cc
index 62aa7e5..e160635 100644
--- a/chrome/browser/history/expire_history_backend.cc
+++ b/chrome/browser/history/expire_history_backend.cc
@@ -317,12 +317,12 @@ void ExpireHistoryBackend::StartArchivingOldStuff(
void ExpireHistoryBackend::DeleteFaviconsIfPossible(
const std::set<FavIconID>& favicon_set) {
- if (!main_db_ || !thumb_db_)
+ if (!thumb_db_)
return;
for (std::set<FavIconID>::const_iterator i = favicon_set.begin();
i != favicon_set.end(); ++i) {
- if (!main_db_->IsFavIconUsed(*i))
+ if (!thumb_db_->HasMappingFor(*i))
thumb_db_->DeleteFavIcon(*i);
}
}
@@ -408,13 +408,20 @@ void ExpireHistoryBackend::DeleteOneURL(
dependencies->deleted_urls.push_back(url_row);
// Delete stuff that references this URL.
- if (thumb_db_)
+ if (thumb_db_) {
thumb_db_->DeleteThumbnail(url_row.id());
- // Collect shared information.
- if (url_row.favicon_id())
- dependencies->affected_favicons.insert(url_row.favicon_id());
-
+ // Collect shared information.
+ std::vector<IconMapping> icon_mappings;
+ if (thumb_db_->GetIconMappingsForPageURL(url_row.url(), &icon_mappings)) {
+ for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
+ m != icon_mappings.end(); ++m) {
+ dependencies->affected_favicons.insert(m->icon_id);
+ }
+ // Delete the mapping entries for the url.
+ thumb_db_->DeleteIconMappings(url_row.url());
+ }
+ }
// Last, delete the URL entry.
main_db_->DeleteURLRow(url_row.id());
}
diff --git a/chrome/browser/history/expire_history_backend_unittest.cc b/chrome/browser/history/expire_history_backend_unittest.cc
index cf080a8..5e53484 100644
--- a/chrome/browser/history/expire_history_backend_unittest.cc
+++ b/chrome/browser/history/expire_history_backend_unittest.cc
@@ -68,6 +68,8 @@ class ExpireHistoryTest : public testing::Test,
bool HasFavIcon(FavIconID favicon_id);
bool HasThumbnail(URLID url_id);
+ FavIconID GetFavIcon(const GURL& page_url, IconType icon_type);
+
// Returns the number of text matches for the given URL in the example data
// added by AddExampleData.
int CountTextMatchesForURL(const GURL& url);
@@ -137,7 +139,7 @@ class ExpireHistoryTest : public testing::Test,
FilePath thumb_name = path().Append(kThumbnailFile);
thumb_db_.reset(new ThumbnailDatabase);
- if (thumb_db_->Init(thumb_name, NULL) != sql::INIT_OK)
+ if (thumb_db_->Init(thumb_name, NULL, main_db_.get()) != sql::INIT_OK)
thumb_db_.reset();
text_db_.reset(new TextDatabaseManager(path(),
@@ -198,28 +200,30 @@ void ExpireHistoryTest::AddExampleData(URLID url_ids[3], Time visit_times[4]) {
// Two favicons. The first two URLs will share the same one, while the last
// one will have a unique favicon.
- FavIconID favicon1 = thumb_db_->AddFavIcon(GURL("http://favicon/url1"));
- FavIconID favicon2 = thumb_db_->AddFavIcon(GURL("http://favicon/url2"));
+ FavIconID favicon1 = thumb_db_->AddFavIcon(GURL("http://favicon/url1"),
+ FAV_ICON);
+ FavIconID favicon2 = thumb_db_->AddFavIcon(GURL("http://favicon/url2"),
+ FAV_ICON);
// Three URLs.
URLRow url_row1(GURL("http://www.google.com/1"));
url_row1.set_last_visit(visit_times[0]);
- url_row1.set_favicon_id(favicon1);
url_row1.set_visit_count(1);
url_ids[0] = main_db_->AddURL(url_row1);
+ thumb_db_->AddIconMapping(url_row1.url(), favicon1);
URLRow url_row2(GURL("http://www.google.com/2"));
url_row2.set_last_visit(visit_times[2]);
- url_row2.set_favicon_id(favicon1);
url_row2.set_visit_count(2);
url_row2.set_typed_count(1);
url_ids[1] = main_db_->AddURL(url_row2);
+ thumb_db_->AddIconMapping(url_row2.url(), favicon1);
URLRow url_row3(GURL("http://www.google.com/3"));
url_row3.set_last_visit(visit_times[3]);
- url_row3.set_favicon_id(favicon2);
url_row3.set_visit_count(1);
url_ids[2] = main_db_->AddURL(url_row3);
+ thumb_db_->AddIconMapping(url_row3.url(), favicon2);
// Thumbnails for each URL.
scoped_ptr<SkBitmap> thumbnail(
@@ -307,7 +311,7 @@ void ExpireHistoryTest::AddExampleSourceData(const GURL& url, URLID* id) {
}
bool ExpireHistoryTest::HasFavIcon(FavIconID favicon_id) {
- if (!thumb_db_.get())
+ if (!thumb_db_.get() || favicon_id == 0)
return false;
Time last_updated;
std::vector<unsigned char> icon_data_unused;
@@ -316,6 +320,13 @@ bool ExpireHistoryTest::HasFavIcon(FavIconID favicon_id) {
&icon_url);
}
+FavIconID ExpireHistoryTest::GetFavIcon(const GURL& page_url,
+ IconType icon_type) {
+ IconMapping icon_mapping;
+ thumb_db_->GetIconMappingForPageURL(page_url, icon_type, &icon_mapping);
+ return icon_mapping.icon_id;
+}
+
bool ExpireHistoryTest::HasThumbnail(URLID url_id) {
// TODO(sky): fix this. This test isn't really valid for TopSites. For
// TopSites we should be checking URL always, not the id.
@@ -402,7 +413,7 @@ void ExpireHistoryTest::EnsureURLInfoGone(const URLRow& row) {
TEST_F(ExpireHistoryTest, DeleteFaviconsIfPossible) {
// Add a favicon record.
const GURL favicon_url("http://www.google.com/favicon.ico");
- FavIconID icon_id = thumb_db_->AddFavIcon(favicon_url);
+ FavIconID icon_id = thumb_db_->AddFavIcon(favicon_url, FAV_ICON);
EXPECT_TRUE(icon_id);
EXPECT_TRUE(HasFavIcon(icon_id));
@@ -413,15 +424,15 @@ TEST_F(ExpireHistoryTest, DeleteFaviconsIfPossible) {
EXPECT_FALSE(HasFavIcon(icon_id));
// Add back the favicon.
- icon_id = thumb_db_->AddFavIcon(favicon_url);
+ icon_id = thumb_db_->AddFavIcon(favicon_url, TOUCH_ICON);
EXPECT_TRUE(icon_id);
EXPECT_TRUE(HasFavIcon(icon_id));
// Add a page that references the favicon.
URLRow row(GURL("http://www.google.com/2"));
row.set_visit_count(1);
- row.set_favicon_id(icon_id);
EXPECT_TRUE(main_db_->AddURL(row));
+ thumb_db_->AddIconMapping(row.url(), icon_id);
// Favicon should not be deletable.
favicon_set.clear();
@@ -449,7 +460,8 @@ TEST_F(ExpireHistoryTest, FLAKY_DeleteURLAndFavicon) {
// Verify things are the way we expect with a URL row, favicon, thumbnail.
URLRow last_row;
ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &last_row));
- EXPECT_TRUE(HasFavIcon(last_row.favicon_id()));
+ FavIconID fav_icon_id = GetFavIcon(last_row.url(), FAV_ICON);
+ EXPECT_TRUE(HasFavIcon(fav_icon_id));
// TODO(sky): fix this, see comment in HasThumbnail.
// EXPECT_TRUE(HasThumbnail(url_ids[2]));
@@ -498,7 +510,8 @@ TEST_F(ExpireHistoryTest, FLAKY_DeleteURLAndFavicon) {
// All the normal data + the favicon should be gone.
EnsureURLInfoGone(last_row);
- EXPECT_FALSE(HasFavIcon(last_row.favicon_id()));
+ EXPECT_FALSE(GetFavIcon(last_row.url(), FAV_ICON));
+ EXPECT_FALSE(HasFavIcon(fav_icon_id));
}
// Deletes a URL with a favicon that other URLs reference, so that the favicon
@@ -511,7 +524,8 @@ TEST_F(ExpireHistoryTest, DeleteURLWithoutFavicon) {
// Verify things are the way we expect with a URL row, favicon, thumbnail.
URLRow last_row;
ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &last_row));
- EXPECT_TRUE(HasFavIcon(last_row.favicon_id()));
+ FavIconID fav_icon_id = GetFavIcon(last_row.url(), FAV_ICON);
+ EXPECT_TRUE(HasFavIcon(fav_icon_id));
// TODO(sky): fix this, see comment in HasThumbnail.
// EXPECT_TRUE(HasThumbnail(url_ids[1]));
@@ -525,7 +539,7 @@ TEST_F(ExpireHistoryTest, DeleteURLWithoutFavicon) {
// All the normal data + the favicon should be gone.
EnsureURLInfoGone(last_row);
- EXPECT_TRUE(HasFavIcon(last_row.favicon_id()));
+ EXPECT_TRUE(HasFavIcon(fav_icon_id));
}
// DeleteURL should not delete starred urls.
@@ -548,7 +562,8 @@ TEST_F(ExpireHistoryTest, DontDeleteStarredURL) {
ASSERT_TRUE(main_db_->GetRowForURL(url, &url_row));
// And the favicon should exist.
- EXPECT_TRUE(HasFavIcon(url_row.favicon_id()));
+ FavIconID fav_icon_id = GetFavIcon(url_row.url(), FAV_ICON);
+ EXPECT_TRUE(HasFavIcon(fav_icon_id));
// But there should be no fts.
ASSERT_EQ(0, CountTextMatchesForURL(url_row.url()));
@@ -617,13 +632,15 @@ TEST_F(ExpireHistoryTest, FlushRecentURLsUnstarred) {
EXPECT_EQ(0, temp_row.typed_count());
// Verify that the middle URL's favicon and thumbnail is still there.
- EXPECT_TRUE(HasFavIcon(url_row1.favicon_id()));
+ FavIconID fav_icon_id = GetFavIcon(url_row1.url(), FAV_ICON);
+ EXPECT_TRUE(HasFavIcon(fav_icon_id));
// TODO(sky): fix this, see comment in HasThumbnail.
// EXPECT_TRUE(HasThumbnail(url_row1.id()));
// Verify that the last URL was deleted.
+ FavIconID fav_icon_id2 = GetFavIcon(url_row2.url(), FAV_ICON);
EnsureURLInfoGone(url_row2);
- EXPECT_FALSE(HasFavIcon(url_row2.favicon_id()));
+ EXPECT_FALSE(HasFavIcon(fav_icon_id2));
}
// Expires only a specific URLs more recent than a given time, with no starred
@@ -674,13 +691,14 @@ TEST_F(ExpireHistoryTest, FlushRecentURLsUnstarredRestricted) {
EXPECT_EQ(0, temp_row.typed_count());
// Verify that the middle URL's favicon and thumbnail is still there.
- EXPECT_TRUE(HasFavIcon(url_row1.favicon_id()));
+ FavIconID fav_icon_id = GetFavIcon(url_row1.url(), FAV_ICON);
+ EXPECT_TRUE(HasFavIcon(fav_icon_id));
// TODO(sky): fix this, see comment in HasThumbnail.
// EXPECT_TRUE(HasThumbnail(url_row1.id()));
// Verify that the last URL was not touched.
EXPECT_TRUE(main_db_->GetURLRow(url_ids[2], &temp_row));
- EXPECT_TRUE(HasFavIcon(url_row2.favicon_id()));
+ EXPECT_TRUE(HasFavIcon(fav_icon_id));
// TODO(sky): fix this, see comment in HasThumbnail.
// EXPECT_TRUE(HasThumbnail(url_row2.id()));
}
@@ -722,10 +740,12 @@ TEST_F(ExpireHistoryTest, FlushRecentURLsStarred) {
// that may have been updated since the time threshold. Since the URL still
// exists in history, this should not be a privacy problem, we only update
// the visit counts in this case for consistency anyway.
- EXPECT_TRUE(HasFavIcon(new_url_row1.favicon_id()));
+ FavIconID fav_icon_id = GetFavIcon(url_row1.url(), FAV_ICON);
+ EXPECT_TRUE(HasFavIcon(fav_icon_id));
// TODO(sky): fix this, see comment in HasThumbnail.
// EXPECT_TRUE(HasThumbnail(new_url_row1.id()));
- EXPECT_TRUE(HasFavIcon(new_url_row2.favicon_id()));
+ fav_icon_id = GetFavIcon(url_row1.url(), FAV_ICON);
+ EXPECT_TRUE(HasFavIcon(fav_icon_id));
// TODO(sky): fix this, see comment in HasThumbnail.
// EXPECT_TRUE(HasThumbnail(new_url_row2.id()));
}
diff --git a/chrome/browser/history/history.cc b/chrome/browser/history/history.cc
index 4bbf6a8..d74e889 100644
--- a/chrome/browser/history/history.cc
+++ b/chrome/browser/history/history.cc
@@ -451,7 +451,7 @@ HistoryService::Handle HistoryService::GetPageThumbnail(
void HistoryService::GetFavicon(FaviconService::GetFaviconRequest* request,
const GURL& icon_url) {
Schedule(PRIORITY_NORMAL, &HistoryBackend::GetFavIcon, NULL, request,
- icon_url);
+ icon_url, history::FAV_ICON);
}
void HistoryService::UpdateFaviconMappingAndFetch(
@@ -459,14 +459,14 @@ void HistoryService::UpdateFaviconMappingAndFetch(
const GURL& page_url,
const GURL& icon_url) {
Schedule(PRIORITY_NORMAL, &HistoryBackend::UpdateFavIconMappingAndFetch, NULL,
- request, page_url, icon_url);
+ request, page_url, icon_url, history::FAV_ICON);
}
void HistoryService::GetFaviconForURL(
FaviconService::GetFaviconRequest* request,
const GURL& page_url) {
Schedule(PRIORITY_NORMAL, &HistoryBackend::GetFavIconForURL, NULL, request,
- page_url);
+ page_url, history::FAV_ICON);
}
void HistoryService::SetFavicon(const GURL& page_url,
@@ -477,7 +477,8 @@ void HistoryService::SetFavicon(const GURL& page_url,
ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetFavIcon,
page_url, icon_url,
- scoped_refptr<RefCountedMemory>(new RefCountedBytes(image_data)));
+ scoped_refptr<RefCountedMemory>(new RefCountedBytes(image_data)),
+ history::FAV_ICON);
}
void HistoryService::SetFaviconOutOfDateForPage(const GURL& page_url) {
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index dd7bb12..015991a 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -588,7 +588,8 @@ void HistoryBackend::InitImpl(const std::string& languages) {
thumbnail_name = GetFaviconsFileName();
}
if (thumbnail_db_->Init(thumbnail_name,
- history_publisher_.get()) != sql::INIT_OK) {
+ history_publisher_.get(),
+ db_.get()) != sql::INIT_OK) {
// Unlike the main database, we don't error out when the database is too
// new because this error is much less severe. Generally, this shouldn't
// happen since the thumbnail and main datbase versions should be in sync.
@@ -1600,27 +1601,31 @@ bool HistoryBackend::GetThumbnailFromOlderRedirect(
}
void HistoryBackend::GetFavIcon(scoped_refptr<GetFavIconRequest> request,
- const GURL& icon_url) {
- UpdateFavIconMappingAndFetchImpl(NULL, icon_url, request);
+ const GURL& icon_url,
+ int icon_types) {
+ UpdateFavIconMappingAndFetchImpl(NULL, icon_url, request, icon_types);
}
void HistoryBackend::UpdateFavIconMappingAndFetch(
scoped_refptr<GetFavIconRequest> request,
const GURL& page_url,
- const GURL& icon_url) {
- UpdateFavIconMappingAndFetchImpl(&page_url, icon_url, request);
+ const GURL& icon_url,
+ IconType icon_type) {
+ UpdateFavIconMappingAndFetchImpl(&page_url, icon_url, request, icon_type);
}
void HistoryBackend::SetFavIconOutOfDateForPage(const GURL& page_url) {
- if (!thumbnail_db_.get() || !db_.get())
- return;
+ std::vector<IconMapping> icon_mappings;
- URLRow url_row;
- URLID url_id = db_->GetRowForURL(page_url, &url_row);
- if (!url_id || !url_row.favicon_id())
+ if (!thumbnail_db_.get() ||
+ !thumbnail_db_->GetIconMappingsForPageURL(page_url,
+ &icon_mappings))
return;
- thumbnail_db_->SetFavIconLastUpdateTime(url_row.favicon_id(), Time());
+ for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
+ m != icon_mappings.end(); ++m) {
+ thumbnail_db_->SetFavIconLastUpdateTime(m->icon_id, Time());
+ }
ScheduleCommit();
}
@@ -1636,10 +1641,11 @@ void HistoryBackend::SetImportedFavicons(
for (size_t i = 0; i < favicon_usage.size(); i++) {
FavIconID favicon_id = thumbnail_db_->GetFavIconIDForFavIconURL(
- favicon_usage[i].favicon_url);
+ favicon_usage[i].favicon_url, history::FAV_ICON, NULL);
if (!favicon_id) {
// This favicon doesn't exist yet, so we create it using the given data.
- favicon_id = thumbnail_db_->AddFavIcon(favicon_usage[i].favicon_url);
+ favicon_id = thumbnail_db_->AddFavIcon(favicon_usage[i].favicon_url,
+ history::FAV_ICON);
if (!favicon_id)
continue; // Unable to add the favicon.
thumbnail_db_->SetFavIcon(favicon_id,
@@ -1663,16 +1669,17 @@ void HistoryBackend::SetImportedFavicons(
url_info.set_typed_count(0);
url_info.set_last_visit(base::Time());
url_info.set_hidden(false);
- url_info.set_favicon_id(favicon_id);
db_->AddURL(url_info);
+ thumbnail_db_->AddIconMapping(*url, favicon_id);
+ favicons_changed.insert(*url);
+ }
+ } else {
+ if (!thumbnail_db_->GetIconMappingForPageURL(*url, FAV_ICON, NULL)) {
+ // URL is present in history, update the favicon *only* if it is not
+ // set already.
+ thumbnail_db_->AddIconMapping(*url, favicon_id);
favicons_changed.insert(*url);
}
- } else if (url_row.favicon_id() == 0) {
- // URL is present in history, update the favicon *only* if it
- // is not set already.
- url_row.set_favicon_id(favicon_id);
- db_->UpdateURLRow(url_row.id(), url_row);
- favicons_changed.insert(*url);
}
}
}
@@ -1688,7 +1695,12 @@ void HistoryBackend::SetImportedFavicons(
void HistoryBackend::UpdateFavIconMappingAndFetchImpl(
const GURL* page_url,
const GURL& icon_url,
- scoped_refptr<GetFavIconRequest> request) {
+ scoped_refptr<GetFavIconRequest> request,
+ int icon_types) {
+ // Check only a single type was given when the page_url was specified.
+ DCHECK(!page_url || (page_url && (icon_types == FAV_ICON ||
+ icon_types == TOUCH_ICON || icon_types == TOUCH_PRECOMPOSED_ICON)));
+
if (request->canceled())
return;
@@ -1697,8 +1709,10 @@ void HistoryBackend::UpdateFavIconMappingAndFetchImpl(
scoped_refptr<RefCountedBytes> data;
if (thumbnail_db_.get()) {
+ IconType returned_icon_type;
const FavIconID favicon_id =
- thumbnail_db_->GetFavIconIDForFavIconURL(icon_url);
+ thumbnail_db_->GetFavIconIDForFavIconURL(
+ icon_url, icon_types, &returned_icon_type);
if (favicon_id) {
data = new RefCountedBytes;
know_favicon = true;
@@ -1710,7 +1724,7 @@ void HistoryBackend::UpdateFavIconMappingAndFetchImpl(
}
if (page_url)
- SetFavIconMapping(*page_url, favicon_id);
+ SetFavIconMapping(*page_url, favicon_id, returned_icon_type);
}
// else case, haven't cached entry yet. Caller is responsible for
// downloading the favicon and invoking SetFavIcon.
@@ -1722,7 +1736,8 @@ void HistoryBackend::UpdateFavIconMappingAndFetchImpl(
void HistoryBackend::GetFavIconForURL(
scoped_refptr<GetFavIconRequest> request,
- const GURL& page_url) {
+ const GURL& page_url,
+ int icon_types) {
if (request->canceled())
return;
@@ -1736,11 +1751,12 @@ void HistoryBackend::GetFavIconForURL(
// Time the query.
TimeTicks beginning_time = TimeTicks::Now();
- URLRow url_info;
+ std::vector<IconMapping> icon_mappings;
data = new RefCountedBytes;
Time last_updated;
- if (db_->GetRowForURL(page_url, &url_info) && url_info.favicon_id() &&
- thumbnail_db_->GetFavIcon(url_info.favicon_id(), &last_updated,
+ if (thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings) &&
+ (icon_mappings.front().icon_type & icon_types) &&
+ thumbnail_db_->GetFavIcon(icon_mappings.front().icon_id, &last_updated,
&data->data, &icon_url)) {
know_favicon = true;
expired = (Time::Now() - last_updated) >
@@ -1759,23 +1775,29 @@ void HistoryBackend::GetFavIconForURL(
void HistoryBackend::SetFavIcon(
const GURL& page_url,
const GURL& icon_url,
- scoped_refptr<RefCountedMemory> data) {
+ scoped_refptr<RefCountedMemory> data,
+ IconType icon_type) {
DCHECK(data.get());
if (!thumbnail_db_.get() || !db_.get())
return;
- FavIconID id = thumbnail_db_->GetFavIconIDForFavIconURL(icon_url);
+ FavIconID id = thumbnail_db_->GetFavIconIDForFavIconURL(
+ icon_url, icon_type, NULL);
if (!id)
- id = thumbnail_db_->AddFavIcon(icon_url);
+ id = thumbnail_db_->AddFavIcon(icon_url, icon_type);
// Set the image data.
thumbnail_db_->SetFavIcon(id, data, Time::Now());
- SetFavIconMapping(page_url, id);
+ SetFavIconMapping(page_url, id, icon_type);
}
void HistoryBackend::SetFavIconMapping(const GURL& page_url,
- FavIconID id) {
+ FavIconID id,
+ IconType icon_type) {
+ if (!thumbnail_db_.get())
+ return;
+
// Find all the pages whose favicons we should set, we want to set it for
// all the pages in the redirect chain if it redirected.
history::RedirectList dummy_list;
@@ -1799,27 +1821,18 @@ void HistoryBackend::SetFavIconMapping(const GURL& page_url,
// Save page <-> favicon association.
for (history::RedirectList::const_iterator i(redirects->begin());
i != redirects->end(); ++i) {
- URLRow row;
- if (!db_->GetRowForURL(*i, &row) || row.favicon_id() == id)
- continue;
-
- FavIconID old_id = row.favicon_id();
- if (old_id == id)
- continue;
- row.set_favicon_id(id);
- db_->UpdateURLRow(row.id(), row);
-
- if (old_id) {
+ FavIconID replaced_id;
+ if (AddOrUpdateIconMapping(*i, id, icon_type, &replaced_id)) {
// The page's favicon ID changed. This means that the one we just
// changed from could have been orphaned, and we need to re-check it.
// This is not super fast, but this case will get triggered rarely,
// since normally a page will always map to the same favicon ID. It
// will mostly happen for favicons we import.
- if (!db_->IsFavIconUsed(old_id) && thumbnail_db_.get())
- thumbnail_db_->DeleteFavIcon(old_id);
- }
+ if (replaced_id && !thumbnail_db_->HasMappingFor(replaced_id))
+ thumbnail_db_->DeleteFavIcon(replaced_id);
- favicons_changed.insert(row.url());
+ favicons_changed.insert(*i);
+ }
}
// Send the notification about the changed favicons.
@@ -1830,6 +1843,43 @@ void HistoryBackend::SetFavIconMapping(const GURL& page_url,
ScheduleCommit();
}
+bool HistoryBackend::AddOrUpdateIconMapping(const GURL& page_url,
+ FavIconID id,
+ IconType icon_type,
+ FavIconID* replaced_icon) {
+ *replaced_icon = 0;
+ std::vector<IconMapping> icon_mappings;
+ if (!thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings)) {
+ // There is no mapping add it directly.
+ thumbnail_db_->AddIconMapping(page_url, id);
+ return true;
+ }
+ // Iterate all matched icon mappings,
+ // a. If the given icon id and matched icon id are same, return.
+ // b. If the given icon type and matched icon type are same, but icon id
+ // are not, update the IconMapping.
+ // c. If the given icon_type and matched icon type are not same, but
+ // either of them is ICON_TOUCH or ICON_PRECOMPOSED_TOUCH, update the
+ // IconMapping.
+ // d. Otherwise add a icon mapping.
+ for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
+ m != icon_mappings.end(); ++m) {
+ if (m->icon_id == id)
+ // The mapping is already there.
+ return false;
+
+ if ((icon_type == TOUCH_ICON && m->icon_type == TOUCH_PRECOMPOSED_ICON) ||
+ (icon_type == TOUCH_PRECOMPOSED_ICON && m->icon_type == TOUCH_ICON) ||
+ (icon_type == m->icon_type)) {
+ thumbnail_db_->UpdateIconMapping(m->mapping_id, id);
+ *replaced_icon = m->icon_id;
+ return true;
+ }
+ }
+ thumbnail_db_->AddIconMapping(page_url, id);
+ return true;
+}
+
void HistoryBackend::Commit() {
if (!db_.get())
return;
@@ -2120,6 +2170,9 @@ bool HistoryBackend::ClearAllThumbnailHistory(
if (!thumbnail_db_->InitTemporaryFavIconsTable())
return false;
+ if (!thumbnail_db_->InitTemporaryIconMappingTable())
+ return false;
+
// This maps existing favicon IDs to the ones in the temporary table.
typedef std::map<FavIconID, FavIconID> FavIconMap;
FavIconMap copied_favicons;
@@ -2128,26 +2181,33 @@ bool HistoryBackend::ClearAllThumbnailHistory(
// URLs to have the new IDs.
for (std::vector<URLRow>::iterator i = kept_urls->begin();
i != kept_urls->end(); ++i) {
- FavIconID old_id = i->favicon_id();
- if (!old_id)
- continue; // URL has no favicon.
- FavIconID new_id;
-
- FavIconMap::const_iterator found = copied_favicons.find(old_id);
- if (found == copied_favicons.end()) {
- new_id = thumbnail_db_->CopyToTemporaryFavIconTable(old_id);
- copied_favicons[old_id] = new_id;
- } else {
- // We already encountered a URL that used this favicon, use the ID we
- // previously got.
- new_id = found->second;
+ std::vector<IconMapping> icon_mappings;
+ if (!thumbnail_db_->GetIconMappingsForPageURL(i->url(), &icon_mappings))
+ continue;
+
+ for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
+ m != icon_mappings.end(); ++m) {
+ FavIconID old_id = m->icon_id;
+ FavIconID new_id;
+ FavIconMap::const_iterator found = copied_favicons.find(old_id);
+ if (found == copied_favicons.end()) {
+ new_id = thumbnail_db_->CopyToTemporaryFavIconTable(old_id);
+ copied_favicons[old_id] = new_id;
+ } else {
+ // We already encountered a URL that used this favicon, use the ID we
+ // previously got.
+ new_id = found->second;
+ }
+ // Add Icon mapping, and we don't care wheteher it suceeded or not.
+ thumbnail_db_->AddToTemporaryIconMappingTable(i->url(), new_id);
}
- i->set_favicon_id(new_id);
}
- // Rename the duplicate favicon table back and recreate the other tables.
- // This will make the database consistent again.
+ // Rename the duplicate favicon and icon_mapping back table and recreate the
+ // other tables. This will make the database consistent again.
thumbnail_db_->CommitTemporaryFavIconTable();
+ thumbnail_db_->CommitTemporaryIconMappingTable();
+
thumbnail_db_->RecreateThumbnailTable();
// Vacuum to remove all the pages associated with the dropped tables. There
diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h
index 4ce7aea..06be843 100644
--- a/chrome/browser/history/history_backend.h
+++ b/chrome/browser/history/history_backend.h
@@ -210,16 +210,25 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// Favicon -------------------------------------------------------------------
void GetFavIcon(scoped_refptr<GetFavIconRequest> request,
- const GURL& icon_url);
+ const GURL& icon_url,
+ int icon_types);
+
void GetFavIconForURL(scoped_refptr<GetFavIconRequest> request,
- const GURL& page_url);
+ const GURL& page_url,
+ int icon_types);
+
void SetFavIcon(const GURL& page_url,
const GURL& icon_url,
- scoped_refptr<RefCountedMemory> data);
+ scoped_refptr<RefCountedMemory> data,
+ IconType icon_type);
+
void UpdateFavIconMappingAndFetch(scoped_refptr<GetFavIconRequest> request,
const GURL& page_url,
- const GURL& icon_url);
+ const GURL& icon_url,
+ IconType icon_type);
+
void SetFavIconOutOfDateForPage(const GURL& page_url);
+
void SetImportedFavicons(
const std::vector<ImportedFavIconUsage>& favicon_usage);
@@ -320,6 +329,7 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
private:
friend class base::RefCountedThreadSafe<HistoryBackend>;
friend class CommitLaterTask; // The commit task needs to call Commit().
+ friend class HistoryBackendTest;
friend class HistoryTest; // So the unit tests can poke our innards.
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, DeleteAll);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, ImportedFaviconsTest);
@@ -331,6 +341,10 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, AddVisitsSource);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, RemoveVisitsSource);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, MigrationVisitSource);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, MigrationIconMapping);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, SetFavIconMapping);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, AddOrUpdateIconMapping);
+
friend class ::TestingProfile;
// Computes the name of the specified database on disk.
@@ -433,14 +447,28 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// If page_url is non-null and SetFavIcon has previously been invoked for
// icon_url the favicon url for page_url (and all redirects) is set to
// icon_url.
+ // Only a single type can be given in icon_type when page_url is specified.
void UpdateFavIconMappingAndFetchImpl(
const GURL* page_url,
const GURL& icon_url,
- scoped_refptr<GetFavIconRequest> request);
+ scoped_refptr<GetFavIconRequest> request,
+ int icon_type);
// Sets the favicon url id for page_url to id. This will also broadcast
// notifications as necessary.
- void SetFavIconMapping(const GURL& page_url, FavIconID id);
+ void SetFavIconMapping(const GURL& page_url,
+ FavIconID id,
+ IconType icon_type);
+
+ // Updates the FavIconID associated with the url of a page. If there is an
+ // existing mapping between |page_url| and |id| this does nothing and returns
+ // false. If the mapping needs to be added or updated, true is returned. If
+ // there is an existing mapping but it does not map to |id|, then the |id| of
+ // the replaced FavIconID is set in |replaced_icon_id|.
+ bool AddOrUpdateIconMapping(const GURL& page_url,
+ FavIconID id,
+ IconType icon_type,
+ FavIconID* replaced_icon_id);
// Generic stuff -------------------------------------------------------------
diff --git a/chrome/browser/history/history_backend_unittest.cc b/chrome/browser/history/history_backend_unittest.cc
index c930558a..b72ed5a 100644
--- a/chrome/browser/history/history_backend_unittest.cc
+++ b/chrome/browser/history/history_backend_unittest.cc
@@ -35,6 +35,14 @@ using base::Time;
// history unit test. Because of the elaborate callbacks involved, this is no
// harder than calling it directly for many things.
+namespace {
+
+// data we'll put into the thumbnail database
+static const unsigned char blob1[] =
+ "12346102356120394751634516591348710478123649165419234519234512349134";
+
+} // namepace
+
namespace history {
class HistoryBackendTest;
@@ -122,6 +130,15 @@ class HistoryBackendTest : public testing::Test {
return test_dir_;
}
+ FavIconID GetFavIcon(const GURL& url, IconType icon_type) {
+ IconMapping icon_mapping;
+ if (backend_->thumbnail_db_->GetIconMappingForPageURL(url, icon_type,
+ &icon_mapping))
+ return icon_mapping.icon_id;
+ else
+ return 0;
+ }
+
BookmarkModel bookmark_model_;
protected:
@@ -199,8 +216,10 @@ TEST_F(HistoryBackendTest, DeleteAll) {
// deleted. This way we can test that updating works properly.
GURL favicon_url1("http://www.google.com/favicon.ico");
GURL favicon_url2("http://news.google.com/favicon.ico");
- FavIconID favicon2 = backend_->thumbnail_db_->AddFavIcon(favicon_url2);
- FavIconID favicon1 = backend_->thumbnail_db_->AddFavIcon(favicon_url1);
+ FavIconID favicon2 = backend_->thumbnail_db_->AddFavIcon(favicon_url2,
+ FAV_ICON);
+ FavIconID favicon1 = backend_->thumbnail_db_->AddFavIcon(favicon_url1,
+ FAV_ICON);
std::vector<unsigned char> data;
data.push_back('1');
@@ -216,12 +235,12 @@ TEST_F(HistoryBackendTest, DeleteAll) {
row1.set_visit_count(2);
row1.set_typed_count(1);
row1.set_last_visit(Time::Now());
- row1.set_favicon_id(favicon1);
+ backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1);
URLRow row2(GURL("http://news.google.com/"));
row2.set_visit_count(1);
row2.set_last_visit(Time::Now());
- row2.set_favicon_id(favicon2);
+ backend_->thumbnail_db_->AddIconMapping(row2.url(), favicon2);
std::vector<URLRow> rows;
rows.push_back(row2); // Reversed order for the same reason as favicons.
@@ -281,6 +300,7 @@ TEST_F(HistoryBackendTest, DeleteAll) {
// The first URL should be preserved but the time should be cleared.
EXPECT_TRUE(backend_->db_->GetRowForURL(row1.url(), &outrow1));
+ EXPECT_EQ(row1.url(), outrow1.url());
EXPECT_EQ(0, outrow1.visit_count());
EXPECT_EQ(0, outrow1.typed_count());
EXPECT_TRUE(Time() == outrow1.last_visit());
@@ -303,15 +323,15 @@ TEST_F(HistoryBackendTest, DeleteAll) {
// We should have a favicon for the first URL only. We look them up by favicon
// URL since the IDs may hav changed.
FavIconID out_favicon1 = backend_->thumbnail_db_->
- GetFavIconIDForFavIconURL(favicon_url1);
+ GetFavIconIDForFavIconURL(favicon_url1, FAV_ICON, NULL);
EXPECT_TRUE(out_favicon1);
FavIconID out_favicon2 = backend_->thumbnail_db_->
- GetFavIconIDForFavIconURL(favicon_url2);
+ GetFavIconIDForFavIconURL(favicon_url2, FAV_ICON, NULL);
EXPECT_FALSE(out_favicon2) << "Favicon not deleted";
// The remaining URL should still reference the same favicon, even if its
// ID has changed.
- EXPECT_EQ(out_favicon1, outrow1.favicon_id());
+ EXPECT_EQ(out_favicon1, GetFavIcon(outrow1.url(), FAV_ICON));
// The first URL should still be bookmarked.
EXPECT_TRUE(bookmark_model_.IsBookmarked(row1.url()));
@@ -329,8 +349,10 @@ TEST_F(HistoryBackendTest, DeleteAll) {
TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) {
GURL favicon_url1("http://www.google.com/favicon.ico");
GURL favicon_url2("http://news.google.com/favicon.ico");
- FavIconID favicon2 = backend_->thumbnail_db_->AddFavIcon(favicon_url2);
- FavIconID favicon1 = backend_->thumbnail_db_->AddFavIcon(favicon_url1);
+ FavIconID favicon2 = backend_->thumbnail_db_->AddFavIcon(favicon_url2,
+ FAV_ICON);
+ FavIconID favicon1 = backend_->thumbnail_db_->AddFavIcon(favicon_url1,
+ FAV_ICON);
std::vector<unsigned char> data;
data.push_back('1');
@@ -346,12 +368,12 @@ TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) {
row1.set_visit_count(2);
row1.set_typed_count(1);
row1.set_last_visit(Time::Now());
- row1.set_favicon_id(favicon1);
+ EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1));
URLRow row2(GURL("http://news.google.com/"));
row2.set_visit_count(1);
row2.set_last_visit(Time::Now());
- row2.set_favicon_id(favicon2);
+ EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row2.url(), favicon2));
std::vector<URLRow> rows;
rows.push_back(row2); // Reversed order for the same reason as favicons.
@@ -377,7 +399,9 @@ TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) {
EXPECT_EQ(0U, visits.size());
// The favicon should still be valid.
EXPECT_EQ(favicon2,
- backend_->thumbnail_db_->GetFavIconIDForFavIconURL(favicon_url2));
+ backend_->thumbnail_db_->GetFavIconIDForFavIconURL(favicon_url2,
+ FAV_ICON,
+ NULL));
// Unstar row2.
bookmark_model_.SetURLStarred(row2.url(), string16(), false);
@@ -391,7 +415,9 @@ TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) {
EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &tmp_url_row));
// And the favicon should be deleted.
EXPECT_EQ(0,
- backend_->thumbnail_db_->GetFavIconIDForFavIconURL(favicon_url2));
+ backend_->thumbnail_db_->GetFavIconIDForFavIconURL(favicon_url2,
+ FAV_ICON,
+ NULL));
// Unstar row 1.
bookmark_model_.SetURLStarred(row1.url(), string16(), false);
@@ -411,7 +437,9 @@ TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) {
// The favicon should still be valid.
EXPECT_EQ(favicon1,
- backend_->thumbnail_db_->GetFavIconIDForFavIconURL(favicon_url1));
+ backend_->thumbnail_db_->GetFavIconIDForFavIconURL(favicon_url1,
+ FAV_ICON,
+ NULL));
}
// Tests a handful of assertions for a navigation with a type of
@@ -494,15 +522,17 @@ TEST_F(HistoryBackendTest, ImportedFaviconsTest) {
// Setup test data - two Urls in the history, one with favicon assigned and
// one without.
GURL favicon_url1("http://www.google.com/favicon.ico");
- FavIconID favicon1 = backend_->thumbnail_db_->AddFavIcon(favicon_url1);
+ FavIconID favicon1 = backend_->thumbnail_db_->AddFavIcon(favicon_url1,
+ FAV_ICON);
std::vector<unsigned char> data;
data.push_back('1');
EXPECT_TRUE(backend_->thumbnail_db_->SetFavIcon(favicon1,
RefCountedBytes::TakeVector(&data), Time::Now()));
URLRow row1(GURL("http://www.google.com/"));
- row1.set_favicon_id(favicon1);
row1.set_visit_count(1);
row1.set_last_visit(Time::Now());
+ EXPECT_TRUE(backend_->thumbnail_db_->AddIconMapping(row1.url(), favicon1));
+
URLRow row2(GURL("http://news.google.com/"));
row2.set_visit_count(1);
row2.set_last_visit(Time::Now());
@@ -513,8 +543,8 @@ TEST_F(HistoryBackendTest, ImportedFaviconsTest) {
URLRow url_row1, url_row2;
EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0);
EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0);
- EXPECT_FALSE(url_row1.favicon_id() == 0);
- EXPECT_TRUE(url_row2.favicon_id() == 0);
+ EXPECT_FALSE(GetFavIcon(row1.url(), FAV_ICON) == 0);
+ EXPECT_TRUE(GetFavIcon(row2.url(), FAV_ICON) == 0);
// Now provide one imported favicon for both URLs already in the registry.
// The new favicon should only be used with the URL that doesn't already have
@@ -529,9 +559,10 @@ TEST_F(HistoryBackendTest, ImportedFaviconsTest) {
backend_->SetImportedFavicons(favicons);
EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0);
EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0);
- EXPECT_FALSE(url_row1.favicon_id() == 0);
- EXPECT_FALSE(url_row2.favicon_id() == 0);
- EXPECT_FALSE(url_row1.favicon_id() == url_row2.favicon_id());
+ EXPECT_FALSE(GetFavIcon(row1.url(), FAV_ICON) == 0);
+ EXPECT_FALSE(GetFavIcon(row2.url(), FAV_ICON) == 0);
+ EXPECT_FALSE(GetFavIcon(row1.url(), FAV_ICON) ==
+ GetFavIcon(row2.url(), FAV_ICON));
// A URL should not be added to history (to store favicon), if
// the URL is not bookmarked.
@@ -789,4 +820,112 @@ TEST_F(HistoryBackendTest, MigrationVisitSource) {
EXPECT_FALSE(s.Step());
}
+TEST_F(HistoryBackendTest, SetFavIconMapping) {
+ // Init recent_redirects_
+ const GURL url1("http://www.google.com");
+ const GURL url2("http://www.google.com/m");
+ URLRow url_info1(url1);
+ url_info1.set_visit_count(0);
+ url_info1.set_typed_count(0);
+ url_info1.set_last_visit(base::Time());
+ url_info1.set_hidden(false);
+ backend_->db_->AddURL(url_info1);
+
+ URLRow url_info2(url2);
+ url_info2.set_visit_count(0);
+ url_info2.set_typed_count(0);
+ url_info2.set_last_visit(base::Time());
+ url_info2.set_hidden(false);
+ backend_->db_->AddURL(url_info2);
+
+ history::RedirectList redirects;
+ redirects.push_back(url2);
+ redirects.push_back(url1);
+ backend_->recent_redirects_.Put(url1, redirects);
+
+ const GURL icon_url("http://www.google.com/icon");
+ std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
+ // Add a fav icon
+ backend_->SetFavIcon(
+ url1, icon_url, RefCountedBytes::TakeVector(&data), FAV_ICON);
+ EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingForPageURL(
+ url1, FAV_ICON, NULL));
+ EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingForPageURL(
+ url2, FAV_ICON, NULL));
+
+ // Add a touch_icon
+ backend_->SetFavIcon(
+ url1, icon_url, RefCountedBytes::TakeVector(&data), TOUCH_ICON);
+ EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingForPageURL(
+ url1, TOUCH_ICON, NULL));
+ EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingForPageURL(
+ url2, TOUCH_ICON, NULL));
+ EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingForPageURL(
+ url1, FAV_ICON, NULL));
+
+ // Add a TOUCH_PRECOMPOSED_ICON
+ backend_->SetFavIcon(url1,
+ icon_url,
+ RefCountedBytes::TakeVector(&data),
+ TOUCH_PRECOMPOSED_ICON);
+ // The touch_icon was replaced.
+ EXPECT_FALSE(backend_->thumbnail_db_->GetIconMappingForPageURL(
+ url1, TOUCH_ICON, NULL));
+ EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingForPageURL(
+ url1, FAV_ICON, NULL));
+ EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingForPageURL(
+ url1, TOUCH_PRECOMPOSED_ICON, NULL));
+ EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingForPageURL(
+ url2, TOUCH_PRECOMPOSED_ICON, NULL));
+
+ // Add a touch_icon
+ backend_->SetFavIcon(
+ url1, icon_url, RefCountedBytes::TakeVector(&data), TOUCH_ICON);
+ EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingForPageURL(
+ url1, TOUCH_ICON, NULL));
+ EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingForPageURL(
+ url1, FAV_ICON, NULL));
+ // The TOUCH_PRECOMPOSED_ICON was replaced.
+ EXPECT_FALSE(backend_->thumbnail_db_->GetIconMappingForPageURL(
+ url1, TOUCH_PRECOMPOSED_ICON, NULL));
+
+ // Add a fav_icon
+ const GURL icon_url2("http://www.google.com/icon2");
+ backend_->SetFavIcon(
+ url1, icon_url2, RefCountedBytes::TakeVector(&data), FAV_ICON);
+ FavIconID icon_id = backend_->thumbnail_db_->GetFavIconIDForFavIconURL(
+ icon_url2, FAV_ICON, NULL);
+ EXPECT_NE(0, icon_id);
+ std::vector<IconMapping> icon_mapping;
+ EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
+ url1, &icon_mapping));
+ // The old icon was replaced.
+ EXPECT_TRUE(icon_mapping.size() > 1);
+ EXPECT_EQ(icon_id, icon_mapping[1].icon_id);
+}
+
+TEST_F(HistoryBackendTest, AddOrUpdateIconMapping) {
+ // Test the same icon and page mapping will not be added twice. other case
+ // should be covered in TEST_F(HistoryBackendTest, SetFavIconMapping)
+ const GURL url("http://www.google.com/");
+ const GURL icon_url("http://www.google.com/icon");
+ std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
+
+ backend_->SetFavIcon(
+ url, icon_url, RefCountedBytes::TakeVector(&data), FAV_ICON);
+ FavIconID icon_id = backend_->thumbnail_db_->GetFavIconIDForFavIconURL(
+ icon_url, FAV_ICON, NULL);
+
+ // Add the same mapping
+ FavIconID replaced;
+ EXPECT_FALSE(backend_->AddOrUpdateIconMapping(
+ url, icon_id, FAV_ICON, &replaced));
+ EXPECT_EQ(0, replaced);
+
+ std::vector<IconMapping> icon_mapping;
+ EXPECT_TRUE(backend_->thumbnail_db_->GetIconMappingsForPageURL(
+ url, &icon_mapping));
+ EXPECT_EQ(1u, icon_mapping.size());
+}
+
} // namespace history
diff --git a/chrome/browser/history/history_database.cc b/chrome/browser/history/history_database.cc
index bdd3cb4..b748e2f 100644
--- a/chrome/browser/history/history_database.cc
+++ b/chrome/browser/history/history_database.cc
@@ -119,7 +119,6 @@ sql::InitStatus HistoryDatabase::Init(const FilePath& history_name,
return sql::INIT_FAILURE;
CreateMainURLIndex();
CreateKeywordSearchTermsIndices();
- CreateSupplimentaryURLIndices();
// Version check.
sql::InitStatus version_status = EnsureCurrentVersion(bookmarks_path);
@@ -168,7 +167,6 @@ bool HistoryDatabase::RecreateAllTablesButURL() {
// We also add the supplementary URL indices at this point. This index is
// over parts of the URL table that weren't automatically created when the
// temporary URL table was
- CreateSupplimentaryURLIndices();
CreateKeywordSearchTermsIndices();
return true;
}
diff --git a/chrome/browser/history/history_database.h b/chrome/browser/history/history_database.h
index 1f0c219..6bc53d8 100644
--- a/chrome/browser/history/history_database.h
+++ b/chrome/browser/history/history_database.h
@@ -145,6 +145,7 @@ class HistoryDatabase : public DownloadDatabase,
virtual void UpdateEarlyExpirationThreshold(base::Time threshold);
private:
+ FRIEND_TEST_ALL_PREFIXES(IconMappingMigrationTest, TestIconMappingMigration);
// Implemented for URLDatabase.
virtual sql::Connection& GetDB();
diff --git a/chrome/browser/history/history_types.cc b/chrome/browser/history/history_types.cc
index 9f56ff0..aa83bc8 100644
--- a/chrome/browser/history/history_types.cc
+++ b/chrome/browser/history/history_types.cc
@@ -40,7 +40,6 @@ URLRow& URLRow::operator=(const URLRow& other) {
typed_count_ = other.typed_count_;
last_visit_ = other.last_visit_;
hidden_ = other.hidden_;
- favicon_id_ = other.favicon_id_;
return *this;
}
@@ -52,7 +51,6 @@ void URLRow::Swap(URLRow* other) {
std::swap(typed_count_, other->typed_count_);
std::swap(last_visit_, other->last_visit_);
std::swap(hidden_, other->hidden_);
- std::swap(favicon_id_, other->favicon_id_);
}
void URLRow::Initialize() {
@@ -61,7 +59,6 @@ void URLRow::Initialize() {
typed_count_ = 0;
last_visit_ = base::Time();
hidden_ = false;
- favicon_id_ = 0;
}
// VisitRow --------------------------------------------------------------------
@@ -403,4 +400,14 @@ bool RowQualifiesAsSignificant(const URLRow& row,
(row.last_visit() >= real_threshold);
}
+// IconMapping ----------------------------------------------------------------
+
+IconMapping::IconMapping()
+ : mapping_id(0),
+ icon_id(0),
+ icon_type(INVALID_ICON) {
+}
+
+IconMapping::~IconMapping() {}
+
} // namespace history
diff --git a/chrome/browser/history/history_types.h b/chrome/browser/history/history_types.h
index ed219a8..a6822cb 100644
--- a/chrome/browser/history/history_types.h
+++ b/chrome/browser/history/history_types.h
@@ -42,6 +42,7 @@ typedef int64 UIStarID; // Identifier for star entries that come from the UI.
typedef int64 DownloadID; // Identifier for a download.
typedef int64 FavIconID; // For FavIcons.
typedef int64 SegmentID; // URL segments for the most visited view.
+typedef int64 IconMappingID; // For page url and icon mapping.
// URLRow ---------------------------------------------------------------------
@@ -116,12 +117,6 @@ class URLRow {
hidden_ = hidden;
}
- // ID of the favicon. A value of 0 means the favicon isn't known yet.
- FavIconID favicon_id() const { return favicon_id_; }
- void set_favicon_id(FavIconID favicon_id) {
- favicon_id_ = favicon_id;
- }
-
protected:
// Swaps the contents of this URLRow with another, which allows it to be
// destructively copied without memory allocations.
@@ -162,9 +157,6 @@ class URLRow {
// is usually for subframes.
bool hidden_;
- // The ID of the favicon for this url.
- FavIconID favicon_id_;
-
// We support the implicit copy constuctor and operator=.
};
@@ -684,6 +676,33 @@ base::Time AutocompleteAgeThreshold();
// AutocompleteAgeThreshold() (or any other desired time in the past).
bool RowQualifiesAsSignificant(const URLRow& row, const base::Time& threshold);
+// Defines the icon types. They are also stored in icon_type field of favicons
+// table.
+enum IconType {
+ INVALID_ICON = 0x0,
+ FAV_ICON = 1 << 0,
+ TOUCH_ICON = 1 << 1,
+ TOUCH_PRECOMPOSED_ICON = 1 << 2
+};
+
+// Used for the mapping between the page and icon.
+struct IconMapping {
+ IconMapping();
+ ~IconMapping();
+
+ // The unique id of the mapping.
+ IconMappingID mapping_id;
+
+ // The url of a web page.
+ GURL page_url;
+
+ // The unique id of the icon.
+ FavIconID icon_id;
+
+ // The type of icon.
+ IconType icon_type;
+};
+
} // namespace history
#endif // CHROME_BROWSER_HISTORY_HISTORY_TYPES_H_
diff --git a/chrome/browser/history/history_unittest_base.cc b/chrome/browser/history/history_unittest_base.cc
new file mode 100644
index 0000000..dfd2eaa
--- /dev/null
+++ b/chrome/browser/history/history_unittest_base.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "app/sql/connection.h"
+#include "base/format_macros.h"
+#include "base/string_util.h"
+#include "chrome/browser/history/history_unittest_base.h"
+
+namespace history {
+
+HistoryUnitTestBase::~HistoryUnitTestBase() {
+}
+
+void HistoryUnitTestBase::ExecuteSQLScript(const FilePath& sql_path,
+ const FilePath& db_path) {
+ std::string sql;
+ ASSERT_TRUE(file_util::ReadFileToString(sql_path, &sql));
+
+ // Replace the 'last_visit_time', 'visit_time', 'time_slot' values in this
+ // SQL with the current time.
+ int64 now = base::Time::Now().ToInternalValue();
+ std::vector<std::string> sql_time;
+ sql_time.push_back(StringPrintf("%" PRId64, now)); // last_visit_time
+ sql_time.push_back(StringPrintf("%" PRId64, now)); // visit_time
+ sql_time.push_back(StringPrintf("%" PRId64, now)); // time_slot
+ sql = ReplaceStringPlaceholders(sql, sql_time, NULL);
+
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(db_path));
+ ASSERT_TRUE(connection.Execute(sql.c_str()));
+}
+
+HistoryUnitTestBase::HistoryUnitTestBase() {
+}
+
+} // namespace history
diff --git a/chrome/browser/history/history_unittest_base.h b/chrome/browser/history/history_unittest_base.h
new file mode 100644
index 0000000..1d9512d
--- /dev/null
+++ b/chrome/browser/history/history_unittest_base.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_HISTORY_HISTORY_UNITTEST_BASE_H_
+#define CHROME_BROWSER_HISTORY_HISTORY_UNITTEST_BASE_H_
+
+#include "base/file_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace history {
+// A base class for a history unit test. It provides the common test methods.
+//
+class HistoryUnitTestBase : public testing::Test {
+ public:
+ virtual ~HistoryUnitTestBase();
+
+ // Executes the sql from the file |sql_path| in the database at |db_path|.
+ // |sql_path| is the SQL script file name with full path.
+ // |db_path| is the db file name with full path.
+ static void ExecuteSQLScript(const FilePath& sql_path,
+ const FilePath& db_path);
+
+ protected:
+ HistoryUnitTestBase();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HistoryUnitTestBase);
+};
+
+} // namespace history
+
+#endif // CHROME_BROWSER_HISTORY_HISTORY_UNITTEST_BASE_H_
diff --git a/chrome/browser/history/thumbnail_database.cc b/chrome/browser/history/thumbnail_database.cc
index 3f863da..28a0d93 100644
--- a/chrome/browser/history/thumbnail_database.cc
+++ b/chrome/browser/history/thumbnail_database.cc
@@ -27,14 +27,25 @@
#include "base/mac/mac_util.h"
#endif
+static void FillIconMapping(const sql::Statement& statement,
+ const GURL& page_url,
+ history::IconMapping* icon_mapping) {
+ icon_mapping->mapping_id = statement.ColumnInt64(0);
+ icon_mapping->icon_id = statement.ColumnInt64(1);
+ icon_mapping->icon_type =
+ static_cast<history::IconType>(statement.ColumnInt(2));
+ icon_mapping->page_url = page_url;
+}
+
namespace history {
// Version number of the database.
-static const int kCurrentVersionNumber = 3;
-static const int kCompatibleVersionNumber = 3;
+static const int kCurrentVersionNumber = 4;
+static const int kCompatibleVersionNumber = 4;
-ThumbnailDatabase::ThumbnailDatabase() : history_publisher_(NULL),
- use_top_sites_(false) {
+ThumbnailDatabase::ThumbnailDatabase()
+ : history_publisher_(NULL),
+ use_top_sites_(false) {
}
ThumbnailDatabase::~ThumbnailDatabase() {
@@ -43,7 +54,8 @@ ThumbnailDatabase::~ThumbnailDatabase() {
sql::InitStatus ThumbnailDatabase::Init(
const FilePath& db_name,
- const HistoryPublisher* history_publisher) {
+ const HistoryPublisher* history_publisher,
+ URLDatabase* url_db) {
history_publisher_ = history_publisher;
sql::InitStatus status = OpenDatabase(&db_, db_name);
if (status != sql::INIT_OK)
@@ -66,11 +78,13 @@ sql::InitStatus ThumbnailDatabase::Init(
if (!meta_table_.Init(&db_, kCurrentVersionNumber,
kCompatibleVersionNumber) ||
!InitThumbnailTable() ||
- !InitFavIconsTable(&db_, false)) {
+ !InitFavIconsTable(&db_, false) ||
+ !InitIconMappingTable(&db_, false)) {
db_.Close();
return sql::INIT_FAILURE;
}
InitFavIconsIndex();
+ InitIconMappingIndex();
// Version check. We should not encounter a database too old for us to handle
// in the wild, so we try to continue in that case.
@@ -89,6 +103,15 @@ sql::InitStatus ThumbnailDatabase::Init(
++cur_version;
}
+ if (cur_version == 3) {
+ if (!UpgradeToVersion4() || !MigrateIconMappingData(url_db)) {
+ LOG(WARNING) << "Unable to update to thumbnail database to version 4.";
+ db_.Close();
+ return sql::INIT_FAILURE;
+ }
+ ++cur_version;
+ }
+
LOG_IF(WARNING, cur_version < kCurrentVersionNumber) <<
"Thumbnail database version " << cur_version << " is too old to handle.";
@@ -180,7 +203,11 @@ bool ThumbnailDatabase::InitFavIconsTable(sql::Connection* db,
"id INTEGER PRIMARY KEY,"
"url LONGVARCHAR NOT NULL,"
"last_updated INTEGER DEFAULT 0,"
- "image_data BLOB)");
+ "image_data BLOB,"
+ "icon_type INTEGER DEFAULT 1)"); // Set the default as FAV_ICON
+ // to be consistent with table
+ // upgrade in
+ // UpgradeToVersion4().
if (!db->Execute(sql.c_str()))
return false;
}
@@ -372,16 +399,22 @@ bool ThumbnailDatabase::SetFavIconLastUpdateTime(FavIconID icon_id,
return statement.Run();
}
-FavIconID ThumbnailDatabase::GetFavIconIDForFavIconURL(const GURL& icon_url) {
+FavIconID ThumbnailDatabase::GetFavIconIDForFavIconURL(const GURL& icon_url,
+ int required_icon_type,
+ IconType* icon_type) {
sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
- "SELECT id FROM favicons WHERE url=?"));
+ "SELECT id, icon_type FROM favicons WHERE url=? AND (icon_type & ? > 0) "
+ "ORDER BY icon_type DESC"));
if (!statement)
return 0;
statement.BindString(0, URLDatabase::GURLToDatabaseURL(icon_url));
+ statement.BindInt(1, required_icon_type);
if (!statement.Step())
return 0; // not cached
+ if (icon_type)
+ *icon_type = static_cast<IconType>(statement.ColumnInt(1));
return statement.ColumnInt64(0);
}
@@ -411,13 +444,16 @@ bool ThumbnailDatabase::GetFavIcon(
return true;
}
-FavIconID ThumbnailDatabase::AddFavIcon(const GURL& icon_url) {
+FavIconID ThumbnailDatabase::AddFavIcon(const GURL& icon_url,
+ IconType icon_type) {
+
sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
- "INSERT INTO favicons (url) VALUES (?)"));
+ "INSERT INTO favicons (url, icon_type) VALUES (?, ?)"));
if (!statement)
return 0;
statement.BindString(0, URLDatabase::GURLToDatabaseURL(icon_url));
+ statement.BindInt(1, icon_type);
if (!statement.Run())
return 0;
return db_.GetLastInsertRowId();
@@ -428,14 +464,134 @@ bool ThumbnailDatabase::DeleteFavIcon(FavIconID id) {
"DELETE FROM favicons WHERE id = ?"));
if (!statement)
return false;
+
statement.BindInt64(0, id);
return statement.Run();
}
+bool ThumbnailDatabase::GetIconMappingForPageURL(const GURL& page_url,
+ IconType required_icon_type,
+ IconMapping* icon_mapping) {
+ std::vector<IconMapping> icon_mappings;
+ if (!GetIconMappingsForPageURL(page_url, &icon_mappings))
+ return false;
+
+ for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
+ m != icon_mappings.end(); ++m) {
+ if (m->icon_type == required_icon_type) {
+ if (icon_mapping != NULL)
+ *icon_mapping = *m;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ThumbnailDatabase::GetIconMappingsForPageURL(
+ const GURL& page_url,
+ std::vector<IconMapping>* mapping_data) {
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+ "SELECT icon_mapping.id, icon_mapping.icon_id, favicons.icon_type "
+ "FROM icon_mapping "
+ "INNER JOIN favicons "
+ "ON icon_mapping.icon_id = favicons.id "
+ "WHERE icon_mapping.page_url=? "
+ "ORDER BY favicons.icon_type DESC"));
+ if (!statement)
+ return false;
+
+ statement.BindString(0, URLDatabase::GURLToDatabaseURL(page_url));
+
+ bool result = false;
+ while (statement.Step()) {
+ result = true;
+ if (!mapping_data)
+ return result;
+
+ IconMapping icon_mapping;
+ FillIconMapping(statement, page_url, &icon_mapping);
+ mapping_data->push_back(icon_mapping);
+ }
+ return result;
+}
+
+IconMappingID ThumbnailDatabase::AddIconMapping(const GURL& page_url,
+ FavIconID icon_id) {
+ return AddIconMapping(page_url, icon_id, false);
+}
+
+bool ThumbnailDatabase::UpdateIconMapping(IconMappingID mapping_id,
+ FavIconID icon_id) {
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+ "UPDATE icon_mapping SET icon_id=? WHERE id=?"));
+ if (!statement)
+ return 0;
+
+ statement.BindInt64(0, icon_id);
+ statement.BindInt64(1, mapping_id);
+ return statement.Run();
+}
+
+bool ThumbnailDatabase::DeleteIconMappings(const GURL& page_url) {
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+ "DELETE FROM icon_mapping WHERE page_url = ?"));
+ if (!statement)
+ return false;
+
+ statement.BindString(0, URLDatabase::GURLToDatabaseURL(page_url));
+ return statement.Run();
+}
+
+bool ThumbnailDatabase::HasMappingFor(FavIconID id) {
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+ "SELECT id FROM icon_mapping "
+ "WHERE icon_id=?"));
+ if (!statement)
+ return false;
+
+ statement.BindInt64(0, id);
+ return statement.Step();
+}
+
+bool ThumbnailDatabase::MigrateIconMappingData(URLDatabase* url_db) {
+ URLDatabase::IconMappingEnumerator e;
+ if (!url_db->InitIconMappingEnumeratorForEverything(&e))
+ return false;
+
+ IconMapping info;
+ while (e.GetNextIconMapping(&info)) {
+ // TODO: Using bulk insert to improve the performance.
+ if (!AddIconMapping(info.page_url, info.icon_id))
+ return false;
+ }
+ return true;
+}
+
+IconMappingID ThumbnailDatabase::AddToTemporaryIconMappingTable(
+ const GURL& page_url, const FavIconID icon_id) {
+ return AddIconMapping(page_url, icon_id, true);
+}
+
+bool ThumbnailDatabase::CommitTemporaryIconMappingTable() {
+ // Delete the old icon_mapping table.
+ if (!db_.Execute("DROP TABLE icon_mapping"))
+ return false;
+
+ // Rename the temporary one.
+ if (!db_.Execute("ALTER TABLE temp_icon_mapping RENAME TO icon_mapping"))
+ return false;
+
+ // The renamed table needs the index (the temporary table doesn't have one).
+ InitIconMappingIndex();
+
+ return true;
+}
+
FavIconID ThumbnailDatabase::CopyToTemporaryFavIconTable(FavIconID source) {
sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
- "INSERT INTO temp_favicons (url, last_updated, image_data)"
- "SELECT url, last_updated, image_data "
+ "INSERT INTO temp_favicons (url, last_updated, image_data, icon_type)"
+ "SELECT url, last_updated, image_data, icon_type "
"FROM favicons WHERE id = ?"));
if (!statement)
return 0;
@@ -472,8 +628,9 @@ bool ThumbnailDatabase::RenameAndDropThumbnails(const FilePath& old_db_file,
if (OpenDatabase(&favicons, new_db_file) != sql::INIT_OK)
return false;
- if (!InitFavIconsTable(&favicons, false)) {
- NOTREACHED() << "Couldn't init favicons table.";
+ if (!InitFavIconsTable(&favicons, false) ||
+ !InitIconMappingTable(&favicons, false)) {
+ NOTREACHED() << "Couldn't init favicons and icon-mapping table.";
favicons.Close();
return false;
}
@@ -538,4 +695,67 @@ bool ThumbnailDatabase::RenameAndDropThumbnails(const FilePath& old_db_file,
return true;
}
+bool ThumbnailDatabase::InitIconMappingTable(sql::Connection* db,
+ bool is_temporary) {
+ const char* name = is_temporary ? "temp_icon_mapping" : "icon_mapping";
+ if (!db->DoesTableExist(name)) {
+ std::string sql;
+ sql.append("CREATE TABLE ");
+ sql.append(name);
+ sql.append("("
+ "id INTEGER PRIMARY KEY,"
+ "page_url LONGVARCHAR NOT NULL,"
+ "icon_id INTEGER)");
+ if (!db->Execute(sql.c_str()))
+ return false;
+ }
+ return true;
+}
+
+void ThumbnailDatabase::InitIconMappingIndex() {
+ // Add an index on the url column. We ignore errors. Since this is always
+ // called during startup, the index will normally already exist.
+ db_.Execute("CREATE INDEX icon_mapping_page_url_idx"
+ " ON icon_mapping(page_url)");
+ db_.Execute("CREATE INDEX icon_mapping_icon_id_idx ON icon_mapping(icon_id)");
+}
+
+IconMappingID ThumbnailDatabase::AddIconMapping(const GURL& page_url,
+ FavIconID icon_id,
+ bool is_temporary) {
+ const char* name = is_temporary ? "temp_icon_mapping" : "icon_mapping";
+ const char* statement_name =
+ is_temporary ? "add_temp_icon_mapping" : "add_icon_mapping";
+
+ std::string sql;
+ sql.append("INSERT INTO ");
+ sql.append(name);
+ sql.append("(page_url, icon_id) VALUES (?, ?)");
+
+ sql::Statement statement(
+ db_.GetCachedStatement(sql::StatementID(statement_name), sql.c_str()));
+ if (!statement)
+ return 0;
+
+ statement.BindString(0, URLDatabase::GURLToDatabaseURL(page_url));
+ statement.BindInt64(1, icon_id);
+
+ if (!statement.Run())
+ return 0;
+
+ return db_.GetLastInsertRowId();
+}
+
+bool ThumbnailDatabase::UpgradeToVersion4() {
+ // Set the default icon type as favicon, so the current data are set
+ // correctly.
+ if (!db_.Execute("ALTER TABLE favicons ADD icon_type INTEGER DEFAULT 1")) {
+ NOTREACHED();
+ return false;
+ }
+ meta_table_.SetVersionNumber(4);
+ meta_table_.SetCompatibleVersionNumber(std::min(4, kCompatibleVersionNumber));
+ return true;
+}
+
} // namespace history
diff --git a/chrome/browser/history/thumbnail_database.h b/chrome/browser/history/thumbnail_database.h
index 94fb043..b210729 100644
--- a/chrome/browser/history/thumbnail_database.h
+++ b/chrome/browser/history/thumbnail_database.h
@@ -11,7 +11,9 @@
#include "app/sql/connection.h"
#include "app/sql/init_status.h"
#include "app/sql/meta_table.h"
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/history/history_types.h"
class FilePath;
@@ -43,7 +45,8 @@ class ThumbnailDatabase {
// Must be called after creation but before any other methods are called.
// When not INIT_OK, no other functions should be called.
sql::InitStatus Init(const FilePath& db_name,
- const HistoryPublisher* history_publisher);
+ const HistoryPublisher* history_publisher,
+ URLDatabase* url_database);
// Open database on a given filename. If the file does not exist,
// it is created.
@@ -102,9 +105,16 @@ class ThumbnailDatabase {
// Sets the time the favicon was last updated.
bool SetFavIconLastUpdateTime(FavIconID icon_id, base::Time time);
- // Returns the id of the entry in the favicon database with the specified url.
+ // Returns the id of the entry in the favicon database with the specified url
+ // and icon type. If |required_icon_type| contains multiple icon types and
+ // there are more than one matched icon in database, only one icon will be
+ // returned in the priority of TOUCH_PRECOMPOSED_ICON, TOUCH_ICON, and
+ // FAV_ICON, and the icon type is returned in icon_type parameter if it is not
+ // NULL.
// Returns 0 if no entry exists for the specified url.
- FavIconID GetFavIconIDForFavIconURL(const GURL& icon_url);
+ FavIconID GetFavIconIDForFavIconURL(const GURL& icon_url,
+ int required_icon_type,
+ IconType* icon_type);
// Gets the png encoded favicon and last updated time for the specified
// favicon id.
@@ -113,12 +123,70 @@ class ThumbnailDatabase {
std::vector<unsigned char>* png_icon_data,
GURL* icon_url);
- // Adds the favicon URL to the favicon db, returning its id.
- FavIconID AddFavIcon(const GURL& icon_url);
+ // Adds the favicon URL and icon type to the favicon db, returning its id.
+ FavIconID AddFavIcon(const GURL& icon_url, IconType icon_type);
// Delete the favicon with the provided id. Returns false on failure
bool DeleteFavIcon(FavIconID id);
+ // Icon Mapping --------------------------------------------------------------
+ //
+ // Returns true if there is a matched icon mapping for the given page and
+ // icon type.
+ // The matched icon mapping is returned in the icon_mapping parameter if it is
+ // not NULL.
+ bool GetIconMappingForPageURL(const GURL& page_url,
+ IconType required_icon_type,
+ IconMapping* icon_mapping);
+
+ // Returns true if there is any matched icon mapping for the given page.
+ // All matched icon mappings are returned in descent order of IconType if
+ // mapping_data is not NULL.
+ bool GetIconMappingsForPageURL(const GURL& page_url,
+ std::vector<IconMapping>* mapping_data);
+
+ // Adds a mapping between the given page_url and icon_id.
+ // Returns the new mapping id if the adding succeeds, otherwise 0 is returned.
+ IconMappingID AddIconMapping(const GURL& page_url, FavIconID icon_id);
+
+ // Updates the page and icon mapping for the given mapping_id with the given
+ // icon_id.
+ // Returns true if the update succeeded.
+ bool UpdateIconMapping(IconMappingID mapping_id, FavIconID icon_id);
+
+ // Deletes the icon mapping entries for the given page url.
+ // Returns true if the deletion succeeded.
+ bool DeleteIconMappings(const GURL& page_url);
+
+ // Checks whether a favicon is used by any URLs in the database.
+ bool HasMappingFor(FavIconID id);
+
+ // Temporary IconMapping -----------------------------------------------------
+ //
+ // Creates a temporary table to store icon mapping. Icon mapping will be
+ // copied to this table by AddToTemporaryIconMappingTable() and then the
+ // original table will be dropped, leaving only those copied mapping
+ // remaining. This is used to quickly delete most of the icon mapping when
+ // clearing history.
+ bool InitTemporaryIconMappingTable() {
+ return InitIconMappingTable(&db_, true);
+ }
+
+ // Copies the given icon mapping from the "main" icon_mapping table to the
+ // temporary one. This is only valid in between calls to
+ // InitTemporaryIconMappingTable()
+ // and CommitTemporaryIconMappingTable().
+ //
+ // The ID of the favicon will change when this copy takes place. The new ID
+ // is returned, or 0 on failure.
+ IconMappingID AddToTemporaryIconMappingTable(const GURL& page_url,
+ const FavIconID icon_id);
+
+ // Replaces the main icon mapping table with the temporary table created by
+ // InitTemporaryIconMappingTable(). This will mean all icon mapping not copied
+ // over will be deleted. Returns true on success.
+ bool CommitTemporaryIconMappingTable();
+
// Temporary FavIcons --------------------------------------------------------
// Create a temporary table to store favicons. Favicons will be copied to
@@ -152,6 +220,8 @@ class ThumbnailDatabase {
private:
friend class ExpireHistoryBackend;
+ FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, UpgradeToVersion4);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, MigrationIconMapping);
// Creates the thumbnail table, returning true if the table already exists
// or was successfully created.
@@ -169,12 +239,37 @@ class ThumbnailDatabase {
// Adds support for the new metadata on web page thumbnails.
bool UpgradeToVersion3();
+ // Adds support for the icon_type in favicon table.
+ bool UpgradeToVersion4();
+
+ // Migrates the icon mapping data from URL database to Thumbnail database.
+ // Return whether the migration succeeds.
+ bool MigrateIconMappingData(URLDatabase* url_db);
+
// Creates the index over the favicon table. This will be called during
// initialization after the table is created. This is a separate function
// because it is used by SwapFaviconTables to create an index over the
// newly-renamed favicons table (formerly the temporary table with no index).
void InitFavIconsIndex();
+ // Creates the icon_map table, return true if the table already exists or was
+ // successfully created.
+ bool InitIconMappingTable(sql::Connection* db, bool is_temporary);
+
+ // Creates the index over the icon_mapping table, This will be called during
+ // initialization after the table is created. This is a separate function
+ // because it is used by CommitTemporaryIconMappingTable to create an index
+ // over the newly-renamed icon_mapping table (formerly the temporary table
+ // with no index).
+ void InitIconMappingIndex();
+
+ // Adds a mapping between the given page_url and icon_id; The mapping will be
+ // added to temp_icon_mapping table if is_temporary is true.
+ // Returns the new mapping id if the adding succeeds, otherwise 0 is returned.
+ IconMappingID AddIconMapping(const GURL& page_url,
+ FavIconID icon_id,
+ bool is_temporary);
+
sql::Connection db_;
sql::MetaTable meta_table_;
diff --git a/chrome/browser/history/thumbnail_database_unittest.cc b/chrome/browser/history/thumbnail_database_unittest.cc
index 6483a25..cd40298 100644
--- a/chrome/browser/history/thumbnail_database_unittest.cc
+++ b/chrome/browser/history/thumbnail_database_unittest.cc
@@ -12,9 +12,13 @@
#include "base/path_service.h"
#include "base/ref_counted_memory.h"
#include "base/scoped_temp_dir.h"
+#include "chrome/browser/history/history_database.h"
+#include "chrome/browser/history/history_unittest_base.h"
#include "chrome/browser/history/thumbnail_database.h"
+#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/thumbnail_score.h"
+#include "chrome/test/testing_profile.h"
#include "chrome/tools/profiles/thumbnail-inl.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -58,7 +62,7 @@ class ThumbnailDatabaseTest : public testing::Test {
file_name_ = temp_dir_.path().AppendASCII("TestThumbnails.db");
new_file_name_ = temp_dir_.path().AppendASCII("TestFavicons.db");
-
+ history_db_name_ = temp_dir_.path().AppendASCII("TestHistory.db");
google_bitmap_.reset(
gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail)));
}
@@ -68,18 +72,54 @@ class ThumbnailDatabaseTest : public testing::Test {
ScopedTempDir temp_dir_;
FilePath file_name_;
FilePath new_file_name_;
+ FilePath history_db_name_;
+};
+
+class IconMappingMigrationTest : public HistoryUnitTestBase {
+ public:
+ IconMappingMigrationTest() {
+ }
+ ~IconMappingMigrationTest() {
+ }
+
+ protected:
+ virtual void SetUp() {
+ profile_.reset(new TestingProfile);
+
+ FilePath data_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
+ data_path = data_path.AppendASCII("History");
+
+ history_db_name_ = profile_->GetPath().Append(chrome::kHistoryFilename);
+ // Set up history and thumbnails as they would be before migration.
+ ASSERT_NO_FATAL_FAILURE(
+ ExecuteSQLScript(data_path.AppendASCII("history.20.sql"),
+ history_db_name_));
+ thumbnail_db_name_ =
+ profile_->GetPath().Append(chrome::kThumbnailsFilename);
+ ASSERT_NO_FATAL_FAILURE(
+ ExecuteSQLScript(data_path.AppendASCII("thumbnails.3.sql"),
+ thumbnail_db_name_));
+ }
+
+ protected:
+ FilePath history_db_name_;
+ FilePath thumbnail_db_name_;
+
+ private:
+ scoped_ptr<TestingProfile> profile_;
};
TEST_F(ThumbnailDatabaseTest, GetFaviconAfterMigrationToTopSites) {
ThumbnailDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL));
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
db.BeginTransaction();
std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
GURL url("http://google.com");
- FavIconID id = db.AddFavIcon(url);
+ FavIconID id = db.AddFavIcon(url, FAV_ICON);
base::Time time = base::Time::Now();
db.SetFavIcon(id, favicon, time);
EXPECT_TRUE(db.RenameAndDropThumbnails(file_name_, new_file_name_));
@@ -96,4 +136,327 @@ TEST_F(ThumbnailDatabaseTest, GetFaviconAfterMigrationToTopSites) {
favicon_out.begin()));
}
+TEST_F(ThumbnailDatabaseTest, AddIconMapping) {
+ ThumbnailDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
+ db.BeginTransaction();
+
+ std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
+ scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
+
+ GURL url("http://google.com");
+ FavIconID id = db.AddFavIcon(url, TOUCH_ICON);
+ EXPECT_NE(0, id);
+ base::Time time = base::Time::Now();
+ db.SetFavIcon(id, favicon, time);
+
+ EXPECT_NE(0, db.AddIconMapping(url, id));
+ std::vector<IconMapping> icon_mapping;
+ EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
+ EXPECT_EQ(1u, icon_mapping.size());
+ EXPECT_EQ(url, icon_mapping.front().page_url);
+ EXPECT_EQ(id, icon_mapping.front().icon_id);
+}
+
+TEST_F(ThumbnailDatabaseTest, UpdateIconMapping) {
+ ThumbnailDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
+ db.BeginTransaction();
+
+ std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
+ scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
+
+ GURL url("http://google.com");
+ FavIconID id = db.AddFavIcon(url, TOUCH_ICON);
+ base::Time time = base::Time::Now();
+ db.SetFavIcon(id, favicon, time);
+
+ EXPECT_TRUE(0 < db.AddIconMapping(url, id));
+ std::vector<IconMapping> icon_mapping;
+ EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
+ ASSERT_EQ(1u, icon_mapping.size());
+ EXPECT_EQ(url, icon_mapping.front().page_url);
+ EXPECT_EQ(id, icon_mapping.front().icon_id);
+
+ GURL url1("http://www.google.com/");
+ FavIconID new_id = db.AddFavIcon(url1, TOUCH_ICON);
+ EXPECT_TRUE(db.UpdateIconMapping(icon_mapping.front().mapping_id, new_id));
+
+ icon_mapping.clear();
+ EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
+ ASSERT_EQ(1u, icon_mapping.size());
+ EXPECT_EQ(url, icon_mapping.front().page_url);
+ EXPECT_EQ(new_id, icon_mapping.front().icon_id);
+ EXPECT_NE(id, icon_mapping.front().icon_id);
+}
+
+TEST_F(ThumbnailDatabaseTest, DeleteIconMappings) {
+ ThumbnailDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
+ db.BeginTransaction();
+
+ std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
+ scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
+
+ GURL url("http://google.com");
+ FavIconID id = db.AddFavIcon(url, TOUCH_ICON);
+ base::Time time = base::Time::Now();
+ db.SetFavIcon(id, favicon, time);
+ EXPECT_TRUE(0 < db.AddIconMapping(url, id));
+
+ FavIconID id2 = db.AddFavIcon(url, FAV_ICON);
+ db.SetFavIcon(id2, favicon, time);
+ EXPECT_TRUE(0 < db.AddIconMapping(url, id2));
+ ASSERT_NE(id, id2);
+
+ std::vector<IconMapping> icon_mapping;
+ EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
+ ASSERT_EQ(2u, icon_mapping.size());
+ EXPECT_EQ(icon_mapping.front().icon_type, TOUCH_ICON);
+ EXPECT_TRUE(db.GetIconMappingForPageURL(url, FAV_ICON, NULL));
+
+ db.DeleteIconMappings(url);
+
+ EXPECT_FALSE(db.GetIconMappingsForPageURL(url, NULL));
+ EXPECT_FALSE(db.GetIconMappingForPageURL(url, FAV_ICON, NULL));
+}
+
+TEST_F(ThumbnailDatabaseTest, GetIconMappingsForPageURL) {
+ ThumbnailDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
+ db.BeginTransaction();
+
+ std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
+ scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
+
+ GURL url("http://google.com");
+
+ FavIconID id1 = db.AddFavIcon(url, TOUCH_ICON);
+ base::Time time = base::Time::Now();
+ db.SetFavIcon(id1, favicon, time);
+ EXPECT_TRUE(0 < db.AddIconMapping(url, id1));
+
+ FavIconID id2 = db.AddFavIcon(url, FAV_ICON);
+ EXPECT_NE(id1, id2);
+ db.SetFavIcon(id2, favicon, time);
+ EXPECT_TRUE(0 < db.AddIconMapping(url, id2));
+
+ std::vector<IconMapping> icon_mapping;
+ EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
+ ASSERT_EQ(2u, icon_mapping.size());
+ EXPECT_NE(icon_mapping[0].icon_id, icon_mapping[1].icon_id);
+ EXPECT_TRUE(icon_mapping[0].icon_id == id1 && icon_mapping[1].icon_id == id2);
+}
+
+TEST_F(ThumbnailDatabaseTest, UpgradeToVersion4) {
+ ThumbnailDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
+ db.BeginTransaction();
+
+ const char* name = "favicons";
+ std::string sql;
+ sql.append("DROP TABLE IF EXISTS ");
+ sql.append(name);
+ EXPECT_TRUE(db.db_.Execute(sql.c_str()));
+
+ sql.resize(0);
+ sql.append("CREATE TABLE ");
+ sql.append(name);
+ sql.append("("
+ "id INTEGER PRIMARY KEY,"
+ "url LONGVARCHAR NOT NULL,"
+ "last_updated INTEGER DEFAULT 0,"
+ "image_data BLOB)");
+ EXPECT_TRUE(db.db_.Execute(sql.c_str()));
+
+ EXPECT_TRUE(db.UpgradeToVersion4());
+
+ std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
+ scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
+
+ GURL url("http://google.com");
+ FavIconID id = db.AddFavIcon(url, TOUCH_ICON);
+ base::Time time = base::Time::Now();
+ db.SetFavIcon(id, favicon, time);
+
+ EXPECT_TRUE(0 < db.AddIconMapping(url, id));
+ IconMapping icon_mapping;
+ EXPECT_TRUE(db.GetIconMappingForPageURL(url, TOUCH_ICON, &icon_mapping));
+ EXPECT_EQ(url, icon_mapping.page_url);
+ EXPECT_EQ(id, icon_mapping.icon_id);
+}
+
+TEST_F(ThumbnailDatabaseTest, TemporayIconMapping) {
+ ThumbnailDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
+
+ db.BeginTransaction();
+
+ EXPECT_TRUE(db.InitTemporaryIconMappingTable());
+
+ std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
+ scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
+
+ GURL url("http://google.com");
+ FavIconID id = db.AddFavIcon(url, FAV_ICON);
+ base::Time time = base::Time::Now();
+ db.SetFavIcon(id, favicon, time);
+
+ db.AddToTemporaryIconMappingTable(url, id);
+ db.CommitTemporaryIconMappingTable();
+ IconMapping icon_mapping;
+ EXPECT_TRUE(db.GetIconMappingForPageURL(url, FAV_ICON, &icon_mapping));
+ EXPECT_EQ(id, icon_mapping.icon_id);
+ EXPECT_EQ(url, icon_mapping.page_url);
+}
+
+TEST_F(ThumbnailDatabaseTest, GetIconMappingsForPageURLForReturnOrder) {
+ ThumbnailDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
+ db.BeginTransaction();
+
+ // Add a favicon
+ std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
+ scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
+
+ GURL url("http://google.com");
+ FavIconID id = db.AddFavIcon(url, FAV_ICON);
+ base::Time time = base::Time::Now();
+ db.SetFavIcon(id, favicon, time);
+
+ EXPECT_NE(0, db.AddIconMapping(url, id));
+ std::vector<IconMapping> icon_mapping;
+ EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
+
+ EXPECT_EQ(url, icon_mapping.front().page_url);
+ EXPECT_EQ(id, icon_mapping.front().icon_id);
+ EXPECT_EQ(FAV_ICON, icon_mapping.front().icon_type);
+
+ // Add a touch icon
+ std::vector<unsigned char> data2(blob2, blob2 + sizeof(blob2));
+ scoped_refptr<RefCountedBytes> favicon2(new RefCountedBytes(data));
+
+ FavIconID id2 = db.AddFavIcon(url, TOUCH_ICON);
+ db.SetFavIcon(id2, favicon2, time);
+ EXPECT_NE(0, db.AddIconMapping(url, id2));
+
+ icon_mapping.clear();
+ EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
+
+ EXPECT_EQ(url, icon_mapping.front().page_url);
+ EXPECT_EQ(id2, icon_mapping.front().icon_id);
+ EXPECT_EQ(TOUCH_ICON, icon_mapping.front().icon_type);
+
+ // Add a touch precomposed icon
+ scoped_refptr<RefCountedBytes> favicon3(new RefCountedBytes(data2));
+
+ FavIconID id3 = db.AddFavIcon(url, TOUCH_PRECOMPOSED_ICON);
+ db.SetFavIcon(id3, favicon3, time);
+ EXPECT_NE(0, db.AddIconMapping(url, id3));
+
+ icon_mapping.clear();
+ EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
+
+ EXPECT_EQ(url, icon_mapping.front().page_url);
+ EXPECT_EQ(id3, icon_mapping.front().icon_id);
+ EXPECT_EQ(TOUCH_PRECOMPOSED_ICON, icon_mapping.front().icon_type);
+}
+
+TEST_F(ThumbnailDatabaseTest, HasMappingFor) {
+ ThumbnailDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
+ db.BeginTransaction();
+
+ std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
+ scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
+
+ // Add a favicon which will have icon_mappings
+ FavIconID id1 = db.AddFavIcon(GURL("http://google.com"), FAV_ICON);
+ EXPECT_NE(id1, 0);
+ base::Time time = base::Time::Now();
+ db.SetFavIcon(id1, favicon, time);
+
+ // Add another type of favicon
+ FavIconID id2 = db.AddFavIcon(GURL("http://www.google.com/icon"), TOUCH_ICON);
+ EXPECT_NE(id2, 0);
+ time = base::Time::Now();
+ db.SetFavIcon(id2, favicon, time);
+
+ // Add 3rd favicon
+ FavIconID id3 = db.AddFavIcon(GURL("http://www.google.com/icon"), TOUCH_ICON);
+ EXPECT_NE(id3, 0);
+ time = base::Time::Now();
+ db.SetFavIcon(id3, favicon, time);
+
+ // Add 2 icon mapping
+ GURL page_url("http://www.google.com");
+ EXPECT_TRUE(db.AddIconMapping(page_url, id1));
+ EXPECT_TRUE(db.AddIconMapping(page_url, id2));
+
+ EXPECT_TRUE(db.HasMappingFor(id1));
+ EXPECT_TRUE(db.HasMappingFor(id2));
+ EXPECT_FALSE(db.HasMappingFor(id3));
+
+ // Remove all mappings
+ db.DeleteIconMappings(page_url);
+ EXPECT_FALSE(db.HasMappingFor(id1));
+ EXPECT_FALSE(db.HasMappingFor(id2));
+ EXPECT_FALSE(db.HasMappingFor(id3));
+}
+
+TEST_F(IconMappingMigrationTest, TestIconMappingMigration) {
+ HistoryDatabase history_db;
+ ASSERT_TRUE(history_db.db_.Open(history_db_name_));
+ history_db.BeginTransaction();
+
+ const GURL icon1 = GURL("http://www.google.com/favicon.ico");
+ const GURL icon2 = GURL("http://www.yahoo.com/favicon.ico");
+
+ ThumbnailDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(thumbnail_db_name_, NULL, &history_db));
+ db.BeginTransaction();
+
+ // Migration should be done.
+ // Test one icon_mapping.
+ GURL page_url1 = GURL("http://google.com/");
+ std::vector<IconMapping> icon_mappings;
+ EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url1, &icon_mappings));
+ ASSERT_EQ(1u, icon_mappings.size());
+ EXPECT_EQ(FAV_ICON, icon_mappings[0].icon_type);
+ EXPECT_EQ(page_url1, icon_mappings[0].page_url);
+ EXPECT_EQ(1, icon_mappings[0].icon_id);
+ base::Time time;
+ std::vector<unsigned char> out_data;
+ GURL out_icon_url;
+ ASSERT_TRUE(db.GetFavIcon(
+ icon_mappings[0].icon_id, &time, &out_data, &out_icon_url));
+ EXPECT_EQ(icon1, out_icon_url);
+
+ // Test a page which has the same icon.
+ GURL page_url3 = GURL("http://www.google.com/");
+ icon_mappings.clear();
+ EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url3, &icon_mappings));
+ ASSERT_EQ(1u, icon_mappings.size());
+ EXPECT_EQ(FAV_ICON, icon_mappings[0].icon_type);
+ EXPECT_EQ(page_url3, icon_mappings[0].page_url);
+ EXPECT_EQ(1, icon_mappings[0].icon_id);
+
+ // Test a icon_mapping with different IconID.
+ GURL page_url2 = GURL("http://yahoo.com/");
+ icon_mappings.clear();
+ EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url2, &icon_mappings));
+ ASSERT_EQ(1u, icon_mappings.size());
+ EXPECT_EQ(FAV_ICON, icon_mappings[0].icon_type);
+ EXPECT_EQ(page_url2, icon_mappings[0].page_url);
+ EXPECT_EQ(2, icon_mappings[0].icon_id);
+ ASSERT_TRUE(db.GetFavIcon(
+ icon_mappings[0].icon_id, &time, &out_data, &out_icon_url));
+ EXPECT_EQ(icon2, out_icon_url);
+
+ // Test a page without icon
+ GURL page_url4 = GURL("http://www.google.com/blank.html");
+ EXPECT_FALSE(db.GetIconMappingsForPageURL(page_url4, NULL));
+}
+
} // namespace history
diff --git a/chrome/browser/history/top_sites_unittest.cc b/chrome/browser/history/top_sites_unittest.cc
index 866ba3c..f818bb7 100644
--- a/chrome/browser/history/top_sites_unittest.cc
+++ b/chrome/browser/history/top_sites_unittest.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/history/history_database.h"
#include "chrome/browser/history/history_marshaling.h"
#include "chrome/browser/history/history_notifications.h"
+#include "chrome/browser/history/history_unittest_base.h"
#include "chrome/browser/history/top_sites.h"
#include "chrome/browser/history/top_sites_backend.h"
#include "chrome/browser/history/top_sites_cache.h"
@@ -124,7 +125,7 @@ bool ThumbnailsAreEqual(RefCountedBytes* t1, RefCountedBytes* t2) {
} // namespace
-class TopSitesTest : public testing::Test {
+class TopSitesTest : public HistoryUnitTestBase {
public:
TopSitesTest()
: ui_thread_(BrowserThread::UI, &message_loop_),
@@ -334,12 +335,12 @@ class TopSitesMigrationTest : public TopSitesTest {
data_path = data_path.AppendASCII("top_sites");
// Set up history and thumbnails as they would be before migration.
- ASSERT_NO_FATAL_FAILURE(
- ExecuteSQL(data_path.AppendASCII("history.19.sql"),
- profile()->GetPath().Append(chrome::kHistoryFilename)));
- ASSERT_NO_FATAL_FAILURE(
- ExecuteSQL(data_path.AppendASCII("thumbnails.3.sql"),
- profile()->GetPath().Append(chrome::kThumbnailsFilename)));
+ ASSERT_NO_FATAL_FAILURE(ExecuteSQLScript(
+ data_path.AppendASCII("history.19.sql"),
+ profile()->GetPath().Append(chrome::kHistoryFilename)));
+ ASSERT_NO_FATAL_FAILURE(ExecuteSQLScript(
+ data_path.AppendASCII("thumbnails.3.sql"),
+ profile()->GetPath().Append(chrome::kThumbnailsFilename)));
profile()->CreateHistoryService(false, false);
profile()->CreateTopSites();
@@ -377,25 +378,6 @@ class TopSitesMigrationTest : public TopSitesTest {
}
private:
- // Executes the sql from the file |sql_path| in the database at |db_path|.
- void ExecuteSQL(const FilePath& sql_path,
- const FilePath& db_path) {
- std::string sql;
- ASSERT_TRUE(file_util::ReadFileToString(sql_path, &sql));
-
- // Replace the 'last_visit_time', 'visit_time', 'time_slot' values in this
- // SQL with the current time.
- int64 now = base::Time::Now().ToInternalValue();
- std::vector<std::string> sql_time;
- sql_time.push_back(StringPrintf("%" PRId64, now)); // last_visit_time
- sql_time.push_back(StringPrintf("%" PRId64, now)); // visit_time
- sql_time.push_back(StringPrintf("%" PRId64, now)); // time_slot
- sql = ReplaceStringPlaceholders(sql, sql_time, NULL);
-
- sql::Connection connection;
- ASSERT_TRUE(connection.Open(db_path));
- ASSERT_TRUE(connection.Execute(sql.c_str()));
- }
DISALLOW_COPY_AND_ASSIGN(TopSitesMigrationTest);
};
diff --git a/chrome/browser/history/url_database.cc b/chrome/browser/history/url_database.cc
index f6c041c..78ca0c5 100644
--- a/chrome/browser/history/url_database.cc
+++ b/chrome/browser/history/url_database.cc
@@ -20,6 +20,19 @@ namespace history {
const char URLDatabase::kURLRowFields[] = HISTORY_URL_ROW_FIELDS;
const int URLDatabase::kNumURLRowFields = 9;
+URLDatabase::URLEnumeratorBase::URLEnumeratorBase()
+ : initialized_(false) {
+}
+
+URLDatabase::URLEnumeratorBase::~URLEnumeratorBase() {
+}
+
+URLDatabase::URLEnumerator::URLEnumerator() {
+}
+
+URLDatabase::IconMappingEnumerator::IconMappingEnumerator() {
+}
+
bool URLDatabase::URLEnumerator::GetNextURL(URLRow* r) {
if (statement_.Step()) {
FillURLRow(statement_, r);
@@ -28,7 +41,17 @@ bool URLDatabase::URLEnumerator::GetNextURL(URLRow* r) {
return false;
}
-URLDatabase::URLDatabase() : has_keyword_search_terms_(false) {
+bool URLDatabase::IconMappingEnumerator::GetNextIconMapping(IconMapping* r) {
+ if (!statement_.Step())
+ return false;
+
+ r->page_url = GURL(statement_.ColumnString(0));
+ r->icon_id = statement_.ColumnInt64(1);
+ return true;
+}
+
+URLDatabase::URLDatabase()
+ : has_keyword_search_terms_(false) {
}
URLDatabase::~URLDatabase() {
@@ -57,7 +80,6 @@ void URLDatabase::FillURLRow(sql::Statement& s, history::URLRow* i) {
i->typed_count_ = s.ColumnInt(4);
i->last_visit_ = base::Time::FromInternalValue(s.ColumnInt64(5));
i->hidden_ = s.ColumnInt(6) != 0;
- i->favicon_id_ = s.ColumnInt64(7);
}
bool URLDatabase::GetURLRow(URLID url_id, URLRow* info) {
@@ -112,7 +134,7 @@ bool URLDatabase::UpdateURLRow(URLID url_id,
const history::URLRow& info) {
sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
"UPDATE urls SET title=?,visit_count=?,typed_count=?,last_visit_time=?,"
- "hidden=?,favicon_id=?"
+ "hidden=?"
"WHERE id=?"));
if (!statement)
return false;
@@ -122,8 +144,7 @@ bool URLDatabase::UpdateURLRow(URLID url_id,
statement.BindInt(2, info.typed_count());
statement.BindInt64(3, info.last_visit().ToInternalValue());
statement.BindInt(4, info.hidden() ? 1 : 0);
- statement.BindInt64(5, info.favicon_id());
- statement.BindInt64(6, url_id);
+ statement.BindInt64(5, url_id);
return statement.Run();
}
@@ -135,8 +156,8 @@ URLID URLDatabase::AddURLInternal(const history::URLRow& info,
// invalid in the insert syntax.
#define ADDURL_COMMON_SUFFIX \
" (url, title, visit_count, typed_count, "\
- "last_visit_time, hidden, favicon_id) "\
- "VALUES (?,?,?,?,?,?,?)"
+ "last_visit_time, hidden) "\
+ "VALUES (?,?,?,?,?,?)"
const char* statement_name;
const char* statement_sql;
if (is_temporary) {
@@ -161,7 +182,6 @@ URLID URLDatabase::AddURLInternal(const history::URLRow& info,
statement.BindInt(3, info.typed_count());
statement.BindInt64(4, info.last_visit().ToInternalValue());
statement.BindInt(5, info.hidden() ? 1 : 0);
- statement.BindInt64(6, info.favicon_id());
if (!statement.Run()) {
VLOG(0) << "Failed to add url " << info.url().possibly_invalid_spec()
@@ -257,14 +277,17 @@ bool URLDatabase::InitURLEnumeratorForSignificant(URLEnumerator* enumerator) {
return true;
}
-bool URLDatabase::IsFavIconUsed(FavIconID favicon_id) {
- sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
- "SELECT id FROM urls WHERE favicon_id=? LIMIT 1"));
- if (!statement)
+bool URLDatabase::InitIconMappingEnumeratorForEverything(
+ IconMappingEnumerator* enumerator) {
+ DCHECK(!enumerator->initialized_);
+ enumerator->statement_.Assign(GetDB().GetUniqueStatement(
+ "SELECT url, favicon_id FROM urls WHERE favicon_id <> 0"));
+ if (!enumerator->statement_) {
+ NOTREACHED() << GetDB().GetErrorMessage();
return false;
-
- statement.BindInt64(0, favicon_id);
- return statement.Step();
+ }
+ enumerator->initialized_ = true;
+ return true;
}
void URLDatabase::AutocompleteForPrefix(const string16& prefix,
@@ -480,15 +503,6 @@ void URLDatabase::GetMostRecentKeywordSearchTerms(
}
}
-bool URLDatabase::MigrateFromVersion11ToVersion12() {
- URLRow about_row;
- if (GetRowForURL(GURL(chrome::kAboutBlankURL), &about_row)) {
- about_row.set_favicon_id(0);
- return UpdateURLRow(about_row.id(), about_row);
- }
- return true;
-}
-
bool URLDatabase::DropStarredIDFromURLs() {
if (!GetDB().DoesColumnExist("urls", "starred_id"))
return true; // urls is already updated, no need to continue.
@@ -512,9 +526,6 @@ bool URLDatabase::DropStarredIDFromURLs() {
// Rename/commit the tmp table.
CommitTemporaryURLTable();
- // This isn't created by CommitTemporaryURLTable.
- CreateSupplimentaryURLIndices();
-
return true;
}
@@ -534,7 +545,7 @@ bool URLDatabase::CreateURLTable(bool is_temporary) {
"typed_count INTEGER DEFAULT 0 NOT NULL,"
"last_visit_time INTEGER NOT NULL,"
"hidden INTEGER DEFAULT 0 NOT NULL,"
- "favicon_id INTEGER DEFAULT 0 NOT NULL)");
+ "favicon_id INTEGER DEFAULT 0 NOT NULL)"); // favicon_id is not used now.
return GetDB().Execute(sql.c_str());
}
@@ -545,9 +556,4 @@ void URLDatabase::CreateMainURLIndex() {
GetDB().Execute("CREATE INDEX urls_url_index ON urls (url)");
}
-void URLDatabase::CreateSupplimentaryURLIndices() {
- // Add a favicon index. This is useful when we delete urls.
- GetDB().Execute("CREATE INDEX urls_favicon_id_INDEX ON urls (favicon_id)");
-}
-
} // namespace history
diff --git a/chrome/browser/history/url_database.h b/chrome/browser/history/url_database.h
index c821ce7..c21d925 100644
--- a/chrome/browser/history/url_database.h
+++ b/chrome/browser/history/url_database.h
@@ -111,20 +111,44 @@ class URLDatabase {
// Enumeration ---------------------------------------------------------------
+ // A basic enumerator to enumerate urls database.
+ class URLEnumeratorBase {
+ public:
+ URLEnumeratorBase();
+ virtual ~URLEnumeratorBase();
+
+ private:
+ friend class URLDatabase;
+
+ bool initialized_;
+ sql::Statement statement_;
+
+ DISALLOW_COPY_AND_ASSIGN(URLEnumeratorBase);
+ };
+
// A basic enumerator to enumerate urls
- class URLEnumerator {
+ class URLEnumerator : public URLEnumeratorBase {
public:
- URLEnumerator() : initialized_(false) {
- }
+ URLEnumerator();
// Retreives the next url. Returns false if no more urls are available
bool GetNextURL(history::URLRow* r);
private:
- friend class URLDatabase;
+ DISALLOW_COPY_AND_ASSIGN(URLEnumerator);
+ };
- bool initialized_;
- sql::Statement statement_;
+ // A basic enumerator to enumerate icon mapping, it is only used for icon
+ // mapping migration.
+ class IconMappingEnumerator : public URLEnumeratorBase {
+ public:
+ IconMappingEnumerator();
+
+ // Retreives the next url. Returns false if no more urls are available
+ bool GetNextIconMapping(IconMapping* r);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IconMappingEnumerator);
};
// Initializes the given enumerator to enumerator all URLs in the database.
@@ -138,9 +162,6 @@ class URLDatabase {
// Favicons ------------------------------------------------------------------
- // Check whether a favicon is used by any URLs in the database.
- bool IsFavIconUsed(FavIconID favicon_id);
-
// Autocomplete --------------------------------------------------------------
// Fills the given array with URLs matching the given prefix. They will be
@@ -194,6 +215,11 @@ class URLDatabase {
// the favicon couldn't be updated.
bool MigrateFromVersion11ToVersion12();
+ // Initializes the given enumerator to enumerator all URL and icon mappings
+ // in the database. Only used for icon mapping migration.
+ bool InitIconMappingEnumeratorForEverything(
+ IconMappingEnumerator* enumerator);
+
protected:
friend class VisitDatabase;
@@ -220,12 +246,8 @@ class URLDatabase {
// different name but the same schema.
bool CreateURLTable(bool is_temporary);
// We have two tiers of indices for the URL table. The main tier is used by
- // all URL databases, and is an index over the URL itself. The main history
- // DB also creates indices over the favicons and bookmark IDs. The archived
- // and in-memory databases don't need these supplimentary indices so we can
- // save space by not creating them.
+ // all URL databases, and is an index over the URL itself.
void CreateMainURLIndex();
- void CreateSupplimentaryURLIndices();
// Ensures the keyword search terms table exists.
bool InitKeywordSearchTermsTable();
@@ -267,7 +289,7 @@ class URLDatabase {
// string dynamically anyway, use the constant, it will save space.
#define HISTORY_URL_ROW_FIELDS \
" urls.id, urls.url, urls.title, urls.visit_count, urls.typed_count, " \
- "urls.last_visit_time, urls.hidden, urls.favicon_id "
+ "urls.last_visit_time, urls.hidden "
} // history
diff --git a/chrome/browser/history/url_database_unittest.cc b/chrome/browser/history/url_database_unittest.cc
index c2f22ff6..10e80c7 100644
--- a/chrome/browser/history/url_database_unittest.cc
+++ b/chrome/browser/history/url_database_unittest.cc
@@ -38,6 +38,12 @@ class URLDatabaseTest : public testing::Test,
URLDatabaseTest() {
}
+ protected:
+ // Provided for URL/VisitDatabase.
+ virtual sql::Connection& GetDB() {
+ return db_;
+ }
+
private:
// Test setup.
void SetUp() {
@@ -50,7 +56,6 @@ class URLDatabaseTest : public testing::Test,
// Initialize the tables for this test.
CreateURLTable(false);
CreateMainURLIndex();
- CreateSupplimentaryURLIndices();
InitKeywordSearchTermsTable();
CreateKeywordSearchTermsIndices();
}
@@ -59,11 +64,6 @@ class URLDatabaseTest : public testing::Test,
file_util::Delete(db_file_, false);
}
- // Provided for URL/VisitDatabase.
- virtual sql::Connection& GetDB() {
- return db_;
- }
-
FilePath db_file_;
sql::Connection db_;
};
@@ -222,4 +222,50 @@ TEST_F(URLDatabaseTest, EnumeratorForSignificant) {
EXPECT_EQ(3, row_count);
}
+TEST_F(URLDatabaseTest, IconMappingEnumerator) {
+ const GURL url1("http://www.google.com/");
+ URLRow url_info1(url1);
+ url_info1.set_title(UTF8ToUTF16("Google"));
+ url_info1.set_visit_count(4);
+ url_info1.set_typed_count(2);
+ url_info1.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
+ url_info1.set_hidden(false);
+
+ // Insert a row with favicon
+ URLID url_id1 = AddURL(url_info1);
+ ASSERT_TRUE(url_id1 != 0);
+
+ FavIconID icon_id = 1;
+ sql::Statement statement(GetDB().GetCachedStatement(
+ SQL_FROM_HERE,
+ "UPDATE urls SET favicon_id =? WHERE id=?"));
+
+ ASSERT_TRUE(statement);
+
+ statement.BindInt64(0, icon_id);
+ statement.BindInt64(1, url_id1);
+ ASSERT_TRUE(statement.Run());
+
+ // Insert another row without favicon
+ const GURL url2("http://www.google.com/no_icon");
+ URLRow url_info2(url2);
+ url_info2.set_title(UTF8ToUTF16("Google"));
+ url_info2.set_visit_count(4);
+ url_info2.set_typed_count(2);
+ url_info2.set_last_visit(Time::Now() - TimeDelta::FromDays(1));
+ url_info2.set_hidden(false);
+
+ // Insert a row with favicon
+ URLID url_id2 = AddURL(url_info2);
+ ASSERT_TRUE(url_id2 != 0);
+
+ IconMappingEnumerator e;
+ InitIconMappingEnumeratorForEverything(&e);
+ IconMapping icon_mapping;
+ ASSERT_TRUE(e.GetNextIconMapping(&icon_mapping));
+ ASSERT_EQ(url1, icon_mapping.page_url);
+ ASSERT_EQ(icon_id, icon_mapping.icon_id);
+ ASSERT_FALSE(e.GetNextIconMapping(&icon_mapping));
+}
+
} // namespace history
diff --git a/chrome/browser/history/visit_database_unittest.cc b/chrome/browser/history/visit_database_unittest.cc
index 28a0e15..1cf1868 100644
--- a/chrome/browser/history/visit_database_unittest.cc
+++ b/chrome/browser/history/visit_database_unittest.cc
@@ -52,7 +52,6 @@ class VisitDatabaseTest : public PlatformTest,
// Initialize the tables for this test.
CreateURLTable(false);
CreateMainURLIndex();
- CreateSupplimentaryURLIndices();
InitVisitTable();
}
void TearDown() {
diff --git a/chrome/browser/importer/importer_messages.h b/chrome/browser/importer/importer_messages.h
index 46d6c98..854343a 100644
--- a/chrome/browser/importer/importer_messages.h
+++ b/chrome/browser/importer/importer_messages.h
@@ -78,7 +78,6 @@ struct ParamTraits<history::URLRow> {
WriteParam(m, p.typed_count());
WriteParam(m, p.last_visit());
WriteParam(m, p.hidden());
- WriteParam(m, p.favicon_id());
}
static bool Read(const Message* m, void** iter, param_type* p) {
history::URLID id;
@@ -103,7 +102,6 @@ struct ParamTraits<history::URLRow> {
p->set_typed_count(typed_count);
p->set_last_visit(last_visit);
p->set_hidden(hidden);
- p->set_favicon_id(favicon_id);
return true;
}
static void Log(const param_type& p, std::string* l) {
@@ -121,8 +119,6 @@ struct ParamTraits<history::URLRow> {
LogParam(p.last_visit(), l);
l->append(", ");
LogParam(p.hidden(), l);
- l->append(", ");
- LogParam(p.favicon_id(), l);
l->append(")");
}
}; // ParamTraits<history::URLRow>
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index f849a4f..069b884 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1318,6 +1318,8 @@
'browser/history/history_querying_unittest.cc',
'browser/history/history_types_unittest.cc',
'browser/history/history_unittest.cc',
+ 'browser/history/history_unittest_base.cc',
+ 'browser/history/history_unittest_base.h',
'browser/history/in_memory_url_index_unittest.cc',
'browser/history/query_parser_unittest.cc',
'browser/history/snippet_unittest.cc',
diff --git a/chrome/test/data/History/history.20.sql b/chrome/test/data/History/history.20.sql
new file mode 100644
index 0000000..2adb73c
--- /dev/null
+++ b/chrome/test/data/History/history.20.sql
@@ -0,0 +1,11 @@
+BEGIN TRANSACTION;
+CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
+INSERT INTO "meta" VALUES('version','20');
+INSERT INTO "meta" VALUES('last_compatible_version','16');
+CREATE TABLE urls(id INTEGER PRIMARY KEY,url LONGVARCHAR,title LONGVARCHAR,visit_count INTEGER DEFAULT 0 NOT NULL,typed_count INTEGER DEFAULT 0 NOT NULL,last_visit_time INTEGER NOT NULL,hidden INTEGER DEFAULT 0 NOT NULL,favicon_id INTEGER DEFAULT 0 NOT NULL);
+INSERT INTO "urls" VALUES(1,'http://google.com/','Google',1,1,$1,0,1);
+INSERT INTO "urls" VALUES(2,'http://www.google.com/','Google',1,0,$1,0,1);
+INSERT INTO "urls" VALUES(3,'http://www.google.com/blank.html','',1,0,$1,1,0);
+INSERT INTO "urls" VALUES(4,'http://yahoo.com/','Yahoo!',1,1,$1,0,2);
+INSERT INTO "urls" VALUES(5,'http://www.yahoo.com/','Yahoo!',1,0,$1,0,2);
+COMMIT;
diff --git a/chrome/test/data/History/thumbnails.3.sql b/chrome/test/data/History/thumbnails.3.sql
new file mode 100644
index 0000000..ab7d395
--- /dev/null
+++ b/chrome/test/data/History/thumbnails.3.sql
@@ -0,0 +1,9 @@
+BEGIN TRANSACTION;
+CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
+INSERT INTO "meta" VALUES('version','3');
+INSERT INTO "meta" VALUES('last_compatible_version','3');
+CREATE TABLE favicons(id INTEGER PRIMARY KEY,url LONGVARCHAR NOT NULL,last_updated INTEGER DEFAULT 0,image_data BLOB);
+INSERT INTO "favicons" VALUES(1,'http://www.google.com/favicon.ico',1287424416,X'FFD8FFE000104A46494600010100000100010000FFDB0043000302020302020303030304030304050805050404050A070706080C0A0C0C0B0A0B0B0D0E12100D0E110E0B0B1016101113141515150C0F171816141812141514FFDB00430103040405040509050509140D0B0D1414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414FFC00011080002000203012200021101031101FFC4001F0000010501010101010100000000000000000102030405060708090A0BFFC400B5100002010303020403050504040000017D01020300041105122131410613516107227114328191A1082342B1C11552D1F02433627282090A161718191A25262728292A3435363738393A434445464748494A535455565758595A636465666768696A737475767778797A838485868788898A92939495969798999AA2A3A4A5A6A7A8A9AAB2B3B4B5B6B7B8B9BAC2C3C4C5C6C7C8C9CAD2D3D4D5D6D7D8D9DAE1E2E3E4E5E6E7E8E9EAF1F2F3F4F5F6F7F8F9FAFFC4001F0100030101010101010101010000000000000102030405060708090A0BFFC400B51100020102040403040705040400010277000102031104052131061241510761711322328108144291A1B1C109233352F0156272D10A162434E125F11718191A262728292A35363738393A434445464748494A535455565758595A636465666768696A737475767778797A82838485868788898A92939495969798999AA2A3A4A5A6A7A8A9AAB2B3B4B5B6B7B8B9BAC2C3C4C5C6C7C8C9CAD2D3D4D5D6D7D8D9DAE2E3E4E5E6E7E8E9EAF2F3F4F5F6F7F8F9FAFFDA000C03010002110311003F00F9D28A28AFC30FF54CFFD9');
+INSERT INTO "favicons" VALUES(2,'http://www.yahoo.com/favicon.ico',1287424428,X'FFD8FFE000104A46494600010100000100010000FFDB0043000302020302020303030304030304050805050404050A070706080C0A0C0C0B0A0B0B0D0E12100D0E110E0B0B1016101113141515150C0F171816141812141514FFDB00430103040405040509050509140D0B0D1414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414FFC00011080003000303012200021101031101FFC4001F0000010501010101010100000000000000000102030405060708090A0BFFC400B5100002010303020403050504040000017D01020300041105122131410613516107227114328191A1082342B1C11552D1F02433627282090A161718191A25262728292A3435363738393A434445464748494A535455565758595A636465666768696A737475767778797A838485868788898A92939495969798999AA2A3A4A5A6A7A8A9AAB2B3B4B5B6B7B8B9BAC2C3C4C5C6C7C8C9CAD2D3D4D5D6D7D8D9DAE1E2E3E4E5E6E7E8E9EAF1F2F3F4F5F6F7F8F9FAFFC4001F0100030101010101010101010000000000000102030405060708090A0BFFC400B51100020102040403040705040400010277000102031104052131061241510761711322328108144291A1B1C109233352F0156272D10A162434E125F11718191A262728292A35363738393A434445464748494A535455565758595A636465666768696A737475767778797A82838485868788898A92939495969798999AA2A3A4A5A6A7A8A9AAB2B3B4B5B6B7B8B9BAC2C3C4C5C6C7C8C9CAD2D3D4D5D6D7D8D9DAE2E3E4E5E6E7E8E9EAF2F3F4F5F6F7F8F9FAFFDA000C03010002110311003F00F9D28A28AFC30FF54CFFD9');
+CREATE INDEX favicons_url ON favicons(url);
+COMMIT;
diff --git a/chrome/test/data/profiles/typical_history/Default/Favicons b/chrome/test/data/profiles/typical_history/Default/Favicons
index b42db08..716aea0 100644
--- a/chrome/test/data/profiles/typical_history/Default/Favicons
+++ b/chrome/test/data/profiles/typical_history/Default/Favicons
Binary files differ
diff --git a/chrome/test/data/profiles/typical_history/Default/History b/chrome/test/data/profiles/typical_history/Default/History
index f4e176b..00299e3 100644
--- a/chrome/test/data/profiles/typical_history/Default/History
+++ b/chrome/test/data/profiles/typical_history/Default/History
Binary files differ