1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/predictors/autocomplete_action_predictor_table.h" 6 7 #include "base/guid.h" 8 #include "base/logging.h" 9 #include "base/metrics/histogram.h" 10 #include "base/strings/stringprintf.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "content/public/browser/browser_thread.h" 13 #include "sql/statement.h" 14 15 namespace { 16 17 // TODO(shishir): Rename the table for consistency. 18 const char kAutocompletePredictorTableName[] = "network_action_predictor"; 19 20 // The maximum length allowed for strings in the database. 21 const size_t kMaxDataLength = 2048; 22 23 void BindRowToStatement( 24 const predictors::AutocompleteActionPredictorTable::Row& row, 25 sql::Statement* statement) { 26 DCHECK(base::IsValidGUID(row.id)); 27 statement->BindString(0, row.id); 28 statement->BindString16(1, row.user_text.substr(0, kMaxDataLength)); 29 statement->BindString(2, row.url.spec().substr(0, kMaxDataLength)); 30 statement->BindInt(3, row.number_of_hits); 31 statement->BindInt(4, row.number_of_misses); 32 } 33 34 bool StepAndInitializeRow( 35 sql::Statement* statement, 36 predictors::AutocompleteActionPredictorTable::Row* row) { 37 if (!statement->Step()) 38 return false; 39 40 row->id = statement->ColumnString(0); 41 row->user_text = statement->ColumnString16(1); 42 row->url = GURL(statement->ColumnString(2)); 43 row->number_of_hits = statement->ColumnInt(3); 44 row->number_of_misses = statement->ColumnInt(4); 45 return true; 46 } 47 48 } // namespace 49 50 namespace predictors { 51 52 AutocompleteActionPredictorTable::Row::Row() 53 : number_of_hits(0), 54 number_of_misses(0) { 55 } 56 57 AutocompleteActionPredictorTable::Row::Row(const Row::Id& id, 58 const string16& user_text, 59 const GURL& url, 60 int number_of_hits, 61 int number_of_misses) 62 : id(id), 63 user_text(user_text), 64 url(url), 65 number_of_hits(number_of_hits), 66 number_of_misses(number_of_misses) { 67 } 68 69 AutocompleteActionPredictorTable::Row::Row(const Row& row) 70 : id(row.id), 71 user_text(row.user_text), 72 url(row.url), 73 number_of_hits(row.number_of_hits), 74 number_of_misses(row.number_of_misses) { 75 } 76 77 78 void AutocompleteActionPredictorTable::GetRow(const Row::Id& id, Row* row) { 79 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); 80 if (CantAccessDatabase()) 81 return; 82 83 sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE, 84 base::StringPrintf("SELECT * FROM %s WHERE id=?", 85 kAutocompletePredictorTableName).c_str())); 86 statement.BindString(0, id); 87 88 bool success = StepAndInitializeRow(&statement, row); 89 DCHECK(success) << "Failed to get row " << id << " from " 90 << kAutocompletePredictorTableName; 91 } 92 93 void AutocompleteActionPredictorTable::GetAllRows(Rows* row_buffer) { 94 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); 95 if (CantAccessDatabase()) 96 return; 97 98 row_buffer->clear(); 99 100 sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE, 101 base::StringPrintf( 102 "SELECT * FROM %s", kAutocompletePredictorTableName).c_str())); 103 if (!statement.is_valid()) 104 return; 105 106 Row row; 107 while (StepAndInitializeRow(&statement, &row)) 108 row_buffer->push_back(row); 109 } 110 111 void AutocompleteActionPredictorTable::AddRow( 112 const AutocompleteActionPredictorTable::Row& row) { 113 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); 114 if (CantAccessDatabase()) 115 return; 116 117 AddAndUpdateRows(Rows(1, row), Rows()); 118 } 119 120 void AutocompleteActionPredictorTable::UpdateRow( 121 const AutocompleteActionPredictorTable::Row& row) { 122 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); 123 if (CantAccessDatabase()) 124 return; 125 126 AddAndUpdateRows(Rows(), Rows(1, row)); 127 } 128 129 void AutocompleteActionPredictorTable::AddAndUpdateRows( 130 const Rows& rows_to_add, 131 const Rows& rows_to_update) { 132 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); 133 if (CantAccessDatabase()) 134 return; 135 136 if (!DB()->BeginTransaction()) 137 return; 138 for (Rows::const_iterator it = rows_to_add.begin(); 139 it != rows_to_add.end(); ++it) { 140 sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE, 141 base::StringPrintf( 142 "INSERT INTO %s " 143 "(id, user_text, url, number_of_hits, number_of_misses) " 144 "VALUES (?,?,?,?,?)", kAutocompletePredictorTableName).c_str())); 145 if (!statement.is_valid()) { 146 DB()->RollbackTransaction(); 147 return; 148 } 149 150 BindRowToStatement(*it, &statement); 151 if (!statement.Run()) { 152 DB()->RollbackTransaction(); 153 return; 154 } 155 } 156 for (Rows::const_iterator it = rows_to_update.begin(); 157 it != rows_to_update.end(); ++it) { 158 sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE, 159 base::StringPrintf( 160 "UPDATE %s " 161 "SET id=?, user_text=?, url=?, number_of_hits=?, number_of_misses=?" 162 " WHERE id=?1", kAutocompletePredictorTableName).c_str())); 163 if (!statement.is_valid()) { 164 DB()->RollbackTransaction(); 165 return; 166 } 167 168 BindRowToStatement(*it, &statement); 169 if (!statement.Run()) { 170 DB()->RollbackTransaction(); 171 return; 172 } 173 DCHECK_GT(DB()->GetLastChangeCount(), 0); 174 } 175 DB()->CommitTransaction(); 176 } 177 178 void AutocompleteActionPredictorTable::DeleteRows( 179 const std::vector<Row::Id>& id_list) { 180 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); 181 if (CantAccessDatabase()) 182 return; 183 184 if (!DB()->BeginTransaction()) 185 return; 186 for (std::vector<Row::Id>::const_iterator it = id_list.begin(); 187 it != id_list.end(); ++it) { 188 sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE, 189 base::StringPrintf( 190 "DELETE FROM %s WHERE id=?", 191 kAutocompletePredictorTableName).c_str())); 192 if (!statement.is_valid()) { 193 DB()->RollbackTransaction(); 194 return; 195 } 196 197 statement.BindString(0, *it); 198 if (!statement.Run()) { 199 DB()->RollbackTransaction(); 200 return; 201 } 202 } 203 DB()->CommitTransaction(); 204 } 205 206 void AutocompleteActionPredictorTable::DeleteAllRows() { 207 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); 208 if (CantAccessDatabase()) 209 return; 210 211 sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE, 212 base::StringPrintf("DELETE FROM %s", 213 kAutocompletePredictorTableName).c_str())); 214 if (!statement.is_valid()) 215 return; 216 217 statement.Run(); 218 } 219 220 AutocompleteActionPredictorTable::AutocompleteActionPredictorTable() 221 : PredictorTableBase() { 222 } 223 224 AutocompleteActionPredictorTable::~AutocompleteActionPredictorTable() { 225 } 226 227 void AutocompleteActionPredictorTable::CreateTableIfNonExistent() { 228 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); 229 if (CantAccessDatabase()) 230 return; 231 232 if (DB()->DoesTableExist(kAutocompletePredictorTableName)) 233 return; 234 235 bool success = DB()->Execute(base::StringPrintf( 236 "CREATE TABLE %s ( " 237 "id TEXT PRIMARY KEY, " 238 "user_text TEXT, " 239 "url TEXT, " 240 "number_of_hits INTEGER, " 241 "number_of_misses INTEGER)", kAutocompletePredictorTableName).c_str()); 242 if (!success) 243 ResetDB(); 244 } 245 246 void AutocompleteActionPredictorTable::LogDatabaseStats() { 247 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::DB)); 248 if (CantAccessDatabase()) 249 return; 250 251 sql::Statement count_statement(DB()->GetUniqueStatement( 252 base::StringPrintf("SELECT count(id) FROM %s", 253 kAutocompletePredictorTableName).c_str())); 254 if (!count_statement.is_valid() || !count_statement.Step()) 255 return; 256 UMA_HISTOGRAM_COUNTS("AutocompleteActionPredictor.DatabaseRowCount", 257 count_statement.ColumnInt(0)); 258 } 259 260 } // namespace predictors 261