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 "components/history/core/browser/download_database.h" | 5 #include "components/history/core/browser/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 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") && | 223 return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") && |
224 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0"); | 224 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0"); |
225 } else { | 225 } else { |
226 // If the "downloads" table doesn't exist, the downloads_url_chain | 226 // If the "downloads" table doesn't exist, the downloads_url_chain |
227 // table better not. | 227 // table better not. |
228 return (!GetDB().DoesTableExist("downloads_url_chain") && | 228 return (!GetDB().DoesTableExist("downloads_url_chain") && |
229 GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema)); | 229 GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema)); |
230 } | 230 } |
231 } | 231 } |
232 | 232 |
233 uint32 DownloadDatabase::GetNextDownloadId() { | 233 uint32_t DownloadDatabase::GetNextDownloadId() { |
234 sql::Statement select_max_id(GetDB().GetUniqueStatement( | 234 sql::Statement select_max_id(GetDB().GetUniqueStatement( |
235 "SELECT max(id) FROM downloads")); | 235 "SELECT max(id) FROM downloads")); |
236 bool result = select_max_id.Step(); | 236 bool result = select_max_id.Step(); |
237 DCHECK(result); | 237 DCHECK(result); |
238 // If there are zero records in the downloads table, then max(id) will | 238 // If there are zero records in the downloads table, then max(id) will |
239 // return 0 = kInvalidDownloadId, so GetNextDownloadId() will set | 239 // return 0 = kInvalidDownloadId, so GetNextDownloadId() will set |
240 // *id = kInvalidDownloadId + 1. | 240 // *id = kInvalidDownloadId + 1. |
241 // | 241 // |
242 // If there is at least one record but all of the |id|s are | 242 // If there is at least one record but all of the |id|s are |
243 // <= kInvalidDownloadId, then max(id) will return <= kInvalidDownloadId, | 243 // <= kInvalidDownloadId, then max(id) will return <= kInvalidDownloadId, |
244 // so GetNextDownloadId() should return kInvalidDownloadId + 1. | 244 // so GetNextDownloadId() should return kInvalidDownloadId + 1. |
245 // | 245 // |
246 // Note that any records with |id <= kInvalidDownloadId| will be dropped in | 246 // Note that any records with |id <= kInvalidDownloadId| will be dropped in |
247 // QueryDownloads(). | 247 // QueryDownloads(). |
248 // | 248 // |
249 // SQLITE doesn't have unsigned integers. | 249 // SQLITE doesn't have unsigned integers. |
250 return 1 + static_cast<uint32>(std::max( | 250 return 1 + static_cast<uint32_t>( |
251 static_cast<int64>(kInvalidDownloadId), | 251 std::max(static_cast<int64_t>(kInvalidDownloadId), |
252 select_max_id.ColumnInt64(0))); | 252 select_max_id.ColumnInt64(0))); |
253 } | 253 } |
254 | 254 |
255 bool DownloadDatabase::DropDownloadTable() { | 255 bool DownloadDatabase::DropDownloadTable() { |
256 return GetDB().Execute("DROP TABLE downloads"); | 256 return GetDB().Execute("DROP TABLE downloads"); |
257 } | 257 } |
258 | 258 |
259 void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) { | 259 void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) { |
260 EnsureInProgressEntriesCleanedUp(); | 260 EnsureInProgressEntriesCleanedUp(); |
261 | 261 |
262 results->clear(); | 262 results->clear(); |
263 std::set<uint32> ids; | 263 std::set<uint32_t> ids; |
264 | 264 |
265 std::map<uint32, DownloadRow*> info_map; | 265 std::map<uint32_t, DownloadRow*> info_map; |
266 | 266 |
267 sql::Statement statement_main(GetDB().GetCachedStatement(SQL_FROM_HERE, | 267 sql::Statement statement_main(GetDB().GetCachedStatement(SQL_FROM_HERE, |
268 "SELECT id, current_path, target_path, " | 268 "SELECT id, current_path, target_path, " |
269 "mime_type, original_mime_type, " | 269 "mime_type, original_mime_type, " |
270 "start_time, received_bytes, " | 270 "start_time, received_bytes, " |
271 "total_bytes, state, danger_type, interrupt_reason, end_time, opened, " | 271 "total_bytes, state, danger_type, interrupt_reason, end_time, opened, " |
272 "referrer, by_ext_id, by_ext_name, etag, last_modified " | 272 "referrer, by_ext_id, by_ext_name, etag, last_modified " |
273 "FROM downloads ORDER BY start_time")); | 273 "FROM downloads ORDER BY start_time")); |
274 | 274 |
275 while (statement_main.Step()) { | 275 while (statement_main.Step()) { |
276 scoped_ptr<DownloadRow> info(new DownloadRow()); | 276 scoped_ptr<DownloadRow> info(new DownloadRow()); |
277 int column = 0; | 277 int column = 0; |
278 | 278 |
279 // SQLITE does not have unsigned integers, so explicitly handle negative | 279 // SQLITE does not have unsigned integers, so explicitly handle negative |
280 // |id|s instead of casting them to very large uint32s, which would break | 280 // |id|s instead of casting them to very large uint32s, which would break |
281 // the max(id) logic in GetNextDownloadId(). | 281 // the max(id) logic in GetNextDownloadId(). |
282 int64 signed_id = statement_main.ColumnInt64(column++); | 282 int64_t signed_id = statement_main.ColumnInt64(column++); |
283 info->id = IntToDownloadId(signed_id); | 283 info->id = IntToDownloadId(signed_id); |
284 info->current_path = ColumnFilePath(statement_main, column++); | 284 info->current_path = ColumnFilePath(statement_main, column++); |
285 info->target_path = ColumnFilePath(statement_main, column++); | 285 info->target_path = ColumnFilePath(statement_main, column++); |
286 info->mime_type = statement_main.ColumnString(column++); | 286 info->mime_type = statement_main.ColumnString(column++); |
287 info->original_mime_type = statement_main.ColumnString(column++); | 287 info->original_mime_type = statement_main.ColumnString(column++); |
288 info->start_time = | 288 info->start_time = |
289 base::Time::FromInternalValue(statement_main.ColumnInt64(column++)); | 289 base::Time::FromInternalValue(statement_main.ColumnInt64(column++)); |
290 info->received_bytes = statement_main.ColumnInt64(column++); | 290 info->received_bytes = statement_main.ColumnInt64(column++); |
291 info->total_bytes = statement_main.ColumnInt64(column++); | 291 info->total_bytes = statement_main.ColumnInt64(column++); |
292 int state = statement_main.ColumnInt(column++); | 292 int state = statement_main.ColumnInt(column++); |
293 info->state = IntToDownloadState(state); | 293 info->state = IntToDownloadState(state); |
294 if (info->state == DownloadState::INVALID) | 294 if (info->state == DownloadState::INVALID) |
295 UMA_HISTOGRAM_COUNTS("Download.DatabaseInvalidState", state); | 295 UMA_HISTOGRAM_COUNTS("Download.DatabaseInvalidState", state); |
296 info->danger_type = | 296 info->danger_type = |
297 IntToDownloadDangerType(statement_main.ColumnInt(column++)); | 297 IntToDownloadDangerType(statement_main.ColumnInt(column++)); |
298 info->interrupt_reason = | 298 info->interrupt_reason = |
299 IntToDownloadInterruptReason(statement_main.ColumnInt(column++)); | 299 IntToDownloadInterruptReason(statement_main.ColumnInt(column++)); |
300 info->end_time = | 300 info->end_time = |
301 base::Time::FromInternalValue(statement_main.ColumnInt64(column++)); | 301 base::Time::FromInternalValue(statement_main.ColumnInt64(column++)); |
302 info->opened = statement_main.ColumnInt(column++) != 0; | 302 info->opened = statement_main.ColumnInt(column++) != 0; |
303 info->referrer_url = GURL(statement_main.ColumnString(column++)); | 303 info->referrer_url = GURL(statement_main.ColumnString(column++)); |
304 info->by_ext_id = statement_main.ColumnString(column++); | 304 info->by_ext_id = statement_main.ColumnString(column++); |
305 info->by_ext_name = statement_main.ColumnString(column++); | 305 info->by_ext_name = statement_main.ColumnString(column++); |
306 info->etag = statement_main.ColumnString(column++); | 306 info->etag = statement_main.ColumnString(column++); |
307 info->last_modified = statement_main.ColumnString(column++); | 307 info->last_modified = statement_main.ColumnString(column++); |
308 | 308 |
309 // If the record is corrupted, note that and drop it. | 309 // If the record is corrupted, note that and drop it. |
310 // http://crbug.com/251269 | 310 // http://crbug.com/251269 |
311 DroppedReason dropped_reason = DROPPED_REASON_MAX; | 311 DroppedReason dropped_reason = DROPPED_REASON_MAX; |
312 if (signed_id <= static_cast<int64>(kInvalidDownloadId)) { | 312 if (signed_id <= static_cast<int64_t>(kInvalidDownloadId)) { |
313 // SQLITE doesn't have unsigned integers. | 313 // SQLITE doesn't have unsigned integers. |
314 dropped_reason = DROPPED_REASON_BAD_ID; | 314 dropped_reason = DROPPED_REASON_BAD_ID; |
315 } else if (!ids.insert(info->id).second) { | 315 } else if (!ids.insert(info->id).second) { |
316 dropped_reason = DROPPED_REASON_DUPLICATE_ID; | 316 dropped_reason = DROPPED_REASON_DUPLICATE_ID; |
317 NOTREACHED() << info->id; | 317 NOTREACHED() << info->id; |
318 } else if (info->state == DownloadState::INVALID) { | 318 } else if (info->state == DownloadState::INVALID) { |
319 dropped_reason = DROPPED_REASON_BAD_STATE; | 319 dropped_reason = DROPPED_REASON_BAD_STATE; |
320 } else if (info->danger_type == DownloadDangerType::INVALID) { | 320 } else if (info->danger_type == DownloadDangerType::INVALID) { |
321 dropped_reason = DROPPED_REASON_BAD_DANGER_TYPE; | 321 dropped_reason = DROPPED_REASON_BAD_DANGER_TYPE; |
322 } | 322 } |
323 if (dropped_reason != DROPPED_REASON_MAX) { | 323 if (dropped_reason != DROPPED_REASON_MAX) { |
324 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseRecordDropped", | 324 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseRecordDropped", |
325 dropped_reason, | 325 dropped_reason, |
326 DROPPED_REASON_MAX + 1); | 326 DROPPED_REASON_MAX + 1); |
327 } else { | 327 } else { |
328 DCHECK(!ContainsKey(info_map, info->id)); | 328 DCHECK(!ContainsKey(info_map, info->id)); |
329 uint32 id = info->id; | 329 uint32_t id = info->id; |
330 info_map[id] = info.release(); | 330 info_map[id] = info.release(); |
331 } | 331 } |
332 } | 332 } |
333 | 333 |
334 sql::Statement statement_chain(GetDB().GetCachedStatement( | 334 sql::Statement statement_chain(GetDB().GetCachedStatement( |
335 SQL_FROM_HERE, | 335 SQL_FROM_HERE, |
336 "SELECT id, chain_index, url FROM downloads_url_chains " | 336 "SELECT id, chain_index, url FROM downloads_url_chains " |
337 "ORDER BY id, chain_index")); | 337 "ORDER BY id, chain_index")); |
338 | 338 |
339 while (statement_chain.Step()) { | 339 while (statement_chain.Step()) { |
340 int column = 0; | 340 int column = 0; |
341 // See the comment above about SQLITE lacking unsigned integers. | 341 // See the comment above about SQLITE lacking unsigned integers. |
342 int64 signed_id = statement_chain.ColumnInt64(column++); | 342 int64_t signed_id = statement_chain.ColumnInt64(column++); |
343 int chain_index = statement_chain.ColumnInt(column++); | 343 int chain_index = statement_chain.ColumnInt(column++); |
344 | 344 |
345 if (signed_id <= static_cast<int64>(kInvalidDownloadId)) | 345 if (signed_id <= static_cast<int64_t>(kInvalidDownloadId)) |
346 continue; | 346 continue; |
347 uint32 id = IntToDownloadId(signed_id); | 347 uint32_t id = IntToDownloadId(signed_id); |
348 | 348 |
349 // Note that these DCHECKs may trip as a result of corrupted databases. | 349 // Note that these DCHECKs may trip as a result of corrupted databases. |
350 // We have them because in debug builds the chances are higher there's | 350 // We have them because in debug builds the chances are higher there's |
351 // an actual bug than that the database is corrupt, but we handle the | 351 // an actual bug than that the database is corrupt, but we handle the |
352 // DB corruption case in production code. | 352 // DB corruption case in production code. |
353 | 353 |
354 // Confirm the id has already been seen--if it hasn't, discard the | 354 // Confirm the id has already been seen--if it hasn't, discard the |
355 // record. | 355 // record. |
356 DCHECK(ContainsKey(info_map, id)); | 356 DCHECK(ContainsKey(info_map, id)); |
357 if (!ContainsKey(info_map, id)) | 357 if (!ContainsKey(info_map, id)) |
358 continue; | 358 continue; |
359 | 359 |
360 // Confirm all previous URLs in the chain have already been seen; | 360 // Confirm all previous URLs in the chain have already been seen; |
361 // if not, fill in with null or discard record. | 361 // if not, fill in with null or discard record. |
362 int current_chain_size = static_cast<int>(info_map[id]->url_chain.size()); | 362 int current_chain_size = static_cast<int>(info_map[id]->url_chain.size()); |
363 std::vector<GURL>* url_chain(&info_map[id]->url_chain); | 363 std::vector<GURL>* url_chain(&info_map[id]->url_chain); |
364 DCHECK_EQ(chain_index, current_chain_size); | 364 DCHECK_EQ(chain_index, current_chain_size); |
365 while (current_chain_size < chain_index) { | 365 while (current_chain_size < chain_index) { |
366 url_chain->push_back(GURL()); | 366 url_chain->push_back(GURL()); |
367 current_chain_size++; | 367 current_chain_size++; |
368 } | 368 } |
369 if (current_chain_size > chain_index) | 369 if (current_chain_size > chain_index) |
370 continue; | 370 continue; |
371 | 371 |
372 // Save the record. | 372 // Save the record. |
373 url_chain->push_back(GURL(statement_chain.ColumnString(2))); | 373 url_chain->push_back(GURL(statement_chain.ColumnString(2))); |
374 } | 374 } |
375 | 375 |
376 for (std::map<uint32, DownloadRow*>::iterator | 376 for (std::map<uint32_t, DownloadRow*>::iterator it = info_map.begin(); |
377 it = info_map.begin(); it != info_map.end(); ++it) { | 377 it != info_map.end(); ++it) { |
378 DownloadRow* row = it->second; | 378 DownloadRow* row = it->second; |
379 bool empty_url_chain = row->url_chain.empty(); | 379 bool empty_url_chain = row->url_chain.empty(); |
380 UMA_HISTOGRAM_BOOLEAN("Download.DatabaseEmptyUrlChain", empty_url_chain); | 380 UMA_HISTOGRAM_BOOLEAN("Download.DatabaseEmptyUrlChain", empty_url_chain); |
381 if (empty_url_chain) { | 381 if (empty_url_chain) { |
382 RemoveDownload(row->id); | 382 RemoveDownload(row->id); |
383 } else { | 383 } else { |
384 // Copy the contents of the stored info. | 384 // Copy the contents of the stored info. |
385 results->push_back(*row); | 385 results->push_back(*row); |
386 } | 386 } |
387 delete row; | 387 delete row; |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
534 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainInsertError", | 534 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainInsertError", |
535 GetDB().GetErrorCode() & 0xff, 50); | 535 GetDB().GetErrorCode() & 0xff, 50); |
536 RemoveDownload(info.id); | 536 RemoveDownload(info.id); |
537 return false; | 537 return false; |
538 } | 538 } |
539 statement_insert_chain.Reset(true); | 539 statement_insert_chain.Reset(true); |
540 } | 540 } |
541 return true; | 541 return true; |
542 } | 542 } |
543 | 543 |
544 void DownloadDatabase::RemoveDownload(uint32 id) { | 544 void DownloadDatabase::RemoveDownload(uint32_t id) { |
545 EnsureInProgressEntriesCleanedUp(); | 545 EnsureInProgressEntriesCleanedUp(); |
546 | 546 |
547 sql::Statement downloads_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 547 sql::Statement downloads_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
548 "DELETE FROM downloads WHERE id=?")); | 548 "DELETE FROM downloads WHERE id=?")); |
549 downloads_statement.BindInt(0, id); | 549 downloads_statement.BindInt(0, id); |
550 if (!downloads_statement.Run()) { | 550 if (!downloads_statement.Run()) { |
551 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseMainDeleteError", | 551 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseMainDeleteError", |
552 GetDB().GetErrorCode() & 0xff, 50); | 552 GetDB().GetErrorCode() & 0xff, 50); |
553 return; | 553 return; |
554 } | 554 } |
555 RemoveDownloadURLs(id); | 555 RemoveDownloadURLs(id); |
556 } | 556 } |
557 | 557 |
558 void DownloadDatabase::RemoveDownloadURLs(uint32 id) { | 558 void DownloadDatabase::RemoveDownloadURLs(uint32_t id) { |
559 sql::Statement urlchain_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 559 sql::Statement urlchain_statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
560 "DELETE FROM downloads_url_chains WHERE id=?")); | 560 "DELETE FROM downloads_url_chains WHERE id=?")); |
561 urlchain_statement.BindInt(0, id); | 561 urlchain_statement.BindInt(0, id); |
562 if (!urlchain_statement.Run()) { | 562 if (!urlchain_statement.Run()) { |
563 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainDeleteError", | 563 UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainDeleteError", |
564 GetDB().GetErrorCode() & 0xff, 50); | 564 GetDB().GetErrorCode() & 0xff, 50); |
565 } | 565 } |
566 } | 566 } |
567 | 567 |
568 size_t DownloadDatabase::CountDownloads() { | 568 size_t DownloadDatabase::CountDownloads() { |
569 EnsureInProgressEntriesCleanedUp(); | 569 EnsureInProgressEntriesCleanedUp(); |
570 | 570 |
571 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 571 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
572 "SELECT count(*) from downloads")); | 572 "SELECT count(*) from downloads")); |
573 statement.Step(); | 573 statement.Step(); |
574 return statement.ColumnInt(0); | 574 return statement.ColumnInt(0); |
575 } | 575 } |
576 | 576 |
577 } // namespace history | 577 } // namespace history |
OLD | NEW |