15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/visit_database.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/url_database.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/visit_filter.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/page_transition_types.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/statement.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace history {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VisitDatabase::VisitDatabase() {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VisitDatabase::~VisitDatabase() {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::InitVisitTable() {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetDB().DoesTableExist("visits")) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetDB().Execute("CREATE TABLE visits("
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "id INTEGER PRIMARY KEY,"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "url INTEGER NOT NULL," // key of the URL this corresponds to
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "visit_time INTEGER NOT NULL,"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "from_visit INTEGER,"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "transition INTEGER DEFAULT 0 NOT NULL,"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "segment_id INTEGER,"
37bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        // Some old DBs may have an "is_indexed" field here, but this is no
38bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        // longer used and should NOT be read or written from any longer.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "visit_duration INTEGER DEFAULT 0 NOT NULL)"))
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Visit source table contains the source information for all the visits. To
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // save space, we do not record those user browsed visits which would be the
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // majority in this table. Only other sources are recorded.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Due to the tight relationship between visit_source and visits table, they
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // should be created and dropped at the same time.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetDB().DoesTableExist("visit_source")) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetDB().Execute("CREATE TABLE visit_source("
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         "id INTEGER PRIMARY KEY,source INTEGER NOT NULL)"))
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Index over url so we can quickly find visits for a page.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetDB().Execute(
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "CREATE INDEX IF NOT EXISTS visits_url_index ON visits (url)"))
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an index over from visits so that we can efficiently find
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // referrers and redirects.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetDB().Execute(
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "CREATE INDEX IF NOT EXISTS visits_from_index ON "
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "visits (from_visit)"))
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an index over time so that we can efficiently find the visits in a
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // given time range (most history views are time-based).
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetDB().Execute(
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "CREATE INDEX IF NOT EXISTS visits_time_index ON "
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "visits (visit_time)"))
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::DropVisitTable() {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This will also drop the indices over the table.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetDB().Execute("DROP TABLE IF EXISTS visit_source") &&
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetDB().Execute("DROP TABLE visits");
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Must be in sync with HISTORY_VISIT_ROW_FIELDS.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void VisitDatabase::FillVisitRow(sql::Statement& statement, VisitRow* visit) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit->visit_id = statement.ColumnInt64(0);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit->url_id = statement.ColumnInt64(1);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit->visit_time = base::Time::FromInternalValue(statement.ColumnInt64(2));
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit->referring_visit = statement.ColumnInt64(3);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit->transition = content::PageTransitionFromInt(statement.ColumnInt(4));
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit->segment_id = statement.ColumnInt64(5);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit->visit_duration =
93bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      base::TimeDelta::FromInternalValue(statement.ColumnInt64(6));
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::FillVisitVector(sql::Statement& statement,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    VisitVector* visits) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.is_valid())
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (statement.Step()) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    history::VisitRow visit;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FillVisitRow(statement, &visit);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visits->push_back(visit);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Succeeded();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// static
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool VisitDatabase::FillVisitVectorWithOptions(sql::Statement& statement,
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                               const QueryOptions& options,
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                               VisitVector* visits) {
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::set<URLID> found_urls;
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Keeps track of the day that |found_urls| is holding the URLs for, in order
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // to handle removing per-day duplicates.
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::Time found_urls_midnight;
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  while (statement.Step()) {
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    VisitRow visit;
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    FillVisitRow(statement, &visit);
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (options.duplicate_policy != QueryOptions::KEEP_ALL_DUPLICATES) {
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (options.duplicate_policy == QueryOptions::REMOVE_DUPLICATES_PER_DAY &&
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          found_urls_midnight != visit.visit_time.LocalMidnight()) {
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        found_urls.clear();
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        found_urls_midnight = visit.visit_time.LocalMidnight();
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Make sure the URL this visit corresponds to is unique.
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (found_urls.find(visit.url_id) != found_urls.end())
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        continue;
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      found_urls.insert(visit.url_id);
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (static_cast<int>(visits->size()) >= options.EffectiveMaxCount())
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return true;
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    visits->push_back(visit);
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return false;
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VisitID VisitDatabase::AddVisit(VisitRow* visit, VisitSource source) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "INSERT INTO visits "
147bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      "(url, visit_time, from_visit, transition, segment_id, "
148bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      "visit_duration) VALUES (?,?,?,?,?,?)"));
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, visit->url_id);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(1, visit->visit_time.ToInternalValue());
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(2, visit->referring_visit);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(3, visit->transition);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(4, visit->segment_id);
154bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  statement.BindInt64(5, visit->visit_duration.ToInternalValue());
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Run()) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(0) << "Failed to execute visit insert statement:  "
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << "url_id = " << visit->url_id;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visit->visit_id = GetDB().GetLastInsertRowId();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (source != SOURCE_BROWSED) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Record the source of this visit when it is not browsed.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement statement1(GetDB().GetCachedStatement(SQL_FROM_HERE,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "INSERT INTO visit_source (id, source) VALUES (?,?)"));
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement1.BindInt64(0, visit->visit_id);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement1.BindInt64(1, source);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!statement1.Run()) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(0) << "Failed to execute visit_source insert statement:  "
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              << "id = " << visit->visit_id;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return visit->visit_id;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void VisitDatabase::DeleteVisit(const VisitRow& visit) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Patch around this visit. Any visits that this went to will now have their
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "source" be the deleted visit's source.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement update_chain(GetDB().GetCachedStatement(SQL_FROM_HERE,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "UPDATE visits SET from_visit=? WHERE from_visit=?"));
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  update_chain.BindInt64(0, visit.referring_visit);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  update_chain.BindInt64(1, visit.visit_id);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!update_chain.Run())
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now delete the actual visit.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement del(GetDB().GetCachedStatement(SQL_FROM_HERE,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "DELETE FROM visits WHERE id=?"));
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  del.BindInt64(0, visit.visit_id);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!del.Run())
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try to delete the entry in visit_source table as well.
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the visit was browsed, there is no corresponding entry in visit_source
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // table, and nothing will be deleted.
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  del.Assign(GetDB().GetCachedStatement(SQL_FROM_HERE,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             "DELETE FROM visit_source WHERE id=?"));
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  del.BindInt64(0, visit.visit_id);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  del.Run();
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::GetRowForVisit(VisitID visit_id, VisitRow* out_visit) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits WHERE id=?"));
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, visit_id);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Step())
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillVisitRow(statement, out_visit);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We got a different visit than we asked for, something is wrong.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(visit_id, out_visit->visit_id);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_id != out_visit->visit_id)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::UpdateVisitRow(const VisitRow& visit) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't store inconsistent data to the database.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(visit.visit_id, visit.referring_visit);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit.visit_id == visit.referring_visit)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "UPDATE visits SET "
233bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      "url=?,visit_time=?,from_visit=?,transition=?,segment_id=?,"
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "visit_duration=? WHERE id=?"));
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, visit.url_id);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(1, visit.visit_time.ToInternalValue());
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(2, visit.referring_visit);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(3, visit.transition);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(4, visit.segment_id);
240bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  statement.BindInt64(5, visit.visit_duration.ToInternalValue());
241bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  statement.BindInt64(6, visit.visit_id);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Run();
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::GetVisitsForURL(URLID url_id, VisitVector* visits) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visits->clear();
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT" HISTORY_VISIT_ROW_FIELDS
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "FROM visits "
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE url=? "
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ORDER BY visit_time ASC"));
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, url_id);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FillVisitVector(statement, visits);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool VisitDatabase::GetVisitsForURLWithOptions(URLID url_id,
259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                               const QueryOptions& options,
260eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                               VisitVector* visits) {
261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  visits->clear();
262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (options.REMOVE_ALL_DUPLICATES) {
264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    VisitRow visit_row;
265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    VisitID visit_id = GetMostRecentVisitForURL(url_id, &visit_row);
266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (visit_id && options.EffectiveMaxCount() != 0) {
267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      visits->push_back(visit_row);
268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return options.EffectiveMaxCount() == 0 && visit_id;
270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else {
271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "SELECT" HISTORY_VISIT_ROW_FIELDS
273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "FROM visits "
274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "WHERE url=? AND visit_time >= ? AND visit_time < ? "
275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        "ORDER BY visit_time DESC"));
276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    statement.BindInt64(0, url_id);
277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    statement.BindInt64(1, options.EffectiveBeginTime());
278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    statement.BindInt64(2, options.EffectiveEndTime());
279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return FillVisitVectorWithOptions(statement, options, visits);
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool VisitDatabase::GetVisitsForTimes(const std::vector<base::Time>& times,
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      VisitVector* visits) {
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  visits->clear();
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::vector<base::Time>::const_iterator it = times.begin();
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != times.end(); ++it) {
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits "
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "WHERE visit_time == ?"));
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    statement.BindInt64(0, it->ToInternalValue());
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!FillVisitVector(statement, visits))
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::GetAllVisitsInRange(base::Time begin_time,
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        base::Time end_time,
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        int max_results,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        VisitVector* visits) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visits->clear();
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits "
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE visit_time >= ? AND visit_time < ?"
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ORDER BY visit_time LIMIT ?"));
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See GetVisibleVisitsInRange for more info on how these times are bound.
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 end = end_time.ToInternalValue();
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, begin_time.ToInternalValue());
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max());
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(2,
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_results ? max_results : std::numeric_limits<int64>::max());
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FillVisitVector(statement, visits);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::GetVisitsInRangeForTransition(
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time begin_time,
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time end_time,
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_results,
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition,
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VisitVector* visits) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(visits);
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visits->clear();
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits "
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE visit_time >= ? AND visit_time < ? "
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "AND (transition & ?) == ?"
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ORDER BY visit_time LIMIT ?"));
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See GetVisibleVisitsInRange for more info on how these times are bound.
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 end = end_time.ToInternalValue();
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, begin_time.ToInternalValue());
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max());
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(2, content::PAGE_TRANSITION_CORE_MASK);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(3, transition);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(4,
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_results ? max_results : std::numeric_limits<int64>::max());
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FillVisitVector(statement, visits);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool VisitDatabase::GetVisibleVisitsInRange(const QueryOptions& options,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            VisitVector* visits) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visits->clear();
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The visit_time values can be duplicated in a redirect chain, so we sort
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // by id too, to ensure a consistent ordering just in case.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits "
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE visit_time >= ? AND visit_time < ? "
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "AND (transition & ?) != 0 "  // CHAIN_END
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "AND (transition & ?) NOT IN (?, ?, ?) "  // NO SUBFRAME or
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                // KEYWORD_GENERATED
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ORDER BY visit_time DESC, id DESC"));
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement.BindInt64(0, options.EffectiveBeginTime());
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement.BindInt64(1, options.EffectiveEndTime());
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(2, content::PAGE_TRANSITION_CHAIN_END);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(3, content::PAGE_TRANSITION_CORE_MASK);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(4, content::PAGE_TRANSITION_AUTO_SUBFRAME);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(5, content::PAGE_TRANSITION_MANUAL_SUBFRAME);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(6, content::PAGE_TRANSITION_KEYWORD_GENERATED);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return FillVisitVectorWithOptions(statement, options, visits);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void VisitDatabase::GetDirectVisitsDuringTimes(const VisitFilter& time_filter,
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                int max_results,
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                VisitVector* visits) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visits->clear();
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (max_results)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visits->reserve(max_results);
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (VisitFilter::TimeVector::const_iterator it = time_filter.times().begin();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != time_filter.times().end(); ++it) {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits "
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "WHERE visit_time >= ? AND visit_time < ? "
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "AND (transition & ?) != 0 "  // CHAIN_START
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "AND (transition & ?) IN (?, ?) "  // TYPED or AUTO_BOOKMARK only
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "ORDER BY visit_time DESC, id DESC"));
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.BindInt64(0, it->first.ToInternalValue());
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.BindInt64(1, it->second.ToInternalValue());
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.BindInt(2, content::PAGE_TRANSITION_CHAIN_START);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.BindInt(3, content::PAGE_TRANSITION_CORE_MASK);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.BindInt(4, content::PAGE_TRANSITION_TYPED);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.BindInt(5, content::PAGE_TRANSITION_AUTO_BOOKMARK);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (statement.Step()) {
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VisitRow visit;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FillVisitRow(statement, &visit);
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visits->push_back(visit);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (max_results > 0 && static_cast<int>(visits->size()) >= max_results)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VisitID VisitDatabase::GetMostRecentVisitForURL(URLID url_id,
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                VisitRow* visit_row) {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The visit_time values can be duplicated in a redirect chain, so we sort
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // by id too, to ensure a consistent ordering just in case.
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits "
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE url=? "
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ORDER BY visit_time DESC, id DESC "
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "LIMIT 1"));
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, url_id);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Step())
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;  // No visits for this URL.
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (visit_row) {
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FillVisitRow(statement, visit_row);
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return visit_row->visit_id;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.ColumnInt64(0);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::GetMostRecentVisitsForURL(URLID url_id,
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              int max_results,
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              VisitVector* visits) {
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  visits->clear();
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The visit_time values can be duplicated in a redirect chain, so we sort
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // by id too, to ensure a consistent ordering just in case.
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT" HISTORY_VISIT_ROW_FIELDS
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "FROM visits "
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE url=? "
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ORDER BY visit_time DESC, id DESC "
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "LIMIT ?"));
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, url_id);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(1, max_results);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FillVisitVector(statement, visits);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::GetRedirectFromVisit(VisitID from_visit,
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         VisitID* to_visit,
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         GURL* to_url) {
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT v.id,u.url "
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "FROM visits v JOIN urls u ON v.url = u.id "
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE v.from_visit = ? "
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "AND (v.transition & ?) != 0"));  // IS_REDIRECT_MASK
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, from_visit);
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(1, content::PAGE_TRANSITION_IS_REDIRECT_MASK);
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Step())
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No redirect from this visit. (Or SQL error)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (to_visit)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *to_visit = statement.ColumnInt64(0);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (to_url)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *to_url = GURL(statement.ColumnString(1));
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::GetRedirectToVisit(VisitID to_visit,
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       VisitID* from_visit,
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       GURL* from_url) {
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VisitRow row;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetRowForVisit(to_visit, &row))
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (from_visit)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *from_visit = row.referring_visit;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (from_url) {
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "SELECT u.url "
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "FROM visits v JOIN urls u ON v.url = u.id "
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "WHERE v.id = ?"));
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.BindInt64(0, row.referring_visit);
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!statement.Step())
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *from_url = GURL(statement.ColumnString(0));
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::GetVisibleVisitCountToHost(const GURL& url,
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               int* count,
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               base::Time* first_visit) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!url.SchemeIs(chrome::kHttpScheme) && !url.SchemeIs(chrome::kHttpsScheme))
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to search for URLs with a matching host/port. One way to query for
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this is to use the LIKE operator, eg 'url LIKE http://google.com/%'. This
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is inefficient though in that it doesn't use the index and each entry must
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be visited. The same query can be executed by using >= and < operator.
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The query becomes:
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 'url >= http://google.com/' and url < http://google.com0'.
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 0 is used as it is one character greater than '/'.
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string host_query_min = url.GetOrigin().spec();
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (host_query_min.empty())
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We also want to restrict ourselves to main frame navigations that are not
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in the middle of redirect chains, hence the transition checks.
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT MIN(v.visit_time), COUNT(*) "
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "FROM visits v INNER JOIN urls u ON v.url = u.id "
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE u.url >= ? AND u.url < ? "
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "AND (transition & ?) != 0 "
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "AND (transition & ?) NOT IN (?, ?, ?)"));
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindString(0, host_query_min);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindString(1,
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      host_query_min.substr(0, host_query_min.size() - 1) + '0');
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(2, content::PAGE_TRANSITION_CHAIN_END);
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(3, content::PAGE_TRANSITION_CORE_MASK);
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(4, content::PAGE_TRANSITION_AUTO_SUBFRAME);
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(5, content::PAGE_TRANSITION_MANUAL_SUBFRAME);
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(6, content::PAGE_TRANSITION_KEYWORD_GENERATED);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Step()) {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We've never been to this page before.
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *count = 0;
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Succeeded())
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *first_visit = base::Time::FromInternalValue(statement.ColumnInt64(0));
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *count = statement.ColumnInt(1);
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::GetStartDate(base::Time* first_visit) {
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT MIN(visit_time) FROM visits WHERE visit_time != 0"));
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.Step() || statement.ColumnInt64(0) == 0) {
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *first_visit = base::Time::Now();
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *first_visit = base::Time::FromInternalValue(statement.ColumnInt64(0));
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void VisitDatabase::GetVisitsSource(const VisitVector& visits,
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    VisitSourceMap* sources) {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(sources);
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sources->clear();
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We query the source in batch. Here defines the batch size.
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t batch_size = 500;
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t visits_size = visits.size();
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t start_index = 0, end_index = 0;
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (end_index < visits_size) {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    start_index = end_index;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    end_index = end_index + batch_size < visits_size ? end_index + batch_size
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     : visits_size;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Compose the sql statement with a list of ids.
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string sql = "SELECT id,source FROM visit_source ";
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql.append("WHERE id IN (");
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Append all the ids in the statement.
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t j = start_index; j < end_index; j++) {
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (j != start_index)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sql.push_back(',');
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sql.append(base::Int64ToString(visits[j].visit_id));
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql.append(") ORDER BY id");
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement statement(GetDB().GetUniqueStatement(sql.c_str()));
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the source entries out of the query result.
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (statement.Step()) {
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::pair<VisitID, VisitSource> source_entry(statement.ColumnInt64(0),
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_cast<VisitSource>(statement.ColumnInt(1)));
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sources->insert(source_entry);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VisitDatabase::MigrateVisitsWithoutDuration() {
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetDB().DoesTableExist("visits")) {
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << " Visits table should exist before migration";
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetDB().DoesColumnExist("visits", "visit_duration")) {
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Old versions don't have the visit_duration column, we modify the table
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to add that field.
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetDB().Execute("ALTER TABLE visits "
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "ADD COLUMN visit_duration INTEGER DEFAULT 0 NOT NULL"))
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void VisitDatabase::GetBriefVisitInfoOfMostRecentVisits(
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_visits,
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<BriefVisitInfo>* result_vector) {
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result_vector->clear();
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetUniqueStatement(
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT url,visit_time,transition FROM visits "
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ORDER BY id DESC LIMIT ?"));
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt64(0, max_visits);
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!statement.is_valid())
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (statement.Step()) {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BriefVisitInfo info;
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info.url_id = statement.ColumnInt64(0);
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info.time = base::Time::FromInternalValue(statement.ColumnInt64(1));
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info.transition = content::PageTransitionFromInt(statement.ColumnInt(2));
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result_vector->push_back(info);
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace history
626