Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/webdata/keyword_table.h" | 5 #include "chrome/browser/webdata/keyword_table.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 12 #include "base/metrics/stats_counters.h" | 12 #include "base/metrics/stats_counters.h" |
| 13 #include "base/string_number_conversions.h" | 13 #include "base/string_number_conversions.h" |
| 14 #include "base/string_split.h" | 14 #include "base/string_split.h" |
| 15 #include "base/string_util.h" | 15 #include "base/string_util.h" |
| 16 #include "base/stringprintf.h" | 16 #include "base/stringprintf.h" |
| 17 #include "base/utf_string_conversions.h" | 17 #include "base/utf_string_conversions.h" |
| 18 #include "chrome/browser/history/history_database.h" | 18 #include "chrome/browser/history/history_database.h" |
| 19 #include "chrome/browser/protector/histograms.h" | 19 #include "chrome/browser/protector/histograms.h" |
| 20 #include "chrome/browser/protector/protector_utils.h" | 20 #include "chrome/browser/protector/protector_utils.h" |
| 21 #include "chrome/browser/search_engines/search_terms_data.h" | |
| 21 #include "chrome/browser/search_engines/template_url.h" | 22 #include "chrome/browser/search_engines/template_url.h" |
| 23 #include "chrome/browser/search_engines/template_url_service.h" | |
| 24 #include "chrome/browser/webdata/web_database.h" | |
| 22 #include "googleurl/src/gurl.h" | 25 #include "googleurl/src/gurl.h" |
| 23 #include "sql/statement.h" | 26 #include "sql/statement.h" |
| 24 #include "sql/transaction.h" | 27 #include "sql/transaction.h" |
| 25 | 28 |
| 26 using base::Time; | 29 using base::Time; |
| 27 | 30 |
| 28 // static | 31 // static |
| 29 const char KeywordTable::kDefaultSearchProviderKey[] = | 32 const char KeywordTable::kDefaultSearchProviderKey[] = |
| 30 "Default Search Provider ID"; | 33 "Default Search Provider ID"; |
| 31 const char KeywordTable::kDefaultSearchIDBackupKey[] = | 34 const char KeywordTable::kDefaultSearchIDBackupKey[] = |
| 32 "Default Search Provider ID Backup"; | 35 "Default Search Provider ID Backup"; |
| 33 const char KeywordTable::kBackupSignatureKey[] = | 36 const char KeywordTable::kBackupSignatureKey[] = |
| 34 "Default Search Provider ID Backup Signature"; | 37 "Default Search Provider ID Backup Signature"; |
| 35 const char KeywordTable::kKeywordColumns[] = "id, short_name, keyword, " | 38 const char KeywordTable::kKeywordColumns[] = "id, short_name, keyword, " |
| 36 "favicon_url, url, safe_for_autoreplace, originating_url, date_created, " | 39 "favicon_url, url, safe_for_autoreplace, originating_url, date_created, " |
| 37 "usage_count, input_encodings, show_in_default_list, suggest_url, " | 40 "usage_count, input_encodings, show_in_default_list, suggest_url, " |
| 38 "prepopulate_id, autogenerate_keyword, logo_id, created_by_policy, " | 41 "prepopulate_id, created_by_policy, instant_url, last_modified, sync_guid"; |
| 39 "instant_url, last_modified, sync_guid"; | |
| 40 | 42 |
| 41 namespace { | 43 namespace { |
| 42 | 44 |
| 43 // Keys used in the meta table. | 45 // Keys used in the meta table. |
| 44 const char kBuiltinKeywordVersion[] = "Builtin Keyword Version"; | 46 const char kBuiltinKeywordVersion[] = "Builtin Keyword Version"; |
| 45 | 47 |
| 48 // The set of columns up through version 44. (There were different columns | |
| 49 // below version 29 but none of the code below needs to worry about that case.) | |
| 50 const char kKeywordColumnsVersion44Concatenated[] = "id || short_name || " | |
| 51 "keyword || favicon_url || url || safe_for_autoreplace || " | |
| 52 "originating_url || date_created || usage_count || input_encodings || " | |
| 53 "show_in_default_list || suggest_url || prepopulate_id || " | |
| 54 "autogenerate_keyword || logo_id || created_by_policy || instant_url || " | |
| 55 "last_modified || sync_guid"; | |
| 56 const char kKeywordColumnsVersion44[] = "id, short_name, keyword, favicon_url, " | |
| 57 "url, safe_for_autoreplace, originating_url, date_created, usage_count, " | |
| 58 "input_encodings, show_in_default_list, suggest_url, prepopulate_id, " | |
| 59 "autogenerate_keyword, logo_id, created_by_policy, instant_url, " | |
| 60 "last_modified, sync_guid"; | |
| 61 // NOTE: Remember to change what |kKeywordColumnsVersion45| says if the column | |
| 62 // set in |kKeywordColumns| changes, and update any code that needs to switch | |
| 63 // column sets based on a version number! | |
| 64 const char* const kKeywordColumnsVersion45 = KeywordTable::kKeywordColumns; | |
| 65 | |
| 66 // The current columns. | |
| 46 const char kKeywordColumnsConcatenated[] = "id || short_name || keyword || " | 67 const char kKeywordColumnsConcatenated[] = "id || short_name || keyword || " |
| 47 "favicon_url || url || safe_for_autoreplace || originating_url || " | 68 "favicon_url || url || safe_for_autoreplace || originating_url || " |
| 48 "date_created || usage_count || input_encodings || show_in_default_list || " | 69 "date_created || usage_count || input_encodings || show_in_default_list || " |
| 49 "suggest_url || prepopulate_id || autogenerate_keyword || logo_id || " | 70 "suggest_url || prepopulate_id || created_by_policy || instant_url || " |
| 50 "created_by_policy || instant_url || last_modified || sync_guid"; | 71 "last_modified || sync_guid"; |
| 51 | 72 |
| 52 // Inserts the data from |data| into |s|. |s| is assumed to have slots for all | 73 // Inserts the data from |data| into |s|. |s| is assumed to have slots for all |
| 53 // the columns in the keyword table. |id_column| is the slot number to bind | 74 // the columns in the keyword table. |id_column| is the slot number to bind |
| 54 // |data|'s id() to; |starting_column| is the slot number of the first of a | 75 // |data|'s |id| to; |starting_column| is the slot number of the first of a |
| 55 // contiguous set of slots to bind all the other fields to. | 76 // contiguous set of slots to bind all the other fields to. |
| 56 void BindURLToStatement(const TemplateURL& url, | 77 void BindURLToStatement(const TemplateURLData& data, |
| 57 sql::Statement* s, | 78 sql::Statement* s, |
| 58 int id_column, | 79 int id_column, |
| 59 int starting_column) { | 80 int starting_column) { |
| 60 const TemplateURLData& data = url.data(); | |
| 61 s->BindInt64(id_column, data.id); | 81 s->BindInt64(id_column, data.id); |
| 62 s->BindString16(starting_column, data.short_name); | 82 s->BindString16(starting_column, data.short_name); |
| 63 // TODO(pkasting): See comment on TempalteURL::EnsureKeyword(). | 83 s->BindString16(starting_column + 1, data.keyword()); |
| 64 s->BindString16(starting_column + 1, | |
| 65 data.keyword(const_cast<TemplateURL*>(&url))); | |
| 66 s->BindString(starting_column + 2, data.favicon_url.is_valid() ? | 84 s->BindString(starting_column + 2, data.favicon_url.is_valid() ? |
| 67 history::HistoryDatabase::GURLToDatabaseURL(data.favicon_url) : | 85 history::HistoryDatabase::GURLToDatabaseURL(data.favicon_url) : |
| 68 std::string()); | 86 std::string()); |
| 69 s->BindString(starting_column + 3, data.url()); | 87 s->BindString(starting_column + 3, data.url()); |
| 70 s->BindBool(starting_column + 4, data.safe_for_autoreplace); | 88 s->BindBool(starting_column + 4, data.safe_for_autoreplace); |
| 71 s->BindString(starting_column + 5, data.originating_url.is_valid() ? | 89 s->BindString(starting_column + 5, data.originating_url.is_valid() ? |
| 72 history::HistoryDatabase::GURLToDatabaseURL(data.originating_url) : | 90 history::HistoryDatabase::GURLToDatabaseURL(data.originating_url) : |
| 73 std::string()); | 91 std::string()); |
| 74 s->BindInt64(starting_column + 6, data.date_created.ToTimeT()); | 92 s->BindInt64(starting_column + 6, data.date_created.ToTimeT()); |
| 75 s->BindInt(starting_column + 7, data.usage_count); | 93 s->BindInt(starting_column + 7, data.usage_count); |
| 76 s->BindString(starting_column + 8, JoinString(data.input_encodings, ';')); | 94 s->BindString(starting_column + 8, JoinString(data.input_encodings, ';')); |
| 77 s->BindBool(starting_column + 9, data.show_in_default_list); | 95 s->BindBool(starting_column + 9, data.show_in_default_list); |
| 78 s->BindString(starting_column + 10, data.suggestions_url); | 96 s->BindString(starting_column + 10, data.suggestions_url); |
| 79 s->BindInt(starting_column + 11, data.prepopulate_id); | 97 s->BindInt(starting_column + 11, data.prepopulate_id); |
| 80 s->BindBool(starting_column + 12, data.autogenerate_keyword()); | 98 s->BindBool(starting_column + 12, data.created_by_policy); |
| 81 s->BindInt(starting_column + 13, 0); | 99 s->BindString(starting_column + 13, data.instant_url); |
| 82 s->BindBool(starting_column + 14, data.created_by_policy); | 100 s->BindInt64(starting_column + 14, data.last_modified.ToTimeT()); |
| 83 s->BindString(starting_column + 15, data.instant_url); | 101 s->BindString(starting_column + 15, data.sync_guid); |
| 84 s->BindInt64(starting_column + 16, data.last_modified.ToTimeT()); | |
| 85 s->BindString(starting_column + 17, data.sync_guid); | |
| 86 } | 102 } |
| 87 | 103 |
| 88 // Signs search provider id and returns its signature. | 104 // Signs search provider id and returns its signature. |
| 89 std::string GetSearchProviderIDSignature(int64 id) { | 105 std::string GetSearchProviderIDSignature(int64 id) { |
| 90 return protector::SignSetting(base::Int64ToString(id)); | 106 return protector::SignSetting(base::Int64ToString(id)); |
| 91 } | 107 } |
| 92 | 108 |
| 93 // Checks if signature for search provider id is correct and returns the | 109 // Checks if signature for search provider id is correct and returns the |
| 94 // result. | 110 // result. |
| 95 bool IsSearchProviderIDValid(int64 id, const std::string& signature) { | 111 bool IsSearchProviderIDValid(int64 id, const std::string& signature) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 109 "favicon_url VARCHAR NOT NULL," | 125 "favicon_url VARCHAR NOT NULL," |
| 110 "url VARCHAR NOT NULL," | 126 "url VARCHAR NOT NULL," |
| 111 "safe_for_autoreplace INTEGER," | 127 "safe_for_autoreplace INTEGER," |
| 112 "originating_url VARCHAR," | 128 "originating_url VARCHAR," |
| 113 "date_created INTEGER DEFAULT 0," | 129 "date_created INTEGER DEFAULT 0," |
| 114 "usage_count INTEGER DEFAULT 0," | 130 "usage_count INTEGER DEFAULT 0," |
| 115 "input_encodings VARCHAR," | 131 "input_encodings VARCHAR," |
| 116 "show_in_default_list INTEGER," | 132 "show_in_default_list INTEGER," |
| 117 "suggest_url VARCHAR," | 133 "suggest_url VARCHAR," |
| 118 "prepopulate_id INTEGER DEFAULT 0," | 134 "prepopulate_id INTEGER DEFAULT 0," |
| 119 "autogenerate_keyword INTEGER DEFAULT 0," | |
| 120 "logo_id INTEGER DEFAULT 0," | |
| 121 "created_by_policy INTEGER DEFAULT 0," | 135 "created_by_policy INTEGER DEFAULT 0," |
| 122 "instant_url VARCHAR," | 136 "instant_url VARCHAR," |
| 123 "last_modified INTEGER DEFAULT 0," | 137 "last_modified INTEGER DEFAULT 0," |
| 124 "sync_guid VARCHAR)") && | 138 "sync_guid VARCHAR)") && |
| 125 UpdateBackupSignature()); | 139 UpdateBackupSignature(WebDatabase::kCurrentVersionNumber)); |
| 126 } | 140 } |
| 127 | 141 |
| 128 bool KeywordTable::IsSyncable() { | 142 bool KeywordTable::IsSyncable() { |
| 129 return true; | 143 return true; |
| 130 } | 144 } |
| 131 | 145 |
| 132 bool KeywordTable::AddKeyword(const TemplateURL& url) { | 146 bool KeywordTable::AddKeyword(const TemplateURLData& data) { |
| 133 DCHECK(url.id()); | 147 DCHECK(data.id); |
| 134 std::string query("INSERT INTO keywords (" + std::string(kKeywordColumns) + | 148 std::string query("INSERT INTO keywords (" + std::string(kKeywordColumns) + |
| 135 ") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); | 149 ") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); |
| 136 sql::Statement s(db_->GetUniqueStatement(query.c_str())); | 150 sql::Statement s(db_->GetUniqueStatement(query.c_str())); |
| 137 BindURLToStatement(url, &s, 0, 1); | 151 BindURLToStatement(data, &s, 0, 1); |
| 138 | 152 |
| 139 return s.Run() && UpdateBackupSignature(); | 153 return s.Run() && UpdateBackupSignature(WebDatabase::kCurrentVersionNumber); |
| 140 } | 154 } |
| 141 | 155 |
| 142 bool KeywordTable::RemoveKeyword(TemplateURLID id) { | 156 bool KeywordTable::RemoveKeyword(TemplateURLID id) { |
| 143 DCHECK(id); | 157 DCHECK(id); |
| 144 sql::Statement s( | 158 sql::Statement s( |
| 145 db_->GetUniqueStatement("DELETE FROM keywords WHERE id = ?")); | 159 db_->GetUniqueStatement("DELETE FROM keywords WHERE id = ?")); |
| 146 s.BindInt64(0, id); | 160 s.BindInt64(0, id); |
| 147 | 161 |
| 148 return s.Run() && UpdateBackupSignature(); | 162 return s.Run() && UpdateBackupSignature(WebDatabase::kCurrentVersionNumber); |
| 149 } | 163 } |
| 150 | 164 |
| 151 bool KeywordTable::GetKeywords(Keywords* keywords) { | 165 bool KeywordTable::GetKeywords(Keywords* keywords) { |
| 152 std::string query("SELECT " + std::string(kKeywordColumns) + | 166 std::string query("SELECT " + std::string(kKeywordColumns) + |
| 153 " FROM keywords ORDER BY id ASC"); | 167 " FROM keywords ORDER BY id ASC"); |
| 154 sql::Statement s(db_->GetUniqueStatement(query.c_str())); | 168 sql::Statement s(db_->GetUniqueStatement(query.c_str())); |
| 155 | 169 |
| 156 std::set<TemplateURLID> bad_entries; | 170 std::set<TemplateURLID> bad_entries; |
| 157 while (s.Step()) { | 171 while (s.Step()) { |
| 158 keywords->push_back(TemplateURLData()); | 172 keywords->push_back(TemplateURLData()); |
| 159 if (!GetKeywordDataFromStatement(s, &keywords->back())) { | 173 if (!GetKeywordDataFromStatement(s, &keywords->back())) { |
| 160 bad_entries.insert(s.ColumnInt64(0)); | 174 bad_entries.insert(s.ColumnInt64(0)); |
| 161 keywords->pop_back(); | 175 keywords->pop_back(); |
| 162 } | 176 } |
| 163 } | 177 } |
| 164 bool succeeded = s.Succeeded(); | 178 bool succeeded = s.Succeeded(); |
| 165 for (std::set<TemplateURLID>::const_iterator i(bad_entries.begin()); | 179 for (std::set<TemplateURLID>::const_iterator i(bad_entries.begin()); |
| 166 i != bad_entries.end(); ++i) | 180 i != bad_entries.end(); ++i) |
| 167 succeeded &= RemoveKeyword(*i); | 181 succeeded &= RemoveKeyword(*i); |
| 168 return succeeded; | 182 return succeeded; |
| 169 } | 183 } |
| 170 | 184 |
| 171 bool KeywordTable::UpdateKeyword(const TemplateURL& url) { | 185 bool KeywordTable::UpdateKeyword(const TemplateURLData& data) { |
| 172 DCHECK(url.id()); | 186 DCHECK(data.id); |
| 173 sql::Statement s(db_->GetUniqueStatement("UPDATE keywords SET short_name=?, " | 187 sql::Statement s(db_->GetUniqueStatement("UPDATE keywords SET short_name=?, " |
| 174 "keyword=?, favicon_url=?, url=?, safe_for_autoreplace=?, " | 188 "keyword=?, favicon_url=?, url=?, safe_for_autoreplace=?, " |
| 175 "originating_url=?, date_created=?, usage_count=?, input_encodings=?, " | 189 "originating_url=?, date_created=?, usage_count=?, input_encodings=?, " |
| 176 "show_in_default_list=?, suggest_url=?, prepopulate_id=?, " | 190 "show_in_default_list=?, suggest_url=?, prepopulate_id=?, " |
| 177 "autogenerate_keyword=?, logo_id=?, created_by_policy=?, instant_url=?, " | 191 "created_by_policy=?, instant_url=?, last_modified=?, sync_guid=? WHERE " |
| 178 "last_modified=?, sync_guid=? WHERE id=?")); | 192 "id=?")); |
| 179 BindURLToStatement(url, &s, 18, 0); // "18" binds id() as the last item. | 193 BindURLToStatement(data, &s, 16, 0); // "16" binds id() as the last item. |
| 180 | 194 |
| 181 return s.Run() && UpdateBackupSignature(); | 195 return s.Run() && UpdateBackupSignature(WebDatabase::kCurrentVersionNumber); |
| 182 } | 196 } |
| 183 | 197 |
| 184 bool KeywordTable::SetDefaultSearchProviderID(int64 id) { | 198 bool KeywordTable::SetDefaultSearchProviderID(int64 id) { |
| 185 // Added for http://crbug.com/116952. | 199 // Added for http://crbug.com/116952. |
| 186 UMA_HISTOGRAM_COUNTS_100("Search.DefaultSearchProviderID", | 200 UMA_HISTOGRAM_COUNTS_100("Search.DefaultSearchProviderID", |
| 187 static_cast<int32>(id)); | 201 static_cast<int32>(id)); |
| 188 return meta_table_->SetValue(kDefaultSearchProviderKey, id) && | 202 return meta_table_->SetValue(kDefaultSearchProviderKey, id) && |
| 189 UpdateBackupSignature(); | 203 UpdateBackupSignature(WebDatabase::kCurrentVersionNumber); |
| 190 } | 204 } |
| 191 | 205 |
| 192 int64 KeywordTable::GetDefaultSearchProviderID() { | 206 int64 KeywordTable::GetDefaultSearchProviderID() { |
| 193 int64 value = kInvalidTemplateURLID; | 207 int64 value = kInvalidTemplateURLID; |
| 194 meta_table_->GetValue(kDefaultSearchProviderKey, &value); | 208 meta_table_->GetValue(kDefaultSearchProviderKey, &value); |
| 195 return value; | 209 return value; |
| 196 } | 210 } |
| 197 | 211 |
| 198 bool KeywordTable::GetDefaultSearchProviderBackup(TemplateURLData* backup) { | 212 bool KeywordTable::GetDefaultSearchProviderBackup(TemplateURLData* backup) { |
| 199 if (!IsBackupSignatureValid()) | 213 if (!IsBackupSignatureValid(WebDatabase::kCurrentVersionNumber)) |
| 200 return false; | 214 return false; |
| 201 | 215 |
| 202 int64 backup_id = kInvalidTemplateURLID; | 216 int64 backup_id = kInvalidTemplateURLID; |
| 203 if (!meta_table_->GetValue(kDefaultSearchIDBackupKey, &backup_id)) { | 217 if (!meta_table_->GetValue(kDefaultSearchIDBackupKey, &backup_id)) { |
| 204 LOG(ERROR) << "No default search id backup found."; | 218 LOG(ERROR) << "No default search id backup found."; |
| 205 return false; | 219 return false; |
| 206 } | 220 } |
| 207 std::string query("SELECT " + std::string(kKeywordColumns) + | 221 std::string query("SELECT " + std::string(kKeywordColumns) + |
| 208 " FROM keywords_backup WHERE id=?"); | 222 " FROM keywords_backup WHERE id=?"); |
| 209 sql::Statement s(db_->GetUniqueStatement(query.c_str())); | 223 sql::Statement s(db_->GetUniqueStatement(query.c_str())); |
| 210 s.BindInt64(0, backup_id); | 224 s.BindInt64(0, backup_id); |
| 211 | 225 |
| 212 if (!s.Step()) { | 226 if (!s.Step()) { |
| 213 LOG_IF(ERROR, s.Succeeded()) | 227 LOG_IF(ERROR, s.Succeeded()) |
| 214 << "No default search provider with backup id."; | 228 << "No default search provider with backup id."; |
| 215 return NULL; | 229 return false; |
| 216 } | 230 } |
| 217 | 231 |
| 218 if (!GetKeywordDataFromStatement(s, backup)) | 232 if (!GetKeywordDataFromStatement(s, backup)) |
| 219 return false; | 233 return false; |
| 220 | 234 |
| 221 // ID has no meaning for the backup and should be kInvalidTemplateURLID in | 235 // ID has no meaning for the backup and should be kInvalidTemplateURLID in |
| 222 // case the TemplateURL will be added to keywords if missing. | 236 // case the TemplateURL will be added to keywords if missing. |
| 223 backup->id = kInvalidTemplateURLID; | 237 backup->id = kInvalidTemplateURLID; |
| 224 return true; | 238 return true; |
| 225 } | 239 } |
| 226 | 240 |
| 227 bool KeywordTable::DidDefaultSearchProviderChange() { | 241 bool KeywordTable::DidDefaultSearchProviderChange() { |
| 228 if (!IsBackupSignatureValid()) { | 242 if (!IsBackupSignatureValid(WebDatabase::kCurrentVersionNumber)) { |
| 229 UMA_HISTOGRAM_ENUMERATION( | 243 UMA_HISTOGRAM_ENUMERATION( |
| 230 protector::kProtectorHistogramDefaultSearchProvider, | 244 protector::kProtectorHistogramDefaultSearchProvider, |
| 231 protector::kProtectorErrorBackupInvalid, | 245 protector::kProtectorErrorBackupInvalid, |
| 232 protector::kProtectorErrorCount); | 246 protector::kProtectorErrorCount); |
| 233 LOG(ERROR) << "Backup signature is invalid."; | 247 LOG(ERROR) << "Backup signature is invalid."; |
| 234 return true; | 248 return true; |
| 235 } | 249 } |
| 236 | 250 |
| 237 int64 backup_id = kInvalidTemplateURLID; | 251 int64 backup_id = kInvalidTemplateURLID; |
| 238 meta_table_->GetValue(kDefaultSearchIDBackupKey, &backup_id); | 252 meta_table_->GetValue(kDefaultSearchIDBackupKey, &backup_id); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 333 bool KeywordTable::MigrateToVersion38AddLastModifiedColumn() { | 347 bool KeywordTable::MigrateToVersion38AddLastModifiedColumn() { |
| 334 return db_->Execute( | 348 return db_->Execute( |
| 335 "ALTER TABLE keywords ADD COLUMN last_modified INTEGER DEFAULT 0"); | 349 "ALTER TABLE keywords ADD COLUMN last_modified INTEGER DEFAULT 0"); |
| 336 } | 350 } |
| 337 | 351 |
| 338 bool KeywordTable::MigrateToVersion39AddSyncGUIDColumn() { | 352 bool KeywordTable::MigrateToVersion39AddSyncGUIDColumn() { |
| 339 return db_->Execute("ALTER TABLE keywords ADD COLUMN sync_guid VARCHAR"); | 353 return db_->Execute("ALTER TABLE keywords ADD COLUMN sync_guid VARCHAR"); |
| 340 } | 354 } |
| 341 | 355 |
| 342 bool KeywordTable::MigrateToVersion44AddDefaultSearchProviderBackup() { | 356 bool KeywordTable::MigrateToVersion44AddDefaultSearchProviderBackup() { |
| 343 return IsBackupSignatureValid() || UpdateBackupSignature(); | 357 return IsBackupSignatureValid(44) || UpdateBackupSignature(44); |
| 358 } | |
| 359 | |
| 360 bool KeywordTable::MigrateToVersion45RemoveLogoIDAndAutogenerateColumns() { | |
| 361 sql::Transaction transaction(db_); | |
| 362 if (!transaction.Begin()) | |
| 363 return false; | |
| 364 | |
| 365 // The version 43 migration should have been written to do this, but since it | |
| 366 // wasn't, we'll do it now. Unfortunately a previous change deleted this for | |
| 367 // some users, so we can't be sure this will succeed (so don't bail on error). | |
| 368 meta_table_->DeleteKey("Default Search Provider Backup"); | |
| 369 | |
| 370 if (!MigrateKeywordsTableForVersion45("keywords")) | |
| 371 return false; | |
| 372 | |
| 373 if (IsBackupSignatureValid(44)) { | |
| 374 // Migrate the keywords backup table as well. | |
| 375 if (!MigrateKeywordsTableForVersion45("keywords_backup") || !SignBackup(45)) | |
| 376 return false; | |
| 377 } else { | |
| 378 // Old backup was invalid; drop the table entirely, which will prompt the | |
| 379 // user. | |
| 380 // REVIEWERS: Should I eventually return false if I went through this | |
| 381 // codepath, even if we successfully drop the table and commit the | |
| 382 // transaction? | |
|
sky
2012/05/04 23:20:25
Don't you want to create backup table if you end u
Peter Kasting
2012/05/07 17:50:24
Ivan said no in email.
| |
| 383 if (!db_->Execute("DROP TABLE keywords_backup")) | |
| 384 return false; | |
| 385 } | |
| 386 | |
| 387 return transaction.Commit(); | |
| 344 } | 388 } |
| 345 | 389 |
| 346 // static | 390 // static |
| 347 bool KeywordTable::GetKeywordDataFromStatement(const sql::Statement& s, | 391 bool KeywordTable::GetKeywordDataFromStatement(const sql::Statement& s, |
| 348 TemplateURLData* data) { | 392 TemplateURLData* data) { |
| 349 DCHECK(data); | 393 DCHECK(data); |
| 350 data->short_name = s.ColumnString16(1); | 394 data->short_name = s.ColumnString16(1); |
|
sky
2012/05/04 23:20:25
nit: making the order of these match the order we
Peter Kasting
2012/05/07 17:50:24
You lose either way; the order here is the order i
| |
| 351 data->SetKeyword(s.ColumnString16(2)); | 395 data->SetKeyword(s.ColumnString16(2)); |
| 352 data->SetAutogenerateKeyword(s.ColumnBool(13)); | |
| 353 // Due to past bugs, we might have persisted entries with empty URLs. Avoid | 396 // Due to past bugs, we might have persisted entries with empty URLs. Avoid |
| 354 // reading these out. (GetKeywords() will delete these entries on return.) | 397 // reading these out. (GetKeywords() will delete these entries on return.) |
| 355 // NOTE: This code should only be needed as long as we might be reading such | 398 // NOTE: This code should only be needed as long as we might be reading such |
| 356 // potentially-old data and can be removed afterward. | 399 // potentially-old data and can be removed afterward. |
| 357 if (s.ColumnString(4).empty()) | 400 if (s.ColumnString(4).empty()) |
| 358 return false; | 401 return false; |
| 359 data->SetURL(s.ColumnString(4)); | 402 data->SetURL(s.ColumnString(4)); |
| 360 data->suggestions_url = s.ColumnString(11); | 403 data->suggestions_url = s.ColumnString(11); |
| 361 data->instant_url = s.ColumnString(16); | 404 data->instant_url = s.ColumnString(14); |
| 362 data->favicon_url = GURL(s.ColumnString(3)); | 405 data->favicon_url = GURL(s.ColumnString(3)); |
| 363 data->originating_url = GURL(s.ColumnString(6)); | 406 data->originating_url = GURL(s.ColumnString(6)); |
| 364 data->show_in_default_list = s.ColumnBool(10); | 407 data->show_in_default_list = s.ColumnBool(10); |
| 365 data->safe_for_autoreplace = s.ColumnBool(5); | 408 data->safe_for_autoreplace = s.ColumnBool(5); |
| 366 base::SplitString(s.ColumnString(9), ';', &data->input_encodings); | 409 base::SplitString(s.ColumnString(9), ';', &data->input_encodings); |
| 367 data->id = s.ColumnInt64(0); | 410 data->id = s.ColumnInt64(0); |
| 368 data->date_created = Time::FromTimeT(s.ColumnInt64(7)); | 411 data->date_created = Time::FromTimeT(s.ColumnInt64(7)); |
| 369 data->last_modified = Time::FromTimeT(s.ColumnInt64(17)); | 412 data->last_modified = Time::FromTimeT(s.ColumnInt64(15)); |
| 370 data->created_by_policy = s.ColumnBool(15); | 413 data->created_by_policy = s.ColumnBool(13); |
| 371 data->usage_count = s.ColumnInt(8); | 414 data->usage_count = s.ColumnInt(8); |
| 372 data->prepopulate_id = s.ColumnInt(12); | 415 data->prepopulate_id = s.ColumnInt(12); |
| 373 data->sync_guid = s.ColumnString(18); | 416 data->sync_guid = s.ColumnString(16); |
| 374 return true; | 417 return true; |
| 375 } | 418 } |
| 376 | 419 |
| 377 bool KeywordTable::GetSignatureData(std::string* backup) { | 420 bool KeywordTable::GetSignatureData(int table_version, std::string* backup) { |
| 378 DCHECK(backup); | 421 DCHECK(backup); |
| 379 | 422 |
| 380 int64 backup_value = kInvalidTemplateURLID; | 423 int64 backup_value = kInvalidTemplateURLID; |
| 381 if (!meta_table_->GetValue(kDefaultSearchIDBackupKey, &backup_value)) { | 424 if (!meta_table_->GetValue(kDefaultSearchIDBackupKey, &backup_value)) { |
| 382 LOG(ERROR) << "No backup id for signing."; | 425 LOG(ERROR) << "No backup id for signing."; |
| 383 return false; | 426 return false; |
| 384 } | 427 } |
| 385 | 428 |
| 386 std::string keywords_backup_data; | 429 std::string keywords_backup_data; |
| 387 if (!GetTableContents("keywords_backup", &keywords_backup_data)) { | 430 if (!GetTableContents("keywords_backup", table_version, |
| 431 &keywords_backup_data)) { | |
| 388 LOG(ERROR) << "Can't get keywords backup data"; | 432 LOG(ERROR) << "Can't get keywords backup data"; |
| 389 return false; | 433 return false; |
| 390 } | 434 } |
| 391 *backup = base::Int64ToString(backup_value) + keywords_backup_data; | 435 *backup = base::Int64ToString(backup_value) + keywords_backup_data; |
| 392 return true; | 436 return true; |
| 393 } | 437 } |
| 394 | 438 |
| 395 bool KeywordTable::GetTableContents(const char* table_name, | 439 bool KeywordTable::GetTableContents(const char* table_name, |
| 440 int table_version, | |
| 396 std::string* contents) { | 441 std::string* contents) { |
| 397 DCHECK(contents); | 442 DCHECK(contents); |
| 398 | 443 |
| 399 if (!db_->DoesTableExist(table_name)) | 444 if (!db_->DoesTableExist(table_name)) |
| 400 return false; | 445 return false; |
| 401 | 446 |
| 402 contents->clear(); | 447 contents->clear(); |
| 403 std::string query("SELECT " + std::string(kKeywordColumnsConcatenated) + | 448 std::string query("SELECT " + |
| 449 std::string((table_version <= 44) ? | |
| 450 kKeywordColumnsVersion44Concatenated : kKeywordColumnsConcatenated) + | |
| 404 " FROM " + std::string(table_name) + " ORDER BY id ASC"); | 451 " FROM " + std::string(table_name) + " ORDER BY id ASC"); |
| 405 sql::Statement s(db_->GetCachedStatement(sql::StatementID(table_name), | 452 sql::Statement s((table_version == WebDatabase::kCurrentVersionNumber) ? |
| 406 query.c_str())); | 453 db_->GetCachedStatement(sql::StatementID(table_name), query.c_str()) : |
| 454 db_->GetUniqueStatement(query.c_str())); | |
| 407 while (s.Step()) | 455 while (s.Step()) |
| 408 *contents += s.ColumnString(0); | 456 *contents += s.ColumnString(0); |
| 409 return s.Succeeded(); | 457 return s.Succeeded(); |
| 410 } | 458 } |
| 411 | 459 |
| 412 bool KeywordTable::UpdateBackupSignature() { | 460 bool KeywordTable::UpdateBackupSignature(int table_version) { |
| 413 sql::Transaction transaction(db_); | 461 sql::Transaction transaction(db_); |
| 414 if (!transaction.Begin()) | 462 if (!transaction.Begin()) |
| 415 return false; | 463 return false; |
| 416 | 464 |
| 417 int64 id = kInvalidTemplateURLID; | 465 int64 id = kInvalidTemplateURLID; |
| 418 if (!UpdateDefaultSearchProviderIDBackup(&id)) { | 466 if (!UpdateDefaultSearchProviderIDBackup(&id)) { |
| 419 LOG(ERROR) << "Failed to update default search id backup."; | 467 LOG(ERROR) << "Failed to update default search id backup."; |
| 420 return false; | 468 return false; |
| 421 } | 469 } |
| 422 | 470 |
| 423 // Backup of all keywords. | 471 // Backup of all keywords. |
| 424 if (db_->DoesTableExist("keywords_backup") && | 472 if (db_->DoesTableExist("keywords_backup") && |
| 425 !db_->Execute("DROP TABLE keywords_backup")) | 473 !db_->Execute("DROP TABLE keywords_backup")) |
| 426 return false; | 474 return false; |
| 427 | 475 |
| 428 std::string query("CREATE TABLE keywords_backup AS SELECT " + | 476 std::string query("CREATE TABLE keywords_backup AS SELECT " + |
| 429 std::string(kKeywordColumns) + " FROM keywords ORDER BY id ASC"); | 477 std::string((table_version <= 44) ? |
| 478 kKeywordColumnsVersion44 : kKeywordColumns) + | |
| 479 " FROM keywords ORDER BY id ASC"); | |
| 430 if (!db_->Execute(query.c_str())) { | 480 if (!db_->Execute(query.c_str())) { |
| 431 LOG(ERROR) << "Failed to create keywords_backup table."; | 481 LOG(ERROR) << "Failed to create keywords_backup table."; |
| 432 return false; | 482 return false; |
| 433 } | 483 } |
| 434 | 484 |
| 485 return SignBackup(table_version) && transaction.Commit(); | |
| 486 } | |
| 487 | |
| 488 bool KeywordTable::SignBackup(int table_version) { | |
| 435 std::string data_to_sign; | 489 std::string data_to_sign; |
| 436 if (!GetSignatureData(&data_to_sign)) { | 490 if (!GetSignatureData(table_version, &data_to_sign)) { |
| 437 LOG(ERROR) << "No data to sign."; | 491 LOG(ERROR) << "No data to sign."; |
| 438 return false; | 492 return false; |
| 439 } | 493 } |
| 440 | 494 |
| 441 std::string signature = protector::SignSetting(data_to_sign); | 495 std::string signature = protector::SignSetting(data_to_sign); |
| 442 if (signature.empty()) { | 496 if (signature.empty()) { |
| 443 LOG(ERROR) << "Signature is empty"; | 497 LOG(ERROR) << "Signature is empty"; |
| 444 return false; | 498 return false; |
| 445 } | 499 } |
| 446 | 500 |
| 447 return meta_table_->SetValue(kBackupSignatureKey, signature) && | 501 return meta_table_->SetValue(kBackupSignatureKey, signature); |
| 448 transaction.Commit(); | |
| 449 } | 502 } |
| 450 | 503 |
| 451 bool KeywordTable::IsBackupSignatureValid() { | 504 bool KeywordTable::IsBackupSignatureValid(int table_version) { |
| 452 std::string signature; | 505 std::string signature; |
| 453 std::string signature_data; | 506 std::string signature_data; |
| 454 return meta_table_->GetValue(kBackupSignatureKey, &signature) && | 507 return meta_table_->GetValue(kBackupSignatureKey, &signature) && |
| 455 GetSignatureData(&signature_data) && | 508 GetSignatureData(table_version, &signature_data) && |
| 456 protector::IsSettingValid(signature_data, signature); | 509 protector::IsSettingValid(signature_data, signature); |
| 457 } | 510 } |
| 458 | 511 |
| 459 bool KeywordTable::GetKeywordAsString(TemplateURLID id, | 512 bool KeywordTable::GetKeywordAsString(TemplateURLID id, |
| 460 const std::string& table_name, | 513 const std::string& table_name, |
| 461 std::string* result) { | 514 std::string* result) { |
| 462 std::string query("SELECT " + std::string(kKeywordColumnsConcatenated) + | 515 std::string query("SELECT " + std::string(kKeywordColumnsConcatenated) + |
| 463 " FROM " + table_name + " WHERE id=?"); | 516 " FROM " + table_name + " WHERE id=?"); |
| 464 sql::Statement s(db_->GetUniqueStatement(query.c_str())); | 517 sql::Statement s(db_->GetUniqueStatement(query.c_str())); |
| 465 s.BindInt64(0, id); | 518 s.BindInt64(0, id); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 482 int64 default_search_id = GetDefaultSearchProviderID(); | 535 int64 default_search_id = GetDefaultSearchProviderID(); |
| 483 if (!meta_table_->SetValue(kDefaultSearchIDBackupKey, | 536 if (!meta_table_->SetValue(kDefaultSearchIDBackupKey, |
| 484 default_search_id)) { | 537 default_search_id)) { |
| 485 LOG(ERROR) << "Can't write default search id backup."; | 538 LOG(ERROR) << "Can't write default search id backup."; |
| 486 return false; | 539 return false; |
| 487 } | 540 } |
| 488 | 541 |
| 489 *id = default_search_id; | 542 *id = default_search_id; |
| 490 return true; | 543 return true; |
| 491 } | 544 } |
| 545 | |
| 546 bool KeywordTable::MigrateKeywordsTableForVersion45(const std::string& name) { | |
| 547 // Create a new table without the columns we're dropping. | |
| 548 if (!db_->Execute("CREATE TABLE keywords_temp (" | |
| 549 "id INTEGER PRIMARY KEY," | |
| 550 "short_name VARCHAR NOT NULL," | |
| 551 "keyword VARCHAR NOT NULL," | |
| 552 "favicon_url VARCHAR NOT NULL," | |
| 553 "url VARCHAR NOT NULL," | |
| 554 "safe_for_autoreplace INTEGER," | |
| 555 "originating_url VARCHAR," | |
| 556 "date_created INTEGER DEFAULT 0," | |
| 557 "usage_count INTEGER DEFAULT 0," | |
| 558 "input_encodings VARCHAR," | |
| 559 "show_in_default_list INTEGER," | |
| 560 "suggest_url VARCHAR," | |
| 561 "prepopulate_id INTEGER DEFAULT 0," | |
| 562 "created_by_policy INTEGER DEFAULT 0," | |
| 563 "instant_url VARCHAR," | |
| 564 "last_modified INTEGER DEFAULT 0," | |
| 565 "sync_guid VARCHAR)")) | |
| 566 return false; | |
| 567 std::string sql("INSERT INTO keywords_temp SELECT " + | |
| 568 std::string(kKeywordColumnsVersion45) + " FROM " + name); | |
| 569 if (!db_->Execute(sql.c_str())) | |
| 570 return false; | |
| 571 | |
| 572 sql = "SELECT id, keyword, url, autogenerate_keyword FROM " + name; | |
| 573 sql::Statement s(db_->GetUniqueStatement(sql.c_str())); | |
| 574 string16 placeholder_keyword(ASCIIToUTF16("dummy")); | |
| 575 std::set<string16> keywords; | |
| 576 while (s.Step()) { | |
| 577 string16 keyword(s.ColumnString16(1)); | |
| 578 bool generate_keyword = keyword.empty() || s.ColumnBool(3); | |
| 579 if (generate_keyword) | |
| 580 keyword = placeholder_keyword; | |
| 581 TemplateURLData data; | |
| 582 data.SetKeyword(keyword); | |
| 583 data.SetURL(s.ColumnString(2)); | |
| 584 TemplateURL turl(NULL, data); | |
| 585 // Don't persist extension keywords to disk. These will get added to the | |
| 586 // TemplateURLService as the extensions are loaded. | |
| 587 bool delete_entry = turl.IsExtensionKeyword(); | |
| 588 if (!delete_entry && generate_keyword) { | |
| 589 // Explicitly generate keywords for all rows with the autogenerate bit set | |
| 590 // or where the keyword is empty. | |
| 591 SearchTermsData terms_data; | |
| 592 GURL url(TemplateURLService::GenerateSearchURLUsingTermsData(&turl, | |
| 593 terms_data)); | |
| 594 if (!url.is_valid()) { | |
| 595 delete_entry = true; | |
| 596 } else { | |
| 597 // Ensure autogenerated keywords are unique. | |
| 598 keyword = TemplateURLService::GenerateKeyword(url); | |
| 599 while (keywords.count(keyword)) | |
| 600 keyword.append(ASCIIToUTF16("_")); | |
| 601 sql::Statement u(db_->GetUniqueStatement( | |
| 602 "UPDATE keywords_temp SET keyword=? WHERE id=?")); | |
| 603 u.BindString16(0, keyword); | |
| 604 u.BindInt64(1, s.ColumnInt64(0)); | |
| 605 if (!u.Run()) | |
| 606 return false; | |
| 607 } | |
| 608 } | |
| 609 if (delete_entry) { | |
| 610 sql::Statement u(db_->GetUniqueStatement( | |
| 611 "DELETE FROM keywords_temp WHERE id=?")); | |
| 612 u.BindInt64(0, s.ColumnInt64(0)); | |
| 613 if (!u.Run()) | |
| 614 return false; | |
| 615 } else { | |
| 616 keywords.insert(keyword); | |
| 617 } | |
| 618 } | |
| 619 | |
| 620 // Replace the old table with the new one. | |
| 621 sql = "DROP TABLE " + name; | |
| 622 if (!db_->Execute(sql.c_str())) | |
| 623 return false; | |
| 624 sql = "ALTER TABLE keywords_temp RENAME TO " + name; | |
| 625 return db_->Execute(sql.c_str()); | |
| 626 } | |
| OLD | NEW |