1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/history/shortcuts_database.h"
10 #include "base/logging.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/time/time.h"
13 #include "chrome/common/autocomplete_match_type.h"
14 #include "content/public/common/page_transition_types.h"
15 #include "sql/statement.h"
16 #include "sql/transaction.h"
19 // Helpers --------------------------------------------------------------------
23 void BindShortcutToStatement(
24 const history::ShortcutsDatabase::Shortcut& shortcut,
26 DCHECK(base::IsValidGUID(shortcut.id));
27 s->BindString(0, shortcut.id);
28 s->BindString16(1, shortcut.text);
29 s->BindString16(2, shortcut.match_core.fill_into_edit);
30 s->BindString(3, shortcut.match_core.destination_url.spec());
31 s->BindString16(4, shortcut.match_core.contents);
32 s->BindString(5, shortcut.match_core.contents_class);
33 s->BindString16(6, shortcut.match_core.description);
34 s->BindString(7, shortcut.match_core.description_class);
35 s->BindInt(8, shortcut.match_core.transition);
36 s->BindInt(9, shortcut.match_core.type);
37 s->BindString16(10, shortcut.match_core.keyword);
38 s->BindInt64(11, shortcut.last_access_time.ToInternalValue());
39 s->BindInt(12, shortcut.number_of_hits);
42 bool DeleteShortcut(const char* field_name,
43 const std::string& id,
44 sql::Connection& db) {
45 sql::Statement s(db.GetUniqueStatement(
46 base::StringPrintf("DELETE FROM omni_box_shortcuts WHERE %s = ?",
47 field_name).c_str()));
57 // ShortcutsDatabase::Shortcut::MatchCore -------------------------------------
59 ShortcutsDatabase::Shortcut::MatchCore::MatchCore(
60 const base::string16& fill_into_edit,
61 const GURL& destination_url,
62 const base::string16& contents,
63 const std::string& contents_class,
64 const base::string16& description,
65 const std::string& description_class,
68 const base::string16& keyword)
69 : fill_into_edit(fill_into_edit),
70 destination_url(destination_url),
72 contents_class(contents_class),
73 description(description),
74 description_class(description_class),
75 transition(transition),
80 ShortcutsDatabase::Shortcut::MatchCore::~MatchCore() {
83 // ShortcutsDatabase::Shortcut ------------------------------------------------
85 ShortcutsDatabase::Shortcut::Shortcut(
86 const std::string& id,
87 const base::string16& text,
88 const MatchCore& match_core,
89 const base::Time& last_access_time,
93 match_core(match_core),
94 last_access_time(last_access_time),
95 number_of_hits(number_of_hits) {
98 ShortcutsDatabase::Shortcut::Shortcut()
99 : match_core(base::string16(), GURL(), base::string16(), std::string(),
100 base::string16(), std::string(), 0, 0, base::string16()),
101 last_access_time(base::Time::Now()),
105 ShortcutsDatabase::Shortcut::~Shortcut() {
109 // ShortcutsDatabase ----------------------------------------------------------
111 ShortcutsDatabase::ShortcutsDatabase(const base::FilePath& database_path)
112 : database_path_(database_path) {
115 bool ShortcutsDatabase::Init() {
116 db_.set_histogram_tag("Shortcuts");
118 // Set the database page size to something a little larger to give us
119 // better performance (we're typically seek rather than bandwidth limited).
120 // This only has an effect before any tables have been created, otherwise
121 // this is a NOP. Must be a power of 2 and a max of 8192.
122 db_.set_page_size(4096);
124 // Run the database in exclusive mode. Nobody else should be accessing the
125 // database while we're running, and this will give somewhat improved perf.
126 db_.set_exclusive_locking();
128 // Attach the database to our index file.
129 return db_.Open(database_path_) && EnsureTable();
132 bool ShortcutsDatabase::AddShortcut(const Shortcut& shortcut) {
133 sql::Statement s(db_.GetCachedStatement(
135 "INSERT INTO omni_box_shortcuts (id, text, fill_into_edit, url, "
136 "contents, contents_class, description, description_class, "
137 "transition, type, keyword, last_access_time, number_of_hits) "
138 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"));
139 BindShortcutToStatement(shortcut, &s);
143 bool ShortcutsDatabase::UpdateShortcut(const Shortcut& shortcut) {
144 sql::Statement s(db_.GetCachedStatement(
146 "UPDATE omni_box_shortcuts SET id=?, text=?, fill_into_edit=?, url=?, "
147 "contents=?, contents_class=?, description=?, description_class=?, "
148 "transition=?, type=?, keyword=?, last_access_time=?, "
149 "number_of_hits=? WHERE id=?"));
150 BindShortcutToStatement(shortcut, &s);
151 s.BindString(13, shortcut.id);
155 bool ShortcutsDatabase::DeleteShortcutsWithIDs(
156 const ShortcutIDs& shortcut_ids) {
158 db_.BeginTransaction();
159 for (ShortcutIDs::const_iterator it(shortcut_ids.begin());
160 it != shortcut_ids.end(); ++it) {
161 success &= DeleteShortcut("id", *it, db_);
163 db_.CommitTransaction();
167 bool ShortcutsDatabase::DeleteShortcutsWithURL(
168 const std::string& shortcut_url_spec) {
169 return DeleteShortcut("url", shortcut_url_spec, db_);
172 bool ShortcutsDatabase::DeleteAllShortcuts() {
173 if (!db_.Execute("DELETE FROM omni_box_shortcuts"))
176 ignore_result(db_.Execute("VACUUM"));
180 void ShortcutsDatabase::LoadShortcuts(GuidToShortcutMap* shortcuts) {
182 sql::Statement s(db_.GetCachedStatement(
184 "SELECT id, text, fill_into_edit, url, contents, contents_class, "
185 "description, description_class, transition, type, keyword, "
186 "last_access_time, number_of_hits FROM omni_box_shortcuts"));
190 shortcuts->insert(std::make_pair(
193 s.ColumnString(0), // id
194 s.ColumnString16(1), // text
196 s.ColumnString16(2), // fill_into_edit
197 GURL(s.ColumnString(3)), // destination_url
198 s.ColumnString16(4), // contents
199 s.ColumnString(5), // contents_class
200 s.ColumnString16(6), // description
201 s.ColumnString(7), // description_class
202 s.ColumnInt(8), // transition
203 s.ColumnInt(9), // type
204 s.ColumnString16(10)), // keyword
205 base::Time::FromInternalValue(s.ColumnInt64(11)),
207 s.ColumnInt(12)))); // number_of_hits
211 ShortcutsDatabase::~ShortcutsDatabase() {
214 bool ShortcutsDatabase::EnsureTable() {
215 if (!db_.DoesTableExist("omni_box_shortcuts")) {
217 "CREATE TABLE omni_box_shortcuts (id VARCHAR PRIMARY KEY, "
218 "text VARCHAR, fill_into_edit VARCHAR, url VARCHAR, "
219 "contents VARCHAR, contents_class VARCHAR, description VARCHAR, "
220 "description_class VARCHAR, transition INTEGER, type INTEGER, "
221 "keyword VARCHAR, last_access_time INTEGER, "
222 "number_of_hits INTEGER)");
225 // The first version of the shortcuts table lacked the fill_into_edit,
226 // transition, type, and keyword columns.
227 if (!db_.DoesColumnExist("omni_box_shortcuts", "fill_into_edit")) {
228 // Perform the upgrade in a transaction to ensure it doesn't happen
230 sql::Transaction transaction(&db_);
233 db_.Execute("ALTER TABLE omni_box_shortcuts "
234 "ADD COLUMN fill_into_edit VARCHAR") &&
235 db_.Execute("UPDATE omni_box_shortcuts SET fill_into_edit = url") &&
236 db_.Execute("ALTER TABLE omni_box_shortcuts "
237 "ADD COLUMN transition INTEGER") &&
238 db_.Execute(base::StringPrintf(
239 "UPDATE omni_box_shortcuts SET transition = %d",
240 static_cast<int>(content::PAGE_TRANSITION_TYPED)).c_str()) &&
241 db_.Execute("ALTER TABLE omni_box_shortcuts ADD COLUMN type INTEGER") &&
242 db_.Execute(base::StringPrintf(
243 "UPDATE omni_box_shortcuts SET type = %d",
244 static_cast<int>(AutocompleteMatchType::HISTORY_TITLE)).c_str()) &&
245 db_.Execute("ALTER TABLE omni_box_shortcuts "
246 "ADD COLUMN keyword VARCHAR") &&
247 transaction.Commit();
253 } // namespace history