| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 visit->visit_id = statement.ColumnInt64(0); | 97 visit->visit_id = statement.ColumnInt64(0); |
| 98 visit->url_id = statement.ColumnInt64(1); | 98 visit->url_id = statement.ColumnInt64(1); |
| 99 visit->visit_time = base::Time::FromInternalValue(statement.ColumnInt64(2)); | 99 visit->visit_time = base::Time::FromInternalValue(statement.ColumnInt64(2)); |
| 100 visit->referring_visit = statement.ColumnInt64(3); | 100 visit->referring_visit = statement.ColumnInt64(3); |
| 101 visit->transition = content::PageTransitionFromInt(statement.ColumnInt(4)); | 101 visit->transition = content::PageTransitionFromInt(statement.ColumnInt(4)); |
| 102 visit->segment_id = statement.ColumnInt64(5); | 102 visit->segment_id = statement.ColumnInt64(5); |
| 103 visit->is_indexed = !!statement.ColumnInt(6); | 103 visit->is_indexed = !!statement.ColumnInt(6); |
| 104 } | 104 } |
| 105 | 105 |
| 106 // static | 106 // static |
| 107 void VisitDatabase::FillVisitVector(sql::Statement& statement, | 107 bool VisitDatabase::FillVisitVector(sql::Statement& statement, |
| 108 VisitVector* visits) { | 108 VisitVector* visits) { |
| 109 while (statement.Step()) { | 109 while (statement.Step()) { |
| 110 history::VisitRow visit; | 110 history::VisitRow visit; |
| 111 FillVisitRow(statement, &visit); | 111 FillVisitRow(statement, &visit); |
| 112 visits->push_back(visit); | 112 visits->push_back(visit); |
| 113 } | 113 } |
| 114 |
| 115 return statement.Succeeded(); |
| 114 } | 116 } |
| 115 | 117 |
| 116 VisitID VisitDatabase::AddVisit(VisitRow* visit, VisitSource source) { | 118 VisitID VisitDatabase::AddVisit(VisitRow* visit, VisitSource source) { |
| 117 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 119 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 118 "INSERT INTO visits " | 120 "INSERT INTO visits " |
| 119 "(url, visit_time, from_visit, transition, segment_id, is_indexed) " | 121 "(url, visit_time, from_visit, transition, segment_id, is_indexed) " |
| 120 "VALUES (?,?,?,?,?,?)")); | 122 "VALUES (?,?,?,?,?,?)")); |
| 121 if (!statement) { | |
| 122 VLOG(0) << "Failed to build visit insert statement: " | |
| 123 << "url_id = " << visit->url_id; | |
| 124 return 0; | |
| 125 } | |
| 126 | |
| 127 statement.BindInt64(0, visit->url_id); | 123 statement.BindInt64(0, visit->url_id); |
| 128 statement.BindInt64(1, visit->visit_time.ToInternalValue()); | 124 statement.BindInt64(1, visit->visit_time.ToInternalValue()); |
| 129 statement.BindInt64(2, visit->referring_visit); | 125 statement.BindInt64(2, visit->referring_visit); |
| 130 statement.BindInt64(3, visit->transition); | 126 statement.BindInt64(3, visit->transition); |
| 131 statement.BindInt64(4, visit->segment_id); | 127 statement.BindInt64(4, visit->segment_id); |
| 132 statement.BindInt64(5, visit->is_indexed); | 128 statement.BindInt64(5, visit->is_indexed); |
| 133 | 129 |
| 134 if (!statement.Run()) { | 130 if (!statement.Run()) { |
| 135 VLOG(0) << "Failed to execute visit insert statement: " | 131 VLOG(0) << "Failed to execute visit insert statement: " |
| 136 << "url_id = " << visit->url_id; | 132 << "url_id = " << visit->url_id; |
| 137 return 0; | 133 return 0; |
| 138 } | 134 } |
| 139 | 135 |
| 140 visit->visit_id = GetDB().GetLastInsertRowId(); | 136 visit->visit_id = GetDB().GetLastInsertRowId(); |
| 141 | 137 |
| 142 if (source != SOURCE_BROWSED) { | 138 if (source != SOURCE_BROWSED) { |
| 143 // Record the source of this visit when it is not browsed. | 139 // Record the source of this visit when it is not browsed. |
| 144 sql::Statement statement1(GetDB().GetCachedStatement(SQL_FROM_HERE, | 140 sql::Statement statement1(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 145 "INSERT INTO visit_source (id, source) VALUES (?,?)")); | 141 "INSERT INTO visit_source (id, source) VALUES (?,?)")); |
| 146 if (!statement1.is_valid()) { | |
| 147 VLOG(0) << "Failed to build visit_source insert statement: " | |
| 148 << "url_id = " << visit->visit_id; | |
| 149 return 0; | |
| 150 } | |
| 151 | |
| 152 statement1.BindInt64(0, visit->visit_id); | 142 statement1.BindInt64(0, visit->visit_id); |
| 153 statement1.BindInt64(1, source); | 143 statement1.BindInt64(1, source); |
| 144 |
| 154 if (!statement1.Run()) { | 145 if (!statement1.Run()) { |
| 155 VLOG(0) << "Failed to execute visit_source insert statement: " | 146 VLOG(0) << "Failed to execute visit_source insert statement: " |
| 156 << "url_id = " << visit->visit_id; | 147 << "url_id = " << visit->visit_id; |
| 157 return 0; | 148 return 0; |
| 158 } | 149 } |
| 159 } | 150 } |
| 160 | 151 |
| 161 return visit->visit_id; | 152 return visit->visit_id; |
| 162 } | 153 } |
| 163 | 154 |
| 164 void VisitDatabase::DeleteVisit(const VisitRow& visit) { | 155 void VisitDatabase::DeleteVisit(const VisitRow& visit) { |
| 165 // Patch around this visit. Any visits that this went to will now have their | 156 // Patch around this visit. Any visits that this went to will now have their |
| 166 // "source" be the deleted visit's source. | 157 // "source" be the deleted visit's source. |
| 167 sql::Statement update_chain(GetDB().GetCachedStatement(SQL_FROM_HERE, | 158 sql::Statement update_chain(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 168 "UPDATE visits SET from_visit=? WHERE from_visit=?")); | 159 "UPDATE visits SET from_visit=? WHERE from_visit=?")); |
| 169 if (!update_chain) | |
| 170 return; | |
| 171 update_chain.BindInt64(0, visit.referring_visit); | 160 update_chain.BindInt64(0, visit.referring_visit); |
| 172 update_chain.BindInt64(1, visit.visit_id); | 161 update_chain.BindInt64(1, visit.visit_id); |
| 173 update_chain.Run(); | 162 if (!update_chain.Run()) |
| 163 return; |
| 174 | 164 |
| 175 // Now delete the actual visit. | 165 // Now delete the actual visit. |
| 176 sql::Statement del(GetDB().GetCachedStatement(SQL_FROM_HERE, | 166 sql::Statement del(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 177 "DELETE FROM visits WHERE id=?")); | 167 "DELETE FROM visits WHERE id=?")); |
| 178 if (!del) | 168 del.BindInt64(0, visit.visit_id); |
| 169 if (!del.Run()) |
| 179 return; | 170 return; |
| 180 del.BindInt64(0, visit.visit_id); | |
| 181 del.Run(); | |
| 182 | 171 |
| 183 // Try to delete the entry in visit_source table as well. | 172 // Try to delete the entry in visit_source table as well. |
| 184 // If the visit was browsed, there is no corresponding entry in visit_source | 173 // If the visit was browsed, there is no corresponding entry in visit_source |
| 185 // table, and nothing will be deleted. | 174 // table, and nothing will be deleted. |
| 186 del.Assign(GetDB().GetCachedStatement(SQL_FROM_HERE, | 175 del.Assign(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 187 "DELETE FROM visit_source WHERE id=?")); | 176 "DELETE FROM visit_source WHERE id=?")); |
| 188 if (!del.is_valid()) | |
| 189 return; | |
| 190 del.BindInt64(0, visit.visit_id); | 177 del.BindInt64(0, visit.visit_id); |
| 191 del.Run(); | 178 del.Run(); |
| 192 } | 179 } |
| 193 | 180 |
| 194 bool VisitDatabase::GetRowForVisit(VisitID visit_id, VisitRow* out_visit) { | 181 bool VisitDatabase::GetRowForVisit(VisitID visit_id, VisitRow* out_visit) { |
| 195 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 182 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 196 "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits WHERE id=?")); | 183 "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits WHERE id=?")); |
| 197 if (!statement) | 184 statement.BindInt64(0, visit_id); |
| 198 return false; | |
| 199 | 185 |
| 200 statement.BindInt64(0, visit_id); | |
| 201 if (!statement.Step()) | 186 if (!statement.Step()) |
| 202 return false; | 187 return false; |
| 203 | 188 |
| 204 FillVisitRow(statement, out_visit); | 189 FillVisitRow(statement, out_visit); |
| 205 | 190 |
| 206 // We got a different visit than we asked for, something is wrong. | 191 // We got a different visit than we asked for, something is wrong. |
| 207 DCHECK_EQ(visit_id, out_visit->visit_id); | 192 DCHECK_EQ(visit_id, out_visit->visit_id); |
| 208 if (visit_id != out_visit->visit_id) | 193 if (visit_id != out_visit->visit_id) |
| 209 return false; | 194 return false; |
| 210 | 195 |
| 211 return true; | 196 return true; |
| 212 } | 197 } |
| 213 | 198 |
| 214 bool VisitDatabase::UpdateVisitRow(const VisitRow& visit) { | 199 bool VisitDatabase::UpdateVisitRow(const VisitRow& visit) { |
| 215 // Don't store inconsistent data to the database. | 200 // Don't store inconsistent data to the database. |
| 216 DCHECK_NE(visit.visit_id, visit.referring_visit); | 201 DCHECK_NE(visit.visit_id, visit.referring_visit); |
| 217 if (visit.visit_id == visit.referring_visit) | 202 if (visit.visit_id == visit.referring_visit) |
| 218 return false; | 203 return false; |
| 219 | 204 |
| 220 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 205 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 221 "UPDATE visits SET " | 206 "UPDATE visits SET " |
| 222 "url=?,visit_time=?,from_visit=?,transition=?,segment_id=?,is_indexed=? " | 207 "url=?,visit_time=?,from_visit=?,transition=?,segment_id=?,is_indexed=? " |
| 223 "WHERE id=?")); | 208 "WHERE id=?")); |
| 224 if (!statement) | |
| 225 return false; | |
| 226 | |
| 227 statement.BindInt64(0, visit.url_id); | 209 statement.BindInt64(0, visit.url_id); |
| 228 statement.BindInt64(1, visit.visit_time.ToInternalValue()); | 210 statement.BindInt64(1, visit.visit_time.ToInternalValue()); |
| 229 statement.BindInt64(2, visit.referring_visit); | 211 statement.BindInt64(2, visit.referring_visit); |
| 230 statement.BindInt64(3, visit.transition); | 212 statement.BindInt64(3, visit.transition); |
| 231 statement.BindInt64(4, visit.segment_id); | 213 statement.BindInt64(4, visit.segment_id); |
| 232 statement.BindInt64(5, visit.is_indexed); | 214 statement.BindInt64(5, visit.is_indexed); |
| 233 statement.BindInt64(6, visit.visit_id); | 215 statement.BindInt64(6, visit.visit_id); |
| 216 |
| 234 return statement.Run(); | 217 return statement.Run(); |
| 235 } | 218 } |
| 236 | 219 |
| 237 bool VisitDatabase::GetVisitsForURL(URLID url_id, VisitVector* visits) { | 220 bool VisitDatabase::GetVisitsForURL(URLID url_id, VisitVector* visits) { |
| 238 visits->clear(); | 221 visits->clear(); |
| 239 | 222 |
| 240 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 223 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 241 "SELECT" HISTORY_VISIT_ROW_FIELDS | 224 "SELECT" HISTORY_VISIT_ROW_FIELDS |
| 242 "FROM visits " | 225 "FROM visits " |
| 243 "WHERE url=? " | 226 "WHERE url=? " |
| 244 "ORDER BY visit_time ASC")); | 227 "ORDER BY visit_time ASC")); |
| 245 if (!statement) | |
| 246 return false; | |
| 247 | |
| 248 statement.BindInt64(0, url_id); | 228 statement.BindInt64(0, url_id); |
| 249 FillVisitVector(statement, visits); | 229 return FillVisitVector(statement, visits); |
| 250 return true; | |
| 251 } | 230 } |
| 252 | 231 |
| 253 bool VisitDatabase::GetIndexedVisitsForURL(URLID url_id, VisitVector* visits) { | 232 bool VisitDatabase::GetIndexedVisitsForURL(URLID url_id, VisitVector* visits) { |
| 254 visits->clear(); | 233 visits->clear(); |
| 255 | 234 |
| 256 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 235 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 257 "SELECT" HISTORY_VISIT_ROW_FIELDS | 236 "SELECT" HISTORY_VISIT_ROW_FIELDS |
| 258 "FROM visits " | 237 "FROM visits " |
| 259 "WHERE url=? AND is_indexed=1")); | 238 "WHERE url=? AND is_indexed=1")); |
| 260 if (!statement) | |
| 261 return false; | |
| 262 | |
| 263 statement.BindInt64(0, url_id); | 239 statement.BindInt64(0, url_id); |
| 264 FillVisitVector(statement, visits); | 240 return FillVisitVector(statement, visits); |
| 265 return true; | |
| 266 } | 241 } |
| 267 | 242 |
| 268 void VisitDatabase::GetAllVisitsInRange(base::Time begin_time, | 243 bool VisitDatabase::GetAllVisitsInRange(base::Time begin_time, |
| 269 base::Time end_time, | 244 base::Time end_time, |
| 270 int max_results, | 245 int max_results, |
| 271 VisitVector* visits) { | 246 VisitVector* visits) { |
| 272 visits->clear(); | 247 visits->clear(); |
| 273 | 248 |
| 274 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 249 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 275 "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits " | 250 "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits " |
| 276 "WHERE visit_time >= ? AND visit_time < ?" | 251 "WHERE visit_time >= ? AND visit_time < ?" |
| 277 "ORDER BY visit_time LIMIT ?")); | 252 "ORDER BY visit_time LIMIT ?")); |
| 278 if (!statement) | |
| 279 return; | |
| 280 | 253 |
| 281 // See GetVisibleVisitsInRange for more info on how these times are bound. | 254 // See GetVisibleVisitsInRange for more info on how these times are bound. |
| 282 int64 end = end_time.ToInternalValue(); | 255 int64 end = end_time.ToInternalValue(); |
| 283 statement.BindInt64(0, begin_time.ToInternalValue()); | 256 statement.BindInt64(0, begin_time.ToInternalValue()); |
| 284 statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max()); | 257 statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max()); |
| 285 statement.BindInt64(2, | 258 statement.BindInt64(2, |
| 286 max_results ? max_results : std::numeric_limits<int64>::max()); | 259 max_results ? max_results : std::numeric_limits<int64>::max()); |
| 287 | 260 |
| 288 FillVisitVector(statement, visits); | 261 return FillVisitVector(statement, visits); |
| 289 } | 262 } |
| 290 | 263 |
| 291 void VisitDatabase::GetVisitsInRangeForTransition( | 264 bool VisitDatabase::GetVisitsInRangeForTransition( |
| 292 base::Time begin_time, | 265 base::Time begin_time, |
| 293 base::Time end_time, | 266 base::Time end_time, |
| 294 int max_results, | 267 int max_results, |
| 295 content::PageTransition transition, | 268 content::PageTransition transition, |
| 296 VisitVector* visits) { | 269 VisitVector* visits) { |
| 297 DCHECK(visits); | 270 DCHECK(visits); |
| 298 visits->clear(); | 271 visits->clear(); |
| 299 | 272 |
| 300 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 273 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 301 "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits " | 274 "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits " |
| 302 "WHERE visit_time >= ? AND visit_time < ? " | 275 "WHERE visit_time >= ? AND visit_time < ? " |
| 303 "AND (transition & ?) == ?" | 276 "AND (transition & ?) == ?" |
| 304 "ORDER BY visit_time LIMIT ?")); | 277 "ORDER BY visit_time LIMIT ?")); |
| 305 if (!statement) | |
| 306 return; | |
| 307 | 278 |
| 308 // See GetVisibleVisitsInRange for more info on how these times are bound. | 279 // See GetVisibleVisitsInRange for more info on how these times are bound. |
| 309 int64 end = end_time.ToInternalValue(); | 280 int64 end = end_time.ToInternalValue(); |
| 310 statement.BindInt64(0, begin_time.ToInternalValue()); | 281 statement.BindInt64(0, begin_time.ToInternalValue()); |
| 311 statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max()); | 282 statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max()); |
| 312 statement.BindInt(2, content::PAGE_TRANSITION_CORE_MASK); | 283 statement.BindInt(2, content::PAGE_TRANSITION_CORE_MASK); |
| 313 statement.BindInt(3, transition); | 284 statement.BindInt(3, transition); |
| 314 statement.BindInt64(4, | 285 statement.BindInt64(4, |
| 315 max_results ? max_results : std::numeric_limits<int64>::max()); | 286 max_results ? max_results : std::numeric_limits<int64>::max()); |
| 316 | 287 |
| 317 FillVisitVector(statement, visits); | 288 return FillVisitVector(statement, visits); |
| 318 } | 289 } |
| 319 | 290 |
| 320 void VisitDatabase::GetVisibleVisitsInRange(base::Time begin_time, | 291 void VisitDatabase::GetVisibleVisitsInRange(base::Time begin_time, |
| 321 base::Time end_time, | 292 base::Time end_time, |
| 322 int max_count, | 293 int max_count, |
| 323 VisitVector* visits) { | 294 VisitVector* visits) { |
| 324 visits->clear(); | 295 visits->clear(); |
| 325 // The visit_time values can be duplicated in a redirect chain, so we sort | 296 // The visit_time values can be duplicated in a redirect chain, so we sort |
| 326 // by id too, to ensure a consistent ordering just in case. | 297 // by id too, to ensure a consistent ordering just in case. |
| 327 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 298 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 328 "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits " | 299 "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits " |
| 329 "WHERE visit_time >= ? AND visit_time < ? " | 300 "WHERE visit_time >= ? AND visit_time < ? " |
| 330 "AND (transition & ?) != 0 " // CHAIN_END | 301 "AND (transition & ?) != 0 " // CHAIN_END |
| 331 "AND (transition & ?) NOT IN (?, ?, ?) " // NO SUBFRAME or | 302 "AND (transition & ?) NOT IN (?, ?, ?) " // NO SUBFRAME or |
| 332 // KEYWORD_GENERATED | 303 // KEYWORD_GENERATED |
| 333 "ORDER BY visit_time DESC, id DESC")); | 304 "ORDER BY visit_time DESC, id DESC")); |
| 334 if (!statement) | |
| 335 return; | |
| 336 | 305 |
| 337 // Note that we use min/max values for querying unlimited ranges of time using | 306 // Note that we use min/max values for querying unlimited ranges of time using |
| 338 // the same statement. Since the time has an index, this will be about the | 307 // the same statement. Since the time has an index, this will be about the |
| 339 // same amount of work as just doing a query for everything with no qualifier. | 308 // same amount of work as just doing a query for everything with no qualifier. |
| 340 int64 end = end_time.ToInternalValue(); | 309 int64 end = end_time.ToInternalValue(); |
| 341 statement.BindInt64(0, begin_time.ToInternalValue()); | 310 statement.BindInt64(0, begin_time.ToInternalValue()); |
| 342 statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max()); | 311 statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max()); |
| 343 statement.BindInt(2, content::PAGE_TRANSITION_CHAIN_END); | 312 statement.BindInt(2, content::PAGE_TRANSITION_CHAIN_END); |
| 344 statement.BindInt(3, content::PAGE_TRANSITION_CORE_MASK); | 313 statement.BindInt(3, content::PAGE_TRANSITION_CORE_MASK); |
| 345 statement.BindInt(4, content::PAGE_TRANSITION_AUTO_SUBFRAME); | 314 statement.BindInt(4, content::PAGE_TRANSITION_AUTO_SUBFRAME); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 363 | 332 |
| 364 VisitID VisitDatabase::GetMostRecentVisitForURL(URLID url_id, | 333 VisitID VisitDatabase::GetMostRecentVisitForURL(URLID url_id, |
| 365 VisitRow* visit_row) { | 334 VisitRow* visit_row) { |
| 366 // The visit_time values can be duplicated in a redirect chain, so we sort | 335 // The visit_time values can be duplicated in a redirect chain, so we sort |
| 367 // by id too, to ensure a consistent ordering just in case. | 336 // by id too, to ensure a consistent ordering just in case. |
| 368 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 337 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 369 "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits " | 338 "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits " |
| 370 "WHERE url=? " | 339 "WHERE url=? " |
| 371 "ORDER BY visit_time DESC, id DESC " | 340 "ORDER BY visit_time DESC, id DESC " |
| 372 "LIMIT 1")); | 341 "LIMIT 1")); |
| 373 if (!statement) | |
| 374 return 0; | |
| 375 | |
| 376 statement.BindInt64(0, url_id); | 342 statement.BindInt64(0, url_id); |
| 377 if (!statement.Step()) | 343 if (!statement.Step()) |
| 378 return 0; // No visits for this URL. | 344 return 0; // No visits for this URL. |
| 379 | 345 |
| 380 if (visit_row) { | 346 if (visit_row) { |
| 381 FillVisitRow(statement, visit_row); | 347 FillVisitRow(statement, visit_row); |
| 382 return visit_row->visit_id; | 348 return visit_row->visit_id; |
| 383 } | 349 } |
| 384 return statement.ColumnInt64(0); | 350 return statement.ColumnInt64(0); |
| 385 } | 351 } |
| 386 | 352 |
| 387 bool VisitDatabase::GetMostRecentVisitsForURL(URLID url_id, | 353 bool VisitDatabase::GetMostRecentVisitsForURL(URLID url_id, |
| 388 int max_results, | 354 int max_results, |
| 389 VisitVector* visits) { | 355 VisitVector* visits) { |
| 390 visits->clear(); | 356 visits->clear(); |
| 391 | 357 |
| 392 // The visit_time values can be duplicated in a redirect chain, so we sort | 358 // The visit_time values can be duplicated in a redirect chain, so we sort |
| 393 // by id too, to ensure a consistent ordering just in case. | 359 // by id too, to ensure a consistent ordering just in case. |
| 394 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 360 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 395 "SELECT" HISTORY_VISIT_ROW_FIELDS | 361 "SELECT" HISTORY_VISIT_ROW_FIELDS |
| 396 "FROM visits " | 362 "FROM visits " |
| 397 "WHERE url=? " | 363 "WHERE url=? " |
| 398 "ORDER BY visit_time DESC, id DESC " | 364 "ORDER BY visit_time DESC, id DESC " |
| 399 "LIMIT ?")); | 365 "LIMIT ?")); |
| 400 if (!statement) | |
| 401 return false; | |
| 402 | |
| 403 statement.BindInt64(0, url_id); | 366 statement.BindInt64(0, url_id); |
| 404 statement.BindInt(1, max_results); | 367 statement.BindInt(1, max_results); |
| 405 FillVisitVector(statement, visits); | 368 |
| 406 return true; | 369 return FillVisitVector(statement, visits); |
| 407 } | 370 } |
| 408 | 371 |
| 409 bool VisitDatabase::GetRedirectFromVisit(VisitID from_visit, | 372 bool VisitDatabase::GetRedirectFromVisit(VisitID from_visit, |
| 410 VisitID* to_visit, | 373 VisitID* to_visit, |
| 411 GURL* to_url) { | 374 GURL* to_url) { |
| 412 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 375 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 413 "SELECT v.id,u.url " | 376 "SELECT v.id,u.url " |
| 414 "FROM visits v JOIN urls u ON v.url = u.id " | 377 "FROM visits v JOIN urls u ON v.url = u.id " |
| 415 "WHERE v.from_visit = ? " | 378 "WHERE v.from_visit = ? " |
| 416 "AND (v.transition & ?) != 0")); // IS_REDIRECT_MASK | 379 "AND (v.transition & ?) != 0")); // IS_REDIRECT_MASK |
| 417 if (!statement) | |
| 418 return false; | |
| 419 | |
| 420 statement.BindInt64(0, from_visit); | 380 statement.BindInt64(0, from_visit); |
| 421 statement.BindInt(1, content::PAGE_TRANSITION_IS_REDIRECT_MASK); | 381 statement.BindInt(1, content::PAGE_TRANSITION_IS_REDIRECT_MASK); |
| 422 | 382 |
| 423 if (!statement.Step()) | 383 if (!statement.Step()) |
| 424 return false; // No redirect from this visit. | 384 return false; // No redirect from this visit. (Or SQL error) |
| 425 if (to_visit) | 385 if (to_visit) |
| 426 *to_visit = statement.ColumnInt64(0); | 386 *to_visit = statement.ColumnInt64(0); |
| 427 if (to_url) | 387 if (to_url) |
| 428 *to_url = GURL(statement.ColumnString(1)); | 388 *to_url = GURL(statement.ColumnString(1)); |
| 429 return true; | 389 return true; |
| 430 } | 390 } |
| 431 | 391 |
| 432 bool VisitDatabase::GetRedirectToVisit(VisitID to_visit, | 392 bool VisitDatabase::GetRedirectToVisit(VisitID to_visit, |
| 433 VisitID* from_visit, | 393 VisitID* from_visit, |
| 434 GURL* from_url) { | 394 GURL* from_url) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 472 return false; | 432 return false; |
| 473 | 433 |
| 474 // We also want to restrict ourselves to main frame navigations that are not | 434 // We also want to restrict ourselves to main frame navigations that are not |
| 475 // in the middle of redirect chains, hence the transition checks. | 435 // in the middle of redirect chains, hence the transition checks. |
| 476 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 436 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 477 "SELECT MIN(v.visit_time), COUNT(*) " | 437 "SELECT MIN(v.visit_time), COUNT(*) " |
| 478 "FROM visits v INNER JOIN urls u ON v.url = u.id " | 438 "FROM visits v INNER JOIN urls u ON v.url = u.id " |
| 479 "WHERE u.url >= ? AND u.url < ? " | 439 "WHERE u.url >= ? AND u.url < ? " |
| 480 "AND (transition & ?) != 0 " | 440 "AND (transition & ?) != 0 " |
| 481 "AND (transition & ?) NOT IN (?, ?, ?)")); | 441 "AND (transition & ?) NOT IN (?, ?, ?)")); |
| 482 if (!statement) | |
| 483 return false; | |
| 484 | |
| 485 statement.BindString(0, host_query_min); | 442 statement.BindString(0, host_query_min); |
| 486 statement.BindString(1, | 443 statement.BindString(1, |
| 487 host_query_min.substr(0, host_query_min.size() - 1) + '0'); | 444 host_query_min.substr(0, host_query_min.size() - 1) + '0'); |
| 488 statement.BindInt(2, content::PAGE_TRANSITION_CHAIN_END); | 445 statement.BindInt(2, content::PAGE_TRANSITION_CHAIN_END); |
| 489 statement.BindInt(3, content::PAGE_TRANSITION_CORE_MASK); | 446 statement.BindInt(3, content::PAGE_TRANSITION_CORE_MASK); |
| 490 statement.BindInt(4, content::PAGE_TRANSITION_AUTO_SUBFRAME); | 447 statement.BindInt(4, content::PAGE_TRANSITION_AUTO_SUBFRAME); |
| 491 statement.BindInt(5, content::PAGE_TRANSITION_MANUAL_SUBFRAME); | 448 statement.BindInt(5, content::PAGE_TRANSITION_MANUAL_SUBFRAME); |
| 492 statement.BindInt(6, content::PAGE_TRANSITION_KEYWORD_GENERATED); | 449 statement.BindInt(6, content::PAGE_TRANSITION_KEYWORD_GENERATED); |
| 493 | 450 |
| 494 if (!statement.Step()) { | 451 if (!statement.Step()) { |
| 495 // We've never been to this page before. | 452 // We've never been to this page before. |
| 496 *count = 0; | 453 *count = 0; |
| 497 return true; | 454 return true; |
| 498 } | 455 } |
| 499 | 456 |
| 457 if (!statement.Succeeded()) |
| 458 return false; |
| 459 |
| 500 *first_visit = base::Time::FromInternalValue(statement.ColumnInt64(0)); | 460 *first_visit = base::Time::FromInternalValue(statement.ColumnInt64(0)); |
| 501 *count = statement.ColumnInt(1); | 461 *count = statement.ColumnInt(1); |
| 502 return true; | 462 return true; |
| 503 } | 463 } |
| 504 | 464 |
| 505 bool VisitDatabase::GetStartDate(base::Time* first_visit) { | 465 bool VisitDatabase::GetStartDate(base::Time* first_visit) { |
| 506 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 466 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 507 "SELECT MIN(visit_time) FROM visits WHERE visit_time != 0")); | 467 "SELECT MIN(visit_time) FROM visits WHERE visit_time != 0")); |
| 508 if (!statement || !statement.Step() || statement.ColumnInt64(0) == 0) { | 468 if (!statement.Step() || statement.ColumnInt64(0) == 0) { |
| 509 *first_visit = base::Time::Now(); | 469 *first_visit = base::Time::Now(); |
| 510 return false; | 470 return false; |
| 511 } | 471 } |
| 512 *first_visit = base::Time::FromInternalValue(statement.ColumnInt64(0)); | 472 *first_visit = base::Time::FromInternalValue(statement.ColumnInt64(0)); |
| 513 return true; | 473 return true; |
| 514 } | 474 } |
| 515 | 475 |
| 516 void VisitDatabase::GetVisitsSource(const VisitVector& visits, | 476 void VisitDatabase::GetVisitsSource(const VisitVector& visits, |
| 517 VisitSourceMap* sources) { | 477 VisitSourceMap* sources) { |
| 518 DCHECK(sources); | 478 DCHECK(sources); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 532 std::string sql = "SELECT id,source FROM visit_source "; | 492 std::string sql = "SELECT id,source FROM visit_source "; |
| 533 sql.append("WHERE id IN ("); | 493 sql.append("WHERE id IN ("); |
| 534 // Append all the ids in the statement. | 494 // Append all the ids in the statement. |
| 535 for (size_t j = start_index; j < end_index; j++) { | 495 for (size_t j = start_index; j < end_index; j++) { |
| 536 if (j != start_index) | 496 if (j != start_index) |
| 537 sql.push_back(','); | 497 sql.push_back(','); |
| 538 sql.append(base::Int64ToString(visits[j].visit_id)); | 498 sql.append(base::Int64ToString(visits[j].visit_id)); |
| 539 } | 499 } |
| 540 sql.append(") ORDER BY id"); | 500 sql.append(") ORDER BY id"); |
| 541 sql::Statement statement(GetDB().GetUniqueStatement(sql.c_str())); | 501 sql::Statement statement(GetDB().GetUniqueStatement(sql.c_str())); |
| 542 if (!statement) | |
| 543 return; | |
| 544 | 502 |
| 545 // Get the source entries out of the query result. | 503 // Get the source entries out of the query result. |
| 546 while (statement.Step()) { | 504 while (statement.Step()) { |
| 547 std::pair<VisitID, VisitSource> source_entry(statement.ColumnInt64(0), | 505 std::pair<VisitID, VisitSource> source_entry(statement.ColumnInt64(0), |
| 548 static_cast<VisitSource>(statement.ColumnInt(1))); | 506 static_cast<VisitSource>(statement.ColumnInt(1))); |
| 549 sources->insert(source_entry); | 507 sources->insert(source_entry); |
| 550 } | 508 } |
| 551 } | 509 } |
| 552 } | 510 } |
| 553 | 511 |
| 554 } // namespace history | 512 } // namespace history |
| OLD | NEW |