1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2009 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/visit_database.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <limits> 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <map> 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set> 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/sql/statement.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h" 143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/url_database.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h" 17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/page_transition_types.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Rows, in order, of the visit table. 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define HISTORY_VISIT_ROW_FIELDS \ 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch " id,url,visit_time,from_visit,transition,segment_id,is_indexed " 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace history { 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochVisitDatabase::VisitDatabase() { 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochVisitDatabase::~VisitDatabase() { 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool VisitDatabase::InitVisitTable() { 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetDB().DoesTableExist("visits")) { 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetDB().Execute("CREATE TABLE visits(" 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "id INTEGER PRIMARY KEY," 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "url INTEGER NOT NULL," // key of the URL this corresponds to 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "visit_time INTEGER NOT NULL," 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "from_visit INTEGER," 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "transition INTEGER DEFAULT 0 NOT NULL," 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "segment_id INTEGER," 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // True when we have indexed data for this visit. 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "is_indexed BOOLEAN)")) 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (!GetDB().DoesColumnExist("visits", "is_indexed")) { 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Old versions don't have the is_indexed column, we can just add that and 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // not worry about different database revisions, since old ones will 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // continue to work. 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(brettw) this should be removed once we think everybody has been 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // updated (added early Mar 2008). 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetDB().Execute("ALTER TABLE visits ADD COLUMN is_indexed BOOLEAN")) 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Visit source table contains the source information for all the visits. To 553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // save space, we do not record those user browsed visits which would be the 563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // majority in this table. Only other sources are recorded. 573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Due to the tight relationship between visit_source and visits table, they 583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // should be created and dropped at the same time. 593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!GetDB().DoesTableExist("visit_source")) { 603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!GetDB().Execute("CREATE TABLE visit_source(" 613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick "id INTEGER PRIMARY KEY,source INTEGER NOT NULL)")) 623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Index over url so we can quickly find visits for a page. This will just 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // fail if it already exists and we'll ignore it. 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetDB().Execute("CREATE INDEX visits_url_index ON visits (url)"); 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create an index over from visits so that we can efficiently find 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // referrers and redirects. Ignore failures because it likely already exists. 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetDB().Execute("CREATE INDEX visits_from_index ON visits (from_visit)"); 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create an index over time so that we can efficiently find the visits in a 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // given time range (most history views are time-based). Ignore failures 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // because it likely already exists. 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetDB().Execute("CREATE INDEX visits_time_index ON visits (visit_time)"); 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool VisitDatabase::DropVisitTable() { 823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GetDB().Execute("DROP TABLE visit_source"); 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This will also drop the indices over the table. 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return GetDB().Execute("DROP TABLE visits"); 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Must be in sync with HISTORY_VISIT_ROW_FIELDS. 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid VisitDatabase::FillVisitRow(sql::Statement& statement, VisitRow* visit) { 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visit->visit_id = statement.ColumnInt64(0); 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visit->url_id = statement.ColumnInt64(1); 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visit->visit_time = base::Time::FromInternalValue(statement.ColumnInt64(2)); 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visit->referring_visit = statement.ColumnInt64(3); 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visit->transition = PageTransition::FromInt(statement.ColumnInt(4)); 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visit->segment_id = statement.ColumnInt64(5); 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visit->is_indexed = !!statement.ColumnInt(6); 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid VisitDatabase::FillVisitVector(sql::Statement& statement, 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch VisitVector* visits) { 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (statement.Step()) { 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch history::VisitRow visit; 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FillVisitRow(statement, &visit); 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visits->push_back(visit); 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickVisitID VisitDatabase::AddVisit(VisitRow* visit, VisitSource source) { 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "INSERT INTO visits " 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "(url, visit_time, from_visit, transition, segment_id, is_indexed) " 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "VALUES (?,?,?,?,?,?)")); 11472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!statement) { 11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen VLOG(0) << "Failed to build visit insert statement: " 11672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen << "url_id = " << visit->url_id; 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, visit->url_id); 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(1, visit->visit_time.ToInternalValue()); 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(2, visit->referring_visit); 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(3, visit->transition); 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(4, visit->segment_id); 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(5, visit->is_indexed); 12672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!statement.Run()) { 12872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen VLOG(0) << "Failed to execute visit insert statement: " 12972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen << "url_id = " << visit->url_id; 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 13172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visit->visit_id = GetDB().GetLastInsertRowId(); 1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (source != SOURCE_BROWSED) { 1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Record the source of this visit when it is not browsed. 1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick sql::Statement statement1(GetDB().GetCachedStatement(SQL_FROM_HERE, 1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick "INSERT INTO visit_source (id, source) VALUES (?,?)")); 13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!statement1.is_valid()) { 14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen VLOG(0) << "Failed to build visit_source insert statement: " 14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen << "url_id = " << visit->visit_id; 1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return 0; 14372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick statement1.BindInt64(0, visit->visit_id); 1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick statement1.BindInt64(1, source); 14772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!statement1.Run()) { 14872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen VLOG(0) << "Failed to execute visit_source insert statement: " 14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen << "url_id = " << visit->visit_id; 1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return 0; 15172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return visit->visit_id; 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid VisitDatabase::DeleteVisit(const VisitRow& visit) { 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Patch around this visit. Any visits that this went to will now have their 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // "source" be the deleted visit's source. 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement update_chain(GetDB().GetCachedStatement(SQL_FROM_HERE, 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "UPDATE visits SET from_visit=? WHERE from_visit=?")); 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!update_chain) 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch update_chain.BindInt64(0, visit.referring_visit); 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch update_chain.BindInt64(1, visit.visit_id); 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch update_chain.Run(); 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Now delete the actual visit. 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement del(GetDB().GetCachedStatement(SQL_FROM_HERE, 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "DELETE FROM visits WHERE id=?")); 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!del) 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch del.BindInt64(0, visit.visit_id); 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch del.Run(); 1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Try to delete the entry in visit_source table as well. 1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If the visit was browsed, there is no corresponding entry in visit_source 1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // table, and nothing will be deleted. 1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick del.Assign(GetDB().GetCachedStatement(SQL_FROM_HERE, 1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick "DELETE FROM visit_source WHERE id=?")); 1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!del.is_valid()) 1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick del.BindInt64(0, visit.visit_id); 1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick del.Run(); 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool VisitDatabase::GetRowForVisit(VisitID visit_id, VisitRow* out_visit) { 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits WHERE id=?")); 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, visit_id); 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement.Step()) 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FillVisitRow(statement, out_visit); 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We got a different visit than we asked for, something is wrong. 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(visit_id, out_visit->visit_id); 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (visit_id != out_visit->visit_id) 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool VisitDatabase::UpdateVisitRow(const VisitRow& visit) { 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't store inconsistent data to the database. 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_NE(visit.visit_id, visit.referring_visit); 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (visit.visit_id == visit.referring_visit) 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "UPDATE visits SET " 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "url=?,visit_time=?,from_visit=?,transition=?,segment_id=?,is_indexed=? " 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "WHERE id=?")); 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, visit.url_id); 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(1, visit.visit_time.ToInternalValue()); 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(2, visit.referring_visit); 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(3, visit.transition); 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(4, visit.segment_id); 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(5, visit.is_indexed); 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(6, visit.visit_id); 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return statement.Run(); 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool VisitDatabase::GetVisitsForURL(URLID url_id, VisitVector* visits) { 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visits->clear(); 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT" HISTORY_VISIT_ROW_FIELDS 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "FROM visits " 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "WHERE url=? " 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "ORDER BY visit_time ASC")); 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, url_id); 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FillVisitVector(statement, visits); 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid VisitDatabase::GetAllVisitsInRange(base::Time begin_time, 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::Time end_time, 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int max_results, 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch VisitVector* visits) { 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visits->clear(); 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits " 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "WHERE visit_time >= ? AND visit_time < ?" 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "ORDER BY visit_time LIMIT ?")); 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See GetVisibleVisitsInRange for more info on how these times are bound. 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 end = end_time.ToInternalValue(); 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, begin_time.ToInternalValue()); 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max()); 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(2, 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch max_results ? max_results : std::numeric_limits<int64>::max()); 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FillVisitVector(statement, visits); 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid VisitDatabase::GetVisitsInRangeForTransition( 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::Time begin_time, 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::Time end_time, 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int max_results, 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PageTransition::Type transition, 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch VisitVector* visits) { 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(visits); 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visits->clear(); 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits " 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "WHERE visit_time >= ? AND visit_time < ? " 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "AND (transition & ?) == ?" 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "ORDER BY visit_time LIMIT ?")); 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See GetVisibleVisitsInRange for more info on how these times are bound. 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 end = end_time.ToInternalValue(); 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, begin_time.ToInternalValue()); 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max()); 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(2, PageTransition::CORE_MASK); 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(3, transition); 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(4, 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch max_results ? max_results : std::numeric_limits<int64>::max()); 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FillVisitVector(statement, visits); 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid VisitDatabase::GetVisibleVisitsInRange(base::Time begin_time, 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::Time end_time, 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int max_count, 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch VisitVector* visits) { 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visits->clear(); 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The visit_time values can be duplicated in a redirect chain, so we sort 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // by id too, to ensure a consistent ordering just in case. 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits " 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "WHERE visit_time >= ? AND visit_time < ? " 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "AND (transition & ?) != 0 " // CHAIN_END 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "AND (transition & ?) NOT IN (?, ?, ?) " // NO SUBFRAME or 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // KEYWORD_GENERATED 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "ORDER BY visit_time DESC, id DESC")); 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Note that we use min/max values for querying unlimited ranges of time using 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the same statement. Since the time has an index, this will be about the 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // same amount of work as just doing a query for everything with no qualifier. 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 end = end_time.ToInternalValue(); 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, begin_time.ToInternalValue()); 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max()); 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(2, PageTransition::CHAIN_END); 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(3, PageTransition::CORE_MASK); 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(4, PageTransition::AUTO_SUBFRAME); 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(5, PageTransition::MANUAL_SUBFRAME); 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(6, PageTransition::KEYWORD_GENERATED); 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<URLID> found_urls; 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (statement.Step()) { 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch VisitRow visit; 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FillVisitRow(statement, &visit); 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure the URL this visit corresponds to is unique. 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (found_urls.find(visit.url_id) != found_urls.end()) 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch found_urls.insert(visit.url_id); 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visits->push_back(visit); 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (max_count > 0 && static_cast<int>(visits->size()) >= max_count) 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochVisitID VisitDatabase::GetMostRecentVisitForURL(URLID url_id, 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch VisitRow* visit_row) { 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The visit_time values can be duplicated in a redirect chain, so we sort 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // by id too, to ensure a consistent ordering just in case. 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits " 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "WHERE url=? " 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "ORDER BY visit_time DESC, id DESC " 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "LIMIT 1")); 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, url_id); 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement.Step()) 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; // No visits for this URL. 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (visit_row) { 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FillVisitRow(statement, visit_row); 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return visit_row->visit_id; 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return statement.ColumnInt64(0); 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool VisitDatabase::GetMostRecentVisitsForURL(URLID url_id, 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int max_results, 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch VisitVector* visits) { 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch visits->clear(); 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The visit_time values can be duplicated in a redirect chain, so we sort 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // by id too, to ensure a consistent ordering just in case. 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT" HISTORY_VISIT_ROW_FIELDS 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "FROM visits " 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "WHERE url=? " 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "ORDER BY visit_time DESC, id DESC " 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "LIMIT ?")); 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, url_id); 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(1, max_results); 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FillVisitVector(statement, visits); 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool VisitDatabase::GetRedirectFromVisit(VisitID from_visit, 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch VisitID* to_visit, 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL* to_url) { 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT v.id,u.url " 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "FROM visits v JOIN urls u ON v.url = u.id " 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "WHERE v.from_visit = ? " 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "AND (v.transition & ?) != 0")); // IS_REDIRECT_MASK 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, from_visit); 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt(1, PageTransition::IS_REDIRECT_MASK); 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement.Step()) 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; // No redirect from this visit. 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (to_visit) 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *to_visit = statement.ColumnInt64(0); 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (to_url) 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *to_url = GURL(statement.ColumnString(1)); 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool VisitDatabase::GetRedirectToVisit(VisitID to_visit, 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch VisitID* from_visit, 412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL* from_url) { 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch VisitRow row; 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetRowForVisit(to_visit, &row)) 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (from_visit) 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *from_visit = row.referring_visit; 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (from_url) { 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT u.url " 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "FROM visits v JOIN urls u ON v.url = u.id " 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "WHERE v.id = ?")); 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindInt64(0, row.referring_visit); 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement.Step()) 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *from_url = GURL(statement.ColumnString(0)); 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool VisitDatabase::GetVisitCountToHost(const GURL& url, 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int* count, 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::Time* first_visit) { 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!url.SchemeIs(chrome::kHttpScheme) && !url.SchemeIs(chrome::kHttpsScheme)) 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need to search for URLs with a matching host/port. One way to query for 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // this is to use the LIKE operator, eg 'url LIKE http://google.com/%'. This 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // is inefficient though in that it doesn't use the index and each entry must 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // be visited. The same query can be executed by using >= and < operator. 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The query becomes: 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 'url >= http://google.com/' and url < http://google.com0'. 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 0 is used as it is one character greater than '/'. 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL search_url(url); 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string host_query_min = search_url.GetOrigin().spec(); 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (host_query_min.empty()) 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string host_query_max = host_query_min; 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host_query_max[host_query_max.size() - 1] = '0'; 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT MIN(v.visit_time), COUNT(*) " 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "FROM visits v INNER JOIN urls u ON v.url = u.id " 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "WHERE (u.url >= ? AND u.url < ?)")); 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement) 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindString(0, host_query_min); 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch statement.BindString(1, host_query_max); 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement.Step()) { 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We've never been to this page before. 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *count = 0; 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *first_visit = base::Time::FromInternalValue(statement.ColumnInt64(0)); 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *count = statement.ColumnInt(1); 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool VisitDatabase::GetStartDate(base::Time* first_visit) { 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "SELECT MIN(visit_time) FROM visits WHERE visit_time != 0")); 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!statement || !statement.Step() || statement.ColumnInt64(0) == 0) { 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *first_visit = base::Time::Now(); 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *first_visit = base::Time::FromInternalValue(statement.ColumnInt64(0)); 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid VisitDatabase::GetVisitsSource(const VisitVector& visits, 4903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick VisitSourceMap* sources) { 4913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DCHECK(sources); 4923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick sources->clear(); 4933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 4943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We query the source in batch. Here defines the batch size. 4953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const size_t batch_size = 500; 4963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick size_t visits_size = visits.size(); 4973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 4983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick size_t start_index = 0, end_index = 0; 4993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick while (end_index < visits_size) { 5003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick start_index = end_index; 5013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick end_index = end_index + batch_size < visits_size ? end_index + batch_size 5023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick : visits_size; 5033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 5043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Compose the sql statement with a list of ids. 5053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::string sql = "SELECT id,source FROM visit_source "; 5063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick sql.append("WHERE id IN ("); 5073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Append all the ids in the statement. 5083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (size_t j = start_index; j < end_index; j++) { 5093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (j != start_index) 5103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick sql.push_back(','); 5113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick sql.append(base::Int64ToString(visits[j].visit_id)); 5123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 5133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick sql.append(") ORDER BY id"); 5143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick sql::Statement statement(GetDB().GetUniqueStatement(sql.c_str())); 5153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!statement) 5163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 5173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 5183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Get the source entries out of the query result. 5193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick while (statement.Step()) { 5203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::pair<VisitID, VisitSource> source_entry(statement.ColumnInt64(0), 5213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick static_cast<VisitSource>(statement.ColumnInt(1))); 5223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick sources->insert(source_entry); 5233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 5243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 5253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 5263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace history 528