OLD | NEW |
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 |
(...skipping 12 matching lines...) Expand all Loading... |
23 #include "content/public/browser/download_item.h" | 23 #include "content/public/browser/download_item.h" |
24 #include "sql/statement.h" | 24 #include "sql/statement.h" |
25 | 25 |
26 using content::DownloadItem; | 26 using content::DownloadItem; |
27 | 27 |
28 namespace history { | 28 namespace history { |
29 | 29 |
30 // static | 30 // static |
31 const int64 DownloadDatabase::kUninitializedHandle = -1; | 31 const int64 DownloadDatabase::kUninitializedHandle = -1; |
32 | 32 |
| 33 // These constants and the transformation functions below are used to allow |
| 34 // DownloadItem::DownloadState and DownloadDangerType to change without |
| 35 // breaking the database schema. |
| 36 // They guarantee that the values of the |state| field in the database are one |
| 37 // of the values returned by StateToInt, and that the values of the |state| |
| 38 // field of the DownloadRows returned by QueryDownloads() are one of the values |
| 39 // returned by IntToState(). |
| 40 const int DownloadDatabase::kStateInvalid = -1; |
| 41 const int DownloadDatabase::kStateInProgress = 0; |
| 42 const int DownloadDatabase::kStateComplete = 1; |
| 43 const int DownloadDatabase::kStateCancelled = 2; |
| 44 const int DownloadDatabase::kStateBug140687 = 3; |
| 45 const int DownloadDatabase::kStateInterrupted = 4; |
| 46 |
| 47 const int DownloadDatabase::kDangerTypeInvalid = -1; |
| 48 const int DownloadDatabase::kDangerTypeNotDangerous = 0; |
| 49 const int DownloadDatabase::kDangerTypeDangerousFile = 1; |
| 50 const int DownloadDatabase::kDangerTypeDangerousUrl = 2; |
| 51 const int DownloadDatabase::kDangerTypeDangerousContent = 3; |
| 52 const int DownloadDatabase::kDangerTypeMaybeDangerousContent = 4; |
| 53 const int DownloadDatabase::kDangerTypeUncommonContent = 5; |
| 54 const int DownloadDatabase::kDangerTypeUserValidated = 6; |
| 55 const int DownloadDatabase::kDangerTypeDangerousHost = 7; |
| 56 |
33 namespace { | 57 namespace { |
34 | 58 |
35 // Reason for dropping a particular record. | 59 // Reason for dropping a particular record. |
36 enum DroppedReason { | 60 enum DroppedReason { |
37 DROPPED_REASON_BAD_STATE = 0, | 61 DROPPED_REASON_BAD_STATE = 0, |
38 DROPPED_REASON_BAD_DANGER_TYPE = 1, | 62 DROPPED_REASON_BAD_DANGER_TYPE = 1, |
39 DROPPED_REASON_MAX | 63 DROPPED_REASON_MAX |
40 }; | 64 }; |
41 | 65 |
42 static const char kSchema[] = | 66 static const char kSchema[] = |
(...skipping 12 matching lines...) Expand all Loading... |
55 | 79 |
56 static const char kUrlChainSchema[] = | 80 static const char kUrlChainSchema[] = |
57 "CREATE TABLE downloads_url_chains (" | 81 "CREATE TABLE downloads_url_chains (" |
58 "id INTEGER NOT NULL," // downloads.id. | 82 "id INTEGER NOT NULL," // downloads.id. |
59 "chain_index INTEGER NOT NULL," // Index of url in chain | 83 "chain_index INTEGER NOT NULL," // Index of url in chain |
60 // 0 is initial target, | 84 // 0 is initial target, |
61 // MAX is target after redirects. | 85 // MAX is target after redirects. |
62 "url LONGVARCHAR NOT NULL, " // URL. | 86 "url LONGVARCHAR NOT NULL, " // URL. |
63 "PRIMARY KEY (id, chain_index) )"; | 87 "PRIMARY KEY (id, chain_index) )"; |
64 | 88 |
65 // These constants and next two functions are used to allow | |
66 // DownloadItem::DownloadState and DownloadDangerType to change without | |
67 // breaking the database schema. | |
68 // They guarantee that the values of the |state| field in the database are one | |
69 // of the values returned by StateToInt, and that the values of the |state| | |
70 // field of the DownloadRows returned by QueryDownloads() are one of the values | |
71 // returned by IntToState(). | |
72 static const int kStateInvalid = -1; | |
73 static const int kStateInProgress = 0; | |
74 static const int kStateComplete = 1; | |
75 static const int kStateCancelled = 2; | |
76 static const int kStateBug140687 = 3; | |
77 static const int kStateInterrupted = 4; | |
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 | |
89 int StateToInt(DownloadItem::DownloadState state) { | 89 int StateToInt(DownloadItem::DownloadState state) { |
90 switch (state) { | 90 switch (state) { |
91 case DownloadItem::IN_PROGRESS: return kStateInProgress; | 91 case DownloadItem::IN_PROGRESS: return DownloadDatabase::kStateInProgress; |
92 case DownloadItem::COMPLETE: return kStateComplete; | 92 case DownloadItem::COMPLETE: return DownloadDatabase::kStateComplete; |
93 case DownloadItem::CANCELLED: return kStateCancelled; | 93 case DownloadItem::CANCELLED: return DownloadDatabase::kStateCancelled; |
94 case DownloadItem::INTERRUPTED: return kStateInterrupted; | 94 case DownloadItem::INTERRUPTED: return DownloadDatabase::kStateInterrupted; |
95 case DownloadItem::MAX_DOWNLOAD_STATE: | 95 case DownloadItem::MAX_DOWNLOAD_STATE: |
96 NOTREACHED(); | 96 NOTREACHED(); |
97 return kStateInvalid; | 97 return DownloadDatabase::kStateInvalid; |
98 } | 98 } |
99 NOTREACHED(); | 99 NOTREACHED(); |
100 return kStateInvalid; | 100 return DownloadDatabase::kStateInvalid; |
101 } | 101 } |
102 | 102 |
103 DownloadItem::DownloadState IntToState(int state) { | 103 DownloadItem::DownloadState IntToState(int state) { |
104 switch (state) { | 104 switch (state) { |
105 case kStateInProgress: return DownloadItem::IN_PROGRESS; | 105 case DownloadDatabase::kStateInProgress: return DownloadItem::IN_PROGRESS; |
106 case kStateComplete: return DownloadItem::COMPLETE; | 106 case DownloadDatabase::kStateComplete: return DownloadItem::COMPLETE; |
107 case kStateCancelled: return DownloadItem::CANCELLED; | 107 case DownloadDatabase::kStateCancelled: return DownloadItem::CANCELLED; |
108 // We should not need kStateBug140687 here because MigrateDownloadsState() | 108 // We should not need kStateBug140687 here because MigrateDownloadsState() |
109 // is called in HistoryDatabase::Init(). | 109 // is called in HistoryDatabase::Init(). |
110 case kStateInterrupted: return DownloadItem::INTERRUPTED; | 110 case DownloadDatabase::kStateInterrupted: return DownloadItem::INTERRUPTED; |
111 default: return DownloadItem::MAX_DOWNLOAD_STATE; | 111 default: return DownloadItem::MAX_DOWNLOAD_STATE; |
112 } | 112 } |
113 } | 113 } |
114 | 114 |
115 int DangerTypeToInt(content::DownloadDangerType danger_type) { | 115 int DangerTypeToInt(content::DownloadDangerType danger_type) { |
116 switch (danger_type) { | 116 switch (danger_type) { |
117 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: | 117 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: |
118 return kDangerTypeNotDangerous; | 118 return DownloadDatabase::kDangerTypeNotDangerous; |
119 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: | 119 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: |
120 return kDangerTypeDangerousFile; | 120 return DownloadDatabase::kDangerTypeDangerousFile; |
121 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: | 121 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: |
122 return kDangerTypeDangerousUrl; | 122 return DownloadDatabase::kDangerTypeDangerousUrl; |
123 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: | 123 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: |
124 return kDangerTypeDangerousContent; | 124 return DownloadDatabase::kDangerTypeDangerousContent; |
125 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: | 125 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: |
126 return kDangerTypeMaybeDangerousContent; | 126 return DownloadDatabase::kDangerTypeMaybeDangerousContent; |
127 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: | 127 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: |
128 return kDangerTypeUncommonContent; | 128 return DownloadDatabase::kDangerTypeUncommonContent; |
129 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: | 129 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: |
130 return kDangerTypeUserValidated; | 130 return DownloadDatabase::kDangerTypeUserValidated; |
131 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: | 131 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: |
132 return kDangerTypeDangerousHost; | 132 return DownloadDatabase::kDangerTypeDangerousHost; |
133 case content::DOWNLOAD_DANGER_TYPE_MAX: | 133 case content::DOWNLOAD_DANGER_TYPE_MAX: |
134 NOTREACHED(); | 134 NOTREACHED(); |
135 return kDangerTypeInvalid; | 135 return DownloadDatabase::kDangerTypeInvalid; |
136 } | 136 } |
137 NOTREACHED(); | 137 NOTREACHED(); |
138 return kDangerTypeInvalid; | 138 return DownloadDatabase::kDangerTypeInvalid; |
139 } | 139 } |
140 | 140 |
141 content::DownloadDangerType IntToDangerType(int danger_type) { | 141 content::DownloadDangerType IntToDangerType(int danger_type) { |
142 switch (danger_type) { | 142 switch (danger_type) { |
143 case kDangerTypeNotDangerous: | 143 case DownloadDatabase::kDangerTypeNotDangerous: |
144 return content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS; | 144 return content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS; |
145 case kDangerTypeDangerousFile: | 145 case DownloadDatabase::kDangerTypeDangerousFile: |
146 return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE; | 146 return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE; |
147 case kDangerTypeDangerousUrl: | 147 case DownloadDatabase::kDangerTypeDangerousUrl: |
148 return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL; | 148 return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL; |
149 case kDangerTypeDangerousContent: | 149 case DownloadDatabase::kDangerTypeDangerousContent: |
150 return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT; | 150 return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT; |
151 case kDangerTypeMaybeDangerousContent: | 151 case DownloadDatabase::kDangerTypeMaybeDangerousContent: |
152 return content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT; | 152 return content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT; |
153 case kDangerTypeUncommonContent: | 153 case DownloadDatabase::kDangerTypeUncommonContent: |
154 return content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT; | 154 return content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT; |
155 case kDangerTypeUserValidated: | 155 case DownloadDatabase::kDangerTypeUserValidated: |
156 return content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED; | 156 return content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED; |
157 case kDangerTypeDangerousHost: | 157 case DownloadDatabase::kDangerTypeDangerousHost: |
158 return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST; | 158 return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST; |
159 default: | 159 default: |
160 return content::DOWNLOAD_DANGER_TYPE_MAX; | 160 return content::DOWNLOAD_DANGER_TYPE_MAX; |
161 } | 161 } |
162 } | 162 } |
163 | 163 |
164 #if defined(OS_POSIX) | 164 #if defined(OS_POSIX) |
165 | 165 |
166 // 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. |
167 void BindFilePath(sql::Statement& statement, const base::FilePath& path, | 167 void BindFilePath(sql::Statement& statement, const base::FilePath& path, |
(...skipping 20 matching lines...) Expand all Loading... |
188 // Key in the meta_table containing the next id to use for a new download in | 188 // Key in the meta_table containing the next id to use for a new download in |
189 // this profile. | 189 // this profile. |
190 static const char kNextDownloadId[] = "next_download_id"; | 190 static const char kNextDownloadId[] = "next_download_id"; |
191 | 191 |
192 } // namespace | 192 } // namespace |
193 | 193 |
194 DownloadDatabase::DownloadDatabase() | 194 DownloadDatabase::DownloadDatabase() |
195 : owning_thread_set_(false), | 195 : owning_thread_set_(false), |
196 owning_thread_(0), | 196 owning_thread_(0), |
197 next_id_(0), | 197 next_id_(0), |
198 next_db_handle_(0) { | 198 next_db_handle_(0), |
| 199 in_progress_entry_cleanup_completed_(false) { |
199 } | 200 } |
200 | 201 |
201 DownloadDatabase::~DownloadDatabase() { | 202 DownloadDatabase::~DownloadDatabase() { |
202 } | 203 } |
203 | 204 |
204 bool DownloadDatabase::EnsureColumnExists( | 205 bool DownloadDatabase::EnsureColumnExists( |
205 const std::string& name, const std::string& type) { | 206 const std::string& name, const std::string& type) { |
206 std::string add_col = "ALTER TABLE downloads ADD COLUMN " + name + " " + type; | 207 std::string add_col = "ALTER TABLE downloads ADD COLUMN " + name + " " + type; |
207 return GetDB().DoesColumnExist("downloads", name.c_str()) || | 208 return GetDB().DoesColumnExist("downloads", name.c_str()) || |
208 GetDB().Execute(add_col.c_str()); | 209 GetDB().Execute(add_col.c_str()); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema)); | 277 GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema)); |
277 } | 278 } |
278 } | 279 } |
279 | 280 |
280 bool DownloadDatabase::DropDownloadTable() { | 281 bool DownloadDatabase::DropDownloadTable() { |
281 return GetDB().Execute("DROP TABLE downloads"); | 282 return GetDB().Execute("DROP TABLE downloads"); |
282 } | 283 } |
283 | 284 |
284 void DownloadDatabase::QueryDownloads( | 285 void DownloadDatabase::QueryDownloads( |
285 std::vector<DownloadRow>* results) { | 286 std::vector<DownloadRow>* results) { |
| 287 if (!in_progress_entry_cleanup_completed_) |
| 288 CleanUpInProgressEntries(); |
| 289 |
286 results->clear(); | 290 results->clear(); |
287 if (next_db_handle_ < 1) | 291 if (next_db_handle_ < 1) |
288 next_db_handle_ = 1; | 292 next_db_handle_ = 1; |
289 std::set<int64> db_handles; | 293 std::set<int64> db_handles; |
290 | 294 |
291 std::map<DownloadID, DownloadRow*> info_map; | 295 std::map<DownloadID, DownloadRow*> info_map; |
292 | 296 |
293 sql::Statement statement_main(GetDB().GetCachedStatement(SQL_FROM_HERE, | 297 sql::Statement statement_main(GetDB().GetCachedStatement(SQL_FROM_HERE, |
294 "SELECT id, current_path, target_path, start_time, received_bytes, " | 298 "SELECT id, current_path, target_path, start_time, received_bytes, " |
295 "total_bytes, state, danger_type, interrupt_reason, end_time, opened " | 299 "total_bytes, state, danger_type, interrupt_reason, end_time, opened " |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 for (std::map<DownloadID, DownloadRow*>::iterator | 391 for (std::map<DownloadID, DownloadRow*>::iterator |
388 it = info_map.begin(); it != info_map.end(); ++it) { | 392 it = info_map.begin(); it != info_map.end(); ++it) { |
389 // Copy the contents of the stored info. | 393 // Copy the contents of the stored info. |
390 results->push_back(*it->second); | 394 results->push_back(*it->second); |
391 delete it->second; | 395 delete it->second; |
392 it->second = NULL; | 396 it->second = NULL; |
393 } | 397 } |
394 } | 398 } |
395 | 399 |
396 bool DownloadDatabase::UpdateDownload(const DownloadRow& data) { | 400 bool DownloadDatabase::UpdateDownload(const DownloadRow& data) { |
| 401 if (!in_progress_entry_cleanup_completed_) |
| 402 CleanUpInProgressEntries(); |
| 403 |
397 DCHECK(data.db_handle > 0); | 404 DCHECK(data.db_handle > 0); |
398 int state = StateToInt(data.state); | 405 int state = StateToInt(data.state); |
399 if (state == kStateInvalid) { | 406 if (state == kStateInvalid) { |
400 NOTREACHED(); | 407 NOTREACHED(); |
401 return false; | 408 return false; |
402 } | 409 } |
403 int danger_type = DangerTypeToInt(data.danger_type); | 410 int danger_type = DangerTypeToInt(data.danger_type); |
404 if (danger_type == kDangerTypeInvalid) { | 411 if (danger_type == kDangerTypeInvalid) { |
405 NOTREACHED(); | 412 NOTREACHED(); |
406 return false; | 413 return false; |
(...skipping 12 matching lines...) Expand all Loading... |
419 statement.BindInt(column++, danger_type); | 426 statement.BindInt(column++, danger_type); |
420 statement.BindInt(column++, static_cast<int>(data.interrupt_reason)); | 427 statement.BindInt(column++, static_cast<int>(data.interrupt_reason)); |
421 statement.BindInt64(column++, data.end_time.ToInternalValue()); | 428 statement.BindInt64(column++, data.end_time.ToInternalValue()); |
422 statement.BindInt(column++, data.total_bytes); | 429 statement.BindInt(column++, data.total_bytes); |
423 statement.BindInt(column++, (data.opened ? 1 : 0)); | 430 statement.BindInt(column++, (data.opened ? 1 : 0)); |
424 statement.BindInt64(column++, data.db_handle); | 431 statement.BindInt64(column++, data.db_handle); |
425 | 432 |
426 return statement.Run(); | 433 return statement.Run(); |
427 } | 434 } |
428 | 435 |
429 bool DownloadDatabase::CleanUpInProgressEntries() { | 436 void DownloadDatabase::CleanUpInProgressEntries() { |
430 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 437 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
431 "UPDATE downloads SET state=? WHERE state=?")); | 438 "UPDATE downloads SET state=?, interrupt_reason=? WHERE state=?")); |
432 statement.BindInt(0, kStateCancelled); | 439 statement.BindInt(0, kStateInterrupted); |
433 statement.BindInt(1, kStateInProgress); | 440 statement.BindInt(1, content::DOWNLOAD_INTERRUPT_REASON_CRASH); |
| 441 statement.BindInt(2, kStateInProgress); |
434 | 442 |
435 return statement.Run(); | 443 statement.Run(); |
| 444 in_progress_entry_cleanup_completed_ = true; |
436 } | 445 } |
437 | 446 |
438 int64 DownloadDatabase::CreateDownload( | 447 int64 DownloadDatabase::CreateDownload( |
439 const DownloadRow& info) { | 448 const DownloadRow& info) { |
| 449 if (!in_progress_entry_cleanup_completed_) |
| 450 CleanUpInProgressEntries(); |
| 451 |
440 if (next_db_handle_ == 0) { | 452 if (next_db_handle_ == 0) { |
441 // This is unlikely. All current known tests and users already call | 453 // This is unlikely. All current known tests and users already call |
442 // QueryDownloads() before CreateDownload(). | 454 // QueryDownloads() before CreateDownload(). |
443 std::vector<DownloadRow> results; | 455 std::vector<DownloadRow> results; |
444 QueryDownloads(&results); | 456 QueryDownloads(&results); |
445 CHECK_NE(0, next_db_handle_); | 457 CHECK_NE(0, next_db_handle_); |
446 } | 458 } |
447 | 459 |
448 int state = StateToInt(info.state); | 460 int state = StateToInt(info.state); |
449 if (state == kStateInvalid) | 461 if (state == kStateInvalid) |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 statement_insert_chain.Reset(true); | 510 statement_insert_chain.Reset(true); |
499 } | 511 } |
500 | 512 |
501 // TODO(benjhayden) if(info.id>next_id_){setvalue;next_id_=info.id;} | 513 // TODO(benjhayden) if(info.id>next_id_){setvalue;next_id_=info.id;} |
502 GetMetaTable().SetValue(kNextDownloadId, ++next_id_); | 514 GetMetaTable().SetValue(kNextDownloadId, ++next_id_); |
503 | 515 |
504 return db_handle; | 516 return db_handle; |
505 } | 517 } |
506 | 518 |
507 void DownloadDatabase::RemoveDownload(int64 handle) { | 519 void DownloadDatabase::RemoveDownload(int64 handle) { |
| 520 if (!in_progress_entry_cleanup_completed_) |
| 521 CleanUpInProgressEntries(); |
| 522 |
508 sql::Statement downloads_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 523 sql::Statement downloads_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
509 "DELETE FROM downloads WHERE id=?")); | 524 "DELETE FROM downloads WHERE id=?")); |
510 downloads_statement.BindInt64(0, handle); | 525 downloads_statement.BindInt64(0, handle); |
511 downloads_statement.Run(); | 526 downloads_statement.Run(); |
512 | 527 |
513 sql::Statement urlchain_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 528 sql::Statement urlchain_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
514 "DELETE FROM downloads_url_chains WHERE id=?")); | 529 "DELETE FROM downloads_url_chains WHERE id=?")); |
515 urlchain_statement.BindInt64(0, handle); | 530 urlchain_statement.BindInt64(0, handle); |
516 urlchain_statement.Run(); | 531 urlchain_statement.Run(); |
517 } | 532 } |
518 | 533 |
519 int DownloadDatabase::CountDownloads() { | 534 int DownloadDatabase::CountDownloads() { |
| 535 if (!in_progress_entry_cleanup_completed_) |
| 536 CleanUpInProgressEntries(); |
| 537 |
520 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 538 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
521 "SELECT count(*) from downloads")); | 539 "SELECT count(*) from downloads")); |
522 statement.Step(); | 540 statement.Step(); |
523 return statement.ColumnInt(0); | 541 return statement.ColumnInt(0); |
524 } | 542 } |
525 | 543 |
526 } // namespace history | 544 } // namespace history |
OLD | NEW |