Index: chrome/browser/history/android/android_cache_database.cc |
diff --git a/chrome/browser/history/android/android_cache_database.cc b/chrome/browser/history/android/android_cache_database.cc |
new file mode 100755 |
index 0000000000000000000000000000000000000000..77edac13c4ad98f34d4e03e4f4a84a3925f6c74c |
--- /dev/null |
+++ b/chrome/browser/history/android/android_cache_database.cc |
@@ -0,0 +1,198 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/history/android/android_cache_database.h" |
+ |
+#include "base/file_util.h" |
+#include "sql/statement.h" |
+ |
+using base::Time; |
+using base::TimeDelta; |
+ |
+namespace history { |
+ |
+namespace { |
+ |
+int64 ToMilliseconds(const Time& time) { |
+ TimeDelta delta = time - Time::UnixEpoch(); |
+ return delta.InMilliseconds(); |
+} |
+ |
+} // namespace. |
+ |
+AndroidCacheDatabase::AndroidCacheDatabase() { |
sky
2012/03/02 15:59:50
You should either initialize db_attached_, or nuke
michaelbai
2012/03/02 20:04:43
That needs nuked, thanks
On 2012/03/02 15:59:50,
|
+} |
+ |
+AndroidCacheDatabase::~AndroidCacheDatabase() { |
+ if (file_util::PathExists(db_name_)) { |
sky
2012/03/02 15:59:50
Don't you need to close first?
michaelbai
2012/03/02 20:04:43
Thank for finding this, I shouldn't delete the fil
|
+ bool result = file_util::Delete(db_name_, false); |
sky
2012/03/02 15:59:50
spacing
michaelbai
2012/03/02 20:04:43
Code removed.
On 2012/03/02 15:59:50, sky wrote:
|
+ DCHECK(result); |
+ } |
+} |
+ |
+sql::InitStatus AndroidCacheDatabase::InitAndroidCacheDatabase( |
+ const FilePath& db_name) { |
+ if (!CreateDatabase(db_name)) |
+ return sql::INIT_FAILURE; |
+ |
+ if (!Attach()) |
+ return sql::INIT_FAILURE; |
+ |
+ if (!CreateBookmarkCacheTable()) |
+ return sql::INIT_FAILURE; |
+ |
+ return sql::INIT_OK; |
+} |
+ |
+bool AndroidCacheDatabase::AddBookmarkCacheRow(const Time& created_time, |
+ const Time& last_visit_time, |
+ URLID url_id) { |
+ sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
+ "INSERT INTO android_cache_db.bookmark_cache (created_time, " |
+ "last_visit_time, url_id) VALUES (?, ?, ?)")); |
+ |
+ statement.BindInt64(0, ToMilliseconds(created_time)); |
sky
2012/03/02 15:59:50
Why are you using milliseconds instead of Internal
michaelbai
2012/03/02 20:04:43
It because the Android use the milliseconds to que
sky
2012/03/02 20:51:28
Can't you convert when necessary? If not, add a co
michaelbai
2012/03/02 21:16:14
I can't, as the client could just write a SQL as '
|
+ statement.BindInt64(1, ToMilliseconds(last_visit_time)); |
+ statement.BindInt64(2, url_id); |
+ |
+ if (!statement.Run()) { |
+ LOG(ERROR) << GetDB().GetErrorMessage(); |
+ return 0; |
+ } |
+ |
+ return GetDB().GetLastInsertRowId(); |
sky
2012/03/02 15:59:50
Do you want the return value to be a bool or the I
michaelbai
2012/03/02 20:04:43
Return true
On 2012/03/02 15:59:50, sky wrote:
|
+} |
+ |
+bool AndroidCacheDatabase::ClearAllBookmarkCacheRow() { |
+ if (!GetDB().Execute("DELETE FROM android_cache_db.bookmark_cache")) { |
sky
2012/03/02 15:59:50
Don't you want a cached statement?
michaelbai
2012/03/02 20:04:43
Done.
|
+ LOG(ERROR) << GetDB().GetErrorMessage(); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+bool AndroidCacheDatabase::CacheBookmarkBits( |
+ const std::vector<URLID>& url_ids) { |
+ bool has_id = false; |
+ std::ostringstream oss; |
sky
2012/03/02 15:59:50
Why not just build up a string?
michaelbai
2012/03/02 20:04:43
Did you mean use 'string.append()', if so, I need
|
+ for (std::vector<URLID>::const_iterator i = url_ids.begin(); |
+ i != url_ids.end(); ++i) { |
+ if (has_id) |
+ oss << ", "; |
+ else |
+ has_id = true; |
+ oss << *i; |
+ } |
+ |
+ if (!has_id) |
+ return true; |
+ |
+ std::string sql("UPDATE android_cache_db.bookmark_cache " |
+ "SET bookmark = 1 WHERE url_id in ("); |
+ sql.append(oss.str()); |
+ sql.append(")"); |
+ if (!GetDB().Execute(sql.c_str())) { |
+ LOG(ERROR) << GetDB().GetErrorMessage(); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+bool AndroidCacheDatabase::CacheFaviconID(URLID url_id, FaviconID favicon_id) { |
+ sql::Statement update_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
+ "UPDATE android_cache_db.bookmark_cache " |
+ "SET favicon_id = ? WHERE url_id = ? ")); |
+ |
+ update_statement.BindInt64(0, favicon_id); |
+ update_statement.BindInt64(1, url_id); |
+ if (!update_statement.Run()) { |
+ LOG(ERROR) << GetDB().GetErrorMessage(); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+bool AndroidCacheDatabase::CreateDatabase(const FilePath& db_name) { |
+ db_name_ = db_name; |
+ if (file_util::PathExists(db_name_)) |
+ file_util::Delete(db_name_, false); |
+ |
+ // Using a new connection, otherwise we can not create the database. |
+ sql::Connection connection; |
+ |
+ // The db doesn't store too much data, so we don't need that big a page |
+ // size or cache. |
+ connection.set_page_size(2048); |
+ connection.set_cache_size(32); |
+ |
+ // Run the database in exclusive mode. Nobody else should be accessing the |
+ // database while we're running, and this will give somewhat improved perf. |
+ connection.set_exclusive_locking(); |
+ |
+ if (!connection.Open(db_name_)) { |
+ LOG(ERROR) << connection.GetErrorMessage(); |
+ return false; |
+ } |
+ connection.Close(); |
+ return true; |
+} |
+ |
+bool AndroidCacheDatabase::CreateBookmarkCacheTable() { |
+ const char* name = "android_cache_db.bookmark_cache"; |
+ DCHECK(!GetDB().DoesTableExist(name)); |
+ |
+ std::string sql; |
+ sql.append("CREATE TABLE "); |
+ sql.append(name); |
+ sql.append("(" |
+ "id INTEGER PRIMARY KEY," |
+ "created_time INTEGER NOT NULL," // Time in millisecond. |
+ "last_visit_time INTEGER NOT NULL," // Time in millisecond. |
+ "url_id INTEGER NOT NULL," // url id in urls table. |
+ "favicon_id INTEGER DEFAULT NULL," // favicon id. |
sky
2012/03/02 15:59:50
Don't you want 0 here?
michaelbai
2012/03/02 20:04:43
No, this is the tricky thing. The client think the
|
+ "bookmark INTEGER DEFAULT 0" // whether is bookmark. |
+ ")"); |
+ if (!GetDB().Execute(sql.c_str())) { |
+ LOG(ERROR) << GetDB().GetErrorMessage(); |
+ return false; |
+ } |
+ |
+ sql.assign("CREATE INDEX "); |
+ sql.append("android_cache_db.bookmark_cache_url_id_idx ON " |
+ "bookmark_cache(url_id)"); |
+ if (!GetDB().Execute(sql.c_str())) { |
+ LOG(ERROR) << GetDB().GetErrorMessage(); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+bool AndroidCacheDatabase::Attach() { |
+ if (GetDB().transaction_nesting()) |
+ GetDB().CommitTransaction(); |
sky
2012/03/02 15:59:50
Document why this is needed.
michaelbai
2012/03/02 20:04:43
Done.
|
+ |
+ // Attach AndroidCacheDatabase. |
+ { |
+ // This block is needed because otherwise the attach statement is |
+ // never cleared from cache and we can't close the DB :P |
+ std::string sql("ATTACH ? AS android_cache_db"); |
+ sql::Statement attach(GetDB().GetUniqueStatement(sql.c_str())); |
+ if (!attach.is_valid()) { |
+ // Keep the transaction open, even though we failed. |
+ GetDB().BeginTransaction(); |
sky
2012/03/02 15:59:50
This code is fragile because of having to open the
michaelbai
2012/03/02 20:04:43
FYI, This code was copied from ThumbnailDatabase.
sky
2012/03/02 20:51:28
Now is your chance to fix it;)
|
+ return false; |
+ } |
+ |
+ attach.BindString(0, db_name_.value()); |
+ if (!attach.Run()) { |
+ GetDB().BeginTransaction(); |
+ return false; |
+ } |
+ } |
+ GetDB().BeginTransaction(); |
+ db_attached_ = true; |
+ return true; |
+} |
+ |
+} // namespace history |