Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Side by Side Diff: chrome/browser/history/download_database.cc

Issue 11363222: Persist download interrupt reason, both target and current paths, and url_chain. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed try bot problems, specifically issues in http://crbug.com/172672 Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/history/download_database.h" 5 #include "chrome/browser/history/download_database.h"
6 6
7 #include <limits> 7 #include <limits>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/debug/alias.h" 11 #include "base/debug/alias.h"
12 #include "base/file_path.h" 12 #include "base/file_path.h"
13 #include "base/memory/scoped_ptr.h"
13 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
15 #include "base/stl_util.h"
16 #include "base/stringprintf.h"
14 #include "base/time.h" 17 #include "base/time.h"
15 #include "base/utf_string_conversions.h" 18 #include "base/utf_string_conversions.h"
16 #include "build/build_config.h" 19 #include "build/build_config.h"
17 #include "chrome/browser/history/download_row.h" 20 #include "chrome/browser/history/download_row.h"
21 #include "chrome/browser/history/history_types.h"
22 #include "content/public/browser/download_interrupt_reasons.h"
18 #include "content/public/browser/download_item.h" 23 #include "content/public/browser/download_item.h"
19 #include "sql/statement.h" 24 #include "sql/statement.h"
20 25
21 using content::DownloadItem; 26 using content::DownloadItem;
22 27
23 namespace history { 28 namespace history {
24 29
25 // static 30 // static
26 const int64 DownloadDatabase::kUninitializedHandle = -1; 31 const int64 DownloadDatabase::kUninitializedHandle = -1;
27 32
28 namespace { 33 namespace {
29 34
35 // Reason for dropping a particular record.
36 enum DroppedReason {
37 DROPPED_REASON_BAD_STATE = 0,
38 DROPPED_REASON_BAD_DANGER_TYPE = 1,
39 DROPPED_REASON_MAX
40 };
41
30 static const char kSchema[] = 42 static const char kSchema[] =
31 "CREATE TABLE downloads (" 43 "CREATE TABLE downloads ("
32 "id INTEGER PRIMARY KEY," // SQLite-generated primary key. 44 "id INTEGER PRIMARY KEY," // Primary key.
33 "full_path LONGVARCHAR NOT NULL," // Location of the download on disk. 45 "current_path LONGVARCHAR NOT NULL," // Current disk location of the download
34 "url LONGVARCHAR NOT NULL," // URL of the downloaded file. 46 "target_path LONGVARCHAR NOT NULL," // Final disk location of the download
35 "start_time INTEGER NOT NULL," // When the download was started. 47 "start_time INTEGER NOT NULL," // When the download was started.
36 "received_bytes INTEGER NOT NULL," // Total size downloaded. 48 "received_bytes INTEGER NOT NULL," // Total size downloaded.
37 "total_bytes INTEGER NOT NULL," // Total size of the download. 49 "total_bytes INTEGER NOT NULL," // Total size of the download.
38 "state INTEGER NOT NULL," // 1=complete, 2=cancelled, 4=interrupted 50 "state INTEGER NOT NULL," // 1=complete, 4=interrupted
51 "danger_type INTEGER NOT NULL, " // Not dangerous, danger type, validated.
52 "interrupt_reason INTEGER NOT NULL," // Reason the download was interrupted.
39 "end_time INTEGER NOT NULL," // When the download completed. 53 "end_time INTEGER NOT NULL," // When the download completed.
40 "opened INTEGER NOT NULL)"; // 1 if it has ever been opened else 0 54 "opened INTEGER NOT NULL)"; // 1 if it has ever been opened else 0
41 55
56 static const char kUrlChainSchema[] =
57 "CREATE TABLE downloads_url_chains ("
58 "id INTEGER NOT NULL," // downloads.id.
59 "chain_index INTEGER NOT NULL," // Index of url in chain
60 // 0 is initial target,
61 // MAX is target after redirects.
62 "url LONGVARCHAR NOT NULL, " // URL.
63 "PRIMARY KEY (id, chain_index) )";
64
42 // These constants and next two functions are used to allow 65 // These constants and next two functions are used to allow
43 // DownloadItem::DownloadState to change without breaking the database schema. 66 // DownloadItem::DownloadState and DownloadDangerType to change without
67 // breaking the database schema.
44 // They guarantee that the values of the |state| field in the database are one 68 // They guarantee that the values of the |state| field in the database are one
45 // of the values returned by StateToInt, and that the values of the |state| 69 // of the values returned by StateToInt, and that the values of the |state|
46 // field of the DownloadRows returned by QueryDownloads() are one of the values 70 // field of the DownloadRows returned by QueryDownloads() are one of the values
47 // returned by IntToState(). 71 // returned by IntToState().
48 static const int kStateInvalid = -1; 72 static const int kStateInvalid = -1;
49 static const int kStateInProgress = 0; 73 static const int kStateInProgress = 0;
50 static const int kStateComplete = 1; 74 static const int kStateComplete = 1;
51 static const int kStateCancelled = 2; 75 static const int kStateCancelled = 2;
52 static const int kStateBug140687 = 3; 76 static const int kStateBug140687 = 3;
53 static const int kStateInterrupted = 4; 77 static const int kStateInterrupted = 4;
54 78
79 static const int kDangerTypeInvalid = -1;
80 static const int kDangerTypeNotDangerous = 0;
81 static const int kDangerTypeDangerousFile = 1;
82 static const int kDangerTypeDangerousUrl = 2;
83 static const int kDangerTypeDangerousContent = 3;
84 static const int kDangerTypeMaybeDangerousContent = 4;
85 static const int kDangerTypeUncommonContent = 5;
86 static const int kDangerTypeUserValidated = 6;
87
55 int StateToInt(DownloadItem::DownloadState state) { 88 int StateToInt(DownloadItem::DownloadState state) {
56 switch (state) { 89 switch (state) {
57 case DownloadItem::IN_PROGRESS: return kStateInProgress; 90 case DownloadItem::IN_PROGRESS: return kStateInProgress;
58 case DownloadItem::COMPLETE: return kStateComplete; 91 case DownloadItem::COMPLETE: return kStateComplete;
59 case DownloadItem::CANCELLED: return kStateCancelled; 92 case DownloadItem::CANCELLED: return kStateCancelled;
60 case DownloadItem::INTERRUPTED: return kStateInterrupted; 93 case DownloadItem::INTERRUPTED: return kStateInterrupted;
61 case DownloadItem::MAX_DOWNLOAD_STATE: return kStateInvalid; 94 case DownloadItem::MAX_DOWNLOAD_STATE:
62 default: return kStateInvalid; 95 NOTREACHED();
96 return kStateInvalid;
63 } 97 }
98 NOTREACHED();
99 return kStateInvalid;
64 } 100 }
65 101
66 DownloadItem::DownloadState IntToState(int state) { 102 DownloadItem::DownloadState IntToState(int state) {
67 switch (state) { 103 switch (state) {
68 case kStateInProgress: return DownloadItem::IN_PROGRESS; 104 case kStateInProgress: return DownloadItem::IN_PROGRESS;
69 case kStateComplete: return DownloadItem::COMPLETE; 105 case kStateComplete: return DownloadItem::COMPLETE;
70 case kStateCancelled: return DownloadItem::CANCELLED; 106 case kStateCancelled: return DownloadItem::CANCELLED;
71 // We should not need kStateBug140687 here because MigrateDownloadState() 107 // We should not need kStateBug140687 here because MigrateDownloadsState()
72 // is called in HistoryDatabase::Init(). 108 // is called in HistoryDatabase::Init().
73 case kStateInterrupted: return DownloadItem::INTERRUPTED; 109 case kStateInterrupted: return DownloadItem::INTERRUPTED;
74 default: return DownloadItem::MAX_DOWNLOAD_STATE; 110 default: return DownloadItem::MAX_DOWNLOAD_STATE;
75 } 111 }
76 } 112 }
77 113
114 int DangerTypeToInt(content::DownloadDangerType danger_type) {
115 switch (danger_type) {
116 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
117 return kDangerTypeNotDangerous;
118 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
119 return kDangerTypeDangerousFile;
120 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
121 return kDangerTypeDangerousUrl;
122 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
123 return kDangerTypeDangerousContent;
124 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
125 return kDangerTypeMaybeDangerousContent;
126 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
127 return kDangerTypeUncommonContent;
128 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
129 return kDangerTypeUserValidated;
130 case content::DOWNLOAD_DANGER_TYPE_MAX:
131 NOTREACHED();
132 return kDangerTypeInvalid;
133 }
134 NOTREACHED();
135 return kDangerTypeInvalid;
136 }
137
138 content::DownloadDangerType IntToDangerType(int danger_type) {
139 switch (danger_type) {
140 case kDangerTypeNotDangerous:
141 return content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
142 case kDangerTypeDangerousFile:
143 return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE;
144 case kDangerTypeDangerousUrl:
145 return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL;
146 case kDangerTypeDangerousContent:
147 return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT;
148 case kDangerTypeMaybeDangerousContent:
149 return content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT;
150 case kDangerTypeUncommonContent:
151 return content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT;
152 case kDangerTypeUserValidated:
153 return content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED;
154 default:
155 return content::DOWNLOAD_DANGER_TYPE_MAX;
156 }
157 }
158
78 #if defined(OS_POSIX) 159 #if defined(OS_POSIX)
79 160
80 // Binds/reads the given file path to the given column of the given statement. 161 // Binds/reads the given file path to the given column of the given statement.
81 void BindFilePath(sql::Statement& statement, const FilePath& path, int col) { 162 void BindFilePath(sql::Statement& statement, const FilePath& path, int col) {
82 statement.BindString(col, path.value()); 163 statement.BindString(col, path.value());
83 } 164 }
84 FilePath ColumnFilePath(sql::Statement& statement, int col) { 165 FilePath ColumnFilePath(sql::Statement& statement, int col) {
85 return FilePath(statement.ColumnString(col)); 166 return FilePath(statement.ColumnString(col));
86 } 167 }
87 168
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 } 202 }
122 203
123 bool DownloadDatabase::MigrateDownloadsState() { 204 bool DownloadDatabase::MigrateDownloadsState() {
124 sql::Statement statement(GetDB().GetUniqueStatement( 205 sql::Statement statement(GetDB().GetUniqueStatement(
125 "UPDATE downloads SET state=? WHERE state=?")); 206 "UPDATE downloads SET state=? WHERE state=?"));
126 statement.BindInt(0, kStateInterrupted); 207 statement.BindInt(0, kStateInterrupted);
127 statement.BindInt(1, kStateBug140687); 208 statement.BindInt(1, kStateBug140687);
128 return statement.Run(); 209 return statement.Run();
129 } 210 }
130 211
212 bool DownloadDatabase::MigrateDownloadsReasonPathsAndDangerType() {
213 // We need to rename the table and copy back from it because SQLite
214 // provides no way to rename or delete a column.
215 if (!GetDB().Execute("ALTER TABLE downloads RENAME TO downloads_tmp"))
216 return false;
217
218 // Recreate main table.
219 if (!GetDB().Execute(kSchema))
220 return false;
221
222 // Populate it. As we do so, we transform the time values from time_t
223 // (seconds since 1/1/1970 UTC), to our internal measure (microseconds
224 // since the Windows Epoch). Note that this is dependent on the
225 // internal representation of base::Time and needs to change if that changes.
226 sql::Statement statement_populate(GetDB().GetUniqueStatement(
227 "INSERT INTO downloads "
228 "( id, current_path, target_path, start_time, received_bytes, total_bytes, "
229 " state, danger_type, interrupt_reason, end_time, opened ) "
230 "SELECT id, full_path, full_path, "
231 " CASE start_time WHEN 0 THEN 0 ELSE "
232 " (start_time + 11644473600) * 1000000 END, "
233 " received_bytes, total_bytes, "
234 " state, ?, ?, "
235 " CASE end_time WHEN 0 THEN 0 ELSE "
236 " (end_time + 11644473600) * 1000000 END, "
237 " opened "
238 "FROM downloads_tmp"));
239 statement_populate.BindInt(0, content::DOWNLOAD_INTERRUPT_REASON_NONE);
240 statement_populate.BindInt(1, kDangerTypeNotDangerous);
241 if (!statement_populate.Run())
242 return false;
243
244 // Create new chain table and populate it.
245 if (!GetDB().Execute(kUrlChainSchema))
246 return false;
247
248 if (!GetDB().Execute("INSERT INTO downloads_url_chains "
249 " ( id, chain_index, url) "
250 " SELECT id, 0, url from downloads_tmp"))
251 return false;
252
253 // Get rid of temporary table.
254 if (!GetDB().Execute("DROP TABLE downloads_tmp"))
255 return false;
256
257 return true;
258 }
259
131 bool DownloadDatabase::InitDownloadTable() { 260 bool DownloadDatabase::InitDownloadTable() {
132 GetMetaTable().GetValue(kNextDownloadId, &next_id_); 261 GetMetaTable().GetValue(kNextDownloadId, &next_id_);
133 if (GetDB().DoesTableExist("downloads")) { 262 if (GetDB().DoesTableExist("downloads")) {
134 return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") && 263 return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") &&
135 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0"); 264 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0");
136 } else { 265 } else {
137 return GetDB().Execute(kSchema); 266 // If the "downloads" table doesn't exist, the downloads_url_chain
267 // table better not.
268 return (!GetDB().DoesTableExist("downloads_url_chain") &&
269 GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema));
138 } 270 }
139 } 271 }
140 272
141 bool DownloadDatabase::DropDownloadTable() { 273 bool DownloadDatabase::DropDownloadTable() {
142 return GetDB().Execute("DROP TABLE downloads"); 274 return GetDB().Execute("DROP TABLE downloads");
143 } 275 }
144 276
145 void DownloadDatabase::QueryDownloads( 277 void DownloadDatabase::QueryDownloads(
146 std::vector<DownloadRow>* results) { 278 std::vector<DownloadRow>* results) {
147 DCHECK(results);
148 results->clear(); 279 results->clear();
149 if (next_db_handle_ < 1) 280 if (next_db_handle_ < 1)
150 next_db_handle_ = 1; 281 next_db_handle_ = 1;
151 std::set<int64> db_handles; 282 std::set<int64> db_handles;
152 283
153 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 284 std::map<DownloadID, DownloadRow*> info_map;
154 "SELECT id, full_path, url, start_time, received_bytes, " 285
155 "total_bytes, state, end_time, opened " 286 sql::Statement statement_main(GetDB().GetCachedStatement(SQL_FROM_HERE,
287 "SELECT id, current_path, target_path, start_time, received_bytes, "
288 "total_bytes, state, danger_type, interrupt_reason, end_time, opened "
156 "FROM downloads " 289 "FROM downloads "
157 "ORDER BY start_time")); 290 "ORDER BY start_time"));
158 291
159 while (statement.Step()) { 292 while (statement_main.Step()) {
160 DownloadRow info; 293 scoped_ptr<DownloadRow> info(new DownloadRow());
161 info.db_handle = statement.ColumnInt64(0); 294 int column = 0;
162 info.path = ColumnFilePath(statement, 1); 295
163 info.url = GURL(statement.ColumnString(2)); 296 int db_handle = statement_main.ColumnInt64(column++);
164 info.start_time = base::Time::FromTimeT(statement.ColumnInt64(3)); 297 info->db_handle = db_handle;
165 info.received_bytes = statement.ColumnInt64(4); 298 info->current_path = ColumnFilePath(statement_main, column++);
166 info.total_bytes = statement.ColumnInt64(5); 299 info->target_path = ColumnFilePath(statement_main, column++);
167 int state = statement.ColumnInt(6); 300 info->start_time = base::Time::FromInternalValue(
168 info.state = IntToState(state); 301 statement_main.ColumnInt64(column++));
169 info.end_time = base::Time::FromTimeT(statement.ColumnInt64(7)); 302 info->received_bytes = statement_main.ColumnInt64(column++);
170 info.opened = statement.ColumnInt(8) != 0; 303 info->total_bytes = statement_main.ColumnInt64(column++);
171 if (info.db_handle >= next_db_handle_) 304 int state = statement_main.ColumnInt(column++);
172 next_db_handle_ = info.db_handle + 1; 305 info->state = IntToState(state);
173 if (!db_handles.insert(info.db_handle).second) { 306 if (info->state == DownloadItem::MAX_DOWNLOAD_STATE)
174 // info.db_handle was already in db_handles. The database is corrupt. 307 UMA_HISTOGRAM_COUNTS("Download.DatabaseInvalidState", state);
175 base::debug::Alias(&info.db_handle); 308 info->danger_type = IntToDangerType(statement_main.ColumnInt(column++));
309 info->interrupt_reason = static_cast<content::DownloadInterruptReason>(
310 statement_main.ColumnInt(column++));
311 info->end_time = base::Time::FromInternalValue(
312 statement_main.ColumnInt64(column++));
313 info->opened = statement_main.ColumnInt(column++) != 0;
314 if (info->db_handle >= next_db_handle_)
315 next_db_handle_ = info->db_handle + 1;
316 if (!db_handles.insert(info->db_handle).second) {
317 // info->db_handle was already in db_handles. The database is corrupt.
318 base::debug::Alias(&info->db_handle);
176 DCHECK(false); 319 DCHECK(false);
177 } 320 }
178 if (info.state == DownloadItem::MAX_DOWNLOAD_STATE) { 321
179 UMA_HISTOGRAM_COUNTS("Download.DatabaseInvalidState", state); 322 // If the record is corrupted, note that and drop it.
323 if (info->state == DownloadItem::MAX_DOWNLOAD_STATE ||
324 info->danger_type == content::DOWNLOAD_DANGER_TYPE_MAX) {
325 DroppedReason reason = DROPPED_REASON_MAX;
326 if (info->state == DownloadItem::MAX_DOWNLOAD_STATE)
327 reason = DROPPED_REASON_BAD_STATE;
328 else if (info->danger_type == content::DOWNLOAD_DANGER_TYPE_MAX)
329 reason = DROPPED_REASON_BAD_DANGER_TYPE;
330 else
331 NOTREACHED();
332
333 UMA_HISTOGRAM_ENUMERATION(
334 "Download.DatabaseRecordDropped", reason, DROPPED_REASON_MAX + 1);
335
180 continue; 336 continue;
181 } 337 }
182 results->push_back(info); 338
339 DCHECK(!ContainsKey(info_map, info->db_handle));
340 info_map[db_handle] = info.release();
341 }
342
343 sql::Statement statement_chain(GetDB().GetCachedStatement(
344 SQL_FROM_HERE,
345 "SELECT id, chain_index, url FROM downloads_url_chains "
346 "ORDER BY id, chain_index"));
347
348 while (statement_chain.Step()) {
349 int column = 0;
350 int64 db_handle = statement_chain.ColumnInt64(column++);
351 int chain_index = statement_chain.ColumnInt(column++);
352
353 // Note that these DCHECKs may trip as a result of corrupted databases.
354 // We have them because in debug builds the chances are higher there's
355 // an actual bug than that the database is corrupt, but we handle the
356 // DB corruption case in production code.
357
358 // Confirm the handle has already been seen--if it hasn't, discard the
359 // record.
360 DCHECK(ContainsKey(info_map, db_handle));
361 if (!ContainsKey(info_map, db_handle))
362 continue;
363
364 // Confirm all previous URLs in the chain have already been seen;
365 // if not, fill in with null or discard record.
366 int current_chain_size = info_map[db_handle]->url_chain.size();
367 std::vector<GURL>* url_chain(&info_map[db_handle]->url_chain);
368 DCHECK_EQ(chain_index, current_chain_size);
369 while (current_chain_size < chain_index) {
370 url_chain->push_back(GURL());
371 current_chain_size++;
372 }
373 if (current_chain_size > chain_index)
374 continue;
375
376 // Save the record.
377 url_chain->push_back(GURL(statement_chain.ColumnString(2)));
378 }
379
380 for (std::map<DownloadID, DownloadRow*>::iterator
381 it = info_map.begin(); it != info_map.end(); ++it) {
382 // Copy the contents of the stored info.
383 results->push_back(*it->second);
384 delete it->second;
385 it->second = NULL;
183 } 386 }
184 } 387 }
185 388
186 bool DownloadDatabase::UpdateDownload(const DownloadRow& data) { 389 bool DownloadDatabase::UpdateDownload(const DownloadRow& data) {
187 DCHECK(data.db_handle > 0); 390 DCHECK(data.db_handle > 0);
188 int state = StateToInt(data.state); 391 int state = StateToInt(data.state);
189 if (state == kStateInvalid) { 392 if (state == kStateInvalid) {
190 // TODO(benjhayden) [D]CHECK instead. 393 NOTREACHED();
191 return false; 394 return false;
192 } 395 }
396 int danger_type = DangerTypeToInt(data.danger_type);
397 if (danger_type == kDangerTypeInvalid) {
398 NOTREACHED();
399 return false;
400 }
401
193 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 402 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
194 "UPDATE downloads " 403 "UPDATE downloads "
195 "SET full_path=?, received_bytes=?, state=?, end_time=?, total_bytes=?, " 404 "SET current_path=?, target_path=?, received_bytes=?, state=?, "
196 "opened=? WHERE id=?")); 405 "danger_type=?, interrupt_reason=?, end_time=?, total_bytes=?, "
197 BindFilePath(statement, data.path, 0); 406 "opened=? WHERE id=?"));
198 statement.BindInt64(1, data.received_bytes); 407 int column = 0;
199 statement.BindInt(2, state); 408 BindFilePath(statement, data.current_path, column++);
200 statement.BindInt64(3, data.end_time.ToTimeT()); 409 BindFilePath(statement, data.target_path, column++);
201 statement.BindInt(4, data.total_bytes); 410 statement.BindInt64(column++, data.received_bytes);
202 statement.BindInt(5, (data.opened ? 1 : 0)); 411 statement.BindInt(column++, state);
203 statement.BindInt64(6, data.db_handle); 412 statement.BindInt(column++, danger_type);
413 statement.BindInt(column++, static_cast<int>(data.interrupt_reason));
414 statement.BindInt64(column++, data.end_time.ToInternalValue());
415 statement.BindInt(column++, data.total_bytes);
416 statement.BindInt(column++, (data.opened ? 1 : 0));
417 statement.BindInt64(column++, data.db_handle);
204 418
205 return statement.Run(); 419 return statement.Run();
206 } 420 }
207 421
208 bool DownloadDatabase::CleanUpInProgressEntries() { 422 bool DownloadDatabase::CleanUpInProgressEntries() {
209 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 423 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
210 "UPDATE downloads SET state=? WHERE state=?")); 424 "UPDATE downloads SET state=? WHERE state=?"));
211 statement.BindInt(0, kStateCancelled); 425 statement.BindInt(0, kStateCancelled);
212 statement.BindInt(1, kStateInProgress); 426 statement.BindInt(1, kStateInProgress);
213 427
214 return statement.Run(); 428 return statement.Run();
215 } 429 }
216 430
217 int64 DownloadDatabase::CreateDownload( 431 int64 DownloadDatabase::CreateDownload(
218 const DownloadRow& info) { 432 const DownloadRow& info) {
219 if (next_db_handle_ == 0) { 433 if (next_db_handle_ == 0) {
220 // This is unlikely. All current known tests and users already call 434 // This is unlikely. All current known tests and users already call
221 // QueryDownloads() before CreateDownload(). 435 // QueryDownloads() before CreateDownload().
222 std::vector<DownloadRow> results; 436 std::vector<DownloadRow> results;
223 QueryDownloads(&results); 437 QueryDownloads(&results);
224 CHECK_NE(0, next_db_handle_); 438 CHECK_NE(0, next_db_handle_);
225 } 439 }
226 440
227 int state = StateToInt(info.state); 441 int state = StateToInt(info.state);
228 if (state == kStateInvalid) 442 if (state == kStateInvalid)
229 return kUninitializedHandle; 443 return kUninitializedHandle;
230 444
231 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 445 int danger_type = DangerTypeToInt(info.danger_type);
232 "INSERT INTO downloads " 446 if (danger_type == kDangerTypeInvalid)
233 "(id, full_path, url, start_time, received_bytes, total_bytes, state, " 447 return kUninitializedHandle;
234 "end_time, opened) "
235 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"));
236 448
237 int db_handle = next_db_handle_++; 449 int db_handle = next_db_handle_++;
238 450
239 statement.BindInt64(0, db_handle); 451 {
240 BindFilePath(statement, info.path, 1); 452 sql::Statement statement_insert(GetDB().GetCachedStatement(
241 statement.BindString(2, info.url.spec()); 453 SQL_FROM_HERE,
242 statement.BindInt64(3, info.start_time.ToTimeT()); 454 "INSERT INTO downloads "
243 statement.BindInt64(4, info.received_bytes); 455 "(id, current_path, target_path, start_time, "
244 statement.BindInt64(5, info.total_bytes); 456 " received_bytes, total_bytes, state, danger_type, interrupt_reason, "
245 statement.BindInt(6, state); 457 " end_time, opened) "
246 statement.BindInt64(7, info.end_time.ToTimeT()); 458 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
247 statement.BindInt(8, info.opened ? 1 : 0);
248 459
249 if (statement.Run()) { 460 int column = 0;
250 // TODO(benjhayden) if(info.id>next_id_){setvalue;next_id_=info.id;} 461 statement_insert.BindInt64(column++, db_handle);
251 GetMetaTable().SetValue(kNextDownloadId, ++next_id_); 462 BindFilePath(statement_insert, info.current_path, column++);
463 BindFilePath(statement_insert, info.target_path, column++);
464 statement_insert.BindInt64(column++, info.start_time.ToInternalValue());
465 statement_insert.BindInt64(column++, info.received_bytes);
466 statement_insert.BindInt64(column++, info.total_bytes);
467 statement_insert.BindInt(column++, state);
468 statement_insert.BindInt(column++, danger_type);
469 statement_insert.BindInt(column++, info.interrupt_reason);
470 statement_insert.BindInt64(column++, info.end_time.ToInternalValue());
471 statement_insert.BindInt(column++, info.opened ? 1 : 0);
472 if (!statement_insert.Run()) {
473 LOG(WARNING) << "Main insertion for download create failed.";
474 return kUninitializedHandle;
475 }
476 }
252 477
253 return db_handle; 478 sql::Statement statement_insert_chain(
479 GetDB().GetCachedStatement(SQL_FROM_HERE,
480 "INSERT INTO downloads_url_chains "
481 "(id, chain_index, url) "
482 "VALUES (?, ?, ?)"));
483 for (size_t i = 0; i < info.url_chain.size(); ++i) {
484 statement_insert_chain.BindInt64(0, db_handle);
485 statement_insert_chain.BindInt(1, i);
486 statement_insert_chain.BindString(2, info.url_chain[i].spec());
487 if (!statement_insert_chain.Run()) {
488 LOG(WARNING) << "Url insertion for download create failed.";
489 return kUninitializedHandle;
490 }
491 statement_insert_chain.Reset(true);
254 } 492 }
255 return kUninitializedHandle; 493
494 // TODO(benjhayden) if(info.id>next_id_){setvalue;next_id_=info.id;}
495 GetMetaTable().SetValue(kNextDownloadId, ++next_id_);
496
497 return db_handle;
256 } 498 }
257 499
258 void DownloadDatabase::RemoveDownload(int64 handle) { 500 void DownloadDatabase::RemoveDownload(int64 handle) {
259 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 501 sql::Statement downloads_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
260 "DELETE FROM downloads WHERE id=?")); 502 "DELETE FROM downloads WHERE id=?"));
261 statement.BindInt64(0, handle); 503 downloads_statement.BindInt64(0, handle);
262 statement.Run(); 504 downloads_statement.Run();
505
506 sql::Statement urlchain_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
507 "DELETE FROM downloads_url_chains WHERE id=?"));
508 urlchain_statement.BindInt64(0, handle);
509 urlchain_statement.Run();
263 } 510 }
264 511
265 int DownloadDatabase::CountDownloads() { 512 int DownloadDatabase::CountDownloads() {
266 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 513 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
267 "SELECT count(*) from downloads")); 514 "SELECT count(*) from downloads"));
268 statement.Step(); 515 statement.Step();
269 return statement.ColumnInt(0); 516 return statement.ColumnInt(0);
270 } 517 }
271 518
272 } // namespace history 519 } // namespace history
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698