1 // Copyright (c) 2011 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/webdata/keyword_table.h" 6 7 #include "app/sql/statement.h" 8 #include "base/logging.h" 9 #include "base/string_split.h" 10 #include "base/string_util.h" 11 #include "base/utf_string_conversions.h" 12 #include "chrome/browser/history/history_database.h" 13 #include "chrome/browser/search_engines/template_url.h" 14 #include "googleurl/src/gurl.h" 15 16 using base::Time; 17 18 namespace { 19 20 // ID of the url column in keywords. 21 const int kUrlIdPosition = 16; 22 23 // Keys used in the meta table. 24 const char* kDefaultSearchProviderKey = "Default Search Provider ID"; 25 const char* kBuiltinKeywordVersion = "Builtin Keyword Version"; 26 27 void BindURLToStatement(const TemplateURL& url, sql::Statement* s) { 28 s->BindString(0, UTF16ToUTF8(url.short_name())); 29 s->BindString(1, UTF16ToUTF8(url.keyword())); 30 GURL favicon_url = url.GetFaviconURL(); 31 if (!favicon_url.is_valid()) { 32 s->BindString(2, std::string()); 33 } else { 34 s->BindString(2, history::HistoryDatabase::GURLToDatabaseURL( 35 url.GetFaviconURL())); 36 } 37 s->BindString(3, url.url() ? url.url()->url() : std::string()); 38 s->BindInt(4, url.safe_for_autoreplace() ? 1 : 0); 39 if (!url.originating_url().is_valid()) { 40 s->BindString(5, std::string()); 41 } else { 42 s->BindString(5, history::HistoryDatabase::GURLToDatabaseURL( 43 url.originating_url())); 44 } 45 s->BindInt64(6, url.date_created().ToTimeT()); 46 s->BindInt(7, url.usage_count()); 47 s->BindString(8, JoinString(url.input_encodings(), ';')); 48 s->BindInt(9, url.show_in_default_list() ? 1 : 0); 49 s->BindString(10, url.suggestions_url() ? url.suggestions_url()->url() : 50 std::string()); 51 s->BindInt(11, url.prepopulate_id()); 52 s->BindInt(12, url.autogenerate_keyword() ? 1 : 0); 53 s->BindInt(13, url.logo_id()); 54 s->BindBool(14, url.created_by_policy()); 55 s->BindString(15, url.instant_url() ? url.instant_url()->url() : 56 std::string()); 57 } 58 } // anonymous namespace 59 60 KeywordTable::~KeywordTable() {} 61 62 bool KeywordTable::Init() { 63 if (!db_->DoesTableExist("keywords")) { 64 if (!db_->Execute("CREATE TABLE keywords (" 65 "id INTEGER PRIMARY KEY," 66 "short_name VARCHAR NOT NULL," 67 "keyword VARCHAR NOT NULL," 68 "favicon_url VARCHAR NOT NULL," 69 "url VARCHAR NOT NULL," 70 "show_in_default_list INTEGER," 71 "safe_for_autoreplace INTEGER," 72 "originating_url VARCHAR," 73 "date_created INTEGER DEFAULT 0," 74 "usage_count INTEGER DEFAULT 0," 75 "input_encodings VARCHAR," 76 "suggest_url VARCHAR," 77 "prepopulate_id INTEGER DEFAULT 0," 78 "autogenerate_keyword INTEGER DEFAULT 0," 79 "logo_id INTEGER DEFAULT 0," 80 "created_by_policy INTEGER DEFAULT 0," 81 "instant_url VARCHAR)")) { 82 NOTREACHED(); 83 return false; 84 } 85 } 86 return true; 87 } 88 89 bool KeywordTable::IsSyncable() { 90 return true; 91 } 92 93 bool KeywordTable::AddKeyword(const TemplateURL& url) { 94 DCHECK(url.id()); 95 // Be sure to change kUrlIdPosition if you add columns 96 sql::Statement s(db_->GetCachedStatement(SQL_FROM_HERE, 97 "INSERT INTO keywords " 98 "(short_name, keyword, favicon_url, url, safe_for_autoreplace, " 99 "originating_url, date_created, usage_count, input_encodings, " 100 "show_in_default_list, suggest_url, prepopulate_id, " 101 "autogenerate_keyword, logo_id, created_by_policy, instant_url, " 102 "id) VALUES " 103 "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")); 104 if (!s) { 105 NOTREACHED() << "Statement prepare failed"; 106 return false; 107 } 108 BindURLToStatement(url, &s); 109 s.BindInt64(kUrlIdPosition, url.id()); 110 if (!s.Run()) { 111 NOTREACHED(); 112 return false; 113 } 114 return true; 115 } 116 117 bool KeywordTable::RemoveKeyword(TemplateURLID id) { 118 DCHECK(id); 119 sql::Statement s( 120 db_->GetUniqueStatement("DELETE FROM keywords WHERE id = ?")); 121 if (!s) { 122 NOTREACHED() << "Statement prepare failed"; 123 return false; 124 } 125 s.BindInt64(0, id); 126 return s.Run(); 127 } 128 129 bool KeywordTable::GetKeywords(std::vector<TemplateURL*>* urls) { 130 sql::Statement s(db_->GetUniqueStatement( 131 "SELECT id, short_name, keyword, favicon_url, url, " 132 "safe_for_autoreplace, originating_url, date_created, " 133 "usage_count, input_encodings, show_in_default_list, " 134 "suggest_url, prepopulate_id, autogenerate_keyword, logo_id, " 135 "created_by_policy, instant_url " 136 "FROM keywords ORDER BY id ASC")); 137 if (!s) { 138 NOTREACHED() << "Statement prepare failed"; 139 return false; 140 } 141 while (s.Step()) { 142 TemplateURL* template_url = new TemplateURL(); 143 template_url->set_id(s.ColumnInt64(0)); 144 145 std::string tmp; 146 tmp = s.ColumnString(1); 147 DCHECK(!tmp.empty()); 148 template_url->set_short_name(UTF8ToUTF16(tmp)); 149 150 template_url->set_keyword(UTF8ToUTF16(s.ColumnString(2))); 151 152 tmp = s.ColumnString(3); 153 if (!tmp.empty()) 154 template_url->SetFaviconURL(GURL(tmp)); 155 156 template_url->SetURL(s.ColumnString(4), 0, 0); 157 158 template_url->set_safe_for_autoreplace(s.ColumnInt(5) == 1); 159 160 tmp = s.ColumnString(6); 161 if (!tmp.empty()) 162 template_url->set_originating_url(GURL(tmp)); 163 164 template_url->set_date_created(Time::FromTimeT(s.ColumnInt64(7))); 165 166 template_url->set_usage_count(s.ColumnInt(8)); 167 168 std::vector<std::string> encodings; 169 base::SplitString(s.ColumnString(9), ';', &encodings); 170 template_url->set_input_encodings(encodings); 171 172 template_url->set_show_in_default_list(s.ColumnInt(10) == 1); 173 174 template_url->SetSuggestionsURL(s.ColumnString(11), 0, 0); 175 176 template_url->set_prepopulate_id(s.ColumnInt(12)); 177 178 template_url->set_autogenerate_keyword(s.ColumnInt(13) == 1); 179 180 template_url->set_logo_id(s.ColumnInt(14)); 181 182 template_url->set_created_by_policy(s.ColumnBool(15)); 183 184 template_url->SetInstantURL(s.ColumnString(16), 0, 0); 185 186 urls->push_back(template_url); 187 } 188 return s.Succeeded(); 189 } 190 191 bool KeywordTable::UpdateKeyword(const TemplateURL& url) { 192 DCHECK(url.id()); 193 // Be sure to change kUrlIdPosition if you add columns 194 sql::Statement s(db_->GetUniqueStatement( 195 "UPDATE keywords " 196 "SET short_name=?, keyword=?, favicon_url=?, url=?, " 197 "safe_for_autoreplace=?, originating_url=?, date_created=?, " 198 "usage_count=?, input_encodings=?, show_in_default_list=?, " 199 "suggest_url=?, prepopulate_id=?, autogenerate_keyword=?, " 200 "logo_id=?, created_by_policy=?, instant_url=? WHERE id=?")); 201 if (!s) { 202 NOTREACHED() << "Statement prepare failed"; 203 return false; 204 } 205 BindURLToStatement(url, &s); 206 s.BindInt64(kUrlIdPosition, url.id()); 207 return s.Run(); 208 } 209 210 bool KeywordTable::SetDefaultSearchProviderID(int64 id) { 211 return meta_table_->SetValue(kDefaultSearchProviderKey, id); 212 } 213 214 int64 KeywordTable::GetDefaulSearchProviderID() { 215 int64 value = 0; 216 meta_table_->GetValue(kDefaultSearchProviderKey, &value); 217 return value; 218 } 219 220 bool KeywordTable::SetBuitinKeywordVersion(int version) { 221 return meta_table_->SetValue(kBuiltinKeywordVersion, version); 222 } 223 224 int KeywordTable::GetBuitinKeywordVersion() { 225 int version = 0; 226 meta_table_->GetValue(kBuiltinKeywordVersion, &version); 227 return version; 228 } 229 230 bool KeywordTable::MigrateToVersion21AutoGenerateKeywordColumn() { 231 return db_->Execute("ALTER TABLE keywords ADD COLUMN autogenerate_keyword " 232 "INTEGER DEFAULT 0"); 233 } 234 235 bool KeywordTable::MigrateToVersion25AddLogoIDColumn() { 236 return db_->Execute( 237 "ALTER TABLE keywords ADD COLUMN logo_id INTEGER DEFAULT 0"); 238 } 239 240 bool KeywordTable::MigrateToVersion26AddCreatedByPolicyColumn() { 241 return db_->Execute("ALTER TABLE keywords ADD COLUMN created_by_policy " 242 "INTEGER DEFAULT 0"); 243 } 244 245 bool KeywordTable::MigrateToVersion28SupportsInstantColumn() { 246 return db_->Execute("ALTER TABLE keywords ADD COLUMN supports_instant " 247 "INTEGER DEFAULT 0"); 248 } 249 250 bool KeywordTable::MigrateToVersion29InstantUrlToSupportsInstant() { 251 if (!db_->Execute("ALTER TABLE keywords ADD COLUMN instant_url VARCHAR")) 252 return false; 253 254 if (!db_->Execute("CREATE TABLE keywords_temp (" 255 "id INTEGER PRIMARY KEY," 256 "short_name VARCHAR NOT NULL," 257 "keyword VARCHAR NOT NULL," 258 "favicon_url VARCHAR NOT NULL," 259 "url VARCHAR NOT NULL," 260 "show_in_default_list INTEGER," 261 "safe_for_autoreplace INTEGER," 262 "originating_url VARCHAR," 263 "date_created INTEGER DEFAULT 0," 264 "usage_count INTEGER DEFAULT 0," 265 "input_encodings VARCHAR," 266 "suggest_url VARCHAR," 267 "prepopulate_id INTEGER DEFAULT 0," 268 "autogenerate_keyword INTEGER DEFAULT 0," 269 "logo_id INTEGER DEFAULT 0," 270 "created_by_policy INTEGER DEFAULT 0," 271 "instant_url VARCHAR)")) { 272 return false; 273 } 274 275 if (!db_->Execute( 276 "INSERT INTO keywords_temp " 277 "SELECT id, short_name, keyword, favicon_url, url, " 278 "show_in_default_list, safe_for_autoreplace, originating_url, " 279 "date_created, usage_count, input_encodings, suggest_url, " 280 "prepopulate_id, autogenerate_keyword, logo_id, created_by_policy, " 281 "instant_url FROM keywords")) { 282 return false; 283 } 284 285 if (!db_->Execute("DROP TABLE keywords")) 286 return false; 287 288 if (!db_->Execute("ALTER TABLE keywords_temp RENAME TO keywords")) 289 return false; 290 291 return true; 292 } 293