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 |