| 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> |
| 11 | 11 |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/string_number_conversions.h" | 13 #include "base/string_number_conversions.h" |
| 14 #include "chrome/browser/history/url_database.h" | 14 #include "chrome/browser/history/url_database.h" |
| 15 #include "chrome/browser/history/visit_filter.h" | 15 #include "chrome/browser/history/visit_filter.h" |
| 16 #include "chrome/common/url_constants.h" | 16 #include "chrome/common/url_constants.h" |
| 17 #include "content/public/common/page_transition_types.h" | 17 #include "content/public/common/page_transition_types.h" |
| 18 #include "sql/statement.h" | 18 #include "sql/statement.h" |
| 19 | 19 |
| 20 // Rows, in order, of the visit table. | 20 // Rows, in order, of the visit table. |
| 21 #define HISTORY_VISIT_ROW_FIELDS \ | 21 #define HISTORY_VISIT_ROW_FIELDS \ |
| 22 " id,url,visit_time,from_visit,transition,segment_id,is_indexed " | 22 " id,url,visit_time,from_visit,transition,segment_id,is_indexed," \ |
| 23 "visit_duration " |
| 23 | 24 |
| 24 namespace history { | 25 namespace history { |
| 25 | 26 |
| 26 VisitDatabase::VisitDatabase() { | 27 VisitDatabase::VisitDatabase() { |
| 27 } | 28 } |
| 28 | 29 |
| 29 VisitDatabase::~VisitDatabase() { | 30 VisitDatabase::~VisitDatabase() { |
| 30 } | 31 } |
| 31 | 32 |
| 32 bool VisitDatabase::InitVisitTable() { | 33 bool VisitDatabase::InitVisitTable() { |
| 33 if (!GetDB().DoesTableExist("visits")) { | 34 if (!GetDB().DoesTableExist("visits")) { |
| 34 if (!GetDB().Execute("CREATE TABLE visits(" | 35 if (!GetDB().Execute("CREATE TABLE visits(" |
| 35 "id INTEGER PRIMARY KEY," | 36 "id INTEGER PRIMARY KEY," |
| 36 "url INTEGER NOT NULL," // key of the URL this corresponds to | 37 "url INTEGER NOT NULL," // key of the URL this corresponds to |
| 37 "visit_time INTEGER NOT NULL," | 38 "visit_time INTEGER NOT NULL," |
| 38 "from_visit INTEGER," | 39 "from_visit INTEGER," |
| 39 "transition INTEGER DEFAULT 0 NOT NULL," | 40 "transition INTEGER DEFAULT 0 NOT NULL," |
| 40 "segment_id INTEGER," | 41 "segment_id INTEGER," |
| 41 // True when we have indexed data for this visit. | 42 // True when we have indexed data for this visit. |
| 42 "is_indexed BOOLEAN)")) | 43 "is_indexed BOOLEAN," |
| 44 "visit_duration INTEGER DEFAULT 0 NOT NULL)")) |
| 43 return false; | 45 return false; |
| 44 } else if (!GetDB().DoesColumnExist("visits", "is_indexed")) { | 46 } else if (!GetDB().DoesColumnExist("visits", "is_indexed")) { |
| 45 // Old versions don't have the is_indexed column, we can just add that and | 47 // Old versions don't have the is_indexed column, we can just add that and |
| 46 // not worry about different database revisions, since old ones will | 48 // not worry about different database revisions, since old ones will |
| 47 // continue to work. | 49 // continue to work. |
| 48 // | 50 // |
| 49 // TODO(brettw) this should be removed once we think everybody has been | 51 // TODO(brettw) this should be removed once we think everybody has been |
| 50 // updated (added early Mar 2008). | 52 // updated (added early Mar 2008). |
| 51 if (!GetDB().Execute("ALTER TABLE visits ADD COLUMN is_indexed BOOLEAN")) | 53 if (!GetDB().Execute("ALTER TABLE visits ADD COLUMN is_indexed BOOLEAN")) |
| 52 return false; | 54 return false; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 // Must be in sync with HISTORY_VISIT_ROW_FIELDS. | 97 // Must be in sync with HISTORY_VISIT_ROW_FIELDS. |
| 96 // static | 98 // static |
| 97 void VisitDatabase::FillVisitRow(sql::Statement& statement, VisitRow* visit) { | 99 void VisitDatabase::FillVisitRow(sql::Statement& statement, VisitRow* visit) { |
| 98 visit->visit_id = statement.ColumnInt64(0); | 100 visit->visit_id = statement.ColumnInt64(0); |
| 99 visit->url_id = statement.ColumnInt64(1); | 101 visit->url_id = statement.ColumnInt64(1); |
| 100 visit->visit_time = base::Time::FromInternalValue(statement.ColumnInt64(2)); | 102 visit->visit_time = base::Time::FromInternalValue(statement.ColumnInt64(2)); |
| 101 visit->referring_visit = statement.ColumnInt64(3); | 103 visit->referring_visit = statement.ColumnInt64(3); |
| 102 visit->transition = content::PageTransitionFromInt(statement.ColumnInt(4)); | 104 visit->transition = content::PageTransitionFromInt(statement.ColumnInt(4)); |
| 103 visit->segment_id = statement.ColumnInt64(5); | 105 visit->segment_id = statement.ColumnInt64(5); |
| 104 visit->is_indexed = !!statement.ColumnInt(6); | 106 visit->is_indexed = !!statement.ColumnInt(6); |
| 107 visit->visit_duration = |
| 108 base::TimeDelta::FromInternalValue(statement.ColumnInt64(7)); |
| 105 } | 109 } |
| 106 | 110 |
| 107 // static | 111 // static |
| 108 bool VisitDatabase::FillVisitVector(sql::Statement& statement, | 112 bool VisitDatabase::FillVisitVector(sql::Statement& statement, |
| 109 VisitVector* visits) { | 113 VisitVector* visits) { |
| 110 if (!statement.is_valid()) | 114 if (!statement.is_valid()) |
| 111 return false; | 115 return false; |
| 112 | 116 |
| 113 while (statement.Step()) { | 117 while (statement.Step()) { |
| 114 history::VisitRow visit; | 118 history::VisitRow visit; |
| 115 FillVisitRow(statement, &visit); | 119 FillVisitRow(statement, &visit); |
| 116 visits->push_back(visit); | 120 visits->push_back(visit); |
| 117 } | 121 } |
| 118 | 122 |
| 119 return statement.Succeeded(); | 123 return statement.Succeeded(); |
| 120 } | 124 } |
| 121 | 125 |
| 122 VisitID VisitDatabase::AddVisit(VisitRow* visit, VisitSource source) { | 126 VisitID VisitDatabase::AddVisit(VisitRow* visit, VisitSource source) { |
| 123 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 127 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 124 "INSERT INTO visits " | 128 "INSERT INTO visits " |
| 125 "(url, visit_time, from_visit, transition, segment_id, is_indexed) " | 129 "(url, visit_time, from_visit, transition, segment_id, is_indexed, " |
| 126 "VALUES (?,?,?,?,?,?)")); | 130 "visit_duration) VALUES (?,?,?,?,?,?,?)")); |
| 127 statement.BindInt64(0, visit->url_id); | 131 statement.BindInt64(0, visit->url_id); |
| 128 statement.BindInt64(1, visit->visit_time.ToInternalValue()); | 132 statement.BindInt64(1, visit->visit_time.ToInternalValue()); |
| 129 statement.BindInt64(2, visit->referring_visit); | 133 statement.BindInt64(2, visit->referring_visit); |
| 130 statement.BindInt64(3, visit->transition); | 134 statement.BindInt64(3, visit->transition); |
| 131 statement.BindInt64(4, visit->segment_id); | 135 statement.BindInt64(4, visit->segment_id); |
| 132 statement.BindInt64(5, visit->is_indexed); | 136 statement.BindInt64(5, visit->is_indexed); |
| 137 statement.BindInt64(6, visit->visit_duration.ToInternalValue()); |
| 133 | 138 |
| 134 if (!statement.Run()) { | 139 if (!statement.Run()) { |
| 135 VLOG(0) << "Failed to execute visit insert statement: " | 140 VLOG(0) << "Failed to execute visit insert statement: " |
| 136 << "url_id = " << visit->url_id; | 141 << "url_id = " << visit->url_id; |
| 137 return 0; | 142 return 0; |
| 138 } | 143 } |
| 139 | 144 |
| 140 visit->visit_id = GetDB().GetLastInsertRowId(); | 145 visit->visit_id = GetDB().GetLastInsertRowId(); |
| 141 | 146 |
| 142 if (source != SOURCE_BROWSED) { | 147 if (source != SOURCE_BROWSED) { |
| 143 // Record the source of this visit when it is not browsed. | 148 // Record the source of this visit when it is not browsed. |
| 144 sql::Statement statement1(GetDB().GetCachedStatement(SQL_FROM_HERE, | 149 sql::Statement statement1(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 145 "INSERT INTO visit_source (id, source) VALUES (?,?)")); | 150 "INSERT INTO visit_source (id, source) VALUES (?,?)")); |
| 146 statement1.BindInt64(0, visit->visit_id); | 151 statement1.BindInt64(0, visit->visit_id); |
| 147 statement1.BindInt64(1, source); | 152 statement1.BindInt64(1, source); |
| 148 | 153 |
| 149 if (!statement1.Run()) { | 154 if (!statement1.Run()) { |
| 150 VLOG(0) << "Failed to execute visit_source insert statement: " | 155 VLOG(0) << "Failed to execute visit_source insert statement: " |
| 151 << "url_id = " << visit->visit_id; | 156 << "id = " << visit->visit_id; |
| 152 return 0; | 157 return 0; |
| 153 } | 158 } |
| 154 } | 159 } |
| 155 | 160 |
| 156 return visit->visit_id; | 161 return visit->visit_id; |
| 157 } | 162 } |
| 158 | 163 |
| 159 void VisitDatabase::DeleteVisit(const VisitRow& visit) { | 164 void VisitDatabase::DeleteVisit(const VisitRow& visit) { |
| 160 // Patch around this visit. Any visits that this went to will now have their | 165 // Patch around this visit. Any visits that this went to will now have their |
| 161 // "source" be the deleted visit's source. | 166 // "source" be the deleted visit's source. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 } | 206 } |
| 202 | 207 |
| 203 bool VisitDatabase::UpdateVisitRow(const VisitRow& visit) { | 208 bool VisitDatabase::UpdateVisitRow(const VisitRow& visit) { |
| 204 // Don't store inconsistent data to the database. | 209 // Don't store inconsistent data to the database. |
| 205 DCHECK_NE(visit.visit_id, visit.referring_visit); | 210 DCHECK_NE(visit.visit_id, visit.referring_visit); |
| 206 if (visit.visit_id == visit.referring_visit) | 211 if (visit.visit_id == visit.referring_visit) |
| 207 return false; | 212 return false; |
| 208 | 213 |
| 209 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 214 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 210 "UPDATE visits SET " | 215 "UPDATE visits SET " |
| 211 "url=?,visit_time=?,from_visit=?,transition=?,segment_id=?,is_indexed=? " | 216 "url=?,visit_time=?,from_visit=?,transition=?,segment_id=?,is_indexed=?," |
| 212 "WHERE id=?")); | 217 "visit_duration=? WHERE id=?")); |
| 213 statement.BindInt64(0, visit.url_id); | 218 statement.BindInt64(0, visit.url_id); |
| 214 statement.BindInt64(1, visit.visit_time.ToInternalValue()); | 219 statement.BindInt64(1, visit.visit_time.ToInternalValue()); |
| 215 statement.BindInt64(2, visit.referring_visit); | 220 statement.BindInt64(2, visit.referring_visit); |
| 216 statement.BindInt64(3, visit.transition); | 221 statement.BindInt64(3, visit.transition); |
| 217 statement.BindInt64(4, visit.segment_id); | 222 statement.BindInt64(4, visit.segment_id); |
| 218 statement.BindInt64(5, visit.is_indexed); | 223 statement.BindInt64(5, visit.is_indexed); |
| 219 statement.BindInt64(6, visit.visit_id); | 224 statement.BindInt64(6, visit.visit_duration.ToInternalValue()); |
| 225 statement.BindInt64(7, visit.visit_id); |
| 220 | 226 |
| 221 return statement.Run(); | 227 return statement.Run(); |
| 222 } | 228 } |
| 223 | 229 |
| 224 bool VisitDatabase::GetVisitsForURL(URLID url_id, VisitVector* visits) { | 230 bool VisitDatabase::GetVisitsForURL(URLID url_id, VisitVector* visits) { |
| 225 visits->clear(); | 231 visits->clear(); |
| 226 | 232 |
| 227 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 233 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 228 "SELECT" HISTORY_VISIT_ROW_FIELDS | 234 "SELECT" HISTORY_VISIT_ROW_FIELDS |
| 229 "FROM visits " | 235 "FROM visits " |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 | 535 |
| 530 // Get the source entries out of the query result. | 536 // Get the source entries out of the query result. |
| 531 while (statement.Step()) { | 537 while (statement.Step()) { |
| 532 std::pair<VisitID, VisitSource> source_entry(statement.ColumnInt64(0), | 538 std::pair<VisitID, VisitSource> source_entry(statement.ColumnInt64(0), |
| 533 static_cast<VisitSource>(statement.ColumnInt(1))); | 539 static_cast<VisitSource>(statement.ColumnInt(1))); |
| 534 sources->insert(source_entry); | 540 sources->insert(source_entry); |
| 535 } | 541 } |
| 536 } | 542 } |
| 537 } | 543 } |
| 538 | 544 |
| 545 bool VisitDatabase::MigrateVisitsWithoutDuration() { |
| 546 if (!GetDB().DoesTableExist("visits")) { |
| 547 NOTREACHED() << " Visits table should exist before migration"; |
| 548 return false; |
| 549 } |
| 550 |
| 551 if (!GetDB().DoesColumnExist("visits", "visit_duration")) { |
| 552 // Old versions don't have the visit_duration column, we modify the table |
| 553 // to add that field. |
| 554 if (!GetDB().Execute("ALTER TABLE visits " |
| 555 "ADD COLUMN visit_duration INTEGER DEFAULT 0 NOT NULL")) |
| 556 return false; |
| 557 } |
| 558 return true; |
| 559 } |
| 560 |
| 539 } // namespace history | 561 } // namespace history |
| OLD | NEW |