diff options
author | sky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-21 15:20:33 +0000 |
---|---|---|
committer | sky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-21 15:20:33 +0000 |
commit | f25387b62a3cccde48622d0b7fca57cd6fb16ab7 (patch) | |
tree | 06ac2c1972d6608fb65979c3a279a6d214fecc6c /chrome/browser/history | |
parent | bcc682fc4f5050ac911635ab649fbd30002fc2b4 (diff) | |
download | chromium_src-f25387b62a3cccde48622d0b7fca57cd6fb16ab7.zip chromium_src-f25387b62a3cccde48622d0b7fca57cd6fb16ab7.tar.gz chromium_src-f25387b62a3cccde48622d0b7fca57cd6fb16ab7.tar.bz2 |
Moves bookmarks out of history into its own file (JSON).
Interesting points:
. Migration was a bit atypical. Here is the approach I took:
. If the URL db contains bookmarks it writes the bookmarks to a
temporary file.
. When the bookmark bar model is loaded it assumes bookmarks are
stored in a file. If the bookmarks file doesn't exist it then
attempts to load from history, after waiting for history to finish
processing tasks.
. I've broken having the omnibox query for starred only. This patch
was already too ginormous for me to contemplate this too. I'll return
to it after I land this.
. Similarly the history page isn't searching for starred titles
now. As we discussed with Glen, that is probably fine for now.
. I've converted NOTIFY_STARRED_FAVICON_CHANGED to
NOTIFY_FAVICON_CHANGED and it is notified ANY time a favicon
changes. I'm mildly concerned about the extra notifications, but
without having history know about starred it's the best I can do for
now.
. Autocomplete (specifically URLDatabase::AutocompleteForPrefix)
previously sorted by starred. It can no longer do this. I don't
think I can get this functionality back:( Luckily it only mattered
if you had a starred and non-starred URL with the same type count
that matched a query. Probably pretty rare.
What's left:
. Fix up HistoryContentsProvider to query for starred entries titles.
. Clean up the delete all case. I basically just made it compile; it
can be greatly simplified.
. Rename BookmarkBarModel to BookmarksModel.
BUG=1256202
TEST=this is a huge change to bookmarks. Thanfully it's pretty well
covered by tests, none-the-less make sure you exercise bookmarks
pretty heavily to make sure nothing is busted.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1153 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/history')
28 files changed, 351 insertions, 1665 deletions
diff --git a/chrome/browser/history/archived_database.cc b/chrome/browser/history/archived_database.cc index 19f6436..40ba38b 100644 --- a/chrome/browser/history/archived_database.cc +++ b/chrome/browser/history/archived_database.cc @@ -34,7 +34,7 @@ namespace history { namespace { -static const int kDatabaseVersion = 1; +static const int kCurrentVersionNumber = 2; } // namespace @@ -73,15 +73,8 @@ bool ArchivedDatabase::Init(const std::wstring& file_name) { BeginTransaction(); // Version check. - if (!meta_table_.Init(std::string(), kDatabaseVersion, db_)) + if (!meta_table_.Init(std::string(), kCurrentVersionNumber, db_)) return false; - if (meta_table_.GetCompatibleVersionNumber() > kDatabaseVersion) { - // We ignore this error and just run without the database. Normally, if - // the user is running two versions, the main history DB will give a - // warning about a version from the future. - LOG(WARNING) << "Archived database is a future version."; - return false; - } // Create the tables. if (!CreateURLTable(false) || !InitVisitTable() || @@ -89,6 +82,9 @@ bool ArchivedDatabase::Init(const std::wstring& file_name) { return false; CreateMainURLIndex(); + if (EnsureCurrentVersion() != INIT_OK) + return false; + // Succeeded: keep the DB open by detaching the auto-closer. scoper.Detach(); db_closer_.Attach(&db_, &statement_cache_); @@ -123,4 +119,36 @@ SqliteStatementCache& ArchivedDatabase::GetStatementCache() { return *statement_cache_; } +// Migration ------------------------------------------------------------------- + +InitStatus ArchivedDatabase::EnsureCurrentVersion() { + // We can't read databases newer than we were designed for. + if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) + return INIT_TOO_NEW; + + // NOTICE: If you are changing structures for things shared with the archived + // history file like URLs, visits, or downloads, that will need migration as + // well. Instead of putting such migration code in this class, it should be + // in the corresponding file (url_database.cc, etc.) and called from here and + // from the archived_database.cc. + + // When the version is too old, we just try to continue anyway, there should + // not be a released product that makes a database too old for us to handle. + int cur_version = meta_table_.GetVersionNumber(); + + // Put migration code here + + if (cur_version == 1) { + if (!DropStarredIDFromURLs()) + return INIT_FAILURE; + cur_version = 2; + meta_table_.SetVersionNumber(cur_version); + meta_table_.SetCompatibleVersionNumber(cur_version); + } + + LOG_IF(WARNING, cur_version < kCurrentVersionNumber) << + "Archived database version " << cur_version << " is too old to handle."; + + return INIT_OK; +} } // namespace history diff --git a/chrome/browser/history/archived_database.h b/chrome/browser/history/archived_database.h index 985dd35..d6617ff 100644 --- a/chrome/browser/history/archived_database.h +++ b/chrome/browser/history/archived_database.h @@ -67,6 +67,15 @@ class ArchivedDatabase : public URLDatabase, virtual sqlite3* GetDB(); virtual SqliteStatementCache& GetStatementCache(); + // Makes sure the version is up-to-date, updating if necessary. If the + // database is too old to migrate, the user will be notified. In this case, or + // for other errors, false will be returned. True means it is up-to-date and + // ready for use. + // + // This assumes it is called from the init function inside a transaction. It + // may commit the transaction and start a new one if migration requires it. + InitStatus EnsureCurrentVersion(); + // The database. // // The close scoper will free the database and delete the statement cache in diff --git a/chrome/browser/history/expire_history_backend.cc b/chrome/browser/history/expire_history_backend.cc index ba42e07..e8065ff 100644 --- a/chrome/browser/history/expire_history_backend.cc +++ b/chrome/browser/history/expire_history_backend.cc @@ -124,8 +124,8 @@ void ExpireHistoryBackend::DeleteURL(const GURL& url) { text_db_->DeleteURLFromUncommitted(url); // Collect all the visits and delete them. Note that we don't give up if - // there are no visits, since the URL could still have an entry (for example, - // if it's starred) that we should delete. + // there are no visits, since the URL could still have an entry that we should + // delete. // TODO(brettw): bug 1171148: We should also delete from the archived DB. VisitVector visits; main_db_->GetVisitsForURL(url_row.id(), &visits); @@ -205,14 +205,6 @@ void ExpireHistoryBackend::DeleteFaviconsIfPossible( void ExpireHistoryBackend::BroadcastDeleteNotifications( DeleteDependencies* dependencies) { - // Broadcast the "unstarred" notification. - if (!dependencies->unstarred_urls.empty()) { - URLsStarredDetails* unstarred_details = new URLsStarredDetails(false); - unstarred_details->changed_urls.swap(dependencies->unstarred_urls); - unstarred_details->star_entries.swap(dependencies->unstarred_entries); - delegate_->BroadcastNotifications(NOTIFY_URLS_STARRED, unstarred_details); - } - if (!dependencies->deleted_urls.empty()) { // Broadcast the URL deleted notification. Note that we also broadcast when // we were requested to delete everything even if that was a NOP, since @@ -284,15 +276,6 @@ void ExpireHistoryBackend::DeleteOneURL( thumb_db_->DeleteThumbnail(url_row.id()); main_db_->DeleteSegmentForURL(url_row.id()); - // The starred table may need to have its corresponding item deleted. - if (url_row.star_id()) { - // Note that this will update the URLRow's starred field, but our variable - // won't be updated correspondingly. - main_db_->DeleteStarredEntry(url_row.star_id(), - &dependencies->unstarred_urls, - &dependencies->unstarred_entries); - } - // Collect shared information. if (url_row.favicon_id()) dependencies->affected_favicons.insert(url_row.favicon_id()); @@ -362,8 +345,8 @@ void ExpireHistoryBackend::ExpireURLsForVisits( else url_row.set_last_visit(Time()); - // Don't delete starred URLs or ones with visits still in the DB. - if (url_row.starred() || !url_row.last_visit().is_null()) { + // Don't delete URLs with visits still in the DB. + if (!url_row.last_visit().is_null()) { // We're not deleting the URL, update its counts when we're deleting those // visits. // NOTE: The calls to std::max() below are a backstop, but they should diff --git a/chrome/browser/history/expire_history_backend.h b/chrome/browser/history/expire_history_backend.h index 4862f9a..0ed5676 100644 --- a/chrome/browser/history/expire_history_backend.h +++ b/chrome/browser/history/expire_history_backend.h @@ -81,8 +81,7 @@ class ExpireHistoryBackend { // will continue until the object is deleted. void StartArchivingOldStuff(TimeDelta expiration_threshold); - // Deletes everything associated with a URL, regardless of whether it is - // starred or not. + // Deletes everything associated with a URL. void DeleteURL(const GURL& url); // Removes all visits in the given time range, updating the URLs accordingly. @@ -128,10 +127,6 @@ class ExpireHistoryBackend { // that we will need to check when the delete operations are complete. std::set<FavIconID> affected_favicons; - // URLs that were unstarred as a result of the delete. - std::set<GURL> unstarred_urls; - std::vector<StarredEntry> unstarred_entries; - // Tracks the set of databases that have changed so we can optimize when // when we're done. TextDatabaseManager::ChangeSet text_db_changes; diff --git a/chrome/browser/history/expire_history_backend_unittest.cc b/chrome/browser/history/expire_history_backend_unittest.cc index 0cd12da..28d90ab 100644 --- a/chrome/browser/history/expire_history_backend_unittest.cc +++ b/chrome/browser/history/expire_history_backend_unittest.cc @@ -111,7 +111,7 @@ class ExpireHistoryTest : public testing::Test, std::wstring history_name(dir_); file_util::AppendToPath(&history_name, L"History"); main_db_.reset(new HistoryDatabase); - if (main_db_->Init(history_name) != INIT_OK) + if (main_db_->Init(history_name, std::wstring()) != INIT_OK) main_db_.reset(); std::wstring archived_name(dir_); @@ -460,32 +460,6 @@ TEST_F(ExpireHistoryTest, DeleteURLWithoutFavicon) { EXPECT_TRUE(HasFavIcon(last_row.favicon_id())); } -// DeletdeURL should delete URLs that are starred. -TEST_F(ExpireHistoryTest, DeleteStarredURL) { - URLID url_ids[3]; - Time visit_times[4]; - AddExampleData(url_ids, visit_times); - - URLRow url_row; - ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &url_row)); - - // Star the last URL. - StarredEntry starred; - starred.type = StarredEntry::URL; - starred.url = url_row.url(); - starred.url_id = url_row.id(); - starred.parent_group_id = HistoryService::kBookmarkBarID; - ASSERT_TRUE(main_db_->CreateStarredEntry(&starred)); - ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &url_row)); - - // Now delete it, this should delete it even though it's starred. - expirer_.DeleteURL(url_row.url()); - - // All the normal data + the favicon should be gone. - EnsureURLInfoGone(url_row); - EXPECT_FALSE(HasFavIcon(url_row.favicon_id())); -} - // Expires all URLs more recent than a given time, with no starred items. // Our time threshold is such that one URL should be updated (we delete one of // the two visits) and one is deleted. @@ -540,62 +514,6 @@ TEST_F(ExpireHistoryTest, FlushRecentURLsUnstarred) { EXPECT_FALSE(HasFavIcon(url_row2.favicon_id())); } -// Expire a starred URL, it shouldn't get deleted and its visit counts should -// be updated properly. -TEST_F(ExpireHistoryTest, FlushRecentURLsStarred) { - URLID url_ids[3]; - Time visit_times[4]; - AddExampleData(url_ids, visit_times); - - URLRow url_row1, url_row2; - ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &url_row1)); - ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &url_row2)); - - // Star the last two URLs. - StarredEntry starred1; - starred1.type = StarredEntry::URL; - starred1.url = url_row1.url(); - starred1.url_id = url_row1.id(); - starred1.parent_group_id = HistoryService::kBookmarkBarID; - ASSERT_TRUE(main_db_->CreateStarredEntry(&starred1)); - ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &url_row1)); - - StarredEntry starred2; - starred2.type = StarredEntry::URL; - starred2.url = url_row2.url(); - starred2.url_id = url_row2.id(); - starred2.parent_group_id = HistoryService::kBookmarkBarID; - ASSERT_TRUE(main_db_->CreateStarredEntry(&starred2)); - ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &url_row2)); - - // This should delete the last two visits. - expirer_.ExpireHistoryBetween(visit_times[2], Time()); - - // The URL rows should still exist. - URLRow new_url_row1, new_url_row2; - ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &new_url_row1)); - ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &new_url_row2)); - - // The visit times should be updated. - EXPECT_TRUE(new_url_row1.last_visit() == visit_times[1]); - EXPECT_TRUE(new_url_row2.last_visit().is_null()); // No last visit time. - - // Visit counts should be updated. - EXPECT_EQ(0, new_url_row1.typed_count()); - EXPECT_EQ(1, new_url_row1.visit_count()); - EXPECT_EQ(0, new_url_row2.typed_count()); - EXPECT_EQ(0, new_url_row2.visit_count()); - - // Thumbnails and favicons should still exist. Note that we keep thumbnails - // 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())); - EXPECT_TRUE(HasThumbnail(new_url_row1.id())); - EXPECT_TRUE(HasFavIcon(new_url_row2.favicon_id())); - EXPECT_TRUE(HasThumbnail(new_url_row2.id())); -} - TEST_F(ExpireHistoryTest, ArchiveHistoryBeforeUnstarred) { URLID url_ids[3]; Time visit_times[4]; @@ -634,53 +552,6 @@ TEST_F(ExpireHistoryTest, ArchiveHistoryBeforeUnstarred) { EXPECT_EQ(1, archived_visits.size()); } -TEST_F(ExpireHistoryTest, ArchiveHistoryBeforeStarred) { - URLID url_ids[3]; - Time visit_times[4]; - AddExampleData(url_ids, visit_times); - - URLRow url_row0, url_row1; - ASSERT_TRUE(main_db_->GetURLRow(url_ids[0], &url_row0)); - ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &url_row1)); - - // Star the URLs. We use fake star IDs here, but that doesn't matter. - url_row0.set_star_id(1); - main_db_->UpdateURLRow(url_row0.id(), url_row0); - url_row1.set_star_id(2); - main_db_->UpdateURLRow(url_row1.id(), url_row1); - - // Now archive the first three visits (first two URLs). The first two visits - // should be, the thirddeleted, but the URL records should not. - expirer_.ArchiveHistoryBefore(visit_times[2]); - - // The first URL should have its visit deleted, but it should still be present - // in the main DB and not in the archived one since it is starred. - URLRow temp_row; - ASSERT_TRUE(main_db_->GetURLRow(url_ids[0], &temp_row)); - // Note that the ID is different in the archived DB, so look up by URL. - EXPECT_FALSE(archived_db_->GetRowForURL(temp_row.url(), NULL)); - VisitVector visits; - main_db_->GetVisitsForURL(temp_row.id(), &visits); - EXPECT_EQ(0, visits.size()); - - // The second URL should have its first visit deleted and its second visit - // archived. It should be present in both the main DB (because it's starred) - // and the archived DB (for the archived visit). - ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &temp_row)); - main_db_->GetVisitsForURL(temp_row.id(), &visits); - EXPECT_EQ(0, visits.size()); - - // Note that the ID is different in the archived DB, so look up by URL. - ASSERT_TRUE(archived_db_->GetRowForURL(temp_row.url(), &temp_row)); - archived_db_->GetVisitsForURL(temp_row.id(), &visits); - ASSERT_EQ(1, visits.size()); - EXPECT_TRUE(visit_times[2] == visits[0].visit_time); - - // The third URL should be unchanged. - EXPECT_TRUE(main_db_->GetURLRow(url_ids[2], &temp_row)); - EXPECT_FALSE(archived_db_->GetRowForURL(temp_row.url(), NULL)); -} - // Tests the return values from ArchiveSomeOldHistory. The rest of the // functionality of this function is tested by the ArchiveHistoryBefore* // tests which use this function internally. diff --git a/chrome/browser/history/history.cc b/chrome/browser/history/history.cc index d4e6879..bebc348 100644 --- a/chrome/browser/history/history.cc +++ b/chrome/browser/history/history.cc @@ -241,6 +241,13 @@ HistoryService::Handle HistoryService::ScheduleDBTask( request); } +HistoryService::Handle HistoryService::ScheduleEmptyCallback( + CancelableRequestConsumerBase* consumer, + EmptyHistoryCallback* callback) { + return Schedule(PRIORITY_UI, &HistoryBackend::ProcessEmptyRequest, + consumer, new history::EmptyHistoryRequest(callback)); +} + HistoryService::Handle HistoryService::QuerySegmentUsageSince( CancelableRequestConsumerBase* consumer, const Time from_time, @@ -435,55 +442,6 @@ void HistoryService::SetImportedFavicons( &HistoryBackend::SetImportedFavicons, favicon_usage); } -HistoryService::Handle HistoryService::GetAllStarredEntries( - CancelableRequestConsumerBase* consumer, - GetStarredEntriesCallback* callback) { - return Schedule(PRIORITY_UI, &HistoryBackend::GetAllStarredEntries, - consumer, - new history::GetStarredEntriesRequest(callback)); -} - -void HistoryService::UpdateStarredEntry(const history::StarredEntry& entry) { - ScheduleAndForget(PRIORITY_UI, &HistoryBackend::UpdateStarredEntry, entry); -} - -HistoryService::Handle HistoryService::CreateStarredEntry( - const history::StarredEntry& entry, - CancelableRequestConsumerBase* consumer, - CreateStarredEntryCallback* callback) { - DCHECK(entry.type != history::StarredEntry::BOOKMARK_BAR && - entry.type != history::StarredEntry::OTHER); - if (!consumer) { - ScheduleTask(PRIORITY_UI, - NewRunnableMethod(history_backend_.get(), - &HistoryBackend::CreateStarredEntry, - scoped_refptr<history::CreateStarredEntryRequest>(), - entry)); - return 0; - } - return Schedule(PRIORITY_UI, &HistoryBackend::CreateStarredEntry, consumer, - new history::CreateStarredEntryRequest(callback), entry); -} - -void HistoryService::DeleteStarredGroup(history::UIStarID group_id) { - ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteStarredGroup, - group_id); -} - -void HistoryService::DeleteStarredURL(const GURL& url) { - ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteStarredURL, url); -} - -HistoryService::Handle HistoryService::GetMostRecentStarredEntries( - int max_count, - CancelableRequestConsumerBase* consumer, - GetMostRecentStarredEntriesCallback* callback) { - return Schedule(PRIORITY_UI, &HistoryBackend::GetMostRecentStarredEntries, - consumer, - new history::GetMostRecentStarredEntriesRequest(callback), - max_count); -} - void HistoryService::IterateURLs(URLEnumerator* enumerator) { ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::IterateURLs, enumerator); } diff --git a/chrome/browser/history/history.h b/chrome/browser/history/history.h index 9dca73a..3db1e23 100644 --- a/chrome/browser/history/history.h +++ b/chrome/browser/history/history.h @@ -393,29 +393,6 @@ class HistoryService : public CancelableRequestProvider, void SetImportedFavicons( const std::vector<history::ImportedFavIconUsage>& favicon_usage); - // Starring ------------------------------------------------------------------ - - // Starring mutation methods are private, go through the BookmarkBarModel - // instead. - // - // The typedefs are public to allow template magic to work. - - typedef Callback2<Handle, std::vector<history::StarredEntry>* >::Type - GetStarredEntriesCallback; - - typedef Callback2<Handle, history::StarID>::Type CreateStarredEntryCallback; - - typedef Callback2<Handle, std::vector<history::StarredEntry>* >::Type - GetMostRecentStarredEntriesCallback; - - // Fetches up to max_count starred entries of type URL. - // The results are ordered by date added in descending order (most recent - // first). - Handle GetMostRecentStarredEntries( - int max_count, - CancelableRequestConsumerBase* consumer, - GetMostRecentStarredEntriesCallback* callback); - // Database management operations -------------------------------------------- // Delete all the information related to a single url. @@ -544,6 +521,13 @@ class HistoryService : public CancelableRequestProvider, Handle ScheduleDBTask(HistoryDBTask* task, CancelableRequestConsumerBase* consumer); + typedef Callback1<Handle>::Type EmptyHistoryCallback; + + // Schedules a task that does nothing on the backend. This can be used to get + // notification when then history backend is done processing requests. + Handle ScheduleEmptyCallback(CancelableRequestConsumerBase* consumer, + EmptyHistoryCallback* callback); + // Testing ------------------------------------------------------------------- // Designed for unit tests, this passes the given task on to the history @@ -597,51 +581,6 @@ class HistoryService : public CancelableRequestProvider, friend class HistoryOperation; friend class HistoryURLProviderTest; - // Starring ------------------------------------------------------------------ - - // These are private as they should only be invoked from the bookmark bar - // model. - - // Fetches all the starred entries (both groups and entries). - Handle GetAllStarredEntries( - CancelableRequestConsumerBase* consumer, - GetStarredEntriesCallback* callback); - - // Updates the title, parent and visual order of the specified entry. The key - // used to identify the entry is NOT entry.id, rather it is the url (if the - // type is URL), or the group_id (if the type is other than URL). - // - // This can NOT be used to change the type of an entry. - // - // After updating the entry, NOTIFY_STAR_ENTRY_CHANGED is sent. - void UpdateStarredEntry(const history::StarredEntry& entry); - - // Creates a starred entry at the specified position. This can be used - // for creating groups and nodes. - // - // If the entry is a URL and the URL is already starred, this behaves the - // same as invoking UpdateStarredEntry. If the entry is a URL and the URL is - // not starred, the URL is starred appropriately. - // - // This honors the title, parent_group_id, visual_order and url (for URL - // nodes) of the specified entry. All other attributes are ignored. - // - // NOTE: consumer and callback may be null, in which case the request - // isn't cancelable and 0 is returned. - Handle CreateStarredEntry(const history::StarredEntry& entry, - CancelableRequestConsumerBase* consumer, - CreateStarredEntryCallback* callback); - - // Deletes the specified starred group. All children groups are deleted and - // starred descendants unstarred. If successful, this sends out the - // notification NOTIFY_URLS_STARRED. To delete a starred URL, do - // DeletedStarredEntry(id). - void DeleteStarredGroup(history::UIStarID group_id); - - // Deletes the specified starred URL. If successful, this sends out the - // notification NOTIFY_URLS_STARRED. - void DeleteStarredURL(const GURL& url); - // Implementation of NotificationObserver. virtual void Observe(NotificationType type, const NotificationSource& source, diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc index d9ef224..88e40ed 100644 --- a/chrome/browser/history/history_backend.cc +++ b/chrome/browser/history/history_backend.cc @@ -268,10 +268,13 @@ void HistoryBackend::Init() { file_util::AppendToPath(&history_name, chrome::kHistoryFilename); std::wstring thumbnail_name = GetThumbnailFileName(); std::wstring archived_name = GetArchivedFileName(); + std::wstring tmp_bookmarks_file = history_dir_; + file_util::AppendToPath(&tmp_bookmarks_file, + chrome::kHistoryBookmarksFileName); // History database. db_.reset(new HistoryDatabase()); - switch (db_->Init(history_name)) { + switch (db_->Init(history_name, tmp_bookmarks_file)) { case INIT_OK: break; case INIT_FAILURE: @@ -995,16 +998,6 @@ void HistoryBackend::QueryHistory(scoped_refptr<QueryHistoryRequest> request, if (db_.get()) { if (text_query.empty()) { - if (options.begin_time.is_null() && options.end_time.is_null() && - options.only_starred && options.max_count == 0) { - DLOG(WARNING) << "Querying for all bookmarks. You should probably use " - "the dedicated starring functions which will also report unvisited " - "bookmarks and will be faster."; - // If this case is needed and the starring functions aren't right, we - // can optimize the case where we're just querying for starred URLs - // and remove the warning. - } - // Basic history query for the main database. QueryHistoryBasic(db_.get(), db_.get(), options, &request->value); @@ -1060,14 +1053,8 @@ void HistoryBackend::QueryHistoryBasic(URLDatabase* url_db, // catch any interesting stuff. This will update it if it exists in the // main DB, and do nothing otherwise. db_->GetRowForURL(url_result.url(), &url_result); - } else { - // URLs not in the main DB can't be starred, reset this just in case. - url_result.set_star_id(0); } - if (!url_result.starred() && options.only_starred) - continue; // Want non-starred items filtered out. - url_result.set_visit_time(visit.visit_time); // We don't set any of the query-specific parts of the URLResult, since @@ -1076,62 +1063,6 @@ void HistoryBackend::QueryHistoryBasic(URLDatabase* url_db, } } -void HistoryBackend::QueryStarredEntriesByText( - URLQuerier* querier, - const std::wstring& text_query, - const QueryOptions& options, - QueryResults* results) { - // Collect our prepends so we can bulk add them at the end. It is more - // efficient to bluk prepend the URLs than to do one at a time. - QueryResults our_results; - - // We can use only the main DB (not archived) for this operation since we know - // that all currently starred URLs will be in the main DB. - std::set<URLID> ids; - db_->GetURLsForTitlesMatching(text_query, &ids); - - VisitRow visit; - PageVisit page_visit; - URLResult url_result; - for (std::set<URLID>::iterator i = ids.begin(); i != ids.end(); ++i) { - // Turn the ID (associated with the main DB) into a visit row. - if (!db_->GetURLRow(*i, &url_result)) - continue; // Not found, some crazy error. - - // Make sure we haven't already reported this URL and don't add it if so. - if (querier->HasURL(url_result.url())) - continue; - - // Consistency check, all URLs should be valid and starred. - if (!url_result.url().is_valid() || !url_result.starred()) - continue; - - db_->GetStarredEntry(url_result.star_id(), &url_result.starred_entry_); - - // Use the last visit time as the visit time for this result. - // TODO(brettw) when we are not querying for the most recent visit only, - // we should get all the visits in the time range for the given URL and add - // separate results for each of them. Until then, just treat as unique: - // - // Just add this one visit for the last time they visited it, except for - // starred only queries which have no visit times. - if (options.only_starred) { - url_result.set_visit_time(Time()); - } else { - url_result.set_visit_time(url_result.last_visit()); - } - our_results.AppendURLBySwapping(&url_result); - } - - // Now prepend all of the bookmark matches we found. We do this by appending - // the old values to the new ones and swapping the results. - if (our_results.size() > 0) { - our_results.AppendResultsBySwapping(results, - options.most_recent_visit_only); - our_results.Swap(results); - } -} - void HistoryBackend::QueryHistoryFTS(const std::wstring& text_query, const QueryOptions& options, QueryResults* result) { @@ -1162,8 +1093,6 @@ void HistoryBackend::QueryHistoryFTS(const std::wstring& text_query, if (!url_result.url().is_valid()) continue; // Don't report invalid URLs in case of corruption. - if (options.only_starred && !url_result.star_id()) - continue; // Don't add this unstarred item. // Copy over the FTS stuff that the URLDatabase doesn't know about. // We do this with swap() to avoid copying, since we know we don't @@ -1179,21 +1108,10 @@ void HistoryBackend::QueryHistoryFTS(const std::wstring& text_query, // has the time, we can avoid an extra query of the visits table. url_result.set_visit_time(fts_matches[i].time); - if (options.only_starred) { - // When querying for starred pages fetch the starred entry. - DCHECK(url_result.star_id()); - db_->GetStarredEntry(url_result.star_id(), &url_result.starred_entry_); - } else { - url_result.ResetStarredEntry(); - } - // Add it to the vector, this will clear our |url_row| object as a // result of the swap. result->AppendURLBySwapping(&url_result); } - - if (options.include_all_starred) - QueryStarredEntriesByText(&querier, text_query, options, result); } // Frontend to GetMostRecentRedirectsFrom from the history thread. @@ -1399,7 +1317,7 @@ void HistoryBackend::SetImportedFavicons( Time now = Time::Now(); // Track all starred URLs that had their favicons set or updated. - std::set<GURL> starred_favicons_changed; + std::set<GURL> favicons_changed; for (size_t i = 0; i < favicon_usage.size(); i++) { FavIconID favicon_id = thumbnail_db_->GetFavIconIDForFavIconURL( @@ -1422,16 +1340,15 @@ void HistoryBackend::SetImportedFavicons( url_row.set_favicon_id(favicon_id); db_->UpdateURLRow(url_row.id(), url_row); - if (url_row.starred()) - starred_favicons_changed.insert(*url); + favicons_changed.insert(*url); } } - if (!starred_favicons_changed.empty()) { + if (!favicons_changed.empty()) { // Send the notification about the changed favicons for starred URLs. FavIconChangeDetails* changed_details = new FavIconChangeDetails; - changed_details->urls.swap(starred_favicons_changed); - BroadcastNotifications(NOTIFY_STARRED_FAVICON_CHANGED, changed_details); + changed_details->urls.swap(favicons_changed); + BroadcastNotifications(NOTIFY_FAVICON_CHANGED, changed_details); } } @@ -1544,7 +1461,7 @@ void HistoryBackend::SetFavIconMapping(const GURL& page_url, redirects = &dummy_list; } - std::set<GURL> starred_favicons_changed; + std::set<GURL> favicons_changed; // Save page <-> favicon association. for (HistoryService::RedirectList::const_iterator i(redirects->begin()); @@ -1569,147 +1486,15 @@ void HistoryBackend::SetFavIconMapping(const GURL& page_url, thumbnail_db_->DeleteFavIcon(old_id); } - if (row.starred()) - starred_favicons_changed.insert(row.url()); - } - - if (!starred_favicons_changed.empty()) { - // Send the notification about the changed favicons for starred URLs. - FavIconChangeDetails* changed_details = new FavIconChangeDetails; - changed_details->urls.swap(starred_favicons_changed); - BroadcastNotifications(NOTIFY_STARRED_FAVICON_CHANGED, changed_details); - } - - ScheduleCommit(); -} - -void HistoryBackend::GetAllStarredEntries( - scoped_refptr<GetStarredEntriesRequest> request) { - if (request->canceled()) - return; - // Only query for the entries if the starred table is valid. If the starred - // table isn't valid, we may get back garbage which could cause the UI grief. - // - // TODO(sky): bug 1207654: this is temporary, the UI should really query for - // valid state than avoid GetAllStarredEntries if not valid. - if (db_.get() && db_->is_starred_valid()) - db_->GetStarredEntries(0, &(request->value)); - request->ForwardResult( - GetStarredEntriesRequest::TupleType(request->handle(), - &(request->value))); -} - -void HistoryBackend::UpdateStarredEntry(const StarredEntry& new_entry) { - if (!db_.get()) - return; - - StarredEntry resulting_entry = new_entry; - if (!db_->UpdateStarredEntry(&resulting_entry) || !delegate_.get()) - return; - - ScheduleCommit(); - - // Send out notification that the star entry changed. - StarredEntryDetails* entry_details = new StarredEntryDetails(); - entry_details->entry = resulting_entry; - BroadcastNotifications(NOTIFY_STAR_ENTRY_CHANGED, entry_details); -} - -void HistoryBackend::CreateStarredEntry( - scoped_refptr<CreateStarredEntryRequest> request, - const StarredEntry& entry) { - // This method explicitly allows request to be NULL. - if (request.get() && request->canceled()) - return; - - StarID id = 0; - StarredEntry resulting_entry(entry); - if (db_.get()) { - if (entry.type == StarredEntry::USER_GROUP) { - id = db_->CreateStarredEntry(&resulting_entry); - if (id) { - // Broadcast group created notifications. - StarredEntryDetails* entry_details = new StarredEntryDetails; - entry_details->entry = resulting_entry; - BroadcastNotifications(NOTIFY_STAR_GROUP_CREATED, entry_details); - } - } else if (entry.type == StarredEntry::URL) { - // Currently, we only allow one starred entry for this URL. Therefore, we - // check for an existing starred entry for this URL and update it if it - // exists. - if (!db_->GetStarIDForEntry(resulting_entry)) { - // Adding a new starred URL. - id = db_->CreateStarredEntry(&resulting_entry); - - // Broadcast starred notification. - URLsStarredDetails* details = new URLsStarredDetails(true); - details->changed_urls.insert(resulting_entry.url); - details->star_entries.push_back(resulting_entry); - BroadcastNotifications(NOTIFY_URLS_STARRED, details); - } else { - // Updating an existing one. - db_->UpdateStarredEntry(&resulting_entry); - - // Broadcast starred update notification. - StarredEntryDetails* entry_details = new StarredEntryDetails; - entry_details->entry = resulting_entry; - BroadcastNotifications(NOTIFY_STAR_ENTRY_CHANGED, entry_details); - } - } else { - NOTREACHED(); - } - } - - ScheduleCommit(); - - if (request.get()) { - request->ForwardResult( - CreateStarredEntryRequest::TupleType(request->handle(), id)); + favicons_changed.insert(row.url()); } -} -void HistoryBackend::DeleteStarredGroup(UIStarID group_id) { - if (!db_.get()) - return; - - DeleteStarredEntry(db_->GetStarIDForGroupID(group_id)); -} - -void HistoryBackend::DeleteStarredURL(const GURL& url) { - if (!db_.get()) - return; - - history::StarredEntry entry; - entry.url = url; - DeleteStarredEntry(db_->GetStarIDForEntry(entry)); -} - -void HistoryBackend::DeleteStarredEntry(history::StarID star_id) { - if (!star_id) { - NOTREACHED() << "Deleting a nonexistent entry"; - return; - } - - // Delete the entry. - URLsStarredDetails* details = new URLsStarredDetails(false); - db_->DeleteStarredEntry(star_id, &details->changed_urls, - &details->star_entries); + // Send the notification about the changed favicons. + FavIconChangeDetails* changed_details = new FavIconChangeDetails; + changed_details->urls.swap(favicons_changed); + BroadcastNotifications(NOTIFY_FAVICON_CHANGED, changed_details); ScheduleCommit(); - - BroadcastNotifications(NOTIFY_URLS_STARRED, details); -} - -void HistoryBackend::GetMostRecentStarredEntries( - scoped_refptr<GetMostRecentStarredEntriesRequest> request, - int max_count) { - if (request->canceled()) - return; - if (db_.get()) - db_->GetMostRecentStarredEntries(max_count, &(request->value)); - request->ForwardResult( - GetMostRecentStarredEntriesRequest::TupleType(request->handle(), - &(request->value))); } void HistoryBackend::Commit() { @@ -1859,6 +1644,11 @@ void HistoryBackend::ProcessDBTask( } } +void HistoryBackend::ProcessEmptyRequest( + scoped_refptr<EmptyHistoryRequest> request) { + request->ForwardResult(EmptyHistoryRequest::TupleType()); +} + void HistoryBackend::BroadcastNotifications( NotificationType type, HistoryDetails* details_deleted) { @@ -1887,7 +1677,6 @@ void HistoryBackend::DeleteAllHistory() { // Get starred entries and their corresponding URL rows. std::vector<StarredEntry> starred_entries; - db_->GetStarredEntries(0, &starred_entries); std::vector<URLRow> kept_urls; for (size_t i = 0; i < starred_entries.size(); i++) { @@ -2032,19 +1821,6 @@ bool HistoryBackend::ClearAllMainHistory( if (!db_->CommitTemporaryURLTable()) return false; - // The starred table references the old URL IDs. We need to fix it up to refer - // to the new ones. - for (std::vector<StarredEntry>::iterator i = starred_entries->begin(); - i != starred_entries->end(); - ++i) { - if (i->type != StarredEntry::URL) - continue; - - DCHECK(old_to_new.find(i->url_id) != old_to_new.end()); - i->url_id = old_to_new[i->url_id]; - db_->UpdateURLIDForStar(i->id, i->url_id); - } - // Delete the old tables and recreate them empty. db_->RecreateAllButStarAndURLTables(); diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h index c1136de..f73e653 100644 --- a/chrome/browser/history/history_backend.h +++ b/chrome/browser/history/history_backend.h @@ -205,26 +205,6 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>, void SetImportedFavicons( const std::vector<ImportedFavIconUsage>& favicon_usage); - // Starring ------------------------------------------------------------------ - - void GetAllStarredEntries( - scoped_refptr<GetStarredEntriesRequest> request); - - void UpdateStarredEntry(const StarredEntry& new_entry); - - void CreateStarredEntry(scoped_refptr<CreateStarredEntryRequest> request, - const StarredEntry& entry); - - void DeleteStarredGroup(UIStarID group_id); - - void DeleteStarredURL(const GURL& url); - - void DeleteStarredEntry(history::StarID star_id); - - void GetMostRecentStarredEntries( - scoped_refptr<GetMostRecentStarredEntriesRequest> request, - int max_count); - // Downloads ----------------------------------------------------------------- void QueryDownloads(scoped_refptr<DownloadQueryRequest> request); @@ -263,6 +243,8 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>, void ProcessDBTask(scoped_refptr<HistoryDBTaskRequest> request); + void ProcessEmptyRequest(scoped_refptr<EmptyHistoryRequest> request); + // Deleting ------------------------------------------------------------------ void DeleteURL(const GURL& url); @@ -338,15 +320,6 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>, const QueryOptions& options, QueryResults* result); - // Queries the starred database for all URL entries whose title contains the - // specified text. This is called as necessary from QueryHistoryFTS. The - // matches will be added to the beginning of the result vector in no - // particular order. - void QueryStarredEntriesByText(URLQuerier* querier, - const std::wstring& text_query, - const QueryOptions& options, - QueryResults* results); - // Committing ---------------------------------------------------------------- // We always keep a transaction open on the history database so that multiple diff --git a/chrome/browser/history/history_backend_unittest.cc b/chrome/browser/history/history_backend_unittest.cc index e1e6ffe..68bfc19 100644 --- a/chrome/browser/history/history_backend_unittest.cc +++ b/chrome/browser/history/history_backend_unittest.cc @@ -205,14 +205,6 @@ TEST_F(HistoryBackendTest, DeleteAll) { JPEGCodec::Decode(kWeewarThumbnail, sizeof(kWeewarThumbnail))); backend_->thumbnail_db_->SetPageThumbnail(row2_id, *weewar_bitmap, score); - // Mark one of the URLs bookmarked. - StarredEntry entry; - entry.type = StarredEntry::URL; - entry.url = row1.url(); - entry.parent_group_id = HistoryService::kBookmarkBarID; - StarID star_id = backend_->db_->CreateStarredEntry(&entry); - ASSERT_TRUE(star_id); - // Set full text index for each one. backend_->text_database_->AddPageData(row1.url(), row1_id, visit1_id, row1.last_visit(), @@ -224,12 +216,8 @@ TEST_F(HistoryBackendTest, DeleteAll) { // Now finally clear all history. backend_->DeleteAllHistory(); - // The first URL should be preserved, along with its visits, but the time - // should be cleared. - EXPECT_TRUE(backend_->db_->GetRowForURL(row1.url(), &outrow1)); - EXPECT_EQ(2, outrow1.visit_count()); - EXPECT_EQ(1, outrow1.typed_count()); - EXPECT_TRUE(Time() == outrow1.last_visit()); + // The first URL should be deleted. + EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &outrow1)); // The second row should be deleted. URLRow outrow2; @@ -246,27 +234,15 @@ TEST_F(HistoryBackendTest, DeleteAll) { &out_data)); EXPECT_FALSE(backend_->thumbnail_db_->GetPageThumbnail(row2_id, &out_data)); - // We should have a favicon for the first URL only. We look them up by favicon - // URL since the IDs may hav changed. + // Make sure the favicons were deleted. + // TODO(sky): would be nice if this didn't happen. FavIconID out_favicon1 = backend_->thumbnail_db_-> GetFavIconIDForFavIconURL(favicon_url1); - EXPECT_TRUE(out_favicon1); + EXPECT_FALSE(out_favicon1); FavIconID out_favicon2 = backend_->thumbnail_db_-> GetFavIconIDForFavIconURL(favicon_url2); 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()); - - // The first URL should still be bookmarked and have an entry. The star ID - // must not have changed. - EXPECT_TRUE(outrow1.starred()); - StarredEntry outentry; - EXPECT_TRUE(backend_->db_->GetStarredEntry(star_id, &outentry)); - EXPECT_EQ(outrow1.id(), outentry.url_id); - EXPECT_TRUE(outrow1.url() == outentry.url); - // The full text database should have no data. std::vector<TextDatabase::Match> text_matches; Time first_time_searched; diff --git a/chrome/browser/history/history_database.cc b/chrome/browser/history/history_database.cc index e606aeb..d79d14a 100644 --- a/chrome/browser/history/history_database.cc +++ b/chrome/browser/history/history_database.cc @@ -43,7 +43,7 @@ namespace history { namespace { // Current version number. -const int kCurrentVersionNumber = 15; +const int kCurrentVersionNumber = 16; } // namespace @@ -55,7 +55,8 @@ HistoryDatabase::HistoryDatabase() HistoryDatabase::~HistoryDatabase() { } -InitStatus HistoryDatabase::Init(const std::wstring& history_name) { +InitStatus HistoryDatabase::Init(const std::wstring& history_name, + const std::wstring& bookmarks_path) { // Open the history database, using the narrow version of open indicates to // sqlite that we want the database to be in UTF-8 if it doesn't already // exist. @@ -94,18 +95,16 @@ InitStatus HistoryDatabase::Init(const std::wstring& history_name) { return INIT_FAILURE; if (!CreateURLTable(false) || !InitVisitTable() || !InitKeywordSearchTermsTable() || !InitDownloadTable() || - !InitSegmentTables() || !InitStarTable()) + !InitSegmentTables()) return INIT_FAILURE; CreateMainURLIndex(); CreateSupplimentaryURLIndices(); // Version check. - InitStatus version_status = EnsureCurrentVersion(); + InitStatus version_status = EnsureCurrentVersion(bookmarks_path); if (version_status != INIT_OK) return version_status; - EnsureStarredIntegrity(); - // Succeeded: keep the DB open by detaching the auto-closer. scoper.Detach(); db_closer_.Attach(&db_, &statement_cache_); @@ -222,7 +221,8 @@ SqliteStatementCache& HistoryDatabase::GetStatementCache() { // Migration ------------------------------------------------------------------- -InitStatus HistoryDatabase::EnsureCurrentVersion() { +InitStatus HistoryDatabase::EnsureCurrentVersion( + const std::wstring& tmp_bookmarks_path) { // We can't read databases newer than we were designed for. if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) return INIT_TOO_NEW; @@ -239,6 +239,16 @@ InitStatus HistoryDatabase::EnsureCurrentVersion() { // Put migration code here + if (cur_version == 15) { + if (!MigrateBookmarksToFile(tmp_bookmarks_path)) + return INIT_FAILURE; + if (!DropStarredIDFromURLs()) + return INIT_FAILURE; + cur_version = 16; + meta_table_.SetVersionNumber(cur_version); + meta_table_.SetCompatibleVersionNumber(cur_version); + } + LOG_IF(WARNING, cur_version < kCurrentVersionNumber) << "History database version " << cur_version << " is too old to handle."; diff --git a/chrome/browser/history/history_database.h b/chrome/browser/history/history_database.h index 92c356d..f386a2a 100644 --- a/chrome/browser/history/history_database.h +++ b/chrome/browser/history/history_database.h @@ -56,6 +56,9 @@ class TextDatabaseManager; // as the storage interface. Logic for manipulating this storage layer should // be in HistoryBackend.cc. class HistoryDatabase : public DownloadDatabase, + // TODO(sky): See if we can nuke StarredURLDatabase and just create on the + // stack for migration. Then HistoryDatabase would directly descend from + // URLDatabase. public StarredURLDatabase, public VisitDatabase, public VisitSegmentDatabase { @@ -84,7 +87,8 @@ class HistoryDatabase : public DownloadDatabase, // Must call this function to complete initialization. Will return true on // success. On false, no other function should be called. You may want to call // BeginExclusiveMode after this when you are ready. - InitStatus Init(const std::wstring& history_name); + InitStatus Init(const std::wstring& history_name, + const std::wstring& tmp_bookmarks_path); // Call to set the mode on the database to exclusive. The default locking mode // is "normal" but we want to run in exclusive mode for slightly better @@ -141,6 +145,9 @@ class HistoryDatabase : public DownloadDatabase, // visit id wasn't found. SegmentID GetSegmentID(VisitID visit_id); + // Drops the starred table and star_id from urls. + bool MigrateFromVersion15ToVersion16(); + private: // Implemented for URLDatabase. virtual sqlite3* GetDB(); @@ -161,7 +168,7 @@ class HistoryDatabase : public DownloadDatabase, // // This assumes it is called from the init function inside a transaction. It // may commit the transaction and start a new one if migration requires it. - InitStatus EnsureCurrentVersion(); + InitStatus EnsureCurrentVersion(const std::wstring& tmp_bookmarks_path); // --------------------------------------------------------------------------- diff --git a/chrome/browser/history/history_marshaling.h b/chrome/browser/history/history_marshaling.h index d1c4501..d0722e4 100644 --- a/chrome/browser/history/history_marshaling.h +++ b/chrome/browser/history/history_marshaling.h @@ -102,19 +102,6 @@ typedef CancelableRequest<HistoryService::ThumbnailDataCallback> typedef CancelableRequest<HistoryService::FavIconDataCallback> GetFavIconRequest; -// Starring ------------------------------------------------------------------- - -typedef CancelableRequest1<HistoryService::GetStarredEntriesCallback, - std::vector<history::StarredEntry> > - GetStarredEntriesRequest; - -typedef CancelableRequest1<HistoryService::GetMostRecentStarredEntriesCallback, - std::vector<history::StarredEntry> > - GetMostRecentStarredEntriesRequest; - -typedef CancelableRequest<HistoryService::CreateStarredEntryCallback> - CreateStarredEntryRequest; - // Downloads ------------------------------------------------------------------ typedef CancelableRequest1<HistoryService::DownloadQueryCallback, @@ -155,6 +142,9 @@ typedef CancelableRequest1<HistoryService::HistoryDBTaskCallback, scoped_refptr<HistoryDBTask> > HistoryDBTaskRequest; +typedef CancelableRequest<HistoryService::EmptyHistoryCallback> + EmptyHistoryRequest; + } // namespace history #endif // CHROME_BROWSER_HISTORY_HISTORY_MARSHALING_H__ diff --git a/chrome/browser/history/history_notifications.h b/chrome/browser/history/history_notifications.h index d5146ea..66379fd 100644 --- a/chrome/browser/history/history_notifications.h +++ b/chrome/browser/history/history_notifications.h @@ -72,7 +72,6 @@ struct URLsDeletedDetails : public HistoryDetails { // Details for NOTIFY_URLS_STARRED. struct URLsStarredDetails : public HistoryDetails { - URLsStarredDetails(bool being_starred) : starred(being_starred) {} // The new starred state of the list of URLs. True when they are being @@ -81,18 +80,9 @@ struct URLsStarredDetails : public HistoryDetails { // The list of URLs that are changing. std::set<GURL> changed_urls; - - // The star entries that were added or removed as the result of starring - // the entry. This may be empty. - std::vector<StarredEntry> star_entries; -}; - -// Details for NOTIFY_STAR_ENTRY_CHANGED and others. -struct StarredEntryDetails : public HistoryDetails { - StarredEntry entry; }; -// Details for NOTIFY_STARRED_FAVICON_CHANGED. +// Details for NOTIFY_FAVICON_CHANGED. struct FavIconChangeDetails : public HistoryDetails { std::set<GURL> urls; }; diff --git a/chrome/browser/history/history_querying_unittest.cc b/chrome/browser/history/history_querying_unittest.cc index 9d5f74d..7f4c7d5 100644 --- a/chrome/browser/history/history_querying_unittest.cc +++ b/chrome/browser/history/history_querying_unittest.cc @@ -132,19 +132,6 @@ class HistoryQueryTest : public testing::Test { history_->SetPageTitle(url, test_entries[i].title); history_->SetPageContents(url, test_entries[i].body); } - - // Set one of the pages starred. - history::StarredEntry entry; - entry.id = 5; - entry.title = L"Some starred page"; - entry.date_added = Time::Now(); - entry.parent_group_id = StarredEntry::BOOKMARK_BAR; - entry.group_id = 0; - entry.visual_order = 0; - entry.type = history::StarredEntry::URL; - entry.url = GURL(test_entries[0].url); - entry.date_group_modified = Time::Now(); - history_->CreateStarredEntry(entry, NULL, NULL); } virtual void TearDown() { @@ -189,9 +176,6 @@ TEST_F(HistoryQueryTest, Basic) { EXPECT_TRUE(NthResultIs(results, 3, 1)); EXPECT_TRUE(NthResultIs(results, 4, 0)); - // Check that the starred one is marked starred. - EXPECT_TRUE(results[4].starred()); - // Next query a time range. The beginning should be inclusive, the ending // should be exclusive. options.begin_time = test_entries[3].time; @@ -247,11 +231,10 @@ TEST_F(HistoryQueryTest, FTS) { // this query will return the starred item twice since we requested all // starred entries and no de-duping. QueryHistory(std::wstring(L"some"), options, &results); - EXPECT_EQ(4, results.size()); - EXPECT_TRUE(NthResultIs(results, 0, 4)); // Starred item. - EXPECT_TRUE(NthResultIs(results, 1, 2)); - EXPECT_TRUE(NthResultIs(results, 2, 3)); - EXPECT_TRUE(NthResultIs(results, 3, 1)); + EXPECT_EQ(3, results.size()); + EXPECT_TRUE(NthResultIs(results, 0, 2)); + EXPECT_TRUE(NthResultIs(results, 1, 3)); + EXPECT_TRUE(NthResultIs(results, 2, 1)); // Do a query that should only match one of them. QueryHistory(std::wstring(L"PAGETWO"), options, &results); @@ -262,7 +245,6 @@ TEST_F(HistoryQueryTest, FTS) { // should be exclusive. options.begin_time = test_entries[1].time; options.end_time = test_entries[3].time; - options.include_all_starred = false; QueryHistory(std::wstring(L"some"), options, &results); EXPECT_EQ(1, results.size()); EXPECT_TRUE(NthResultIs(results, 0, 1)); @@ -295,10 +277,9 @@ TEST_F(HistoryQueryTest, FTSCount) { // get the N most recent entries. options.max_count = 2; QueryHistory(std::wstring(L"some"), options, &results); - EXPECT_EQ(3, results.size()); - EXPECT_TRUE(NthResultIs(results, 0, 4)); - EXPECT_TRUE(NthResultIs(results, 1, 2)); - EXPECT_TRUE(NthResultIs(results, 2, 3)); + EXPECT_EQ(2, results.size()); + EXPECT_TRUE(NthResultIs(results, 0, 2)); + EXPECT_TRUE(NthResultIs(results, 1, 3)); // Now query a subset of the pages and limit by N items. "FOO" should match // the 2nd & 3rd pages, but we should only get the 3rd one because of the one diff --git a/chrome/browser/history/history_types.cc b/chrome/browser/history/history_types.cc index 920b0bc..758a166 100644 --- a/chrome/browser/history/history_types.cc +++ b/chrome/browser/history/history_types.cc @@ -43,7 +43,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(star_id_, other->star_id_); std::swap(favicon_id_, other->favicon_id_); } @@ -54,7 +53,6 @@ void URLRow::Initialize() { last_visit_ = Time(); hidden_ = false; favicon_id_ = 0; - star_id_ = 0; } // VisitRow -------------------------------------------------------------------- @@ -113,7 +111,6 @@ void URLResult::Swap(URLResult* other) { std::swap(visit_time_, other->visit_time_); snippet_.Swap(&other->snippet_); title_match_positions_.swap(other->title_match_positions_); - starred_entry_.Swap(&other->starred_entry_); } // QueryResults ---------------------------------------------------------------- diff --git a/chrome/browser/history/history_types.h b/chrome/browser/history/history_types.h index 738eda02..cbbd1f7 100644 --- a/chrome/browser/history/history_types.h +++ b/chrome/browser/history/history_types.h @@ -136,14 +136,6 @@ class URLRow { hidden_ = hidden; } - StarID star_id() const { return star_id_; } - void set_star_id(StarID star_id) { - star_id_ = star_id; - } - - // Simple boolean query to see if the page is starred. - bool starred() const { return (star_id_ != 0); } - // 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) { @@ -190,13 +182,6 @@ class URLRow { // is usually for subframes. bool hidden_; - // ID of the starred entry. - // - // NOTE: This is ignored by Add/UpdateURL. To modify the starred state you - // must invoke SetURLStarred. - // TODO: revisit this to see if this limitation can be removed. - StarID star_id_; - // The ID of the favicon for this url. FavIconID favicon_id_; @@ -372,11 +357,6 @@ class URLResult : public URLRow { virtual void Swap(URLResult* other); - // Returns the starred entry for this url. This is only set if the query - // was configured to search for starred only entries (only_starred is true). - const StarredEntry& starred_entry() const { return starred_entry_; } - void ResetStarredEntry() { starred_entry_ = StarredEntry(); } - private: friend class HistoryBackend; @@ -387,9 +367,6 @@ class URLResult : public URLRow { Snippet snippet_; Snippet::MatchPositions title_match_positions_; - // See comment above getter. - StarredEntry starred_entry_; - // We support the implicit copy constructor and operator=. }; @@ -488,8 +465,6 @@ class QueryResults { struct QueryOptions { QueryOptions() : most_recent_visit_only(false), - only_starred(false), - include_all_starred(true), max_count(0) { } @@ -521,26 +496,6 @@ struct QueryOptions { // Defaults to false (all visits). bool most_recent_visit_only; - // Indicates if only starred items should be matched. - // - // Defaults to false. - bool only_starred; - - // When true, and we're doing a full text query, starred entries that have - // never been visited or have been visited outside of the given time range - // will also be included in the results. These items will appear at the - // beginning of the result set. Non-full-text queries won't check this flag - // and will never return unvisited bookmarks. - // - // When false, full text queries will not return unvisited bookmarks, they - // will only be included when they were visited in the given time range. - // - // You probably want to use this in conjunction with most_recent_visit_only - // since it will cause duplicates otherwise. - // - // Defaults to true. - bool include_all_starred; - // The maximum number of results to return. The results will be sorted with // the most recent first, so older results may not be returned if there is not // enough room. When 0, this will return everything (the default). diff --git a/chrome/browser/history/history_unittest.cc b/chrome/browser/history/history_unittest.cc index 37b9179..cc0bfb4 100644 --- a/chrome/browser/history/history_unittest.cc +++ b/chrome/browser/history/history_unittest.cc @@ -120,12 +120,6 @@ class BackendDelegate : public HistoryBackend::Delegate { HistoryTest* history_test_; }; -bool IsURLStarred(URLDatabase* db, const GURL& url) { - URLRow row; - EXPECT_TRUE(db->GetRowForURL(url, &row)) << "URL not found"; - return row.starred(); -} - } // namespace // This must be outside the anonymous namespace for the friend statement in @@ -272,21 +266,6 @@ class HistoryTest : public testing::Test { MessageLoop::current()->Quit(); } - void SetURLStarred(const GURL& url, bool starred) { - history::StarredEntry entry; - entry.type = history::StarredEntry::URL; - entry.url = url; - history::StarID star_id = db_->GetStarIDForEntry(entry); - if (star_id && !starred) { - // Unstar. - backend_->DeleteStarredEntry(star_id); - } else if (!star_id && starred) { - // Star. - entry.parent_group_id = HistoryService::kBookmarkBarID; - backend_->CreateStarredEntry(NULL, entry); - } - } - // PageUsageData vector to test segments. ScopedVector<PageUsageData> page_usage_data_; @@ -870,56 +849,4 @@ TEST_F(HistoryTest, HistoryDBTaskCanceled) { ASSERT_FALSE(task->done_invoked); } -TEST_F(HistoryTest, Starring) { - CreateBackendAndDatabase(); - - // Add one page and star it. - GURL simple_page("http://google.com"); - scoped_refptr<HistoryAddPageArgs> args(MakeAddArgs(simple_page)); - backend_->AddPage(args); - EXPECT_FALSE(IsURLStarred(db_, simple_page)); - EXPECT_FALSE(IsURLStarred(in_mem_backend_->db(), simple_page)); - SetURLStarred(simple_page, true); - - // The URL should be starred in both the main and memory DBs. - EXPECT_TRUE(IsURLStarred(db_, simple_page)); - EXPECT_TRUE(IsURLStarred(in_mem_backend_->db(), simple_page)); - - // Unstar it. - SetURLStarred(simple_page, false); - EXPECT_FALSE(IsURLStarred(db_, simple_page)); - EXPECT_FALSE(IsURLStarred(in_mem_backend_->db(), simple_page)); -} - -TEST_F(HistoryTest, SetStarredOnPageWithTypeCount0) { - CreateBackendAndDatabase(); - - // Add a page to the backend. - const GURL url(L"http://google.com/"); - scoped_refptr<HistoryAddPageArgs> args(new HistoryAddPageArgs( - url, Time::Now(), NULL, 1, GURL(), HistoryService::RedirectList(), - PageTransition::LINK)); - backend_->AddPage(args); - - // Now fetch the URLInfo from the in memory db, it should not be there since - // it was not typed. - URLRow url_info; - EXPECT_EQ(0, in_mem_backend_->db()->GetRowForURL(url, &url_info)); - - // Mark the URL starred. - SetURLStarred(url, true); - - // The type count is 0, so the page shouldn't be starred in the in memory - // db. - EXPECT_EQ(0, in_mem_backend_->db()->GetRowForURL(url, &url_info)); - EXPECT_TRUE(IsURLStarred(db_, url)); - - // Now unstar it. - SetURLStarred(url, false); - - // Make sure both the back end and in memory DB think it is unstarred. - EXPECT_EQ(0, in_mem_backend_->db()->GetRowForURL(url, &url_info)); - EXPECT_FALSE(IsURLStarred(db_, url)); -} - } // namespace history diff --git a/chrome/browser/history/in_memory_history_backend.cc b/chrome/browser/history/in_memory_history_backend.cc index b3619a9..d745423 100644 --- a/chrome/browser/history/in_memory_history_backend.cc +++ b/chrome/browser/history/in_memory_history_backend.cc @@ -54,7 +54,6 @@ InMemoryHistoryBackend::~InMemoryHistoryBackend() { service->RemoveObserver(this, NOTIFY_HISTORY_URL_VISITED, source); service->RemoveObserver(this, NOTIFY_HISTORY_TYPED_URLS_MODIFIED, source); service->RemoveObserver(this, NOTIFY_HISTORY_URLS_DELETED, source); - service->RemoveObserver(this, NOTIFY_URLS_STARRED, source); } } @@ -87,7 +86,6 @@ void InMemoryHistoryBackend::AttachToHistoryService(Profile* profile) { service->AddObserver(this, NOTIFY_HISTORY_URL_VISITED, source); service->AddObserver(this, NOTIFY_HISTORY_TYPED_URLS_MODIFIED, source); service->AddObserver(this, NOTIFY_HISTORY_URLS_DELETED, source); - service->AddObserver(this, NOTIFY_URLS_STARRED, source); } void InMemoryHistoryBackend::Observe(NotificationType type, @@ -110,9 +108,6 @@ void InMemoryHistoryBackend::Observe(NotificationType type, case NOTIFY_HISTORY_URLS_DELETED: OnURLsDeleted(*Details<history::URLsDeletedDetails>(details).ptr()); break; - case NOTIFY_URLS_STARRED: - OnURLsStarred(*Details<history::URLsStarredDetails>(details).ptr()); - break; default: // For simplicity, the unit tests send us all notifications, even when // we haven't registered for them, so don't assert here. @@ -164,21 +159,4 @@ void InMemoryHistoryBackend::OnURLsDeleted(const URLsDeletedDetails& details) { } } -void InMemoryHistoryBackend::OnURLsStarred( - const history::URLsStarredDetails& details) { - DCHECK(db_.get()); - - for (std::set<GURL>::const_iterator i = details.changed_urls.begin(); - i != details.changed_urls.end(); ++i) { - URLRow row; - if (db_->GetRowForURL(*i, &row)) { - // NOTE: We currently don't care about the star id from the in memory - // db, so that we use a fake value. If this does become a problem, - // then the notification will have to propagate the star id. - row.set_star_id(details.starred ? kBogusStarredID : 0); - db_->UpdateURLRow(row.id(), row); - } - } -} - } // namespace history diff --git a/chrome/browser/history/in_memory_history_backend.h b/chrome/browser/history/in_memory_history_backend.h index 9134bf0..c86ea56 100644 --- a/chrome/browser/history/in_memory_history_backend.h +++ b/chrome/browser/history/in_memory_history_backend.h @@ -85,9 +85,6 @@ class InMemoryHistoryBackend : public NotificationObserver { // Handler for NOTIFY_HISTORY_URLS_DELETED. void OnURLsDeleted(const URLsDeletedDetails& details); - // Handler for NOTIFY_URLS_STARRED. - void OnURLsStarred(const URLsStarredDetails& details); - scoped_ptr<InMemoryDatabase> db_; // The profile that this object is attached. May be NULL before diff --git a/chrome/browser/history/starred_url_database.cc b/chrome/browser/history/starred_url_database.cc index 7294222..950cee3 100644 --- a/chrome/browser/history/starred_url_database.cc +++ b/chrome/browser/history/starred_url_database.cc @@ -29,7 +29,11 @@ #include "chrome/browser/history/starred_url_database.h" +#include "base/file_util.h" #include "base/logging.h" +#include "base/json_writer.h" +#include "chrome/browser/bookmark_bar_model.h" +#include "chrome/browser/bookmark_codec.h" #include "chrome/browser/history/history.h" #include "chrome/browser/history/query_parser.h" #include "chrome/browser/meta_table_helper.h" @@ -102,181 +106,35 @@ void FillInStarredEntry(SQLStatement* s, StarredEntry* entry) { } // namespace -StarredURLDatabase::StarredURLDatabase() - : is_starred_valid_(true), check_starred_integrity_on_mutation_(true) { +StarredURLDatabase::StarredURLDatabase() { } StarredURLDatabase::~StarredURLDatabase() { } -bool StarredURLDatabase::InitStarTable() { - if (!DoesSqliteTableExist(GetDB(), "starred")) { - if (sqlite3_exec(GetDB(), "CREATE TABLE starred (" - "id INTEGER PRIMARY KEY," - "type INTEGER NOT NULL DEFAULT 0," - "url_id INTEGER NOT NULL DEFAULT 0," - "group_id INTEGER NOT NULL DEFAULT 0," - "title VARCHAR," - "date_added INTEGER NOT NULL," - "visual_order INTEGER DEFAULT 0," - "parent_id INTEGER DEFAULT 0," - "date_modified INTEGER DEFAULT 0 NOT NULL)", - NULL, NULL, NULL) != SQLITE_OK) { - NOTREACHED(); - return false; - } - if (sqlite3_exec(GetDB(), "CREATE INDEX starred_index " - "ON starred(id,url_id)", NULL, NULL, NULL)) { - NOTREACHED(); - return false; - } - // Add an entry that represents the bookmark bar. The title is ignored in - // the UI. - StarID bookmark_id = CreateStarredEntryRow( - 0, HistoryService::kBookmarkBarID, 0, L"bookmark-bar", Time::Now(), 0, - history::StarredEntry::BOOKMARK_BAR); - if (bookmark_id != HistoryService::kBookmarkBarID) { - NOTREACHED(); - return false; - } - - // Add an entry that represents other. The title is ignored in the UI. - StarID other_id = CreateStarredEntryRow( - 0, HistoryService::kBookmarkBarID + 1, 0, L"other", Time::Now(), 0, - history::StarredEntry::OTHER); - if (!other_id) { - NOTREACHED(); - return false; - } - } - - sqlite3_exec(GetDB(), "CREATE INDEX starred_group_index" - "ON starred(group_id)", NULL, NULL, NULL); - return true; -} - -bool StarredURLDatabase::EnsureStarredIntegrity() { - if (!is_starred_valid_) - return false; - - // Assume invalid, we'll set to true if succesful. - is_starred_valid_ = false; - - std::set<StarredNode*> roots; - std::set<StarID> groups_with_duplicate_ids; - std::set<StarredNode*> unparented_urls; - std::set<StarID> empty_url_ids; - - if (!BuildStarNodes(&roots, &groups_with_duplicate_ids, &unparented_urls, - &empty_url_ids)) { - return false; - } - - // The table may temporarily get into an invalid state while updating the - // integrity. - bool org_check_starred_integrity_on_mutation = - check_starred_integrity_on_mutation_; - check_starred_integrity_on_mutation_ = false; - is_starred_valid_ = - EnsureStarredIntegrityImpl(&roots, groups_with_duplicate_ids, - &unparented_urls, empty_url_ids); - check_starred_integrity_on_mutation_ = - org_check_starred_integrity_on_mutation; - - STLDeleteElements(&roots); - STLDeleteElements(&unparented_urls); - return is_starred_valid_; -} - -StarID StarredURLDatabase::GetStarIDForEntry(const StarredEntry& entry) { - if (entry.type == StarredEntry::URL) { - URLRow url_row; - URLID url_id = GetRowForURL(entry.url, &url_row); - if (!url_id) - return 0; - return url_row.star_id(); - } - return GetStarIDForGroupID(entry.group_id); -} - -StarID StarredURLDatabase::GetStarIDForGroupID(UIStarID group_id) { - DCHECK(group_id); - - SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(), - "SELECT id FROM starred WHERE group_id = ?"); - if (!statement.is_valid()) - return false; - - statement->bind_int64(0, group_id); - if (statement->step() == SQLITE_ROW) - return statement->column_int64(0); - return 0; -} - -void StarredURLDatabase::DeleteStarredEntry( - StarID star_id, - std::set<GURL>* unstarred_urls, - std::vector<StarredEntry>* deleted_entries) { - DeleteStarredEntryImpl(star_id, unstarred_urls, deleted_entries); - if (check_starred_integrity_on_mutation_) - CheckStarredIntegrity(); -} +bool StarredURLDatabase::MigrateBookmarksToFile(const std::wstring& path) { + if (!DoesSqliteTableExist(GetDB(), "starred")) + return true; -bool StarredURLDatabase::UpdateStarredEntry(StarredEntry* entry) { - // Determine the ID used by the database. - const StarID id = GetStarIDForEntry(*entry); - if (!id) { - NOTREACHED() << "request to update unknown star entry"; + if (EnsureStarredIntegrity() && !MigrateBookmarksToFileImpl(path)) { + NOTREACHED() << " Bookmarks migration failed"; return false; } - StarredEntry original_entry; - if (!GetStarredEntry(id, &original_entry)) { - NOTREACHED() << "Unknown star entry"; + if (sqlite3_exec(GetDB(), "DROP TABLE starred", NULL, NULL, + NULL) != SQLITE_OK) { + NOTREACHED() << "Unable to drop starred table"; return false; } - - if (entry->parent_group_id != original_entry.parent_group_id) { - // Parent has changed. - if (original_entry.parent_group_id) { - AdjustStarredVisualOrder(original_entry.parent_group_id, - original_entry.visual_order, -1); - } - if (entry->parent_group_id) { - AdjustStarredVisualOrder(entry->parent_group_id, entry->visual_order, 1); - } - } else if (entry->visual_order != original_entry.visual_order && - entry->parent_group_id) { - // Same parent, but visual order changed. - // Shift everything down from the old location. - AdjustStarredVisualOrder(original_entry.parent_group_id, - original_entry.visual_order, -1); - // Make room for new location by shifting everything up from the new - // location. - AdjustStarredVisualOrder(original_entry.parent_group_id, - entry->visual_order, 1); - } - - // And update title, parent and visual order. - UpdateStarredEntryRow(id, entry->title, entry->parent_group_id, - entry->visual_order, entry->date_group_modified); - entry->url_id = original_entry.url_id; - entry->date_added = original_entry.date_added; - entry->id = original_entry.id; - if (check_starred_integrity_on_mutation_) - CheckStarredIntegrity(); return true; } -bool StarredURLDatabase::GetStarredEntries( - UIStarID parent_group_id, +bool StarredURLDatabase::GetAllStarredEntries( std::vector<StarredEntry>* entries) { DCHECK(entries); std::string sql = "SELECT "; sql.append(kHistoryStarFields); sql.append("FROM starred LEFT JOIN urls ON starred.url_id = urls.id "); - if (parent_group_id) - sql += "WHERE starred.parent_id = ? "; sql += "ORDER BY parent_id, visual_order"; SQLStatement s; @@ -284,8 +142,6 @@ bool StarredURLDatabase::GetStarredEntries( NOTREACHED() << "Statement prepare failed"; return false; } - if (parent_group_id) - s.bind_int64(0, parent_group_id); history::StarredEntry entry; while (s.step() == SQLITE_ROW) { @@ -299,6 +155,25 @@ bool StarredURLDatabase::GetStarredEntries( return true; } +bool StarredURLDatabase::EnsureStarredIntegrity() { + std::set<StarredNode*> roots; + std::set<StarID> groups_with_duplicate_ids; + std::set<StarredNode*> unparented_urls; + std::set<StarID> empty_url_ids; + + if (!BuildStarNodes(&roots, &groups_with_duplicate_ids, &unparented_urls, + &empty_url_ids)) { + return false; + } + + bool valid = EnsureStarredIntegrityImpl(&roots, groups_with_duplicate_ids, + &unparented_urls, empty_url_ids); + + STLDeleteElements(&roots); + STLDeleteElements(&unparented_urls); + return valid; +} + bool StarredURLDatabase::UpdateStarredEntryRow(StarID star_id, const std::wstring& title, UIStarID parent_group_id, @@ -380,8 +255,6 @@ StarID StarredURLDatabase::CreateStarredEntryRow(URLID url_id, } bool StarredURLDatabase::DeleteStarredEntryRow(StarID star_id) { - if (check_starred_integrity_on_mutation_) - DCHECK(star_id && star_id != HistoryService::kBookmarkBarID); SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(), "DELETE FROM starred WHERE id=?"); if (!statement.is_valid()) @@ -433,11 +306,6 @@ StarID StarredURLDatabase::CreateStarredEntry(StarredEntry* entry) { url_row.set_hidden(false); entry->url_id = this->AddURL(url_row); } else { - // Update the existing row for this URL. - if (url_row.starred()) { - DCHECK(false) << "We are starring an already-starred URL"; - return 0; - } entry->url_id = url_row.id(); // The caller doesn't have to set this. } @@ -447,7 +315,6 @@ StarID StarredURLDatabase::CreateStarredEntry(StarredEntry* entry) { entry->visual_order, entry->type); // Update the URL row to refer to this new starred entry. - url_row.set_star_id(entry->id); UpdateURLRow(entry->url_id, url_row); break; } @@ -456,119 +323,9 @@ StarID StarredURLDatabase::CreateStarredEntry(StarredEntry* entry) { NOTREACHED(); break; } - if (check_starred_integrity_on_mutation_) - CheckStarredIntegrity(); return entry->id; } -void StarredURLDatabase::GetMostRecentStarredEntries( - int max_count, - std::vector<StarredEntry>* entries) { - DCHECK(max_count && entries); - SQLITE_UNIQUE_STATEMENT(s, GetStatementCache(), - "SELECT" STAR_FIELDS "FROM starred " - "LEFT JOIN urls ON starred.url_id = urls.id " - "WHERE starred.type=0 ORDER BY starred.date_added DESC, " - "starred.id DESC " // This is for testing, when the dates are - // typically the same. - "LIMIT ?"); - if (!s.is_valid()) - return; - s->bind_int(0, max_count); - - while (s->step() == SQLITE_ROW) { - history::StarredEntry entry; - FillInStarredEntry(s.statement(), &entry); - entries->push_back(entry); - } -} - -void StarredURLDatabase::GetURLsForTitlesMatching(const std::wstring& query, - std::set<URLID>* ids) { - QueryParser parser; - ScopedVector<QueryNode> nodes; - parser.ParseQuery(query, &nodes.get()); - if (nodes.empty()) - return; - - SQLITE_UNIQUE_STATEMENT(s, GetStatementCache(), - "SELECT url_id, title FROM starred WHERE type=?"); - if (!s.is_valid()) - return; - - s->bind_int(0, static_cast<int>(StarredEntry::URL)); - while (s->step() == SQLITE_ROW) { - if (parser.DoesQueryMatch(s->column_string16(1), nodes.get())) - ids->insert(s->column_int64(0)); - } -} - -bool StarredURLDatabase::UpdateURLIDForStar(StarID star_id, URLID new_url_id) { - SQLITE_UNIQUE_STATEMENT(s, GetStatementCache(), - "UPDATE starred SET url_id=? WHERE id=?"); - if (!s.is_valid()) - return false; - s->bind_int64(0, new_url_id); - s->bind_int64(1, star_id); - return s->step() == SQLITE_DONE; -} - -void StarredURLDatabase::DeleteStarredEntryImpl( - StarID star_id, - std::set<GURL>* unstarred_urls, - std::vector<StarredEntry>* deleted_entries) { - - StarredEntry deleted_entry; - if (!GetStarredEntry(star_id, &deleted_entry)) - return; // Couldn't find information on the entry. - - if (deleted_entry.type == StarredEntry::BOOKMARK_BAR || - deleted_entry.type == StarredEntry::OTHER) { - return; - } - - if (deleted_entry.parent_group_id != 0) { - // This entry has a parent. All siblings after this entry need to be shifted - // down by 1. - AdjustStarredVisualOrder(deleted_entry.parent_group_id, - deleted_entry.visual_order, -1); - } - - deleted_entries->push_back(deleted_entry); - - switch (deleted_entry.type) { - case StarredEntry::URL: { - unstarred_urls->insert(deleted_entry.url); - - // Need to unmark the starred flag in the URL database. - URLRow url_row; - if (GetURLRow(deleted_entry.url_id, &url_row)) { - url_row.set_star_id(0); - UpdateURLRow(deleted_entry.url_id, url_row); - } - break; - } - - case StarredEntry::USER_GROUP: { - // Need to delete all the children of the group. Use the db version which - // avoids shifting the visual order. - std::vector<StarredEntry> descendants; - GetStarredEntries(deleted_entry.group_id, &descendants); - for (std::vector<StarredEntry>::iterator i = - descendants.begin(); i != descendants.end(); ++i) { - // Recurse down into the child. - DeleteStarredEntryImpl(i->id, unstarred_urls, deleted_entries); - } - break; - } - - default: - NOTREACHED(); - break; - } - DeleteStarredEntryRow(star_id); -} - UIStarID StarredURLDatabase::GetMaxGroupID() { SQLStatement max_group_id_statement; if (max_group_id_statement.prepare(GetDB(), @@ -589,7 +346,7 @@ bool StarredURLDatabase::BuildStarNodes( std::set<StarredNode*>* unparented_urls, std::set<StarID>* empty_url_ids) { std::vector<StarredEntry> star_entries; - if (!GetStarredEntries(0, &star_entries)) { + if (!GetAllStarredEntries(&star_entries)) { NOTREACHED() << "Unable to get bookmarks from database"; return false; } @@ -699,11 +456,9 @@ bool StarredURLDatabase::EnsureStarredIntegrityImpl( if (!bookmark_node) { LOG(WARNING) << "No bookmark bar folder in database"; // If there is no bookmark bar entry in the db things are really - // screwed. The UI assumes the bookmark bar entry has a particular - // ID which is hard to enforce when creating a new entry. As this - // shouldn't happen, we take the drastic route of recreating the - // entire table. - return RecreateStarredEntries(); + // screwed. Return false, which won't trigger migration and we'll just + // drop the tables. + return false; } // Make sure the other node exists. @@ -803,86 +558,96 @@ bool StarredURLDatabase::Move(StarredNode* source, StarredNode* new_parent) { return true; } -bool StarredURLDatabase::RecreateStarredEntries() { - if (sqlite3_exec(GetDB(), "DROP TABLE starred", NULL, NULL, - NULL) != SQLITE_OK) { - NOTREACHED() << "Unable to drop starred table"; +bool StarredURLDatabase::MigrateBookmarksToFileImpl(const std::wstring& path) { + std::vector<history::StarredEntry> entries; + if (!GetAllStarredEntries(&entries)) return false; - } - if (!InitStarTable()) { - NOTREACHED() << "Unable to create starred table"; - return false; - } - - if (sqlite3_exec(GetDB(), "UPDATE urls SET starred_id=0", NULL, NULL, - NULL) != SQLITE_OK) { - NOTREACHED() << "Unable to mark all URLs as unstarred"; - return false; + // Create the bookmark bar and other folder nodes. + history::StarredEntry entry; + entry.type = history::StarredEntry::BOOKMARK_BAR; + BookmarkBarNode bookmark_bar_node(NULL, GURL()); + bookmark_bar_node.Reset(entry); + entry.type = history::StarredEntry::OTHER; + BookmarkBarNode other_node(NULL, GURL()); + other_node.Reset(entry); + + std::map<history::UIStarID, history::StarID> group_id_to_id_map; + typedef std::map<history::StarID, BookmarkBarNode*> IDToNodeMap; + IDToNodeMap id_to_node_map; + + history::UIStarID other_folder_group_id = 0; + history::StarID other_folder_id = 0; + + // Iterate through the entries building a mapping between group_id and id. + for (std::vector<history::StarredEntry>::const_iterator i = entries.begin(); + i != entries.end(); ++i) { + if (i->type != history::StarredEntry::URL) { + group_id_to_id_map[i->group_id] = i->id; + if (i->type == history::StarredEntry::OTHER) { + other_folder_id = i->id; + other_folder_group_id = i->group_id; + } + } } - return true; -} -void StarredURLDatabase::CheckVisualOrder(StarredNode* node) { - for (int i = 0; i < node->GetChildCount(); ++i) { - DCHECK(i == node->GetChild(i)->value.visual_order); - CheckVisualOrder(node->GetChild(i)); - } -} + // Register the bookmark bar and other folder nodes in the maps. + id_to_node_map[HistoryService::kBookmarkBarID] = &bookmark_bar_node; + group_id_to_id_map[HistoryService::kBookmarkBarID] = + HistoryService::kBookmarkBarID; + if (other_folder_group_id) { + id_to_node_map[other_folder_id] = &other_node; + group_id_to_id_map[other_folder_group_id] = other_folder_id; + } + + // Iterate through the entries again creating the nodes. + for (std::vector<history::StarredEntry>::iterator i = entries.begin(); + i != entries.end(); ++i) { + if (!i->parent_group_id) { + DCHECK(i->type == history::StarredEntry::BOOKMARK_BAR || + i->type == history::StarredEntry::OTHER); + // Only entries with no parent should be the bookmark bar and other + // bookmarks folders. + continue; + } -void StarredURLDatabase::CheckStarredIntegrity() { -#ifndef NDEBUG - std::set<StarredNode*> roots; - std::set<StarID> groups_with_duplicate_ids; - std::set<StarredNode*> unparented_urls; - std::set<StarID> empty_url_ids; + BookmarkBarNode* node = id_to_node_map[i->id]; + if (!node) { + // Creating a node results in creating the parent. As such, it is + // possible for the node representing a group to have been created before + // encountering the details. - if (!BuildStarNodes(&roots, &groups_with_duplicate_ids, &unparented_urls, - &empty_url_ids)) { - return; - } + // The created nodes are owned by the root node. + node = new BookmarkBarNode(NULL, i->url); + id_to_node_map[i->id] = node; + } + node->Reset(*i); + + DCHECK(group_id_to_id_map.find(i->parent_group_id) != + group_id_to_id_map.end()); + history::StarID parent_id = group_id_to_id_map[i->parent_group_id]; + BookmarkBarNode* parent = id_to_node_map[parent_id]; + if (!parent) { + // Haven't encountered the parent yet, create it now. + parent = new BookmarkBarNode(NULL, GURL()); + id_to_node_map[parent_id] = parent; + } - // There must be root and bookmark bar nodes. - if (!GetNodeByType(roots, StarredEntry::BOOKMARK_BAR)) - NOTREACHED() << "No bookmark bar folder in starred"; - else - CheckVisualOrder(GetNodeByType(roots, StarredEntry::BOOKMARK_BAR)); - - if (!GetNodeByType(roots, StarredEntry::OTHER)) - NOTREACHED() << "No other bookmarks folder in starred"; - else - CheckVisualOrder(GetNodeByType(roots, StarredEntry::OTHER)); - - // The only roots should be the bookmark bar and other nodes. Also count how - // many bookmark bar and other folders exists. - int bookmark_bar_count = 0; - int other_folder_count = 0; - for (std::set<StarredNode*>::const_iterator i = roots.begin(); - i != roots.end(); ++i) { - if ((*i)->value.type == StarredEntry::USER_GROUP) - NOTREACHED() << "Bookmark folder not in bookmark bar or other folders"; - else if ((*i)->value.type == StarredEntry::BOOKMARK_BAR) - bookmark_bar_count++; - else if ((*i)->value.type == StarredEntry::OTHER) - other_folder_count++; + // Add the node to its parent. |entries| is ordered by parent then + // visual order so that we know we maintain visual order by always adding + // to the end. + parent->Add(parent->GetChildCount(), node); } - DCHECK(bookmark_bar_count == 1) << "Should be only one bookmark bar entry"; - DCHECK(other_folder_count == 1) << "Should be only one other folder entry"; - // There shouldn't be any folders with the same group id. - if (!groups_with_duplicate_ids.empty()) - NOTREACHED() << "Bookmark folder with duplicate ids exist"; + // Save to file. + BookmarkCodec encoder; + scoped_ptr<Value> encoded_bookmarks( + encoder.Encode(&bookmark_bar_node, &other_node)); + std::string content; + JSONWriter::Write(encoded_bookmarks.get(), true, &content); - // And all URLs should be parented. - if (!unparented_urls.empty()) - NOTREACHED() << "Bookmarks not on the bookmark/'other folder' exist"; - - if (!empty_url_ids.empty()) - NOTREACHED() << "Bookmarks with no corresponding URL exist"; - - STLDeleteElements(&roots); - STLDeleteElements(&unparented_urls); -#endif NDEBUG + return (file_util::WriteFile(path, content.c_str(), + static_cast<int>(content.length())) != -1); } } // namespace history diff --git a/chrome/browser/history/starred_url_database.h b/chrome/browser/history/starred_url_database.h index d58571d..e7a774f 100644 --- a/chrome/browser/history/starred_url_database.h +++ b/chrome/browser/history/starred_url_database.h @@ -44,12 +44,9 @@ class SqliteStatementCache; namespace history { -// Encapsulates a URL database plus starred information. -// -// WARNING: many of the following methods allow you to update, delete or -// insert starred entries specifying a visual order. These methods do NOT -// adjust the visual order of surrounding entries. You must explicitly do -// it yourself using AdjustStarredVisualOrder as appropriate. +// Bookmarks were originally part of the url database, they have since been +// moved to a separate file. This file exists purely for historical reasons and +// contains just enough to allow migration. class StarredURLDatabase : public URLDatabase { public: // Must call InitStarTable() AND any additional init functions provided by @@ -57,87 +54,22 @@ class StarredURLDatabase : public URLDatabase { StarredURLDatabase(); virtual ~StarredURLDatabase(); - // Returns the id of the starred entry. This does NOT return entry.id, - // rather the database is queried for the id based on entry.url or - // entry.group_id. - StarID GetStarIDForEntry(const StarredEntry& entry); - - // Returns the internal star ID for the externally-generated group ID. - StarID GetStarIDForGroupID(UIStarID group_id); - - // Gets the details for the specified star entry in entry. - bool GetStarredEntry(StarID star_id, StarredEntry* entry); - - // Creates a starred entry with the requested information. The structure will - // be updated with the ID of the newly created entry. The URL table will be - // updated to point to the entry. The URL row will be created if it doesn't - // exist. - // - // We currently only support one entry per URL. This URL should not already be - // starred when calling this function or it will fail and will return 0. - StarID CreateStarredEntry(StarredEntry* entry); - - // Returns starred entries. - // This returns three different result types: - // only_on_bookmark_bar == true: only those entries on the bookmark bar are - // returned. - // only_on_bookmark_bar == false and parent_id == 0: all starred - // entries/groups. - // otherwise only the direct children (groups and entries) of parent_id are - // returned. - bool GetStarredEntries(UIStarID parent_group_id, - std::vector<StarredEntry>* entries); - - // Deletes a starred entry. This adjusts the visual order of all siblings - // after the entry. The deleted entry(s) will be *appended* to - // |*deleted_entries| (so delete can be called more than once with the same - // list) and deleted URLs will additionally be added to the set. - // - // This function invokes DeleteStarredEntryImpl to do the actual work, which - // recurses. - void DeleteStarredEntry(StarID star_id, - std::set<GURL>* unstarred_urls, - std::vector<StarredEntry>* deleted_entries); - - // Implementation to update the database for UpdateStarredEntry. Returns true - // on success. If successful, the parent_id, url_id, id and date_added fields - // of the entry are reset from that of the database. - bool UpdateStarredEntry(StarredEntry* entry); - - // Gets up to max_count starred entries of type URL adding them to entries. - // The results are ordered by date added in descending order (most recent - // first). - void GetMostRecentStarredEntries(int max_count, - std::vector<StarredEntry>* entries); - - // Gets the URLIDs for all starred entries of type URL whose title matches - // the specified query. - void GetURLsForTitlesMatching(const std::wstring& query, - std::set<URLID>* ids); - - // Returns true if the starred table is in a sane state. If false, the starred - // table is likely corrupt and shouldn't be used. - bool is_starred_valid() const { return is_starred_valid_; } - - // Updates the URL ID for the given starred entry. This is used by the expirer - // when URL IDs change. It can't use UpdateStarredEntry since that doesn't - // set the URLID, and it does a bunch of other logic that we don't need. - bool UpdateURLIDForStar(StarID star_id, URLID new_url_id); - protected: // The unit tests poke our innards. friend class HistoryTest; + friend class StarredURLDatabaseTest; FRIEND_TEST(HistoryTest, CreateStarGroup); + // Writes bookmarks to the specified file. + bool MigrateBookmarksToFile(const std::wstring& path); + // Returns the database and statement cache for the functions in this // interface. The decendent of this class implements these functions to // return its objects. virtual sqlite3* GetDB() = 0; virtual SqliteStatementCache& GetStatementCache() = 0; - // Creates the starred tables if necessary. - bool InitStarTable(); - + private: // Makes sure the starred table is in a sane state. This does the following: // . Makes sure there is a bookmark bar and other nodes. If no bookmark bar // node is found, the table is dropped and recreated. @@ -155,17 +87,8 @@ class StarredURLDatabase : public URLDatabase { // This should be invoked after migration. bool EnsureStarredIntegrity(); - // Creates a starred entry with the specified parameters in the database. - // Returns the newly created id, or 0 on failure. - // - // WARNING: Does not update the visual order. - StarID CreateStarredEntryRow(URLID url_id, - UIStarID group_id, - UIStarID parent_group_id, - const std::wstring& title, - const Time& date_added, - int visual_order, - StarredEntry::Type type); + // Gets all the starred entries. + bool GetAllStarredEntries(std::vector<StarredEntry>* entries); // Sets the title, parent_id, parent_group_id, visual_order and date_modifed // of the specified star entry. @@ -185,26 +108,39 @@ class StarredURLDatabase : public URLDatabase { int start_visual_order, int delta); + // Creates a starred entry with the specified parameters in the database. + // Returns the newly created id, or 0 on failure. + // + // WARNING: Does not update the visual order. + StarID CreateStarredEntryRow(URLID url_id, + UIStarID group_id, + UIStarID parent_group_id, + const std::wstring& title, + const Time& date_added, + int visual_order, + StarredEntry::Type type); + // Deletes the entry from the starred database base on the starred id (NOT // the url id). // // WARNING: Does not update the visual order. bool DeleteStarredEntryRow(StarID star_id); - // Should the integrity of the starred table be checked on every mutation? - // Default is true. Set to false when running tests that need to allow the - // table to be in an invalid state while testing. - bool check_starred_integrity_on_mutation_; + // Gets the details for the specified star entry in entry. + bool GetStarredEntry(StarID star_id, StarredEntry* entry); + + // Creates a starred entry with the requested information. The structure will + // be updated with the ID of the newly created entry. The URL table will be + // updated to point to the entry. The URL row will be created if it doesn't + // exist. + // + // We currently only support one entry per URL. This URL should not already be + // starred when calling this function or it will fail and will return 0. + StarID CreateStarredEntry(StarredEntry* entry); - private: // Used when checking integrity of starred table. typedef ChromeViews::TreeNodeWithValue<history::StarredEntry> StarredNode; - // Implementation of DeleteStarredEntryImpl. - void DeleteStarredEntryImpl(StarID star_id, - std::set<GURL>* unstarred_urls, - std::vector<StarredEntry>* deleted_entries); - // Returns the max group id, or 0 if there is an error. UIStarID GetMaxGroupID(); @@ -262,24 +198,9 @@ class StarredURLDatabase : public URLDatabase { // needs to be moved. bool Move(StarredNode* source, StarredNode* new_parent); - // Drops and recreates the starred table as well as marking all URLs as - // unstarred. This is used as a last resort if the bookmarks table is - // totally corrupt. - bool RecreateStarredEntries(); - - // Iterates through the children of node make sure the visual order matches - // the order in node's children. DCHECKs if the order differs. This recurses. - void CheckVisualOrder(StarredNode* node); - - // Makes sure the starred table is in a sane state, if not this DCHECKs. - // This is invoked internally after any mutation to the starred table. - // - // This is a no-op in release builds. - void CheckStarredIntegrity(); - - // True if the starred table is valid. This is initialized in - // EnsureStarredIntegrityImpl. - bool is_starred_valid_; + // Does the work of migrating bookmarks to a temporary file that + // BookmarkStorage will read from. + bool MigrateBookmarksToFileImpl(const std::wstring& path); DISALLOW_EVIL_CONSTRUCTORS(StarredURLDatabase); }; diff --git a/chrome/browser/history/starred_url_database_unittest.cc b/chrome/browser/history/starred_url_database_unittest.cc index aca91d9..c59c122 100644 --- a/chrome/browser/history/starred_url_database_unittest.cc +++ b/chrome/browser/history/starred_url_database_unittest.cc @@ -34,6 +34,7 @@ #include "base/string_util.h" #include "chrome/browser/history/history.h" #include "chrome/browser/history/starred_url_database.h" +#include "chrome/common/chrome_paths.h" #include "chrome/common/sqlite_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -51,18 +52,6 @@ class StarredURLDatabaseTest : public testing::Test, EXPECT_TRUE(AddURL(row)); } - StarredEntry GetStarredEntryByURL(const GURL& url) { - std::vector<StarredEntry> starred; - EXPECT_TRUE(GetStarredEntries(0, &starred)); - for (std::vector<StarredEntry>::iterator i = starred.begin(); - i != starred.end(); ++i) { - if (i->url == url) - return *i; - } - EXPECT_TRUE(false); - return StarredEntry(); - } - void CompareEntryByID(const StarredEntry& entry) { DCHECK(entry.id != 0); StarredEntry db_value; @@ -82,43 +71,20 @@ class StarredURLDatabaseTest : public testing::Test, int GetStarredEntryCount() { DCHECK(db_); std::vector<StarredEntry> entries; - GetStarredEntries(0, &entries); + GetAllStarredEntries(&entries); return static_cast<int>(entries.size()); } - bool GetURLStarred(const GURL& url) { - URLRow row; - if (GetRowForURL(url, &row)) - return row.starred(); - return false; + StarID CreateStarredEntry(StarredEntry* entry) { + return StarredURLDatabase::CreateStarredEntry(entry); + } + + bool GetStarredEntry(StarID star_id, StarredEntry* entry) { + return StarredURLDatabase::GetStarredEntry(star_id, entry); } - void VerifyInitialState() { - std::vector<StarredEntry> star_entries; - EXPECT_TRUE(GetStarredEntries(0, &star_entries)); - EXPECT_EQ(2, star_entries.size()); - - int bb_index = -1; - size_t other_index = -1; - if (star_entries[0].type == history::StarredEntry::BOOKMARK_BAR) { - bb_index = 0; - other_index = 1; - } else { - bb_index = 1; - other_index = 0; - } - EXPECT_EQ(HistoryService::kBookmarkBarID, star_entries[bb_index].id); - EXPECT_EQ(HistoryService::kBookmarkBarID, star_entries[bb_index].group_id); - EXPECT_EQ(0, star_entries[bb_index].parent_group_id); - EXPECT_EQ(StarredEntry::BOOKMARK_BAR, star_entries[bb_index].type); - - EXPECT_TRUE(star_entries[other_index].id != HistoryService::kBookmarkBarID - && star_entries[other_index].id != 0); - EXPECT_TRUE(star_entries[other_index].group_id != - HistoryService::kBookmarkBarID && - star_entries[other_index].group_id != 0); - EXPECT_EQ(0, star_entries[other_index].parent_group_id); - EXPECT_EQ(StarredEntry::OTHER, star_entries[other_index].type); + bool EnsureStarredIntegrity() { + return StarredURLDatabase::EnsureStarredIntegrity(); } private: @@ -129,13 +95,19 @@ class StarredURLDatabaseTest : public testing::Test, db_file_.append(L"VisitTest.db"); file_util::Delete(db_file_, false); + // Copy db file over that contains starred table. + std::wstring old_history_path; + PathService::Get(chrome::DIR_TEST_DATA, &old_history_path); + file_util::AppendToPath(&old_history_path, L"bookmarks"); + file_util::AppendToPath(&old_history_path, L"History_with_empty_starred"); + file_util::CopyFile(old_history_path, db_file_); + EXPECT_EQ(SQLITE_OK, sqlite3_open(WideToUTF8(db_file_).c_str(), &db_)); statement_cache_ = new SqliteStatementCache(db_); // Initialize the tables for this test. CreateURLTable(false); CreateMainURLIndex(); - InitStarTable(); EnsureStarredIntegrity(); } void TearDown() { @@ -159,307 +131,7 @@ class StarredURLDatabaseTest : public testing::Test, //----------------------------------------------------------------------------- -TEST_F(StarredURLDatabaseTest, CreateStarredEntryUnstarred) { - StarredEntry entry; - entry.title = L"blah"; - entry.date_added = Time::Now(); - entry.url = GURL("http://www.google.com"); - entry.parent_group_id = HistoryService::kBookmarkBarID; - - StarID id = CreateStarredEntry(&entry); - - EXPECT_NE(0, id); - EXPECT_EQ(id, entry.id); - CompareEntryByID(entry); -} - -TEST_F(StarredURLDatabaseTest, UpdateStarredEntry) { - const int initial_count = GetStarredEntryCount(); - StarredEntry entry; - entry.title = L"blah"; - entry.date_added = Time::Now(); - entry.url = GURL("http://www.google.com"); - entry.parent_group_id = HistoryService::kBookmarkBarID; - - StarID id = CreateStarredEntry(&entry); - EXPECT_NE(0, id); - EXPECT_EQ(id, entry.id); - CompareEntryByID(entry); - - // Now invoke create again, as the URL hasn't changed this should just - // update the title. - EXPECT_TRUE(UpdateStarredEntry(&entry)); - CompareEntryByID(entry); - - // There should only be two entries (one for the url we created, one for the - // bookmark bar). - EXPECT_EQ(initial_count + 1, GetStarredEntryCount()); -} - -TEST_F(StarredURLDatabaseTest, DeleteStarredGroup) { - const int initial_count = GetStarredEntryCount(); - StarredEntry entry; - entry.type = StarredEntry::USER_GROUP; - entry.title = L"blah"; - entry.date_added = Time::Now(); - entry.group_id = 10; - entry.parent_group_id = HistoryService::kBookmarkBarID; - - StarID id = CreateStarredEntry(&entry); - EXPECT_NE(0, id); - EXPECT_NE(HistoryService::kBookmarkBarID, id); - CompareEntryByID(entry); - - EXPECT_EQ(initial_count + 1, GetStarredEntryCount()); - - // Now delete it. - std::set<GURL> unstarred_urls; - std::vector<StarredEntry> deleted_entries; - DeleteStarredEntry(entry.id, &unstarred_urls, &deleted_entries); - ASSERT_EQ(0, unstarred_urls.size()); - ASSERT_EQ(1, deleted_entries.size()); - EXPECT_EQ(deleted_entries[0].id, id); - - // Should only have the bookmark bar. - EXPECT_EQ(initial_count, GetStarredEntryCount()); -} - -TEST_F(StarredURLDatabaseTest, DeleteStarredGroupWithChildren) { - const int initial_count = GetStarredEntryCount(); - - StarredEntry entry; - entry.type = StarredEntry::USER_GROUP; - entry.title = L"blah"; - entry.date_added = Time::Now(); - entry.group_id = 10; - entry.parent_group_id = HistoryService::kBookmarkBarID; - - StarID id = CreateStarredEntry(&entry); - EXPECT_NE(0, id); - EXPECT_NE(HistoryService::kBookmarkBarID, id); - CompareEntryByID(entry); - - EXPECT_EQ(initial_count + 1, GetStarredEntryCount()); - - // Create a child of the group. - StarredEntry url_entry1; - url_entry1.parent_group_id = entry.group_id; - url_entry1.title = L"blah"; - url_entry1.date_added = Time::Now(); - url_entry1.url = GURL("http://www.google.com"); - StarID url_id1 = CreateStarredEntry(&url_entry1); - EXPECT_NE(0, url_id1); - CompareEntryByID(url_entry1); - - // Create a sibling of the group. - StarredEntry url_entry2; - url_entry2.parent_group_id = HistoryService::kBookmarkBarID; - url_entry2.title = L"blah"; - url_entry2.date_added = Time::Now(); - url_entry2.url = GURL("http://www.google2.com"); - url_entry2.visual_order = 1; - StarID url_id2 = CreateStarredEntry(&url_entry2); - EXPECT_NE(0, url_id2); - CompareEntryByID(url_entry2); - - EXPECT_EQ(initial_count + 3, GetStarredEntryCount()); - - // Now delete the group, which should delete url_entry1 and shift down the - // visual order of url_entry2. - std::set<GURL> unstarred_urls; - std::vector<StarredEntry> deleted_entries; - DeleteStarredEntry(entry.id, &unstarred_urls, &deleted_entries); - EXPECT_EQ(2, deleted_entries.size()); - EXPECT_EQ(1, unstarred_urls.size()); - EXPECT_TRUE((deleted_entries[0].id == id) || (deleted_entries[1].id == id)); - EXPECT_TRUE((deleted_entries[0].id == url_id1) || - (deleted_entries[1].id == url_id1)); - - url_entry2.visual_order--; - CompareEntryByID(url_entry2); - - // Should have the bookmark bar, and url_entry2. - EXPECT_EQ(initial_count + 1, GetStarredEntryCount()); -} - -TEST_F(StarredURLDatabaseTest, InitialState) { - VerifyInitialState(); -} - -TEST_F(StarredURLDatabaseTest, CreateStarGroup) { - const int initial_count = GetStarredEntryCount(); - std::wstring title(L"title"); - Time time(Time::Now()); - int visual_order = 0; - - UIStarID ui_group_id = 10; - UIStarID ui_parent_group_id = HistoryService::kBookmarkBarID; - - StarredEntry entry; - entry.type = StarredEntry::USER_GROUP; - entry.group_id = ui_group_id; - entry.parent_group_id = ui_parent_group_id; - entry.title = title; - entry.date_added = time; - entry.visual_order = visual_order; - StarID group_id = CreateStarredEntry(&entry); - - EXPECT_NE(0, group_id); - EXPECT_NE(HistoryService::kBookmarkBarID, group_id); - - EXPECT_EQ(group_id, GetStarIDForGroupID(ui_group_id)); - - StarredEntry group_entry; - EXPECT_TRUE(GetStarredEntry(group_id, &group_entry)); - EXPECT_EQ(ui_group_id, group_entry.group_id); - EXPECT_EQ(ui_parent_group_id, group_entry.parent_group_id); - EXPECT_TRUE(group_entry.title == title); - // Don't use Time.== here as the conversion to time_t when writing to the db - // is lossy. - EXPECT_TRUE(group_entry.date_added.ToTimeT() == time.ToTimeT()); - EXPECT_EQ(visual_order, group_entry.visual_order); - - // Update the date modified. - Time date_modified = Time::Now(); - entry.date_group_modified = date_modified; - UpdateStarredEntry(&group_entry); - EXPECT_TRUE(GetStarredEntry(group_id, &group_entry)); - EXPECT_TRUE(entry.date_group_modified.ToTimeT() == date_modified.ToTimeT()); -} - -TEST_F(StarredURLDatabaseTest, UpdateStarredEntryChangeVisualOrder) { - const int initial_count = GetStarredEntryCount(); - GURL url1(L"http://google.com/1"); - GURL url2(L"http://google.com/2"); - - // Star url1, making it a child of the bookmark bar. - StarredEntry entry; - entry.url = url1; - entry.title = L"FOO"; - entry.parent_group_id = HistoryService::kBookmarkBarID; - CreateStarredEntry(&entry); - - // Make sure it was created correctly. - entry = GetStarredEntryByURL(url1); - EXPECT_EQ(GetRowForURL(url1, NULL), entry.url_id); - CompareEntryByID(entry); - - // Star url2, making it a child of the bookmark bar, placing it after url2. - StarredEntry entry2; - entry2.url = url2; - entry2.visual_order = 1; - entry2.title = std::wstring(); - entry2.parent_group_id = HistoryService::kBookmarkBarID; - CreateStarredEntry(&entry2); - entry2 = GetStarredEntryByURL(url2); - EXPECT_EQ(GetRowForURL(url2, NULL), entry2.url_id); - CompareEntryByID(entry2); - - // Move url2 to be before url1. - entry2.visual_order = 0; - UpdateStarredEntry(&entry2); - CompareEntryByID(entry2); - - // URL1's visual order should have shifted by one to accommodate URL2. - entry.visual_order = 1; - CompareEntryByID(entry); - - // Now move URL1 to position 0, which will move url2 to position 1. - entry.visual_order = 0; - UpdateStarredEntry(&entry); - CompareEntryByID(entry); - - entry2.visual_order = 1; - CompareEntryByID(entry2); - - // Create a new group between url1 and url2. - StarredEntry g_entry; - g_entry.group_id = 10; - g_entry.parent_group_id = HistoryService::kBookmarkBarID; - g_entry.title = L"blah"; - g_entry.visual_order = 1; - g_entry.date_added = Time::Now(); - g_entry.type = StarredEntry::USER_GROUP; - g_entry.id = CreateStarredEntry(&g_entry); - EXPECT_NE(0, g_entry.id); - CompareEntryByID(g_entry); - - // URL2 should have shifted to position 2. - entry2.visual_order = 2; - CompareEntryByID(entry2); - - // Move url2 inside of group 1. - entry2.visual_order = 0; - entry2.parent_group_id = g_entry.group_id; - UpdateStarredEntry(&entry2); - CompareEntryByID(entry2); - - // Move url1 to be a child of group 1 at position 0. - entry.parent_group_id = g_entry.group_id; - entry.visual_order = 0; - UpdateStarredEntry(&entry); - CompareEntryByID(entry); - - // url2 should have moved to position 1. - entry2.visual_order = 1; - CompareEntryByID(entry2); - - // And the group should have shifted to position 0. - g_entry.visual_order = 0; - CompareEntryByID(g_entry); - - EXPECT_EQ(initial_count + 3, GetStarredEntryCount()); - - // Delete the group, which should unstar url1 and url2. - std::set<GURL> unstarred_urls; - std::vector<StarredEntry> deleted_entries; - DeleteStarredEntry(g_entry.id, &unstarred_urls, &deleted_entries); - EXPECT_EQ(initial_count, GetStarredEntryCount()); - URLRow url_row; - GetRowForURL(url1, &url_row); - EXPECT_EQ(0, url_row.star_id()); - GetRowForURL(url2, &url_row); - EXPECT_EQ(0, url_row.star_id()); -} - -TEST_F(StarredURLDatabaseTest, GetMostRecentStarredEntries) { - // Initially there shouldn't be any entries (only the bookmark bar, which - // isn't returned by GetMostRecentStarredEntries). - std::vector<StarredEntry> starred_entries; - GetMostRecentStarredEntries(10, &starred_entries); - EXPECT_EQ(0, starred_entries.size()); - - // Star url1. - GURL url1(L"http://google.com/1"); - StarredEntry entry1; - entry1.type = StarredEntry::URL; - entry1.url = url1; - entry1.parent_group_id = HistoryService::kBookmarkBarID; - CreateStarredEntry(&entry1); - - // Get the recent ones. - GetMostRecentStarredEntries(10, &starred_entries); - ASSERT_EQ(1, starred_entries.size()); - EXPECT_TRUE(starred_entries[0].url == url1); - - // Add url2 and star it. - GURL url2(L"http://google.com/2"); - StarredEntry entry2; - entry2.type = StarredEntry::URL; - entry2.url = url2; - entry2.parent_group_id = HistoryService::kBookmarkBarID; - CreateStarredEntry(&entry2); - - starred_entries.clear(); - GetMostRecentStarredEntries(10, &starred_entries); - ASSERT_EQ(2, starred_entries.size()); - EXPECT_TRUE(starred_entries[0].url == url2); - EXPECT_TRUE(starred_entries[1].url == url1); -} - TEST_F(StarredURLDatabaseTest, FixOrphanedGroup) { - check_starred_integrity_on_mutation_ = false; - const size_t initial_count = GetStarredEntryCount(); // Create a group that isn't parented to the other/bookmark folders. @@ -482,8 +154,6 @@ TEST_F(StarredURLDatabaseTest, FixOrphanedGroup) { } TEST_F(StarredURLDatabaseTest, FixOrphanedBookmarks) { - check_starred_integrity_on_mutation_ = false; - const size_t initial_count = GetStarredEntryCount(); // Create two bookmarks that aren't in a random folder no on the bookmark bar. @@ -516,8 +186,6 @@ TEST_F(StarredURLDatabaseTest, FixOrphanedBookmarks) { } TEST_F(StarredURLDatabaseTest, FixGroupCycleDepth0) { - check_starred_integrity_on_mutation_ = false; - const size_t initial_count = GetStarredEntryCount(); // Create a group that is parented to itself. @@ -540,8 +208,6 @@ TEST_F(StarredURLDatabaseTest, FixGroupCycleDepth0) { } TEST_F(StarredURLDatabaseTest, FixGroupCycleDepth1) { - check_starred_integrity_on_mutation_ = false; - const size_t initial_count = GetStarredEntryCount(); StarredEntry entry1; @@ -574,8 +240,6 @@ TEST_F(StarredURLDatabaseTest, FixGroupCycleDepth1) { } TEST_F(StarredURLDatabaseTest, FixVisualOrder) { - check_starred_integrity_on_mutation_ = false; - const size_t initial_count = GetStarredEntryCount(); // Star two urls. @@ -607,29 +271,7 @@ TEST_F(StarredURLDatabaseTest, FixVisualOrder) { CompareEntryByID(entry2); } -TEST_F(StarredURLDatabaseTest, RestoreOtherAndBookmarkBar) { - std::vector<StarredEntry> entries; - GetStarredEntries(0, &entries); - - check_starred_integrity_on_mutation_ = false; - - for (std::vector<StarredEntry>::iterator i = entries.begin(); - i != entries.end(); ++i) { - if (i->type != StarredEntry::USER_GROUP) { - // Use this directly, otherwise we assert trying to delete other/bookmark - // bar. - DeleteStarredEntryRow(i->id); - - ASSERT_TRUE(EnsureStarredIntegrity()); - - VerifyInitialState(); - } - } -} - TEST_F(StarredURLDatabaseTest, FixDuplicateGroupIDs) { - check_starred_integrity_on_mutation_ = false; - const size_t initial_count = GetStarredEntryCount(); // Create two groups with the same group id. diff --git a/chrome/browser/history/text_database.h b/chrome/browser/history/text_database.h index f04f8c0..4bcccd0 100644 --- a/chrome/browser/history/text_database.h +++ b/chrome/browser/history/text_database.h @@ -142,8 +142,6 @@ class TextDatabase { // Querying ------------------------------------------------------------------ // Executes the given query. See QueryOptions for more info on input. - // Note that the options.only_starred is ignored since this database does not - // have access to star information. // // The results are appended to any existing ones in |*results|, and the first // time considered for the output is in |first_time_searched| diff --git a/chrome/browser/history/text_database_manager.h b/chrome/browser/history/text_database_manager.h index 2506835..7685135b 100644 --- a/chrome/browser/history/text_database_manager.h +++ b/chrome/browser/history/text_database_manager.h @@ -165,8 +165,6 @@ class TextDatabaseManager { void OptimizeChangedDatabases(const ChangeSet& change_set); // Executes the given query. See QueryOptions for more info on input. - // Note that the options.only_starred is ignored since this database does not - // have access to star information. // // The results are filled into |results|, and the first time considered for // the output is in |first_time_searched| (see QueryResults for more). diff --git a/chrome/browser/history/url_database.cc b/chrome/browser/history/url_database.cc index 0ce8072..899f04c 100644 --- a/chrome/browser/history/url_database.cc +++ b/chrome/browser/history/url_database.cc @@ -74,7 +74,6 @@ void URLDatabase::FillURLRow(SQLStatement& s, history::URLRow* i) { i->last_visit_ = Time::FromInternalValue(s.column_int64(5)); i->hidden_ = s.column_int(6) != 0; i->favicon_id_ = s.column_int64(7); - i->star_id_ = s.column_int64(8); } bool URLDatabase::GetURLRow(URLID url_id, URLRow* info) { @@ -115,7 +114,7 @@ bool URLDatabase::UpdateURLRow(URLID url_id, const history::URLRow& info) { SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(), "UPDATE urls SET title=?,visit_count=?,typed_count=?,last_visit_time=?," - "hidden=?,starred_id=?,favicon_id=?" + "hidden=?,favicon_id=?" "WHERE id=?"); if (!statement.is_valid()) return false; @@ -125,9 +124,8 @@ bool URLDatabase::UpdateURLRow(URLID url_id, statement->bind_int(2, info.typed_count()); statement->bind_int64(3, info.last_visit().ToInternalValue()); statement->bind_int(4, info.hidden() ? 1 : 0); - statement->bind_int64(5, info.star_id()); - statement->bind_int64(6, info.favicon_id()); - statement->bind_int64(7, url_id); + statement->bind_int64(5, info.favicon_id()); + statement->bind_int64(6, url_id); return statement->step() == SQLITE_DONE; } @@ -139,8 +137,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,starred_id,favicon_id)"\ - "VALUES(?,?,?,?,?,?,?,?)" + "last_visit_time,hidden,favicon_id)"\ + "VALUES(?,?,?,?,?,?,?)" const char* statement_name; const char* statement_sql; if (is_temporary) { @@ -163,8 +161,7 @@ URLID URLDatabase::AddURLInternal(const history::URLRow& info, statement->bind_int(3, info.typed_count()); statement->bind_int64(4, info.last_visit().ToInternalValue()); statement->bind_int(5, info.hidden() ? 1 : 0); - statement->bind_int64(6, info.star_id()); - statement->bind_int64(7, info.favicon_id()); + statement->bind_int64(6, info.favicon_id()); if (statement->step() != SQLITE_DONE) return 0; @@ -250,21 +247,15 @@ bool URLDatabase::IsFavIconUsed(FavIconID favicon_id) { } void URLDatabase::AutocompleteForPrefix(const std::wstring& prefix, - size_t max_results, - std::vector<history::URLRow>* results) { + size_t max_results, + std::vector<history::URLRow>* results) { + // TODO(sky): this query should order by starred as the second order by + // clause. results->clear(); - - // NOTE: Sorting by "starred_id == 0" is subtle. First we do the comparison, - // and, according to the SQLite docs, get a numeric result (all binary - // operators except "||" result in a numeric value), which is either 1 or 0 - // (implied by documentation showing the results of various comparison - // operations to always be 1 or 0). Now we sort ascending, meaning all 0s go - // first -- so, all URLs where "starred_id == 0" is 0, i.e. all starred URLs. SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(), "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls " "WHERE url >= ? AND url < ? AND hidden = 0 " - "ORDER BY typed_count DESC, starred_id == 0, visit_count DESC, " - "last_visit_time DESC " + "ORDER BY typed_count DESC, visit_count DESC, last_visit_time DESC " "LIMIT ?"); if (!statement.is_valid()) return; @@ -443,6 +434,36 @@ bool URLDatabase::MigrateFromVersion11ToVersion12() { return true; } +bool URLDatabase::DropStarredIDFromURLs() { + if (!DoesSqliteColumnExist(GetDB(), "urls", "starred_id", NULL)) + return true; // urls is already updated, no need to continue. + + // Create a temporary table to contain the new URLs table. + if (!CreateTemporaryURLTable()) { + NOTREACHED(); + return false; + } + + // Copy the contents. + const char* insert_statement = + "INSERT INTO temp_urls (id, url, title, visit_count, typed_count, " + "last_visit_time, hidden, favicon_id) " + "SELECT id, url, title, visit_count, typed_count, last_visit_time, " + "hidden, favicon_id FROM urls"; + if (sqlite3_exec(GetDB(), insert_statement, NULL, NULL, NULL) != SQLITE_OK) { + NOTREACHED(); + return false; + } + + // Rename/commit the tmp table. + CommitTemporaryURLTable(); + + // This isn't created by CommitTemporaryURLTable. + CreateSupplimentaryURLIndices(); + + return true; +} + bool URLDatabase::CreateURLTable(bool is_temporary) { const char* name = is_temporary ? "temp_urls" : "urls"; if (DoesSqliteTableExist(GetDB(), name)) @@ -459,8 +480,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," - "starred_id INTEGER DEFAULT 0 NOT NULL)"); + "favicon_id INTEGER DEFAULT 0 NOT NULL)"); return sqlite3_exec(GetDB(), sql.c_str(), NULL, NULL, NULL) == SQLITE_OK; } @@ -476,10 +496,6 @@ void URLDatabase::CreateSupplimentaryURLIndices() { // Add a favicon index. This is useful when we delete urls. sqlite3_exec(GetDB(), "CREATE INDEX urls_favicon_id_INDEX ON urls (favicon_id)", NULL, NULL, NULL); - - // Index on starred_id. - sqlite3_exec(GetDB(), "CREATE INDEX urls_starred_id_INDEX ON urls " - "(starred_id)", NULL, NULL, NULL); } } // namespace history diff --git a/chrome/browser/history/url_database.h b/chrome/browser/history/url_database.h index 300c05b..f27c4b9 100644 --- a/chrome/browser/history/url_database.h +++ b/chrome/browser/history/url_database.h @@ -247,6 +247,8 @@ class URLDatabase { int max_count, std::vector<KeywordSearchTermVisit>* matches); + // Migration ----------------------------------------------------------------- + // Do to a bug we were setting the favicon of about:blank. This forces // about:blank to have no icon or title. Returns true on success, false if // the favicon couldn't be updated. @@ -263,6 +265,11 @@ class URLDatabase { // fields following kURLRowFields. static const int kNumURLRowFields; + // Drops the starred_id column from urls, returning true on success. This does + // nothing (and returns true) if the urls doesn't contain the starred_id + // column. + bool DropStarredIDFromURLs(); + // Initialization functions. The indexing functions are separate from the // table creation functions so the in-memory database and the temporary tables // used when clearing history can populate the table and then create the @@ -319,7 +326,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.starred_id " + "urls.last_visit_time, urls.hidden, urls.favicon_id " } // history diff --git a/chrome/browser/history/url_database_unittest.cc b/chrome/browser/history/url_database_unittest.cc index 7f2bdae..4983a5d 100644 --- a/chrome/browser/history/url_database_unittest.cc +++ b/chrome/browser/history/url_database_unittest.cc @@ -48,8 +48,7 @@ bool IsURLRowEqual(const URLRow& a, a.visit_count() == b.visit_count() && a.typed_count() == b.typed_count() && a.last_visit() - b.last_visit() <= TimeDelta::FromSeconds(1) && - a.hidden() == b.hidden() && - a.starred() == b.starred(); + a.hidden() == b.hidden(); } class URLDatabaseTest : public testing::Test, |