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/guid.h"
11 #include "base/logging.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/time/time.h"
14 #include "sql/statement.h"
15 #include "sql/transaction.h"
19 void BindShortcutToStatement(
20 const history::ShortcutsBackend::Shortcut& shortcut,
22 DCHECK(base::IsValidGUID(shortcut.id));
23 s->BindString(0, shortcut.id);
24 s->BindString16(1, shortcut.text);
25 s->BindString16(2, shortcut.match_core.fill_into_edit);
26 s->BindString(3, shortcut.match_core.destination_url.spec());
27 s->BindString16(4, shortcut.match_core.contents);
28 s->BindString(5, AutocompleteMatch::ClassificationsToString(
29 shortcut.match_core.contents_class));
30 s->BindString16(6, shortcut.match_core.description);
31 s->BindString(7, AutocompleteMatch::ClassificationsToString(
32 shortcut.match_core.description_class));
33 s->BindInt(8, shortcut.match_core.transition);
34 s->BindInt(9, shortcut.match_core.type);
35 s->BindString16(10, shortcut.match_core.keyword);
36 s->BindInt64(11, shortcut.last_access_time.ToInternalValue());
37 s->BindInt(12, shortcut.number_of_hits);
40 bool DeleteShortcut(const char* field_name,
41 const std::string& id,
42 sql::Connection& db) {
43 sql::Statement s(db.GetUniqueStatement(
44 base::StringPrintf("DELETE FROM omni_box_shortcuts WHERE %s = ?",
45 field_name).c_str()));
54 ShortcutsDatabase::ShortcutsDatabase(const base::FilePath& database_path)
55 : database_path_(database_path) {
58 bool ShortcutsDatabase::Init() {
59 db_.set_histogram_tag("Shortcuts");
61 // Set the database page size to something a little larger to give us
62 // better performance (we're typically seek rather than bandwidth limited).
63 // This only has an effect before any tables have been created, otherwise
64 // this is a NOP. Must be a power of 2 and a max of 8192.
65 db_.set_page_size(4096);
67 // Run the database in exclusive mode. Nobody else should be accessing the
68 // database while we're running, and this will give somewhat improved perf.
69 db_.set_exclusive_locking();
71 // Attach the database to our index file.
72 return db_.Open(database_path_) && EnsureTable();
75 bool ShortcutsDatabase::AddShortcut(
76 const ShortcutsBackend::Shortcut& shortcut) {
77 sql::Statement s(db_.GetCachedStatement(
79 "INSERT INTO omni_box_shortcuts (id, text, fill_into_edit, url, "
80 "contents, contents_class, description, description_class, "
81 "transition, type, keyword, last_access_time, number_of_hits) "
82 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"));
83 BindShortcutToStatement(shortcut, &s);
87 bool ShortcutsDatabase::UpdateShortcut(
88 const ShortcutsBackend::Shortcut& shortcut) {
89 sql::Statement s(db_.GetCachedStatement(
91 "UPDATE omni_box_shortcuts SET id=?, text=?, fill_into_edit=?, url=?, "
92 "contents=?, contents_class=?, description=?, description_class=?, "
93 "transition=?, type=?, keyword=?, last_access_time=?, "
94 "number_of_hits=? WHERE id=?"));
95 BindShortcutToStatement(shortcut, &s);
96 s.BindString(13, shortcut.id);
100 bool ShortcutsDatabase::DeleteShortcutsWithIds(
101 const std::vector<std::string>& shortcut_ids) {
103 db_.BeginTransaction();
104 for (std::vector<std::string>::const_iterator it(shortcut_ids.begin());
105 it != shortcut_ids.end(); ++it) {
106 success &= DeleteShortcut("id", *it, db_);
108 db_.CommitTransaction();
112 bool ShortcutsDatabase::DeleteShortcutsWithUrl(
113 const std::string& shortcut_url_spec) {
114 return DeleteShortcut("url", shortcut_url_spec, db_);
117 bool ShortcutsDatabase::DeleteAllShortcuts() {
118 if (!db_.Execute("DELETE FROM omni_box_shortcuts"))
121 ignore_result(db_.Execute("VACUUM"));
125 void ShortcutsDatabase::LoadShortcuts(GuidToShortcutMap* shortcuts) {
127 sql::Statement s(db_.GetCachedStatement(
129 "SELECT id, text, fill_into_edit, url, contents, contents_class, "
130 "description, description_class, transition, type, keyword, "
131 "last_access_time, number_of_hits FROM omni_box_shortcuts"));
135 shortcuts->insert(std::make_pair(
137 ShortcutsBackend::Shortcut(
138 s.ColumnString(0), // id
139 s.ColumnString16(1), // text
140 ShortcutsBackend::Shortcut::MatchCore(
141 s.ColumnString16(2), // fill_into_edit
142 GURL(s.ColumnString(3)), // destination_url
143 s.ColumnString16(4), // contents
144 AutocompleteMatch::ClassificationsFromString(s.ColumnString(5)),
146 s.ColumnString16(6), // description
147 AutocompleteMatch::ClassificationsFromString(s.ColumnString(7)),
149 static_cast<content::PageTransition>(s.ColumnInt(8)),
151 static_cast<AutocompleteMatch::Type>(s.ColumnInt(9)),
153 s.ColumnString16(10)), // keyword
154 base::Time::FromInternalValue(s.ColumnInt64(11)),
156 s.ColumnInt(12)))); // number_of_hits
160 ShortcutsDatabase::~ShortcutsDatabase() {
163 bool ShortcutsDatabase::EnsureTable() {
164 if (!db_.DoesTableExist("omni_box_shortcuts")) {
166 "CREATE TABLE omni_box_shortcuts (id VARCHAR PRIMARY KEY, "
167 "text VARCHAR, fill_into_edit VARCHAR, url VARCHAR, "
168 "contents VARCHAR, contents_class VARCHAR, description VARCHAR, "
169 "description_class VARCHAR, transition INTEGER, type INTEGER, "
170 "keyword VARCHAR, last_access_time INTEGER, "
171 "number_of_hits INTEGER)");
174 // The first version of the shortcuts table lacked the fill_into_edit,
175 // transition, type, and keyword columns.
176 if (!db_.DoesColumnExist("omni_box_shortcuts", "fill_into_edit")) {
177 // Perform the upgrade in a transaction to ensure it doesn't happen
179 sql::Transaction transaction(&db_);
182 db_.Execute("ALTER TABLE omni_box_shortcuts "
183 "ADD COLUMN fill_into_edit VARCHAR") &&
184 db_.Execute("UPDATE omni_box_shortcuts SET fill_into_edit = url") &&
185 db_.Execute("ALTER TABLE omni_box_shortcuts "
186 "ADD COLUMN transition INTEGER") &&
187 db_.Execute(base::StringPrintf(
188 "UPDATE omni_box_shortcuts SET transition = %d",
189 static_cast<int>(content::PAGE_TRANSITION_TYPED)).c_str()) &&
190 db_.Execute("ALTER TABLE omni_box_shortcuts ADD COLUMN type INTEGER") &&
191 db_.Execute(base::StringPrintf(
192 "UPDATE omni_box_shortcuts SET type = %d",
193 static_cast<int>(AutocompleteMatchType::HISTORY_TITLE)).c_str()) &&
194 db_.Execute("ALTER TABLE omni_box_shortcuts "
195 "ADD COLUMN keyword VARCHAR") &&
196 transaction.Commit();
202 } // namespace history