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

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

Powered by Google App Engine
This is Rietveld 408576698