Index: chrome/browser/history/download_database.cc |
diff --git a/chrome/browser/history/download_database.cc b/chrome/browser/history/download_database.cc |
index 5039e186765eb606500d8cd6f5e8715703a1a14f..8eea517f2c4aad0c45c0ebcd1a47c151925f95b7 100644 |
--- a/chrome/browser/history/download_database.cc |
+++ b/chrome/browser/history/download_database.cc |
@@ -38,6 +38,43 @@ static const char kSchema[] = |
"end_time INTEGER NOT NULL," // When the download completed. |
"opened INTEGER NOT NULL)"; // 1 if it has ever been opened else 0 |
+// These constants and next two functions are used to allow |
+// DownloadItem::DownloadState to change without breaking the database schema. |
+// They guarantee that the values of the |state| field in the database are one |
+// of the values returned by StateToInt, and that the values of the |state| |
+// field of the DownloadPersistentStoreInfos returned by QueryDownloads() are |
+// one of the values returned by IntToState(). |
+static const int kStateInvalid = -1; |
+static const int kStateInProgress = 0; |
+static const int kStateComplete = 1; |
+static const int kStateCancelled = 2; |
+static const int kStateBug140687 = 3; |
+static const int kStateInterrupted = 4; |
+ |
+int StateToInt(DownloadItem::DownloadState state) { |
+ switch (state) { |
+ case DownloadItem::IN_PROGRESS: return kStateInProgress; |
+ case DownloadItem::COMPLETE: return kStateComplete; |
+ case DownloadItem::CANCELLED: return kStateCancelled; |
+ case DownloadItem::REMOVING: return kStateInvalid; |
+ case DownloadItem::INTERRUPTED: return kStateInterrupted; |
+ case DownloadItem::MAX_DOWNLOAD_STATE: return kStateInvalid; |
+ default: return kStateInvalid; |
+ } |
+} |
+ |
+DownloadItem::DownloadState IntToState(int state) { |
+ switch (state) { |
+ case kStateInProgress: return DownloadItem::IN_PROGRESS; |
+ case kStateComplete: return DownloadItem::COMPLETE; |
+ case kStateCancelled: return DownloadItem::CANCELLED; |
+ // We should not need kStateBug140687 here because MigrateDownloadState() |
+ // is called in HistoryDatabase::Init(). |
+ case kStateInterrupted: return DownloadItem::INTERRUPTED; |
+ default: return DownloadItem::MAX_DOWNLOAD_STATE; |
+ } |
+} |
+ |
#if defined(OS_POSIX) |
// Binds/reads the given file path to the given column of the given statement. |
@@ -92,6 +129,14 @@ bool DownloadDatabase::EnsureColumnExists( |
GetDB().Execute(add_col.c_str()); |
} |
+bool DownloadDatabase::MigrateDownloadsState() { |
+ sql::Statement statement(GetDB().GetUniqueStatement( |
+ "UPDATE downloads SET state=? WHERE state=?")); |
+ statement.BindInt(0, kStateInterrupted); |
+ statement.BindInt(1, kStateBug140687); |
+ return statement.Run(); |
+} |
+ |
bool DownloadDatabase::InitDownloadTable() { |
CheckThread(); |
GetMetaTable().GetValue(kNextDownloadId, &next_id_); |
@@ -130,9 +175,12 @@ void DownloadDatabase::QueryDownloads( |
info.start_time = base::Time::FromTimeT(statement.ColumnInt64(3)); |
info.received_bytes = statement.ColumnInt64(4); |
info.total_bytes = statement.ColumnInt64(5); |
- info.state = statement.ColumnInt(6); |
+ info.state = IntToState(statement.ColumnInt(6)); |
info.end_time = base::Time::FromTimeT(statement.ColumnInt64(7)); |
info.opened = statement.ColumnInt(8) != 0; |
+ if (info.state == DownloadItem::MAX_DOWNLOAD_STATE) { |
+ continue; |
Randy Smith (Not in Mondays)
2012/08/07 20:36:16
UMA? (You're welcome to say not in this CL, but I
sky
2012/08/07 20:54:17
Why add this? At best we do a DCHECK for this sort
asanka
2012/08/07 20:56:14
If you skip this early, wouldn't you risk not upda
Randy Smith (Not in Mondays)
2012/08/07 21:01:35
The basic problem is that almost any sanitization
benjhayden
2012/08/08 01:11:52
This layer of abstraction separates the compiler-g
benjhayden
2012/08/08 01:11:52
Done.
benjhayden
2012/08/08 01:11:52
Done.
benjhayden
2012/08/08 01:11:52
This isn't just sanitization. It's a mapping, a la
Randy Smith (Not in Mondays)
2012/08/08 01:52:25
Good point. Ok.
|
+ } |
results->push_back(info); |
if (info.db_handle >= next_db_handle_) |
next_db_handle_ = info.db_handle + 1; |
@@ -147,11 +195,14 @@ void DownloadDatabase::QueryDownloads( |
bool DownloadDatabase::UpdateDownload(const DownloadPersistentStoreInfo& data) { |
CheckThread(); |
DCHECK(data.db_handle > 0); |
+ int state = StateToInt(data.state); |
+ if (state == kStateInvalid) |
+ return false; |
Randy Smith (Not in Mondays)
2012/08/07 20:36:16
DCHECK? If we get an invalid state here, it means
benjhayden
2012/08/08 01:11:52
Is it possible for UpdateDownload to see a downloa
Randy Smith (Not in Mondays)
2012/08/08 01:52:25
Not sure enough for this CL :-} :-|.
|
sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
"UPDATE downloads " |
"SET received_bytes=?, state=?, end_time=?, opened=? WHERE id=?")); |
statement.BindInt64(0, data.received_bytes); |
- statement.BindInt(1, data.state); |
+ statement.BindInt(1, state); |
statement.BindInt64(2, data.end_time.ToTimeT()); |
statement.BindInt(3, (data.opened ? 1 : 0)); |
statement.BindInt64(4, data.db_handle); |
@@ -175,8 +226,8 @@ bool DownloadDatabase::CleanUpInProgressEntries() { |
CheckThread(); |
sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
"UPDATE downloads SET state=? WHERE state=?")); |
- statement.BindInt(0, DownloadItem::CANCELLED); |
- statement.BindInt(1, DownloadItem::IN_PROGRESS); |
+ statement.BindInt(0, kStateCancelled); |
+ statement.BindInt(1, kStateInProgress); |
return statement.Run(); |
} |
@@ -193,6 +244,10 @@ int64 DownloadDatabase::CreateDownload( |
CHECK_NE(0, next_db_handle_); |
} |
+ int state = StateToInt(info.state); |
+ if (state == kStateInvalid) |
+ return false; |
+ |
sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
"INSERT INTO downloads " |
"(id, full_path, url, start_time, received_bytes, total_bytes, state, " |
@@ -207,7 +262,7 @@ int64 DownloadDatabase::CreateDownload( |
statement.BindInt64(3, info.start_time.ToTimeT()); |
statement.BindInt64(4, info.received_bytes); |
statement.BindInt64(5, info.total_bytes); |
- statement.BindInt(6, info.state); |
+ statement.BindInt(6, state); |
statement.BindInt64(7, info.end_time.ToTimeT()); |
statement.BindInt(8, info.opened ? 1 : 0); |
@@ -245,9 +300,9 @@ bool DownloadDatabase::RemoveDownloadsBetween(base::Time delete_begin, |
count.BindInt64( |
1, |
end_time ? end_time : std::numeric_limits<int64>::max()); |
- count.BindInt(2, DownloadItem::COMPLETE); |
- count.BindInt(3, DownloadItem::CANCELLED); |
- count.BindInt(4, DownloadItem::INTERRUPTED); |
+ count.BindInt(2, kStateComplete); |
+ count.BindInt(3, kStateCancelled); |
+ count.BindInt(4, kStateInterrupted); |
if (count.Step()) |
num_downloads_deleted = count.ColumnInt(0); |
} |
@@ -265,9 +320,9 @@ bool DownloadDatabase::RemoveDownloadsBetween(base::Time delete_begin, |
statement.BindInt64( |
1, |
end_time ? end_time : std::numeric_limits<int64>::max()); |
- statement.BindInt(2, DownloadItem::COMPLETE); |
- statement.BindInt(3, DownloadItem::CANCELLED); |
- statement.BindInt(4, DownloadItem::INTERRUPTED); |
+ statement.BindInt(2, kStateComplete); |
+ statement.BindInt(3, kStateCancelled); |
+ statement.BindInt(4, kStateInterrupted); |
success = statement.Run(); |
} |