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
5513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "app/sql/connection.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/sql/transaction.h"
7513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/file_util.h"
84a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/string_split.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/history/history_types.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/top_sites.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/top_sites_database.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace history {
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstatic const int kVersionNumber = 1;
18513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
19513209b27ff55e2841eac0e4120199c23acce758Ben MurdochTopSitesDatabase::TopSitesDatabase() : may_need_history_migration_(false) {
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
22513209b27ff55e2841eac0e4120199c23acce758Ben MurdochTopSitesDatabase::~TopSitesDatabase() {
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
25513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TopSitesDatabase::Init(const FilePath& db_name) {
26513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool file_existed = file_util::PathExists(db_name);
27513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
28513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!file_existed)
29513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    may_need_history_migration_ = true;
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  db_.reset(CreateDB(db_name));
32513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!db_.get())
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
34513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
35513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool does_meta_exist = sql::MetaTable::DoesTableExist(db_.get());
36513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!does_meta_exist && file_existed) {
37513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    may_need_history_migration_ = true;
38513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
39513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // If the meta file doesn't exist, this version is old. We could remove all
40513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // the entries as they are no longer applicable, but it's safest to just
41513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // remove the file and start over.
42513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    db_.reset(NULL);
43513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (!file_util::Delete(db_name, false) &&
44513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        !file_util::Delete(db_name, false)) {
45513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // Try to delete twice. If we can't, fail.
46513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      LOG(ERROR) << "unable to delete old TopSites file";
47513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      return false;
48513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
49513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    db_.reset(CreateDB(db_name));
50513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (!db_.get())
51513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      return false;
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
54513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!meta_table_.Init(db_.get(), kVersionNumber, kVersionNumber))
55513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
56513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
57513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!InitThumbnailTable())
58513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
59513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
60513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Version check.
61513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (meta_table_.GetVersionNumber() != kVersionNumber)
62513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
63513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
64513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return true;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TopSitesDatabase::InitThumbnailTable() {
68513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!db_->DoesTableExist("thumbnails")) {
69513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (!db_->Execute("CREATE TABLE thumbnails ("
70513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                      "url LONGVARCHAR PRIMARY KEY,"
71513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                      "url_rank INTEGER ,"
72513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                      "title LONGVARCHAR,"
73513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                      "thumbnail BLOB,"
74513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                      "redirects LONGVARCHAR,"
75513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                      "boring_score DOUBLE DEFAULT 1.0, "
76513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                      "good_clipping INTEGER DEFAULT 0, "
77513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                      "at_top INTEGER DEFAULT 0, "
78513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                      "last_updated INTEGER DEFAULT 0) ")) {
79513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      LOG(WARNING) << db_->GetErrorMessage();
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
86513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSitesDatabase::GetPageThumbnails(MostVisitedURLList* urls,
87513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                             URLToImagesMap* thumbnails) {
88513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  sql::Statement statement(db_->GetCachedStatement(
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SQL_FROM_HERE,
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "SELECT url, url_rank, title, thumbnail, redirects, "
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "boring_score, good_clipping, at_top, last_updated "
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "FROM thumbnails ORDER BY url_rank "));
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement) {
95513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(WARNING) << db_->GetErrorMessage();
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  urls->clear();
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  thumbnails->clear();
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (statement.Step()) {
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Results are sorted by url_rank.
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MostVisitedURL url;
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL gurl(statement.ColumnString(0));
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url.url = gurl;
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url.title = statement.ColumnString16(2);
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string redirects = statement.ColumnString(4);
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SetRedirects(redirects, &url);
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    urls->push_back(url);
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<unsigned char> data;
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    statement.ColumnBlobAsVector(3, &data);
1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    Images thumbnail;
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    thumbnail.thumbnail = RefCountedBytes::TakeVector(&data);
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    thumbnail.thumbnail_score.boring_score = statement.ColumnDouble(5);
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    thumbnail.thumbnail_score.good_clipping = statement.ColumnBool(6);
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    thumbnail.thumbnail_score.at_top = statement.ColumnBool(7);
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    thumbnail.thumbnail_score.time_at_snapshot =
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        base::Time::FromInternalValue(statement.ColumnInt64(8));
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*thumbnails)[gurl] = thumbnail;
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
127513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstd::string TopSitesDatabase::GetRedirects(const MostVisitedURL& url) {
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<std::string> redirects;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < url.redirects.size(); i++)
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    redirects.push_back(url.redirects[i].spec());
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return JoinString(redirects, ' ');
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
135513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSitesDatabase::SetRedirects(const std::string& redirects,
136513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                    MostVisitedURL* url) {
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<std::string> redirects_vector;
1384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  base::SplitStringAlongWhitespace(redirects, &redirects_vector);
1394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  for (size_t i = 0; i < redirects_vector.size(); ++i)
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url->redirects.push_back(GURL(redirects_vector[i]));
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSitesDatabase::SetPageThumbnail(const MostVisitedURL& url,
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            int new_rank,
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                            const Images& thumbnail) {
146513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  sql::Transaction transaction(db_.get());
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  transaction.Begin();
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rank = GetURLRank(url);
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (rank == -1) {
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddPageThumbnail(url, new_rank, thumbnail);
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UpdatePageRankNoTransaction(url, new_rank);
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UpdatePageThumbnail(url, thumbnail);
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  transaction.Commit();
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
160513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSitesDatabase::UpdatePageThumbnail(
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const MostVisitedURL& url, const Images& thumbnail) {
162513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  sql::Statement statement(db_->GetCachedStatement(
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SQL_FROM_HERE,
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "UPDATE thumbnails SET "
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "title = ?, thumbnail = ?, redirects = ?, "
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "boring_score = ?, good_clipping = ?, at_top = ?, last_updated = ? "
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "WHERE url = ? "));
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement)
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindString16(0, url.title);
172513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (thumbnail.thumbnail.get() && thumbnail.thumbnail->front()) {
173513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    statement.BindBlob(1, thumbnail.thumbnail->front(),
174513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                       static_cast<int>(thumbnail.thumbnail->size()));
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindString(2, GetRedirects(url));
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const ThumbnailScore& score = thumbnail.thumbnail_score;
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindDouble(3, score.boring_score);
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindBool(4, score.good_clipping);
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindBool(5, score.at_top);
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt64(6, score.time_at_snapshot.ToInternalValue());
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindString(7, url.url.spec());
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement.Run())
184513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    NOTREACHED() << db_->GetErrorMessage();
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
187513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSitesDatabase::AddPageThumbnail(const MostVisitedURL& url,
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            int new_rank,
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                            const Images& thumbnail) {
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int count = GetRowCount();
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
192513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  sql::Statement statement(db_->GetCachedStatement(
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SQL_FROM_HERE,
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "INSERT OR REPLACE INTO thumbnails "
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "(url, url_rank, title, thumbnail, redirects, "
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "boring_score, good_clipping, at_top, last_updated) "
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"));
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement)
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindString(0, url.url.spec());
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt(1, count);  // Make it the last url.
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindString16(2, url.title);
204513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (thumbnail.thumbnail.get() && thumbnail.thumbnail->front()) {
205513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    statement.BindBlob(3, thumbnail.thumbnail->front(),
206513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                       static_cast<int>(thumbnail.thumbnail->size()));
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindString(4, GetRedirects(url));
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const ThumbnailScore& score = thumbnail.thumbnail_score;
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindDouble(5, score.boring_score);
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindBool(6, score.good_clipping);
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindBool(7, score.at_top);
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt64(8, score.time_at_snapshot.ToInternalValue());
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement.Run())
215513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    NOTREACHED() << db_->GetErrorMessage();
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdatePageRankNoTransaction(url, new_rank);
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
220513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSitesDatabase::UpdatePageRank(const MostVisitedURL& url,
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          int new_rank) {
222513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  sql::Transaction transaction(db_.get());
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  transaction.Begin();
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdatePageRankNoTransaction(url, new_rank);
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  transaction.Commit();
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Caller should have a transaction open.
229513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSitesDatabase::UpdatePageRankNoTransaction(
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const MostVisitedURL& url, int new_rank) {
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int prev_rank = GetURLRank(url);
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (prev_rank == -1) {
2333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG(WARNING) << "Updating rank of an unknown URL: " << url.url.spec();
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Shift the ranks.
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (prev_rank > new_rank) {
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Shift up
240513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    sql::Statement shift_statement(db_->GetCachedStatement(
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SQL_FROM_HERE,
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "UPDATE thumbnails "
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "SET url_rank = url_rank + 1 "
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "WHERE url_rank >= ? AND url_rank < ?"));
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    shift_statement.BindInt(0, new_rank);
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    shift_statement.BindInt(1, prev_rank);
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (shift_statement)
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      shift_statement.Run();
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (prev_rank < new_rank) {
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Shift down
251513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    sql::Statement shift_statement(db_->GetCachedStatement(
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SQL_FROM_HERE,
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "UPDATE thumbnails "
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "SET url_rank = url_rank - 1 "
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "WHERE url_rank > ? AND url_rank <= ?"));
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    shift_statement.BindInt(0, prev_rank);
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    shift_statement.BindInt(1, new_rank);
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (shift_statement)
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      shift_statement.Run();
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set the url's rank.
263513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  sql::Statement set_statement(db_->GetCachedStatement(
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SQL_FROM_HERE,
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "UPDATE thumbnails "
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "SET url_rank = ? "
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "WHERE url == ?"));
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set_statement.BindInt(0, new_rank);
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set_statement.BindString(1, url.url.spec());
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (set_statement)
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    set_statement.Run();
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
274513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TopSitesDatabase::GetPageThumbnail(const GURL& url,
2753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                            Images* thumbnail) {
276513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  sql::Statement statement(db_->GetCachedStatement(
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SQL_FROM_HERE,
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "SELECT thumbnail, boring_score, good_clipping, at_top, last_updated "
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "FROM thumbnails WHERE url=?"));
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement) {
282513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(WARNING) << db_->GetErrorMessage();
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindString(0, url.spec());
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement.Step())
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<unsigned char> data;
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.ColumnBlobAsVector(0, &data);
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  thumbnail->thumbnail = RefCountedBytes::TakeVector(&data);
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  thumbnail->thumbnail_score.boring_score = statement.ColumnDouble(1);
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  thumbnail->thumbnail_score.good_clipping = statement.ColumnBool(2);
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  thumbnail->thumbnail_score.at_top = statement.ColumnBool(3);
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  thumbnail->thumbnail_score.time_at_snapshot =
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      base::Time::FromInternalValue(statement.ColumnInt64(4));
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
301513209b27ff55e2841eac0e4120199c23acce758Ben Murdochint TopSitesDatabase::GetRowCount() {
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int result = 0;
303513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  sql::Statement select_statement(db_->GetCachedStatement(
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SQL_FROM_HERE,
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "SELECT COUNT (url) FROM thumbnails"));
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!select_statement) {
307513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(WARNING) << db_->GetErrorMessage();
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (select_statement.Step())
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result = select_statement.ColumnInt(0);
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
317513209b27ff55e2841eac0e4120199c23acce758Ben Murdochint TopSitesDatabase::GetURLRank(const MostVisitedURL& url) {
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int result = -1;
319513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  sql::Statement select_statement(db_->GetCachedStatement(
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SQL_FROM_HERE,
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "SELECT url_rank "
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "FROM thumbnails WHERE url=?"));
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!select_statement) {
324513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(WARNING) << db_->GetErrorMessage();
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  select_statement.BindString(0, url.url.spec());
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (select_statement.Step())
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result = select_statement.ColumnInt(0);
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Remove the record for this URL. Returns true iff removed successfully.
336513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TopSitesDatabase::RemoveURL(const MostVisitedURL& url) {
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int old_rank = GetURLRank(url);
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (old_rank < 0)
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
341513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  sql::Transaction transaction(db_.get());
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  transaction.Begin();
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Decrement all following ranks.
344513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  sql::Statement shift_statement(db_->GetCachedStatement(
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SQL_FROM_HERE,
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "UPDATE thumbnails "
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "SET url_rank = url_rank - 1 "
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "WHERE url_rank > ?"));
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!shift_statement)
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  shift_statement.BindInt(0, old_rank);
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  shift_statement.Run();
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sql::Statement delete_statement(
355513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      db_->GetCachedStatement(SQL_FROM_HERE,
356513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                              "DELETE FROM thumbnails WHERE url = ?"));
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!delete_statement)
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete_statement.BindString(0, url.url.spec());
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete_statement.Run();
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transaction.Commit();
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
365513209b27ff55e2841eac0e4120199c23acce758Ben Murdochsql::Connection* TopSitesDatabase::CreateDB(const FilePath& db_name) {
366513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_ptr<sql::Connection> db(new sql::Connection());
367513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Settings copied from ThumbnailDatabase.
368513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  db->set_error_delegate(GetErrorHandlerForThumbnailDb());
369513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  db->set_page_size(4096);
370513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  db->set_cache_size(32);
371513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
372513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!db->Open(db_name)) {
373513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(ERROR) << db->GetErrorMessage();
374513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return NULL;
375513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
376513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
377513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return db.release();
378513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
379513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace history
381