| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "components/history/core/android/android_cache_database.h" | |
| 6 | |
| 7 #include "base/files/file_util.h" | |
| 8 #include "components/history/core/android/android_time.h" | |
| 9 #include "sql/statement.h" | |
| 10 | |
| 11 using base::Time; | |
| 12 using base::TimeDelta; | |
| 13 | |
| 14 namespace history { | |
| 15 | |
| 16 AndroidCacheDatabase::AndroidCacheDatabase() { | |
| 17 } | |
| 18 | |
| 19 AndroidCacheDatabase::~AndroidCacheDatabase() { | |
| 20 } | |
| 21 | |
| 22 sql::InitStatus AndroidCacheDatabase::InitAndroidCacheDatabase( | |
| 23 const base::FilePath& db_name) { | |
| 24 if (!CreateDatabase(db_name)) | |
| 25 return sql::INIT_FAILURE; | |
| 26 | |
| 27 if (!Attach()) | |
| 28 return sql::INIT_FAILURE; | |
| 29 | |
| 30 if (!CreateBookmarkCacheTable()) | |
| 31 return sql::INIT_FAILURE; | |
| 32 | |
| 33 if (!CreateSearchTermsTable()) | |
| 34 return sql::INIT_FAILURE; | |
| 35 | |
| 36 return sql::INIT_OK; | |
| 37 } | |
| 38 | |
| 39 bool AndroidCacheDatabase::AddBookmarkCacheRow(const Time& created_time, | |
| 40 const Time& last_visit_time, | |
| 41 URLID url_id) { | |
| 42 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
| 43 "INSERT INTO android_cache_db.bookmark_cache (created_time, " | |
| 44 "last_visit_time, url_id) VALUES (?, ?, ?)")); | |
| 45 | |
| 46 statement.BindInt64(0, ToDatabaseTime(created_time)); | |
| 47 statement.BindInt64(1, ToDatabaseTime(last_visit_time)); | |
| 48 statement.BindInt64(2, url_id); | |
| 49 | |
| 50 if (!statement.Run()) { | |
| 51 LOG(ERROR) << GetDB().GetErrorMessage(); | |
| 52 return false; | |
| 53 } | |
| 54 | |
| 55 return true; | |
| 56 } | |
| 57 | |
| 58 bool AndroidCacheDatabase::ClearAllBookmarkCache() { | |
| 59 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
| 60 "DELETE FROM android_cache_db.bookmark_cache")); | |
| 61 if (!statement.Run()) { | |
| 62 LOG(ERROR) << GetDB().GetErrorMessage(); | |
| 63 return false; | |
| 64 } | |
| 65 return true; | |
| 66 } | |
| 67 | |
| 68 bool AndroidCacheDatabase::MarkURLsAsBookmarked( | |
| 69 const std::vector<URLID>& url_ids) { | |
| 70 bool has_id = false; | |
| 71 std::ostringstream oss; | |
| 72 for (std::vector<URLID>::const_iterator i = url_ids.begin(); | |
| 73 i != url_ids.end(); ++i) { | |
| 74 if (has_id) | |
| 75 oss << ", "; | |
| 76 else | |
| 77 has_id = true; | |
| 78 oss << *i; | |
| 79 } | |
| 80 | |
| 81 if (!has_id) | |
| 82 return true; | |
| 83 | |
| 84 std::string sql("UPDATE android_cache_db.bookmark_cache " | |
| 85 "SET bookmark = 1 WHERE url_id in ("); | |
| 86 sql.append(oss.str()); | |
| 87 sql.append(")"); | |
| 88 if (!GetDB().Execute(sql.c_str())) { | |
| 89 LOG(ERROR) << GetDB().GetErrorMessage(); | |
| 90 return false; | |
| 91 } | |
| 92 return true; | |
| 93 } | |
| 94 | |
| 95 bool AndroidCacheDatabase::SetFaviconID(URLID url_id, | |
| 96 favicon_base::FaviconID favicon_id) { | |
| 97 sql::Statement update_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
| 98 "UPDATE android_cache_db.bookmark_cache " | |
| 99 "SET favicon_id = ? WHERE url_id = ? ")); | |
| 100 | |
| 101 update_statement.BindInt64(0, favicon_id); | |
| 102 update_statement.BindInt64(1, url_id); | |
| 103 if (!update_statement.Run()) { | |
| 104 LOG(ERROR) << GetDB().GetErrorMessage(); | |
| 105 return false; | |
| 106 } | |
| 107 return true; | |
| 108 } | |
| 109 | |
| 110 SearchTermID AndroidCacheDatabase::AddSearchTerm( | |
| 111 const base::string16& term, | |
| 112 const base::Time& last_visit_time) { | |
| 113 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
| 114 "INSERT INTO android_cache_db.search_terms (search, " | |
| 115 "date) VALUES (?, ?)")); | |
| 116 | |
| 117 statement.BindString16(0, term); | |
| 118 statement.BindInt64(1, ToDatabaseTime(last_visit_time)); | |
| 119 | |
| 120 if (!statement.Run()) { | |
| 121 LOG(ERROR) << GetDB().GetErrorMessage(); | |
| 122 return 0; | |
| 123 } | |
| 124 | |
| 125 return GetDB().GetLastInsertRowId(); | |
| 126 } | |
| 127 | |
| 128 bool AndroidCacheDatabase::UpdateSearchTerm(SearchTermID id, | |
| 129 const SearchTermRow& row) { | |
| 130 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
| 131 "UPDATE android_cache_db.search_terms " | |
| 132 "SET search = ?, date = ? " | |
| 133 "WHERE _id = ?" | |
| 134 )); | |
| 135 statement.BindString16(0, row.term); | |
| 136 statement.BindInt64(1, ToDatabaseTime(row.last_visit_time)); | |
| 137 statement.BindInt64(2, id); | |
| 138 | |
| 139 return statement.Run(); | |
| 140 } | |
| 141 | |
| 142 SearchTermID AndroidCacheDatabase::GetSearchTerm(const base::string16& term, | |
| 143 SearchTermRow* row) { | |
| 144 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
| 145 "SELECT _id, search, date " | |
| 146 "FROM android_cache_db.search_terms " | |
| 147 "WHERE search = ?" | |
| 148 )); | |
| 149 if (!statement.is_valid()) { | |
| 150 LOG(ERROR) << GetDB().GetErrorMessage(); | |
| 151 return 0; | |
| 152 } | |
| 153 statement.BindString16(0, term); | |
| 154 if (!statement.Step()) | |
| 155 return 0; | |
| 156 | |
| 157 if (row) { | |
| 158 row->id = statement.ColumnInt64(0); | |
| 159 row->term = statement.ColumnString16(1); | |
| 160 row->last_visit_time = FromDatabaseTime(statement.ColumnInt64(2)); | |
| 161 } | |
| 162 return statement.ColumnInt64(0); | |
| 163 } | |
| 164 | |
| 165 bool AndroidCacheDatabase::DeleteUnusedSearchTerms() { | |
| 166 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
| 167 "DELETE FROM android_cache_db.search_terms " | |
| 168 "WHERE search NOT IN (SELECT DISTINCT term FROM keyword_search_terms)" | |
| 169 )); | |
| 170 if (!statement.is_valid()) | |
| 171 return false; | |
| 172 return statement.Run(); | |
| 173 } | |
| 174 | |
| 175 bool AndroidCacheDatabase::CreateDatabase(const base::FilePath& db_name) { | |
| 176 db_name_ = db_name; | |
| 177 sql::Connection::Delete(db_name_); | |
| 178 | |
| 179 // Using a new connection, otherwise we can not create the database. | |
| 180 sql::Connection connection; | |
| 181 | |
| 182 // The db doesn't store too much data, so we don't need that big a page | |
| 183 // size or cache. | |
| 184 connection.set_page_size(2048); | |
| 185 connection.set_cache_size(32); | |
| 186 | |
| 187 // Run the database in exclusive mode. Nobody else should be accessing the | |
| 188 // database while we're running, and this will give somewhat improved perf. | |
| 189 connection.set_exclusive_locking(); | |
| 190 | |
| 191 if (!connection.Open(db_name_)) { | |
| 192 LOG(ERROR) << connection.GetErrorMessage(); | |
| 193 return false; | |
| 194 } | |
| 195 connection.Close(); | |
| 196 return true; | |
| 197 } | |
| 198 | |
| 199 bool AndroidCacheDatabase::CreateBookmarkCacheTable() { | |
| 200 const char* name = "android_cache_db.bookmark_cache"; | |
| 201 DCHECK(!GetDB().DoesTableExist(name)); | |
| 202 | |
| 203 std::string sql; | |
| 204 sql.append("CREATE TABLE "); | |
| 205 sql.append(name); | |
| 206 sql.append("(" | |
| 207 "id INTEGER PRIMARY KEY," | |
| 208 "created_time INTEGER NOT NULL," // Time in millisecond. | |
| 209 "last_visit_time INTEGER NOT NULL," // Time in millisecond. | |
| 210 "url_id INTEGER NOT NULL," // url id in urls table. | |
| 211 "favicon_id INTEGER DEFAULT NULL," // favicon id. | |
| 212 "bookmark INTEGER DEFAULT 0" // whether is bookmark. | |
| 213 ")"); | |
| 214 if (!GetDB().Execute(sql.c_str())) { | |
| 215 LOG(ERROR) << GetDB().GetErrorMessage(); | |
| 216 return false; | |
| 217 } | |
| 218 | |
| 219 sql.assign("CREATE INDEX "); | |
| 220 sql.append("android_cache_db.bookmark_cache_url_id_idx ON " | |
| 221 "bookmark_cache(url_id)"); | |
| 222 if (!GetDB().Execute(sql.c_str())) { | |
| 223 LOG(ERROR) << GetDB().GetErrorMessage(); | |
| 224 return false; | |
| 225 } | |
| 226 return true; | |
| 227 } | |
| 228 | |
| 229 bool AndroidCacheDatabase::CreateSearchTermsTable() { | |
| 230 const char* name = "android_cache_db.search_terms"; | |
| 231 | |
| 232 // The table's column name matchs Android's definition. | |
| 233 std::string sql; | |
| 234 sql.append("CREATE TABLE "); | |
| 235 sql.append(name); | |
| 236 sql.append("(" | |
| 237 "_id INTEGER PRIMARY KEY," | |
| 238 "date INTEGER NOT NULL," // last visit time in millisecond. | |
| 239 "search LONGVARCHAR NOT NULL)"); // The actual search term. | |
| 240 | |
| 241 if (!GetDB().Execute(sql.c_str())) { | |
| 242 LOG(ERROR) << GetDB().GetErrorMessage(); | |
| 243 return false; | |
| 244 } | |
| 245 | |
| 246 sql.assign("CREATE INDEX " | |
| 247 "android_cache_db.search_terms_term_idx ON " | |
| 248 "search_terms(search)"); | |
| 249 if (!GetDB().Execute(sql.c_str())) { | |
| 250 LOG(ERROR) << GetDB().GetErrorMessage(); | |
| 251 return false; | |
| 252 } | |
| 253 return true; | |
| 254 } | |
| 255 | |
| 256 bool AndroidCacheDatabase::Attach() { | |
| 257 // Commit all open transactions to make attach succeed. | |
| 258 int transaction_nesting = GetDB().transaction_nesting(); | |
| 259 int count = transaction_nesting; | |
| 260 while (count--) | |
| 261 GetDB().CommitTransaction(); | |
| 262 | |
| 263 bool result = DoAttach(); | |
| 264 | |
| 265 // No matter whether the attach succeeded or not, we need to create the | |
| 266 // transaction stack again. | |
| 267 count = transaction_nesting; | |
| 268 while (count--) | |
| 269 GetDB().BeginTransaction(); | |
| 270 return result; | |
| 271 } | |
| 272 | |
| 273 bool AndroidCacheDatabase::DoAttach() { | |
| 274 std::string sql("ATTACH ? AS android_cache_db"); | |
| 275 sql::Statement attach(GetDB().GetUniqueStatement(sql.c_str())); | |
| 276 if (!attach.is_valid()) | |
| 277 // Keep the transaction open, even though we failed. | |
| 278 return false; | |
| 279 | |
| 280 attach.BindString(0, db_name_.value()); | |
| 281 if (!attach.Run()) { | |
| 282 LOG(ERROR) << GetDB().GetErrorMessage(); | |
| 283 return false; | |
| 284 } | |
| 285 | |
| 286 return true; | |
| 287 } | |
| 288 | |
| 289 } // namespace history | |
| OLD | NEW |