blob: 73ed0c77be45579bb0e6f6e7261bf0870edd0aec [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/predictors/autocomplete_action_predictor_table.h"
#include "base/guid.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "sql/statement.h"
namespace {
// TODO(shishir): Rename the table for consistency.
const char kAutocompletePredictorTableName[] = "network_action_predictor";
// The maximum length allowed for strings in the database.
const size_t kMaxDataLength = 2048;
void BindRowToStatement(
const predictors::AutocompleteActionPredictorTable::Row& row,
sql::Statement* statement) {
DCHECK(base::IsValidGUID(row.id));
statement->BindString(0, row.id);
statement->BindString16(1, row.user_text.substr(0, kMaxDataLength));
statement->BindString(2, row.url.spec().substr(0, kMaxDataLength));
statement->BindInt(3, row.number_of_hits);
statement->BindInt(4, row.number_of_misses);
}
bool StepAndInitializeRow(
sql::Statement* statement,
predictors::AutocompleteActionPredictorTable::Row* row) {
if (!statement->Step())
return false;
row->id = statement->ColumnString(0);
row->user_text = statement->ColumnString16(1);
row->url = GURL(statement->ColumnString(2));
row->number_of_hits = statement->ColumnInt(3);
row->number_of_misses = statement->ColumnInt(4);
return true;
}
} // namespace
namespace predictors {
AutocompleteActionPredictorTable::Row::Row()
: number_of_hits(0),
number_of_misses(0) {
}
AutocompleteActionPredictorTable::Row::Row(const Row::Id& id,
const base::string16& user_text,
const GURL& url,
int number_of_hits,
int number_of_misses)
: id(id),
user_text(user_text),
url(url),
number_of_hits(number_of_hits),
number_of_misses(number_of_misses) {
}
AutocompleteActionPredictorTable::Row::Row(const Row& row)
: id(row.id),
user_text(row.user_text),
url(row.url),
number_of_hits(row.number_of_hits),
number_of_misses(row.number_of_misses) {
}
void AutocompleteActionPredictorTable::GetRow(const Row::Id& id, Row* row) {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB));
if (CantAccessDatabase())
return;
sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
base::StringPrintf("SELECT * FROM %s WHERE id=?",
kAutocompletePredictorTableName).c_str()));
statement.BindString(0, id);
bool success = StepAndInitializeRow(&statement, row);
DCHECK(success) << "Failed to get row " << id << " from "
<< kAutocompletePredictorTableName;
}
void AutocompleteActionPredictorTable::GetAllRows(Rows* row_buffer) {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB));
if (CantAccessDatabase())
return;
row_buffer->clear();
sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
base::StringPrintf(
"SELECT * FROM %s", kAutocompletePredictorTableName).c_str()));
if (!statement.is_valid())
return;
Row row;
while (StepAndInitializeRow(&statement, &row))
row_buffer->push_back(row);
}
void AutocompleteActionPredictorTable::AddRow(
const AutocompleteActionPredictorTable::Row& row) {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB));
if (CantAccessDatabase())
return;
AddAndUpdateRows(Rows(1, row), Rows());
}
void AutocompleteActionPredictorTable::UpdateRow(
const AutocompleteActionPredictorTable::Row& row) {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB));
if (CantAccessDatabase())
return;
AddAndUpdateRows(Rows(), Rows(1, row));
}
void AutocompleteActionPredictorTable::AddAndUpdateRows(
const Rows& rows_to_add,
const Rows& rows_to_update) {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB));
if (CantAccessDatabase())
return;
if (!DB()->BeginTransaction())
return;
for (Rows::const_iterator it = rows_to_add.begin();
it != rows_to_add.end(); ++it) {
sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
base::StringPrintf(
"INSERT INTO %s "
"(id, user_text, url, number_of_hits, number_of_misses) "
"VALUES (?,?,?,?,?)", kAutocompletePredictorTableName).c_str()));
if (!statement.is_valid()) {
DB()->RollbackTransaction();
return;
}
BindRowToStatement(*it, &statement);
if (!statement.Run()) {
DB()->RollbackTransaction();
return;
}
}
for (Rows::const_iterator it = rows_to_update.begin();
it != rows_to_update.end(); ++it) {
sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
base::StringPrintf(
"UPDATE %s "
"SET id=?, user_text=?, url=?, number_of_hits=?, number_of_misses=?"
" WHERE id=?1", kAutocompletePredictorTableName).c_str()));
if (!statement.is_valid()) {
DB()->RollbackTransaction();
return;
}
BindRowToStatement(*it, &statement);
if (!statement.Run()) {
DB()->RollbackTransaction();
return;
}
DCHECK_GT(DB()->GetLastChangeCount(), 0);
}
DB()->CommitTransaction();
}
void AutocompleteActionPredictorTable::DeleteRows(
const std::vector<Row::Id>& id_list) {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB));
if (CantAccessDatabase())
return;
if (!DB()->BeginTransaction())
return;
for (std::vector<Row::Id>::const_iterator it = id_list.begin();
it != id_list.end(); ++it) {
sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
base::StringPrintf(
"DELETE FROM %s WHERE id=?",
kAutocompletePredictorTableName).c_str()));
if (!statement.is_valid()) {
DB()->RollbackTransaction();
return;
}
statement.BindString(0, *it);
if (!statement.Run()) {
DB()->RollbackTransaction();
return;
}
}
DB()->CommitTransaction();
}
void AutocompleteActionPredictorTable::DeleteAllRows() {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB));
if (CantAccessDatabase())
return;
sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
base::StringPrintf("DELETE FROM %s",
kAutocompletePredictorTableName).c_str()));
if (!statement.is_valid())
return;
statement.Run();
}
AutocompleteActionPredictorTable::AutocompleteActionPredictorTable()
: PredictorTableBase() {
}
AutocompleteActionPredictorTable::~AutocompleteActionPredictorTable() {
}
void AutocompleteActionPredictorTable::CreateTableIfNonExistent() {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB));
if (CantAccessDatabase())
return;
if (DB()->DoesTableExist(kAutocompletePredictorTableName))
return;
bool success = DB()->Execute(base::StringPrintf(
"CREATE TABLE %s ( "
"id TEXT PRIMARY KEY, "
"user_text TEXT, "
"url TEXT, "
"number_of_hits INTEGER, "
"number_of_misses INTEGER)", kAutocompletePredictorTableName).c_str());
if (!success)
ResetDB();
}
void AutocompleteActionPredictorTable::LogDatabaseStats() {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB));
if (CantAccessDatabase())
return;
sql::Statement count_statement(DB()->GetUniqueStatement(
base::StringPrintf("SELECT count(id) FROM %s",
kAutocompletePredictorTableName).c_str()));
if (!count_statement.is_valid() || !count_statement.Step())
return;
UMA_HISTOGRAM_COUNTS("AutocompleteActionPredictor.DatabaseRowCount",
count_statement.ColumnInt(0));
}
} // namespace predictors