Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / webdata / keyword_table.cc
blob585c629ad40a826f255cc244fcd43f2b53615a70
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.
5 #include "chrome/browser/webdata/keyword_table.h"
7 #include <set>
9 #include "base/json/json_reader.h"
10 #include "base/json/json_writer.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/values.h"
18 #include "chrome/browser/history/history_database.h"
19 #include "chrome/browser/search_engines/search_terms_data.h"
20 #include "chrome/browser/search_engines/template_url.h"
21 #include "chrome/browser/search_engines/template_url_service.h"
22 #include "components/webdata/common/web_database.h"
23 #include "sql/statement.h"
24 #include "sql/transaction.h"
25 #include "url/gurl.h"
27 using base::Time;
29 // static
30 const char KeywordTable::kDefaultSearchProviderKey[] =
31 "Default Search Provider ID";
33 namespace {
35 // Keys used in the meta table.
36 const char kBuiltinKeywordVersion[] = "Builtin Keyword Version";
38 const std::string ColumnsForVersion(int version, bool concatenated) {
39 std::vector<std::string> columns;
41 columns.push_back("id");
42 columns.push_back("short_name");
43 columns.push_back("keyword");
44 columns.push_back("favicon_url");
45 columns.push_back("url");
46 columns.push_back("safe_for_autoreplace");
47 columns.push_back("originating_url");
48 columns.push_back("date_created");
49 columns.push_back("usage_count");
50 columns.push_back("input_encodings");
51 columns.push_back("show_in_default_list");
52 columns.push_back("suggest_url");
53 columns.push_back("prepopulate_id");
54 if (version <= 44) {
55 // Columns removed after version 44.
56 columns.push_back("autogenerate_keyword");
57 columns.push_back("logo_id");
59 columns.push_back("created_by_policy");
60 columns.push_back("instant_url");
61 columns.push_back("last_modified");
62 columns.push_back("sync_guid");
63 if (version >= 47) {
64 // Column added in version 47.
65 columns.push_back("alternate_urls");
67 if (version >= 49) {
68 // Column added in version 49.
69 columns.push_back("search_terms_replacement_key");
71 if (version >= 52) {
72 // Column added in version 52.
73 columns.push_back("image_url");
74 columns.push_back("search_url_post_params");
75 columns.push_back("suggest_url_post_params");
76 columns.push_back("instant_url_post_params");
77 columns.push_back("image_url_post_params");
79 if (version >= 53) {
80 // Column added in version 53.
81 columns.push_back("new_tab_url");
84 return JoinString(columns, std::string(concatenated ? " || " : ", "));
88 // Inserts the data from |data| into |s|. |s| is assumed to have slots for all
89 // the columns in the keyword table. |id_column| is the slot number to bind
90 // |data|'s |id| to; |starting_column| is the slot number of the first of a
91 // contiguous set of slots to bind all the other fields to.
92 void BindURLToStatement(const TemplateURLData& data,
93 sql::Statement* s,
94 int id_column,
95 int starting_column) {
96 // Serialize |alternate_urls| to JSON.
97 // TODO(beaudoin): Check what it would take to use a new table to store
98 // alternate_urls while keeping backups and table signature in a good state.
99 // See: crbug.com/153520
100 base::ListValue alternate_urls_value;
101 for (size_t i = 0; i < data.alternate_urls.size(); ++i)
102 alternate_urls_value.AppendString(data.alternate_urls[i]);
103 std::string alternate_urls;
104 base::JSONWriter::Write(&alternate_urls_value, &alternate_urls);
106 s->BindInt64(id_column, data.id);
107 s->BindString16(starting_column, data.short_name);
108 s->BindString16(starting_column + 1, data.keyword());
109 s->BindString(starting_column + 2, data.favicon_url.is_valid() ?
110 history::HistoryDatabase::GURLToDatabaseURL(data.favicon_url) :
111 std::string());
112 s->BindString(starting_column + 3, data.url());
113 s->BindBool(starting_column + 4, data.safe_for_autoreplace);
114 s->BindString(starting_column + 5, data.originating_url.is_valid() ?
115 history::HistoryDatabase::GURLToDatabaseURL(data.originating_url) :
116 std::string());
117 s->BindInt64(starting_column + 6, data.date_created.ToTimeT());
118 s->BindInt(starting_column + 7, data.usage_count);
119 s->BindString(starting_column + 8, JoinString(data.input_encodings, ';'));
120 s->BindBool(starting_column + 9, data.show_in_default_list);
121 s->BindString(starting_column + 10, data.suggestions_url);
122 s->BindInt(starting_column + 11, data.prepopulate_id);
123 s->BindBool(starting_column + 12, data.created_by_policy);
124 s->BindString(starting_column + 13, data.instant_url);
125 s->BindInt64(starting_column + 14, data.last_modified.ToTimeT());
126 s->BindString(starting_column + 15, data.sync_guid);
127 s->BindString(starting_column + 16, alternate_urls);
128 s->BindString(starting_column + 17, data.search_terms_replacement_key);
129 s->BindString(starting_column + 18, data.image_url);
130 s->BindString(starting_column + 19, data.search_url_post_params);
131 s->BindString(starting_column + 20, data.suggestions_url_post_params);
132 s->BindString(starting_column + 21, data.instant_url_post_params);
133 s->BindString(starting_column + 22, data.image_url_post_params);
134 s->BindString(starting_column + 23, data.new_tab_url);
137 WebDatabaseTable::TypeKey GetKey() {
138 // We just need a unique constant. Use the address of a static that
139 // COMDAT folding won't touch in an optimizing linker.
140 static int table_key = 0;
141 return reinterpret_cast<void*>(&table_key);
144 } // namespace
146 KeywordTable::KeywordTable() {
149 KeywordTable::~KeywordTable() {}
151 KeywordTable* KeywordTable::FromWebDatabase(WebDatabase* db) {
152 return static_cast<KeywordTable*>(db->GetTable(GetKey()));
155 WebDatabaseTable::TypeKey KeywordTable::GetTypeKey() const {
156 return GetKey();
159 bool KeywordTable::Init(sql::Connection* db, sql::MetaTable* meta_table) {
160 WebDatabaseTable::Init(db, meta_table);
161 return db_->DoesTableExist("keywords") ||
162 db_->Execute("CREATE TABLE keywords ("
163 "id INTEGER PRIMARY KEY,"
164 "short_name VARCHAR NOT NULL,"
165 "keyword VARCHAR NOT NULL,"
166 "favicon_url VARCHAR NOT NULL,"
167 "url VARCHAR NOT NULL,"
168 "safe_for_autoreplace INTEGER,"
169 "originating_url VARCHAR,"
170 "date_created INTEGER DEFAULT 0,"
171 "usage_count INTEGER DEFAULT 0,"
172 "input_encodings VARCHAR,"
173 "show_in_default_list INTEGER,"
174 "suggest_url VARCHAR,"
175 "prepopulate_id INTEGER DEFAULT 0,"
176 "created_by_policy INTEGER DEFAULT 0,"
177 "instant_url VARCHAR,"
178 "last_modified INTEGER DEFAULT 0,"
179 "sync_guid VARCHAR,"
180 "alternate_urls VARCHAR,"
181 "search_terms_replacement_key VARCHAR,"
182 "image_url VARCHAR,"
183 "search_url_post_params VARCHAR,"
184 "suggest_url_post_params VARCHAR,"
185 "instant_url_post_params VARCHAR,"
186 "image_url_post_params VARCHAR,"
187 "new_tab_url VARCHAR)");
190 bool KeywordTable::IsSyncable() {
191 return true;
194 bool KeywordTable::MigrateToVersion(int version,
195 bool* update_compatible_version) {
196 // Migrate if necessary.
197 switch (version) {
198 case 21:
199 *update_compatible_version = true;
200 return MigrateToVersion21AutoGenerateKeywordColumn();
201 case 25:
202 *update_compatible_version = true;
203 return MigrateToVersion25AddLogoIDColumn();
204 case 26:
205 *update_compatible_version = true;
206 return MigrateToVersion26AddCreatedByPolicyColumn();
207 case 28:
208 *update_compatible_version = true;
209 return MigrateToVersion28SupportsInstantColumn();
210 case 29:
211 *update_compatible_version = true;
212 return MigrateToVersion29InstantURLToSupportsInstant();
213 case 38:
214 *update_compatible_version = true;
215 return MigrateToVersion38AddLastModifiedColumn();
216 case 39:
217 *update_compatible_version = true;
218 return MigrateToVersion39AddSyncGUIDColumn();
219 case 44:
220 *update_compatible_version = true;
221 return MigrateToVersion44AddDefaultSearchProviderBackup();
222 case 45:
223 *update_compatible_version = true;
224 return MigrateToVersion45RemoveLogoIDAndAutogenerateColumns();
225 case 47:
226 *update_compatible_version = true;
227 return MigrateToVersion47AddAlternateURLsColumn();
228 case 48:
229 *update_compatible_version = true;
230 return MigrateToVersion48RemoveKeywordsBackup();
231 case 49:
232 *update_compatible_version = true;
233 return MigrateToVersion49AddSearchTermsReplacementKeyColumn();
234 case 52:
235 *update_compatible_version = true;
236 return MigrateToVersion52AddImageSearchAndPOSTSupport();
237 case 53:
238 *update_compatible_version = true;
239 return MigrateToVersion53AddNewTabURLColumn();
242 return true;
245 bool KeywordTable::AddKeyword(const TemplateURLData& data) {
246 DCHECK(data.id);
247 std::string query("INSERT INTO keywords (" + GetKeywordColumns() + ") "
248 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,"
249 " ?)");
250 sql::Statement s(db_->GetUniqueStatement(query.c_str()));
251 BindURLToStatement(data, &s, 0, 1);
253 return s.Run();
256 bool KeywordTable::RemoveKeyword(TemplateURLID id) {
257 DCHECK(id);
258 sql::Statement s(
259 db_->GetUniqueStatement("DELETE FROM keywords WHERE id = ?"));
260 s.BindInt64(0, id);
262 return s.Run();
265 bool KeywordTable::GetKeywords(Keywords* keywords) {
266 std::string query("SELECT " + GetKeywordColumns() +
267 " FROM keywords ORDER BY id ASC");
268 sql::Statement s(db_->GetUniqueStatement(query.c_str()));
270 std::set<TemplateURLID> bad_entries;
271 while (s.Step()) {
272 keywords->push_back(TemplateURLData());
273 if (!GetKeywordDataFromStatement(s, &keywords->back())) {
274 bad_entries.insert(s.ColumnInt64(0));
275 keywords->pop_back();
278 bool succeeded = s.Succeeded();
279 for (std::set<TemplateURLID>::const_iterator i(bad_entries.begin());
280 i != bad_entries.end(); ++i)
281 succeeded &= RemoveKeyword(*i);
282 return succeeded;
285 bool KeywordTable::UpdateKeyword(const TemplateURLData& data) {
286 DCHECK(data.id);
287 sql::Statement s(db_->GetUniqueStatement("UPDATE keywords SET short_name=?, "
288 "keyword=?, favicon_url=?, url=?, safe_for_autoreplace=?, "
289 "originating_url=?, date_created=?, usage_count=?, input_encodings=?, "
290 "show_in_default_list=?, suggest_url=?, prepopulate_id=?, "
291 "created_by_policy=?, instant_url=?, last_modified=?, sync_guid=?, "
292 "alternate_urls=?, search_terms_replacement_key=?, image_url=?,"
293 "search_url_post_params=?, suggest_url_post_params=?, "
294 "instant_url_post_params=?, image_url_post_params=?, new_tab_url=? "
295 "WHERE id=?"));
296 BindURLToStatement(data, &s, 24, 0); // "24" binds id() as the last item.
298 return s.Run();
301 bool KeywordTable::SetDefaultSearchProviderID(int64 id) {
302 return meta_table_->SetValue(kDefaultSearchProviderKey, id);
305 int64 KeywordTable::GetDefaultSearchProviderID() {
306 int64 value = kInvalidTemplateURLID;
307 meta_table_->GetValue(kDefaultSearchProviderKey, &value);
308 return value;
311 bool KeywordTable::SetBuiltinKeywordVersion(int version) {
312 return meta_table_->SetValue(kBuiltinKeywordVersion, version);
315 int KeywordTable::GetBuiltinKeywordVersion() {
316 int version = 0;
317 return meta_table_->GetValue(kBuiltinKeywordVersion, &version) ? version : 0;
320 // static
321 std::string KeywordTable::GetKeywordColumns() {
322 return ColumnsForVersion(WebDatabase::kCurrentVersionNumber, false);
325 bool KeywordTable::MigrateToVersion21AutoGenerateKeywordColumn() {
326 return db_->Execute("ALTER TABLE keywords ADD COLUMN autogenerate_keyword "
327 "INTEGER DEFAULT 0");
330 bool KeywordTable::MigrateToVersion25AddLogoIDColumn() {
331 return db_->Execute(
332 "ALTER TABLE keywords ADD COLUMN logo_id INTEGER DEFAULT 0");
335 bool KeywordTable::MigrateToVersion26AddCreatedByPolicyColumn() {
336 return db_->Execute("ALTER TABLE keywords ADD COLUMN created_by_policy "
337 "INTEGER DEFAULT 0");
340 bool KeywordTable::MigrateToVersion28SupportsInstantColumn() {
341 return db_->Execute("ALTER TABLE keywords ADD COLUMN supports_instant "
342 "INTEGER DEFAULT 0");
345 bool KeywordTable::MigrateToVersion29InstantURLToSupportsInstant() {
346 sql::Transaction transaction(db_);
347 return transaction.Begin() &&
348 db_->Execute("ALTER TABLE keywords ADD COLUMN instant_url VARCHAR") &&
349 db_->Execute("CREATE TABLE keywords_temp ("
350 "id INTEGER PRIMARY KEY,"
351 "short_name VARCHAR NOT NULL,"
352 "keyword VARCHAR NOT NULL,"
353 "favicon_url VARCHAR NOT NULL,"
354 "url VARCHAR NOT NULL,"
355 "safe_for_autoreplace INTEGER,"
356 "originating_url VARCHAR,"
357 "date_created INTEGER DEFAULT 0,"
358 "usage_count INTEGER DEFAULT 0,"
359 "input_encodings VARCHAR,"
360 "show_in_default_list INTEGER,"
361 "suggest_url VARCHAR,"
362 "prepopulate_id INTEGER DEFAULT 0,"
363 "autogenerate_keyword INTEGER DEFAULT 0,"
364 "logo_id INTEGER DEFAULT 0,"
365 "created_by_policy INTEGER DEFAULT 0,"
366 "instant_url VARCHAR)") &&
367 db_->Execute("INSERT INTO keywords_temp SELECT id, short_name, keyword, "
368 "favicon_url, url, safe_for_autoreplace, originating_url, "
369 "date_created, usage_count, input_encodings, "
370 "show_in_default_list, suggest_url, prepopulate_id, "
371 "autogenerate_keyword, logo_id, created_by_policy, "
372 "instant_url FROM keywords") &&
373 db_->Execute("DROP TABLE keywords") &&
374 db_->Execute("ALTER TABLE keywords_temp RENAME TO keywords") &&
375 transaction.Commit();
378 bool KeywordTable::MigrateToVersion38AddLastModifiedColumn() {
379 return db_->Execute(
380 "ALTER TABLE keywords ADD COLUMN last_modified INTEGER DEFAULT 0");
383 bool KeywordTable::MigrateToVersion39AddSyncGUIDColumn() {
384 return db_->Execute("ALTER TABLE keywords ADD COLUMN sync_guid VARCHAR");
387 bool KeywordTable::MigrateToVersion44AddDefaultSearchProviderBackup() {
388 sql::Transaction transaction(db_);
389 if (!transaction.Begin())
390 return false;
392 int64 default_search_id = GetDefaultSearchProviderID();
393 if (!meta_table_->SetValue("Default Search Provider ID Backup",
394 default_search_id))
395 return false;
397 // Backup of all keywords.
398 if (db_->DoesTableExist("keywords_backup") &&
399 !db_->Execute("DROP TABLE keywords_backup"))
400 return false;
402 std::string query("CREATE TABLE keywords_backup AS SELECT " +
403 ColumnsForVersion(44, false) + " FROM keywords ORDER BY id ASC");
404 if (!db_->Execute(query.c_str()))
405 return false;
407 return transaction.Commit();
410 bool KeywordTable::MigrateToVersion45RemoveLogoIDAndAutogenerateColumns() {
411 sql::Transaction transaction(db_);
412 if (!transaction.Begin())
413 return false;
415 // The version 43 migration should have been written to do this, but since it
416 // wasn't, we'll do it now. Unfortunately a previous change deleted this for
417 // some users, so we can't be sure this will succeed (so don't bail on error).
418 meta_table_->DeleteKey("Default Search Provider Backup");
420 if (!MigrateKeywordsTableForVersion45("keywords"))
421 return false;
423 // Migrate the keywords backup table as well.
424 if (!MigrateKeywordsTableForVersion45("keywords_backup") ||
425 !meta_table_->SetValue("Default Search Provider ID Backup Signature",
426 std::string()))
427 return false;
429 return transaction.Commit();
432 bool KeywordTable::MigrateToVersion47AddAlternateURLsColumn() {
433 sql::Transaction transaction(db_);
435 // Fill the |alternate_urls| column with empty strings, otherwise it breaks
436 // code relying on GetTableContents that concatenates the strings from all
437 // the columns.
438 if (!transaction.Begin() ||
439 !db_->Execute("ALTER TABLE keywords ADD COLUMN "
440 "alternate_urls VARCHAR DEFAULT ''"))
441 return false;
443 // Migrate the keywords backup table as well.
444 if (!db_->Execute("ALTER TABLE keywords_backup ADD COLUMN "
445 "alternate_urls VARCHAR DEFAULT ''") ||
446 !meta_table_->SetValue("Default Search Provider ID Backup Signature",
447 std::string()))
448 return false;
450 return transaction.Commit();
453 bool KeywordTable::MigrateToVersion48RemoveKeywordsBackup() {
454 sql::Transaction transaction(db_);
455 if (!transaction.Begin())
456 return false;
458 if (!meta_table_->DeleteKey("Default Search Provider ID Backup") ||
459 !meta_table_->DeleteKey("Default Search Provider ID Backup Signature"))
460 return false;
462 if (!db_->Execute("DROP TABLE keywords_backup"))
463 return false;
465 return transaction.Commit();
468 bool KeywordTable::MigrateToVersion49AddSearchTermsReplacementKeyColumn() {
469 sql::Transaction transaction(db_);
471 // Fill the |search_terms_replacement_key| column with empty strings;
472 // See comments in MigrateToVersion47AddAlternateURLsColumn().
473 if (!transaction.Begin() ||
474 !db_->Execute("ALTER TABLE keywords ADD COLUMN "
475 "search_terms_replacement_key VARCHAR DEFAULT ''"))
476 return false;
478 return transaction.Commit();
481 bool KeywordTable::MigrateToVersion52AddImageSearchAndPOSTSupport() {
482 sql::Transaction transaction(db_);
484 // Fill the |image_url| and other four post params columns with empty strings;
485 return transaction.Begin() &&
486 db_->Execute("ALTER TABLE keywords ADD COLUMN image_url "
487 "VARCHAR DEFAULT ''") &&
488 db_->Execute("ALTER TABLE keywords ADD COLUMN search_url_post_params "
489 "VARCHAR DEFAULT ''") &&
490 db_->Execute("ALTER TABLE keywords ADD COLUMN suggest_url_post_params "
491 "VARCHAR DEFAULT ''") &&
492 db_->Execute("ALTER TABLE keywords ADD COLUMN instant_url_post_params "
493 "VARCHAR DEFAULT ''") &&
494 db_->Execute("ALTER TABLE keywords ADD COLUMN image_url_post_params "
495 "VARCHAR DEFAULT ''") &&
496 transaction.Commit();
499 bool KeywordTable::MigrateToVersion53AddNewTabURLColumn() {
500 sql::Transaction transaction(db_);
502 return transaction.Begin() &&
503 db_->Execute("ALTER TABLE keywords ADD COLUMN new_tab_url "
504 "VARCHAR DEFAULT ''") &&
505 transaction.Commit();
508 // static
509 bool KeywordTable::GetKeywordDataFromStatement(const sql::Statement& s,
510 TemplateURLData* data) {
511 DCHECK(data);
513 data->short_name = s.ColumnString16(1);
514 data->SetKeyword(s.ColumnString16(2));
515 // Due to past bugs, we might have persisted entries with empty URLs. Avoid
516 // reading these out. (GetKeywords() will delete these entries on return.)
517 // NOTE: This code should only be needed as long as we might be reading such
518 // potentially-old data and can be removed afterward.
519 if (s.ColumnString(4).empty())
520 return false;
521 data->SetURL(s.ColumnString(4));
522 data->suggestions_url = s.ColumnString(11);
523 data->instant_url = s.ColumnString(14);
524 data->image_url = s.ColumnString(19);
525 data->new_tab_url = s.ColumnString(24);
526 data->search_url_post_params = s.ColumnString(20);
527 data->suggestions_url_post_params = s.ColumnString(21);
528 data->instant_url_post_params = s.ColumnString(22);
529 data->image_url_post_params = s.ColumnString(23);
530 data->favicon_url = GURL(s.ColumnString(3));
531 data->originating_url = GURL(s.ColumnString(6));
532 data->show_in_default_list = s.ColumnBool(10);
533 data->safe_for_autoreplace = s.ColumnBool(5);
534 base::SplitString(s.ColumnString(9), ';', &data->input_encodings);
535 data->id = s.ColumnInt64(0);
536 data->date_created = Time::FromTimeT(s.ColumnInt64(7));
537 data->last_modified = Time::FromTimeT(s.ColumnInt64(15));
538 data->created_by_policy = s.ColumnBool(13);
539 data->usage_count = s.ColumnInt(8);
540 data->prepopulate_id = s.ColumnInt(12);
541 data->sync_guid = s.ColumnString(16);
543 data->alternate_urls.clear();
544 base::JSONReader json_reader;
545 scoped_ptr<base::Value> value(json_reader.ReadToValue(s.ColumnString(17)));
546 base::ListValue* alternate_urls_value;
547 if (value.get() && value->GetAsList(&alternate_urls_value)) {
548 std::string alternate_url;
549 for (size_t i = 0; i < alternate_urls_value->GetSize(); ++i) {
550 if (alternate_urls_value->GetString(i, &alternate_url))
551 data->alternate_urls.push_back(alternate_url);
555 data->search_terms_replacement_key = s.ColumnString(18);
557 return true;
560 bool KeywordTable::GetTableContents(const char* table_name,
561 int table_version,
562 std::string* contents) {
563 DCHECK(contents);
565 if (!db_->DoesTableExist(table_name))
566 return false;
568 contents->clear();
569 std::string query("SELECT " + ColumnsForVersion(table_version, true) +
570 " FROM " + std::string(table_name) + " ORDER BY id ASC");
571 sql::Statement s((table_version == WebDatabase::kCurrentVersionNumber) ?
572 db_->GetCachedStatement(sql::StatementID(table_name), query.c_str()) :
573 db_->GetUniqueStatement(query.c_str()));
574 while (s.Step())
575 *contents += s.ColumnString(0);
576 return s.Succeeded();
579 bool KeywordTable::GetKeywordAsString(TemplateURLID id,
580 const std::string& table_name,
581 std::string* result) {
582 std::string query("SELECT " +
583 ColumnsForVersion(WebDatabase::kCurrentVersionNumber, true) +
584 " FROM " + table_name + " WHERE id=?");
585 sql::Statement s(db_->GetUniqueStatement(query.c_str()));
586 s.BindInt64(0, id);
588 if (!s.Step()) {
589 LOG_IF(WARNING, s.Succeeded()) << "No keyword with id: " << id
590 << ", ignoring.";
591 return true;
594 if (!s.Succeeded())
595 return false;
597 *result = s.ColumnString(0);
598 return true;
601 bool KeywordTable::MigrateKeywordsTableForVersion45(const std::string& name) {
602 // Create a new table without the columns we're dropping.
603 if (!db_->Execute("CREATE TABLE keywords_temp ("
604 "id INTEGER PRIMARY KEY,"
605 "short_name VARCHAR NOT NULL,"
606 "keyword VARCHAR NOT NULL,"
607 "favicon_url VARCHAR NOT NULL,"
608 "url VARCHAR NOT NULL,"
609 "safe_for_autoreplace INTEGER,"
610 "originating_url VARCHAR,"
611 "date_created INTEGER DEFAULT 0,"
612 "usage_count INTEGER DEFAULT 0,"
613 "input_encodings VARCHAR,"
614 "show_in_default_list INTEGER,"
615 "suggest_url VARCHAR,"
616 "prepopulate_id INTEGER DEFAULT 0,"
617 "created_by_policy INTEGER DEFAULT 0,"
618 "instant_url VARCHAR,"
619 "last_modified INTEGER DEFAULT 0,"
620 "sync_guid VARCHAR)"))
621 return false;
622 std::string sql("INSERT INTO keywords_temp SELECT " +
623 ColumnsForVersion(46, false) + " FROM " + name);
624 if (!db_->Execute(sql.c_str()))
625 return false;
627 // NOTE: The ORDER BY here ensures that the uniquing process for keywords will
628 // happen identically on both the normal and backup tables.
629 sql = "SELECT id, keyword, url, autogenerate_keyword FROM " + name +
630 " ORDER BY id ASC";
631 sql::Statement s(db_->GetUniqueStatement(sql.c_str()));
632 base::string16 placeholder_keyword(base::ASCIIToUTF16("dummy"));
633 std::set<base::string16> keywords;
634 while (s.Step()) {
635 base::string16 keyword(s.ColumnString16(1));
636 bool generate_keyword = keyword.empty() || s.ColumnBool(3);
637 if (generate_keyword)
638 keyword = placeholder_keyword;
639 TemplateURLData data;
640 data.SetKeyword(keyword);
641 data.SetURL(s.ColumnString(2));
642 TemplateURL turl(NULL, data);
643 // Don't persist extension keywords to disk. These will get added to the
644 // TemplateURLService as the extensions are loaded.
645 bool delete_entry = turl.GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
646 if (!delete_entry && generate_keyword) {
647 // Explicitly generate keywords for all rows with the autogenerate bit set
648 // or where the keyword is empty.
649 SearchTermsData terms_data;
650 GURL url(TemplateURLService::GenerateSearchURLUsingTermsData(&turl,
651 terms_data));
652 if (!url.is_valid()) {
653 delete_entry = true;
654 } else {
655 // Ensure autogenerated keywords are unique.
656 keyword = TemplateURLService::GenerateKeyword(url);
657 while (keywords.count(keyword))
658 keyword.append(base::ASCIIToUTF16("_"));
659 sql::Statement u(db_->GetUniqueStatement(
660 "UPDATE keywords_temp SET keyword=? WHERE id=?"));
661 u.BindString16(0, keyword);
662 u.BindInt64(1, s.ColumnInt64(0));
663 if (!u.Run())
664 return false;
667 if (delete_entry) {
668 sql::Statement u(db_->GetUniqueStatement(
669 "DELETE FROM keywords_temp WHERE id=?"));
670 u.BindInt64(0, s.ColumnInt64(0));
671 if (!u.Run())
672 return false;
673 } else {
674 keywords.insert(keyword);
678 // Replace the old table with the new one.
679 sql = "DROP TABLE " + name;
680 if (!db_->Execute(sql.c_str()))
681 return false;
682 sql = "ALTER TABLE keywords_temp RENAME TO " + name;
683 return db_->Execute(sql.c_str());