1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/starred_url_database.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/sql/statement.h" 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h" 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/json/json_writer.h" 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/logging.h" 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_vector.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/stl_util-inl.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/values.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_codec.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_model.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/query_parser.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The following table is used to store star (aka bookmark) information. This 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// class derives from URLDatabase, which has its own schema. 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// starred 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// id Unique identifier (primary key) for the entry. 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// type Type of entry, if 0 this corresponds to a URL, 1 for 27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// a system folder, 2 for a user created folder, 3 for 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// other. 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// url_id ID of the url, only valid if type == 0 30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// group_id ID of the folder, only valid if type != 0. This id comes 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// from the UI and is NOT the same as id. 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// title User assigned title. 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// date_added Creation date. 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// visual_order Visual order within parent. 35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// parent_id Folder ID of the parent this entry is contained in, if 0 36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// entry is not in a folder. 37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// date_modified Time the folder was last modified. See comments in 38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// StarredEntry::date_folder_modified 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// NOTE: group_id and parent_id come from the UI, id is assigned by the 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// db. 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace history { 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Fields used by FillInStarredEntry. 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define STAR_FIELDS \ 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch " starred.id, starred.type, starred.title, starred.date_added, " \ 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "starred.visual_order, starred.parent_id, urls.url, urls.id, " \ 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "starred.group_id, starred.date_modified " 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kHistoryStarFields[] = STAR_FIELDS; 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid FillInStarredEntry(const sql::Statement& s, StarredEntry* entry) { 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(entry); 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->id = s.ColumnInt64(0); 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (s.ColumnInt(1)) { 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 0: 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->type = history::StarredEntry::URL; 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->url = GURL(s.ColumnString(6)); 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 1: 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->type = history::StarredEntry::BOOKMARK_BAR; 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 2: 65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry->type = history::StarredEntry::USER_FOLDER; 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 3: 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->type = history::StarredEntry::OTHER; 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->title = s.ColumnString16(2); 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->date_added = base::Time::FromInternalValue(s.ColumnInt64(3)); 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->visual_order = s.ColumnInt(4); 77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry->parent_folder_id = s.ColumnInt64(5); 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->url_id = s.ColumnInt64(7); 79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry->folder_id = s.ColumnInt64(8); 80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry->date_folder_modified = base::Time::FromInternalValue(s.ColumnInt64(9)); 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochStarredURLDatabase::StarredURLDatabase() { 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochStarredURLDatabase::~StarredURLDatabase() { 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StarredURLDatabase::MigrateBookmarksToFile(const FilePath& path) { 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetDB().DoesTableExist("starred")) 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (EnsureStarredIntegrity() && !MigrateBookmarksToFileImpl(path)) { 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << " Bookmarks migration failed"; 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetDB().Execute("DROP TABLE starred")) { 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Unable to drop starred table"; 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StarredURLDatabase::GetAllStarredEntries( 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<StarredEntry>* entries) { 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(entries); 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string sql = "SELECT "; 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql.append(kHistoryStarFields); 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql.append("FROM starred LEFT JOIN urls ON starred.url_id = urls.id "); 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql += "ORDER BY parent_id, visual_order"; 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement s(GetDB().GetUniqueStatement(sql.c_str())); 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!s) { 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Statement prepare failed"; 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::StarredEntry entry; 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (s.Step()) { 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FillInStarredEntry(s, &entry); 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Reset the url for non-url types. This is needed as we're reusing the 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // same entry for the loop. 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (entry.type != history::StarredEntry::URL) 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.url = GURL(); 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entries->push_back(entry); 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StarredURLDatabase::EnsureStarredIntegrity() { 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<StarredNode*> roots; 135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::set<StarID> folders_with_duplicate_ids; 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<StarredNode*> unparented_urls; 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<StarID> empty_url_ids; 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!BuildStarNodes(&roots, &folders_with_duplicate_ids, &unparented_urls, 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &empty_url_ids)) { 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool valid = EnsureStarredIntegrityImpl(&roots, folders_with_duplicate_ids, 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &unparented_urls, empty_url_ids); 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteElements(&roots); 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch STLDeleteElements(&unparented_urls); 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return valid; 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StarredURLDatabase::UpdateStarredEntryRow(StarID star_id, 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const string16& title, 154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen UIStarID parent_folder_id, 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int visual_order, 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::Time date_modified) { 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(star_id && visual_order >= 0); 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "UPDATE starred SET title=?, parent_id=?, visual_order=?, " 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "date_modified=? WHERE id=?")); 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindString16(0, title); 165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen statement.BindInt64(1, parent_folder_id); 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(2, visual_order); 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(3, date_modified.ToInternalValue()); 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(4, star_id); 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return statement.Run(); 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool StarredURLDatabase::AdjustStarredVisualOrder(UIStarID parent_folder_id, 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int start_visual_order, 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int delta) { 175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(parent_folder_id && start_visual_order >= 0); 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "UPDATE starred SET visual_order=visual_order+? " 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "WHERE parent_id=? AND visual_order >= ?")); 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(0, delta); 183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen statement.BindInt64(1, parent_folder_id); 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(2, start_visual_order); 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return statement.Run(); 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochStarID StarredURLDatabase::CreateStarredEntryRow(URLID url_id, 189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen UIStarID folder_id, 190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen UIStarID parent_folder_id, 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const string16& title, 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const base::Time& date_added, 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int visual_order, 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredEntry::Type type) { 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(visual_order >= 0 && 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (type != history::StarredEntry::URL || url_id)); 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "INSERT INTO starred " 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "(type, url_id, group_id, title, date_added, visual_order, parent_id, " 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "date_modified) VALUES (?,?,?,?,?,?,?,?)")); 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (type) { 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case history::StarredEntry::URL: 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(0, 0); 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case history::StarredEntry::BOOKMARK_BAR: 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(0, 1); 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case history::StarredEntry::USER_FOLDER: 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(0, 2); 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case history::StarredEntry::OTHER: 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(0, 3); 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(1, url_id); 221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen statement.BindInt64(2, folder_id); 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindString16(3, title); 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(4, date_added.ToInternalValue()); 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(5, visual_order); 225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen statement.BindInt64(6, parent_folder_id); 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(7, base::Time().ToInternalValue()); 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (statement.Run()) 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return GetDB().GetLastInsertRowId(); 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StarredURLDatabase::DeleteStarredEntryRow(StarID star_id) { 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "DELETE FROM starred WHERE id=?")); 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, star_id); 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return statement.Run(); 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StarredURLDatabase::GetStarredEntry(StarID star_id, StarredEntry* entry) { 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(entry && star_id); 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT" STAR_FIELDS "FROM starred LEFT JOIN urls ON " 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "starred.url_id = urls.id WHERE starred.id=?")); 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, star_id); 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (statement.Step()) { 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FillInStarredEntry(statement, entry); 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochStarID StarredURLDatabase::CreateStarredEntry(StarredEntry* entry) { 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->id = 0; // Ensure 0 for failure case. 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Adjust the visual order when we are inserting it somewhere. 263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (entry->parent_folder_id) 264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen AdjustStarredVisualOrder(entry->parent_folder_id, entry->visual_order, 1); 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Insert the new entry. 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (entry->type) { 268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case StarredEntry::USER_FOLDER: 269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry->id = CreateStarredEntryRow(0, entry->folder_id, 270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry->parent_folder_id, entry->title, entry->date_added, 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->visual_order, entry->type); 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case StarredEntry::URL: { 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the row for this URL. 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch URLRow url_row; 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetRowForURL(entry->url, &url_row)) { 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a new URL row for this entry. 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_row = URLRow(entry->url); 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_row.set_title(entry->title); 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_row.set_hidden(false); 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->url_id = this->AddURL(url_row); 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->url_id = url_row.id(); // The caller doesn't have to set this. 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create the star entry referring to the URL row. 288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry->id = CreateStarredEntryRow(entry->url_id, entry->folder_id, 289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry->parent_folder_id, entry->title, entry->date_added, 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->visual_order, entry->type); 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update the URL row to refer to this new starred entry. 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateURLRow(entry->url_id, url_row); 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return entry->id; 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenUIStarID StarredURLDatabase::GetMaxFolderID() { 305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen sql::Statement max_folder_id_statement(GetDB().GetUniqueStatement( 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT MAX(group_id) FROM starred")); 307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!max_folder_id_statement) { 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << GetDB().GetErrorMessage(); 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!max_folder_id_statement.Step()) { 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << GetDB().GetErrorMessage(); 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return max_folder_id_statement.ColumnInt64(0); 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StarredURLDatabase::BuildStarNodes( 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<StarredURLDatabase::StarredNode*>* roots, 320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::set<StarID>* folders_with_duplicate_ids, 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<StarredNode*>* unparented_urls, 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<StarID>* empty_url_ids) { 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<StarredEntry> star_entries; 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetAllStarredEntries(&star_entries)) { 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Unable to get bookmarks from database"; 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Create the folder/bookmark-bar/other nodes. 330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::map<UIStarID, StarredNode*> folder_id_to_node_map; 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < star_entries.size(); ++i) { 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (star_entries[i].type != StarredEntry::URL) { 333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (folder_id_to_node_map.find(star_entries[i].folder_id) != 334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folder_id_to_node_map.end()) { 335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // There's already a folder with this ID. 336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folders_with_duplicate_ids->insert(star_entries[i].id); 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create the node and update the mapping. 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredNode* node = new StarredNode(star_entries[i]); 340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folder_id_to_node_map[star_entries[i].folder_id] = node; 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Iterate again, creating nodes for URL bookmarks and parenting all 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // bookmarks/folders. In addition populate the empty_url_ids with all entries 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // of type URL that have an empty URL. 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::map<StarID, StarredNode*> id_to_node_map; 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < star_entries.size(); ++i) { 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (star_entries[i].type == StarredEntry::URL) { 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (star_entries[i].url.is_empty()) { 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch empty_url_ids->insert(star_entries[i].id); 353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else if (!star_entries[i].parent_folder_id || 354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folder_id_to_node_map.find(star_entries[i].parent_folder_id) == 355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folder_id_to_node_map.end()) { 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This entry has no parent, or we couldn't find the parent. 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredNode* node = new StarredNode(star_entries[i]); 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unparented_urls->insert(node); 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add the node to its parent. 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredNode* parent = 362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folder_id_to_node_map[star_entries[i].parent_folder_id]; 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredNode* node = new StarredNode(star_entries[i]); 364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen parent->Add(node, parent->child_count()); 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else if (folders_with_duplicate_ids->find(star_entries[i].id) == 367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folders_with_duplicate_ids->end()) { 368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // The entry is a folder (or bookmark bar/other node) that isn't 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // marked as a duplicate. 370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!star_entries[i].parent_folder_id || 371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folder_id_to_node_map.find(star_entries[i].parent_folder_id) == 372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folder_id_to_node_map.end()) { 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Entry has no parent, or the parent wasn't found. 374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen roots->insert(folder_id_to_node_map[star_entries[i].folder_id]); 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Parent the folder node. 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredNode* parent = 378ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folder_id_to_node_map[star_entries[i].parent_folder_id]; 379ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen StarredNode* node = folder_id_to_node_map[star_entries[i].folder_id]; 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!node->HasAncestor(parent) && !parent->HasAncestor(node)) { 381ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen parent->Add(node, parent->child_count()); 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The node has a cycle. Add it to the list of roots so the cycle is 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // broken. 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch roots->insert(node); 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochStarredURLDatabase::StarredNode* StarredURLDatabase::GetNodeByType( 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::set<StarredURLDatabase::StarredNode*>& nodes, 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredEntry::Type type) { 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::set<StarredNode*>::const_iterator i = nodes.begin(); 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != nodes.end(); ++i) { 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((*i)->value.type == type) 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return *i; 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StarredURLDatabase::EnsureVisualOrder( 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredURLDatabase::StarredNode* node) { 406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (int i = 0; i < node->child_count(); ++i) { 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (node->GetChild(i)->value.visual_order != i) { 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredEntry& entry = node->GetChild(i)->value; 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.visual_order = i; 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "Bookmark visual order is wrong"; 411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!UpdateStarredEntryRow(entry.id, entry.title, entry.parent_folder_id, 412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen i, entry.date_folder_modified)) { 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Unable to update visual order"; 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!EnsureVisualOrder(node->GetChild(i))) 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StarredURLDatabase::EnsureStarredIntegrityImpl( 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<StarredURLDatabase::StarredNode*>* roots, 425ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const std::set<StarID>& folders_with_duplicate_ids, 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<StarredNode*>* unparented_urls, 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::set<StarID>& empty_url_ids) { 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure the bookmark bar entry exists. 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredNode* bookmark_node = 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetNodeByType(*roots, StarredEntry::BOOKMARK_BAR); 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!bookmark_node) { 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "No bookmark bar folder in database"; 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If there is no bookmark bar entry in the db things are really 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // screwed. Return false, which won't trigger migration and we'll just 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // drop the tables. 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure the other node exists. 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredNode* other_node = GetNodeByType(*roots, StarredEntry::OTHER); 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!other_node) { 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "No bookmark other folder in database"; 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredEntry entry; 444ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry.folder_id = GetMaxFolderID() + 1; 445ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (entry.folder_id == 1) { 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Unable to get new id for other bookmarks folder"; 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.id = CreateStarredEntryRow( 450ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 0, entry.folder_id, 0, UTF8ToUTF16("other"), base::Time::Now(), 0, 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::StarredEntry::OTHER); 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!entry.id) { 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Unable to create other bookmarks folder"; 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.type = StarredEntry::OTHER; 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StarredNode* other_node = new StarredNode(entry); 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch roots->insert(other_node); 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 461ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // We could potentially make sure only one folder with type 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // BOOKMARK_BAR/OTHER, but history backend enforces this. 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Nuke any entries with no url. 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::set<StarID>::const_iterator i = empty_url_ids.begin(); 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != empty_url_ids.end(); ++i) { 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "Bookmark exists with no URL"; 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!DeleteStarredEntryRow(*i)) { 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Unable to delete bookmark"; 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure the visual order of the nodes is correct. 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::set<StarredNode*>::const_iterator i = roots->begin(); 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != roots->end(); ++i) { 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!EnsureVisualOrder(*i)) 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Move any unparented bookmarks to the bookmark bar. 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<StarredNode*>::iterator i = unparented_urls->begin(); 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (i != unparented_urls->end()) { 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "Bookmark not in a bookmark folder found"; 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!Move(*i, bookmark_node)) 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unparented_urls->erase(i++); 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 492ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Nuke any folders with duplicate ids. A duplicate id means there are two 493ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // folders in the starred table with the same folder_id. We only keep the 494ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // first folder, all other folders are removed. 495ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (std::set<StarID>::const_iterator i = folders_with_duplicate_ids.begin(); 496ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen i != folders_with_duplicate_ids.end(); ++i) { 497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen LOG(WARNING) << "Duplicate folder id in bookmark database"; 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!DeleteStarredEntryRow(*i)) { 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Unable to delete folder"; 500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 504ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Move unparented user folders back to the bookmark bar. 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch { 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<StarredNode*>::iterator i = roots->begin(); 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (i != roots->end()) { 508ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if ((*i)->value.type == StarredEntry::USER_FOLDER) { 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "Bookmark folder not on bookmark bar found"; 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!Move(*i, bookmark_node)) 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch roots->erase(i++); 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++i; 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StarredURLDatabase::Move(StarredNode* source, StarredNode* new_parent) { 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::StarredEntry& entry = source->value; 524ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry.visual_order = new_parent->child_count(); 525ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry.parent_folder_id = new_parent->value.folder_id; 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!UpdateStarredEntryRow(entry.id, entry.title, 527ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry.parent_folder_id, entry.visual_order, 528ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen entry.date_folder_modified)) { 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Unable to move folder"; 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 532ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new_parent->Add(source, new_parent->child_count()); 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool StarredURLDatabase::MigrateBookmarksToFileImpl(const FilePath& path) { 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<history::StarredEntry> entries; 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetAllStarredEntries(&entries)) 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create the bookmark bar and other folder nodes. 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::StarredEntry entry; 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.type = history::StarredEntry::BOOKMARK_BAR; 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode bookmark_bar_node(0, GURL()); 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bookmark_bar_node.Reset(entry); 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry.type = history::StarredEntry::OTHER; 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode other_node(0, GURL()); 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch other_node.Reset(entry); 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 550ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::map<history::UIStarID, history::StarID> folder_id_to_id_map; 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch typedef std::map<history::StarID, BookmarkNode*> IDToNodeMap; 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IDToNodeMap id_to_node_map; 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 554ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen history::UIStarID other_folder_folder_id = 0; 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::StarID other_folder_id = 0; 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 557ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Iterate through the entries building a mapping between folder_id and id. 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::vector<history::StarredEntry>::const_iterator i = entries.begin(); 559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != entries.end(); ++i) { 560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (i->type != history::StarredEntry::URL) { 561ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folder_id_to_id_map[i->folder_id] = i->id; 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (i->type == history::StarredEntry::OTHER) { 563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch other_folder_id = i->id; 564ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen other_folder_folder_id = i->folder_id; 565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Register the bookmark bar and other folder nodes in the maps. 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id_to_node_map[HistoryService::kBookmarkBarID] = &bookmark_bar_node; 571ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folder_id_to_id_map[HistoryService::kBookmarkBarID] = 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HistoryService::kBookmarkBarID; 573ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (other_folder_folder_id) { 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id_to_node_map[other_folder_id] = &other_node; 575ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folder_id_to_id_map[other_folder_folder_id] = other_folder_id; 576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Iterate through the entries again creating the nodes. 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::vector<history::StarredEntry>::iterator i = entries.begin(); 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i != entries.end(); ++i) { 581ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!i->parent_folder_id) { 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(i->type == history::StarredEntry::BOOKMARK_BAR || 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i->type == history::StarredEntry::OTHER); 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Only entries with no parent should be the bookmark bar and other 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // bookmarks folders. 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* node = id_to_node_map[i->id]; 590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!node) { 591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Creating a node results in creating the parent. As such, it is 592ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // possible for the node representing a folder to have been created before 593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // encountering the details. 594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The created nodes are owned by the root node. 596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch node = new BookmarkNode(0, i->url); 597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id_to_node_map[i->id] = node; 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch node->Reset(*i); 600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 601ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(folder_id_to_id_map.find(i->parent_folder_id) != 602ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen folder_id_to_id_map.end()); 603ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen history::StarID parent_id = folder_id_to_id_map[i->parent_folder_id]; 604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkNode* parent = id_to_node_map[parent_id]; 605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!parent) { 606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Haven't encountered the parent yet, create it now. 607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parent = new BookmarkNode(0, GURL()); 608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch id_to_node_map[parent_id] = parent; 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add the node to its parent. |entries| is ordered by parent then 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // visual order so that we know we maintain visual order by always adding 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to the end. 614ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen parent->Add(node, parent->child_count()); 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Save to file. 618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BookmarkCodec encoder; 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Value> encoded_bookmarks( 620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch encoder.Encode(&bookmark_bar_node, &other_node)); 621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string content; 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::JSONWriter::Write(encoded_bookmarks.get(), true, &content); 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return (file_util::WriteFile(path, content.c_str(), 625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(content.length())) != -1); 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace history 629