Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / history / android / android_cache_database.cc
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 "chrome/browser/history/android/android_cache_database.h"
6
7 #include "base/file_util.h"
8 #include "chrome/browser/history/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