Chromium Code Reviews| 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/visit_database.h" | 5 #include "chrome/browser/history/visit_database.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <map> | 9 #include <map> |
| 10 #include <set> | 10 #include <set> |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 361 // save space, we do not record those user browsed visits which would be the | 361 // save space, we do not record those user browsed visits which would be the |
| 362 // majority in this table. Only other sources are recorded. | 362 // majority in this table. Only other sources are recorded. |
| 363 // Due to the tight relationship between visit_source and visits table, they | 363 // Due to the tight relationship between visit_source and visits table, they |
| 364 // should be created and dropped at the same time. | 364 // should be created and dropped at the same time. |
| 365 if (!GetDB().DoesTableExist("visit_source")) { | 365 if (!GetDB().DoesTableExist("visit_source")) { |
| 366 if (!GetDB().Execute("CREATE TABLE visit_source(" | 366 if (!GetDB().Execute("CREATE TABLE visit_source(" |
| 367 "id INTEGER PRIMARY KEY,source INTEGER NOT NULL)")) | 367 "id INTEGER PRIMARY KEY,source INTEGER NOT NULL)")) |
| 368 return false; | 368 return false; |
| 369 } | 369 } |
| 370 | 370 |
| 371 // Visit details table contains some extra details about a visit such as | |
| 372 // the visit duration. In the future, more information such as active | |
| 373 // duration or language can be added too. | |
| 374 if (!GetDB().DoesTableExist("visit_details")) { | |
| 375 if (!GetDB().Execute("CREATE TABLE visit_details(" | |
| 376 "id INTEGER PRIMARY KEY," | |
| 377 "duration INTEGER DEFAULT 0 NOT NULL)")) | |
| 378 return false; | |
| 379 } | |
| 380 | |
| 371 // Index over url so we can quickly find visits for a page. | 381 // Index over url so we can quickly find visits for a page. |
| 372 if (!GetDB().Execute( | 382 if (!GetDB().Execute( |
| 373 "CREATE INDEX IF NOT EXISTS visits_url_index ON visits (url)")) | 383 "CREATE INDEX IF NOT EXISTS visits_url_index ON visits (url)")) |
| 374 return false; | 384 return false; |
| 375 | 385 |
| 376 // Create an index over from visits so that we can efficiently find | 386 // Create an index over from visits so that we can efficiently find |
| 377 // referrers and redirects. | 387 // referrers and redirects. |
| 378 if (!GetDB().Execute( | 388 if (!GetDB().Execute( |
| 379 "CREATE INDEX IF NOT EXISTS visits_from_index ON " | 389 "CREATE INDEX IF NOT EXISTS visits_from_index ON " |
| 380 "visits (from_visit)")) | 390 "visits (from_visit)")) |
| 381 return false; | 391 return false; |
| 382 | 392 |
| 383 // Create an index over time so that we can efficiently find the visits in a | 393 // Create an index over time so that we can efficiently find the visits in a |
| 384 // given time range (most history views are time-based). | 394 // given time range (most history views are time-based). |
| 385 if (!GetDB().Execute( | 395 if (!GetDB().Execute( |
| 386 "CREATE INDEX IF NOT EXISTS visits_time_index ON " | 396 "CREATE INDEX IF NOT EXISTS visits_time_index ON " |
| 387 "visits (visit_time)")) | 397 "visits (visit_time)")) |
| 388 return false; | 398 return false; |
| 389 | 399 |
| 390 return true; | 400 return true; |
| 391 } | 401 } |
| 392 | 402 |
| 393 bool VisitDatabase::DropVisitTable() { | 403 bool VisitDatabase::DropVisitTable() { |
| 394 // This will also drop the indices over the table. | 404 // This will also drop the indices over the table. |
| 395 return | 405 return |
| 406 GetDB().Execute("DROP TABLE IF EXISTS visit_details") && | |
| 396 GetDB().Execute("DROP TABLE IF EXISTS visit_source") && | 407 GetDB().Execute("DROP TABLE IF EXISTS visit_source") && |
| 397 GetDB().Execute("DROP TABLE visits"); | 408 GetDB().Execute("DROP TABLE visits"); |
| 398 } | 409 } |
| 399 | 410 |
| 400 // Must be in sync with HISTORY_VISIT_ROW_FIELDS. | 411 // Must be in sync with HISTORY_VISIT_ROW_FIELDS. |
| 401 // static | 412 // static |
| 402 void VisitDatabase::FillVisitRow(sql::Statement& statement, VisitRow* visit) { | 413 void VisitDatabase::FillVisitRow(sql::Statement& statement, VisitRow* visit) { |
| 403 visit->visit_id = statement.ColumnInt64(0); | 414 visit->visit_id = statement.ColumnInt64(0); |
| 404 visit->url_id = statement.ColumnInt64(1); | 415 visit->url_id = statement.ColumnInt64(1); |
| 405 visit->visit_time = base::Time::FromInternalValue(statement.ColumnInt64(2)); | 416 visit->visit_time = base::Time::FromInternalValue(statement.ColumnInt64(2)); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 447 | 458 |
| 448 if (source != SOURCE_BROWSED) { | 459 if (source != SOURCE_BROWSED) { |
| 449 // Record the source of this visit when it is not browsed. | 460 // Record the source of this visit when it is not browsed. |
| 450 sql::Statement statement1(GetDB().GetCachedStatement(SQL_FROM_HERE, | 461 sql::Statement statement1(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 451 "INSERT INTO visit_source (id, source) VALUES (?,?)")); | 462 "INSERT INTO visit_source (id, source) VALUES (?,?)")); |
| 452 statement1.BindInt64(0, visit->visit_id); | 463 statement1.BindInt64(0, visit->visit_id); |
| 453 statement1.BindInt64(1, source); | 464 statement1.BindInt64(1, source); |
| 454 | 465 |
| 455 if (!statement1.Run()) { | 466 if (!statement1.Run()) { |
| 456 VLOG(0) << "Failed to execute visit_source insert statement: " | 467 VLOG(0) << "Failed to execute visit_source insert statement: " |
| 457 << "url_id = " << visit->visit_id; | 468 << "id = " << visit->visit_id; |
| 458 return 0; | 469 return 0; |
| 459 } | 470 } |
| 460 } | 471 } |
| 461 | 472 |
| 473 // Add the visit into visit_details table as well. | |
| 474 sql::Statement statement1(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
| 475 "INSERT INTO visit_details (id, duration) VALUES (?,?)")); | |
| 476 statement1.BindInt64(0, visit->visit_id); | |
| 477 statement1.BindInt64(1, 0); | |
| 478 | |
| 479 if (!statement1.Run()) { | |
| 480 VLOG(0) << "Failed to execute visit_details insert statement: " | |
| 481 << "id = " << visit->visit_id; | |
| 482 return 0; | |
| 483 } | |
| 484 | |
| 462 return visit->visit_id; | 485 return visit->visit_id; |
| 463 } | 486 } |
| 464 | 487 |
| 465 void VisitDatabase::DeleteVisit(const VisitRow& visit) { | 488 void VisitDatabase::DeleteVisit(const VisitRow& visit) { |
| 466 // Patch around this visit. Any visits that this went to will now have their | 489 // Patch around this visit. Any visits that this went to will now have their |
| 467 // "source" be the deleted visit's source. | 490 // "source" be the deleted visit's source. |
| 468 sql::Statement update_chain(GetDB().GetCachedStatement(SQL_FROM_HERE, | 491 sql::Statement update_chain(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 469 "UPDATE visits SET from_visit=? WHERE from_visit=?")); | 492 "UPDATE visits SET from_visit=? WHERE from_visit=?")); |
| 470 update_chain.BindInt64(0, visit.referring_visit); | 493 update_chain.BindInt64(0, visit.referring_visit); |
| 471 update_chain.BindInt64(1, visit.visit_id); | 494 update_chain.BindInt64(1, visit.visit_id); |
| 472 if (!update_chain.Run()) | 495 if (!update_chain.Run()) |
| 473 return; | 496 return; |
| 474 | 497 |
| 475 // Now delete the actual visit. | 498 // Now delete the actual visit. |
| 476 sql::Statement del(GetDB().GetCachedStatement(SQL_FROM_HERE, | 499 sql::Statement del(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 477 "DELETE FROM visits WHERE id=?")); | 500 "DELETE FROM visits WHERE id=?")); |
| 478 del.BindInt64(0, visit.visit_id); | 501 del.BindInt64(0, visit.visit_id); |
| 479 if (!del.Run()) | 502 if (!del.Run()) |
| 480 return; | 503 return; |
| 481 | 504 |
| 482 // Try to delete the entry in visit_source table as well. | 505 // Try to delete the entry in visit_source table as well. |
| 483 // If the visit was browsed, there is no corresponding entry in visit_source | 506 // If the visit was browsed, there is no corresponding entry in visit_source |
| 484 // table, and nothing will be deleted. | 507 // table, and nothing will be deleted. |
| 485 del.Assign(GetDB().GetCachedStatement(SQL_FROM_HERE, | 508 del.Assign(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 486 "DELETE FROM visit_source WHERE id=?")); | 509 "DELETE FROM visit_source WHERE id=?")); |
| 487 del.BindInt64(0, visit.visit_id); | 510 del.BindInt64(0, visit.visit_id); |
| 488 del.Run(); | 511 del.Run(); |
| 512 | |
| 513 // Delete the entry in visit_details table as well. | |
| 514 // We don't care about archiving details information about visits. We will | |
| 515 // simply delete all the information for either archived or deleted visits | |
| 516 // when they are removed from visits database. | |
| 517 del.Assign(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
| 518 "DELETE FROM visit_details WHERE id=?")); | |
| 519 del.BindInt64(0, visit.visit_id); | |
| 520 del.Run(); | |
| 489 } | 521 } |
| 490 | 522 |
| 491 bool VisitDatabase::GetRowForVisit(VisitID visit_id, VisitRow* out_visit) { | 523 bool VisitDatabase::GetRowForVisit(VisitID visit_id, VisitRow* out_visit) { |
| 492 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 524 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 493 "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits WHERE id=?")); | 525 "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits WHERE id=?")); |
| 494 statement.BindInt64(0, visit_id); | 526 statement.BindInt64(0, visit_id); |
| 495 | 527 |
| 496 if (!statement.Step()) | 528 if (!statement.Step()) |
| 497 return false; | 529 return false; |
| 498 | 530 |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 835 | 867 |
| 836 // Get the source entries out of the query result. | 868 // Get the source entries out of the query result. |
| 837 while (statement.Step()) { | 869 while (statement.Step()) { |
| 838 std::pair<VisitID, VisitSource> source_entry(statement.ColumnInt64(0), | 870 std::pair<VisitID, VisitSource> source_entry(statement.ColumnInt64(0), |
| 839 static_cast<VisitSource>(statement.ColumnInt(1))); | 871 static_cast<VisitSource>(statement.ColumnInt(1))); |
| 840 sources->insert(source_entry); | 872 sources->insert(source_entry); |
| 841 } | 873 } |
| 842 } | 874 } |
| 843 } | 875 } |
| 844 | 876 |
| 877 bool VisitDatabase::UpdateVisitDetails(VisitID visit_id, | |
| 878 const base::TimeDelta duration) { | |
| 879 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
| 880 "UPDATE visit_details SET id=?,duration=? WHERE id=?")); | |
|
GeorgeY
2012/03/22 00:36:49
Why do you need to re-set |id|? - you should not d
Wei Li
2012/03/22 20:05:38
Done.
| |
| 881 statement.BindInt64(0, visit_id); | |
| 882 statement.BindInt64(1, duration.ToInternalValue()); | |
| 883 statement.BindInt64(2, visit_id); | |
| 884 | |
| 885 return statement.Run(); | |
| 886 } | |
| 887 | |
| 888 void VisitDatabase::GetVisitDetails(const VisitVector& visits, | |
| 889 VisitDetailMap* details) { | |
| 890 DCHECK(details); | |
| 891 details->clear(); | |
| 892 | |
| 893 // We query the details in batch. Here defines the batch size. | |
| 894 const size_t batch_size = 500; | |
| 895 size_t visits_size = visits.size(); | |
| 896 | |
| 897 size_t start_index = 0, end_index = 0; | |
| 898 while (end_index < visits_size) { | |
| 899 start_index = end_index; | |
| 900 end_index = end_index + batch_size < visits_size ? end_index + batch_size | |
| 901 : visits_size; | |
| 902 | |
| 903 // Compose the sql statement with a list of ids. | |
| 904 std::string sql = "SELECT id,duration FROM visit_details "; | |
| 905 sql.append("WHERE id IN ("); | |
|
GeorgeY
2012/03/22 00:36:49
Have you considered how long it would take to pars
| |
| 906 // Append all the ids in the statement. | |
| 907 for (size_t j = start_index; j < end_index; j++) { | |
| 908 if (j != start_index) | |
| 909 sql.push_back(','); | |
| 910 sql.append(base::Int64ToString(visits[j].visit_id)); | |
| 911 } | |
| 912 sql.append(") ORDER BY id"); | |
| 913 sql::Statement statement(GetDB().GetUniqueStatement(sql.c_str())); | |
| 914 | |
| 915 // Get the source entries out of the query result. | |
| 916 while (statement.Step()) { | |
| 917 VisitDetailRow row = | |
| 918 {base::TimeDelta::FromInternalValue(statement.ColumnInt64(1))}; | |
| 919 std::pair<VisitID, VisitDetailRow> entry(statement.ColumnInt64(0), row); | |
| 920 details->insert(entry); | |
| 921 } | |
| 922 } | |
| 923 } | |
| 924 | |
| 845 } // namespace history | 925 } // namespace history |
| OLD | NEW |