| 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 |