OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "components/history/core/browser/url_database.h" | 5 #include "components/history/core/browser/url_database.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 // TODO(brettw): do something fancy here with encoding, etc. | 51 // TODO(brettw): do something fancy here with encoding, etc. |
52 | 52 |
53 // Strip username and password from URL before sending to DB. | 53 // Strip username and password from URL before sending to DB. |
54 GURL::Replacements replacements; | 54 GURL::Replacements replacements; |
55 replacements.ClearUsername(); | 55 replacements.ClearUsername(); |
56 replacements.ClearPassword(); | 56 replacements.ClearPassword(); |
57 | 57 |
58 return (gurl.ReplaceComponents(replacements)).spec(); | 58 return (gurl.ReplaceComponents(replacements)).spec(); |
59 } | 59 } |
60 | 60 |
61 // Convenience to fill a history::URLRow. Must be in sync with the fields in | 61 // Convenience to fill a URLRow. Must be in sync with the fields in |
62 // kURLRowFields. | 62 // kURLRowFields. |
63 void URLDatabase::FillURLRow(sql::Statement& s, history::URLRow* i) { | 63 void URLDatabase::FillURLRow(sql::Statement& s, URLRow* i) { |
64 DCHECK(i); | 64 DCHECK(i); |
65 i->id_ = s.ColumnInt64(0); | 65 i->id_ = s.ColumnInt64(0); |
66 i->url_ = GURL(s.ColumnString(1)); | 66 i->url_ = GURL(s.ColumnString(1)); |
67 i->title_ = s.ColumnString16(2); | 67 i->title_ = s.ColumnString16(2); |
68 i->visit_count_ = s.ColumnInt(3); | 68 i->visit_count_ = s.ColumnInt(3); |
69 i->typed_count_ = s.ColumnInt(4); | 69 i->typed_count_ = s.ColumnInt(4); |
70 i->last_visit_ = base::Time::FromInternalValue(s.ColumnInt64(5)); | 70 i->last_visit_ = base::Time::FromInternalValue(s.ColumnInt64(5)); |
71 i->hidden_ = s.ColumnInt(6) != 0; | 71 i->hidden_ = s.ColumnInt(6) != 0; |
72 } | 72 } |
73 | 73 |
(...skipping 18 matching lines...) Expand all Loading... |
92 "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls WHERE typed_count > 0")); | 92 "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls WHERE typed_count > 0")); |
93 | 93 |
94 while (statement.Step()) { | 94 while (statement.Step()) { |
95 URLRow info; | 95 URLRow info; |
96 FillURLRow(statement, &info); | 96 FillURLRow(statement, &info); |
97 urls->push_back(info); | 97 urls->push_back(info); |
98 } | 98 } |
99 return true; | 99 return true; |
100 } | 100 } |
101 | 101 |
102 URLID URLDatabase::GetRowForURL(const GURL& url, history::URLRow* info) { | 102 URLID URLDatabase::GetRowForURL(const GURL& url, URLRow* info) { |
103 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 103 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
104 "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls WHERE url=?")); | 104 "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls WHERE url=?")); |
105 std::string url_string = GURLToDatabaseURL(url); | 105 std::string url_string = GURLToDatabaseURL(url); |
106 statement.BindString(0, url_string); | 106 statement.BindString(0, url_string); |
107 | 107 |
108 if (!statement.Step()) | 108 if (!statement.Step()) |
109 return 0; // no data | 109 return 0; // no data |
110 | 110 |
111 if (info) | 111 if (info) |
112 FillURLRow(statement, info); | 112 FillURLRow(statement, info); |
113 return statement.ColumnInt64(0); | 113 return statement.ColumnInt64(0); |
114 } | 114 } |
115 | 115 |
116 bool URLDatabase::UpdateURLRow(URLID url_id, | 116 bool URLDatabase::UpdateURLRow(URLID url_id, const URLRow& info) { |
117 const history::URLRow& info) { | |
118 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 117 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
119 "UPDATE urls SET title=?,visit_count=?,typed_count=?,last_visit_time=?," | 118 "UPDATE urls SET title=?,visit_count=?,typed_count=?,last_visit_time=?," |
120 "hidden=?" | 119 "hidden=?" |
121 "WHERE id=?")); | 120 "WHERE id=?")); |
122 statement.BindString16(0, info.title()); | 121 statement.BindString16(0, info.title()); |
123 statement.BindInt(1, info.visit_count()); | 122 statement.BindInt(1, info.visit_count()); |
124 statement.BindInt(2, info.typed_count()); | 123 statement.BindInt(2, info.typed_count()); |
125 statement.BindInt64(3, info.last_visit().ToInternalValue()); | 124 statement.BindInt64(3, info.last_visit().ToInternalValue()); |
126 statement.BindInt(4, info.hidden() ? 1 : 0); | 125 statement.BindInt(4, info.hidden() ? 1 : 0); |
127 statement.BindInt64(5, url_id); | 126 statement.BindInt64(5, url_id); |
128 | 127 |
129 return statement.Run() && GetDB().GetLastChangeCount() > 0; | 128 return statement.Run() && GetDB().GetLastChangeCount() > 0; |
130 } | 129 } |
131 | 130 |
132 URLID URLDatabase::AddURLInternal(const history::URLRow& info, | 131 URLID URLDatabase::AddURLInternal(const URLRow& info, bool is_temporary) { |
133 bool is_temporary) { | |
134 // This function is used to insert into two different tables, so we have to | 132 // This function is used to insert into two different tables, so we have to |
135 // do some shuffling. Unfortinately, we can't use the macro | 133 // do some shuffling. Unfortinately, we can't use the macro |
136 // HISTORY_URL_ROW_FIELDS because that specifies the table name which is | 134 // HISTORY_URL_ROW_FIELDS because that specifies the table name which is |
137 // invalid in the insert syntax. | 135 // invalid in the insert syntax. |
138 #define ADDURL_COMMON_SUFFIX \ | 136 #define ADDURL_COMMON_SUFFIX \ |
139 " (url, title, visit_count, typed_count, "\ | 137 " (url, title, visit_count, typed_count, "\ |
140 "last_visit_time, hidden) "\ | 138 "last_visit_time, hidden) "\ |
141 "VALUES (?,?,?,?,?,?)" | 139 "VALUES (?,?,?,?,?,?)" |
142 const char* statement_name; | 140 const char* statement_name; |
143 const char* statement_sql; | 141 const char* statement_sql; |
(...skipping 16 matching lines...) Expand all Loading... |
160 statement.BindInt(5, info.hidden() ? 1 : 0); | 158 statement.BindInt(5, info.hidden() ? 1 : 0); |
161 | 159 |
162 if (!statement.Run()) { | 160 if (!statement.Run()) { |
163 VLOG(0) << "Failed to add url " << info.url().possibly_invalid_spec() | 161 VLOG(0) << "Failed to add url " << info.url().possibly_invalid_spec() |
164 << " to table history.urls."; | 162 << " to table history.urls."; |
165 return 0; | 163 return 0; |
166 } | 164 } |
167 return GetDB().GetLastInsertRowId(); | 165 return GetDB().GetLastInsertRowId(); |
168 } | 166 } |
169 | 167 |
170 bool URLDatabase::InsertOrUpdateURLRowByID(const history::URLRow& info) { | 168 bool URLDatabase::InsertOrUpdateURLRowByID(const URLRow& info) { |
171 // SQLite does not support INSERT OR UPDATE, however, it does have INSERT OR | 169 // SQLite does not support INSERT OR UPDATE, however, it does have INSERT OR |
172 // REPLACE, which is feasible to use, because of the following. | 170 // REPLACE, which is feasible to use, because of the following. |
173 // * Before INSERTing, REPLACE will delete all pre-existing rows that cause | 171 // * Before INSERTing, REPLACE will delete all pre-existing rows that cause |
174 // constraint violations. Here, we only have a PRIMARY KEY constraint, so | 172 // constraint violations. Here, we only have a PRIMARY KEY constraint, so |
175 // the only row that might get deleted is an old one with the same ID. | 173 // the only row that might get deleted is an old one with the same ID. |
176 // * Another difference between the two flavors is that the latter actually | 174 // * Another difference between the two flavors is that the latter actually |
177 // deletes the old row, and thus the old values are lost in columns which | 175 // deletes the old row, and thus the old values are lost in columns which |
178 // are not explicitly assigned new values. This is not an issue, however, | 176 // are not explicitly assigned new values. This is not an issue, however, |
179 // as we assign values to all columns. | 177 // as we assign values to all columns. |
180 // * When rows are deleted due to constraint violations, the delete triggers | 178 // * When rows are deleted due to constraint violations, the delete triggers |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 // so we can be sure sqlite is comparing everything in 8-bit mode. Otherwise, | 288 // so we can be sure sqlite is comparing everything in 8-bit mode. Otherwise, |
291 // it will have to convert strings either to UTF-8 or UTF-16 for comparison. | 289 // it will have to convert strings either to UTF-8 or UTF-16 for comparison. |
292 std::string end_query(prefix); | 290 std::string end_query(prefix); |
293 end_query.push_back(std::numeric_limits<unsigned char>::max()); | 291 end_query.push_back(std::numeric_limits<unsigned char>::max()); |
294 | 292 |
295 statement.BindString(0, prefix); | 293 statement.BindString(0, prefix); |
296 statement.BindString(1, end_query); | 294 statement.BindString(1, end_query); |
297 statement.BindInt(2, static_cast<int>(max_results)); | 295 statement.BindInt(2, static_cast<int>(max_results)); |
298 | 296 |
299 while (statement.Step()) { | 297 while (statement.Step()) { |
300 history::URLRow info; | 298 URLRow info; |
301 FillURLRow(statement, &info); | 299 FillURLRow(statement, &info); |
302 if (info.url().is_valid()) | 300 if (info.url().is_valid()) |
303 results->push_back(info); | 301 results->push_back(info); |
304 } | 302 } |
305 return !results->empty(); | 303 return !results->empty(); |
306 } | 304 } |
307 | 305 |
308 bool URLDatabase::IsTypedHost(const std::string& host) { | 306 bool URLDatabase::IsTypedHost(const std::string& host) { |
309 const char* schemes[] = { | 307 const char* schemes[] = { |
310 url::kHttpScheme, | 308 url::kHttpScheme, |
311 url::kHttpsScheme, | 309 url::kHttpsScheme, |
312 url::kFtpScheme | 310 url::kFtpScheme |
313 }; | 311 }; |
314 URLRows dummy; | 312 URLRows dummy; |
315 for (size_t i = 0; i < arraysize(schemes); ++i) { | 313 for (size_t i = 0; i < arraysize(schemes); ++i) { |
316 std::string scheme_and_host(schemes[i]); | 314 std::string scheme_and_host(schemes[i]); |
317 scheme_and_host += url::kStandardSchemeSeparator + host; | 315 scheme_and_host += url::kStandardSchemeSeparator + host; |
318 if (AutocompleteForPrefix(scheme_and_host + '/', 1, true, &dummy) || | 316 if (AutocompleteForPrefix(scheme_and_host + '/', 1, true, &dummy) || |
319 AutocompleteForPrefix(scheme_and_host + ':', 1, true, &dummy)) | 317 AutocompleteForPrefix(scheme_and_host + ':', 1, true, &dummy)) |
320 return true; | 318 return true; |
321 } | 319 } |
322 return false; | 320 return false; |
323 } | 321 } |
324 | 322 |
325 bool URLDatabase::FindShortestURLFromBase(const std::string& base, | 323 bool URLDatabase::FindShortestURLFromBase(const std::string& base, |
326 const std::string& url, | 324 const std::string& url, |
327 int min_visits, | 325 int min_visits, |
328 int min_typed, | 326 int min_typed, |
329 bool allow_base, | 327 bool allow_base, |
330 history::URLRow* info) { | 328 URLRow* info) { |
331 // Select URLs that start with |base| and are prefixes of |url|. All parts | 329 // Select URLs that start with |base| and are prefixes of |url|. All parts |
332 // of this query except the substr() call can be done using the index. We | 330 // of this query except the substr() call can be done using the index. We |
333 // could do this query with a couple of LIKE or GLOB statements as well, but | 331 // could do this query with a couple of LIKE or GLOB statements as well, but |
334 // those wouldn't use the index, and would run into problems with "wildcard" | 332 // those wouldn't use the index, and would run into problems with "wildcard" |
335 // characters that appear in URLs (% for LIKE, or *, ? for GLOB). | 333 // characters that appear in URLs (% for LIKE, or *, ? for GLOB). |
336 std::string sql("SELECT "); | 334 std::string sql("SELECT "); |
337 sql.append(kURLRowFields); | 335 sql.append(kURLRowFields); |
338 sql.append(" FROM urls WHERE url "); | 336 sql.append(" FROM urls WHERE url "); |
339 sql.append(allow_base ? ">=" : ">"); | 337 sql.append(allow_base ? ">=" : ">"); |
340 sql.append(" ? AND url < :end AND url = substr(:end, 1, length(url)) " | 338 sql.append(" ? AND url < :end AND url = substr(:end, 1, length(url)) " |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 // |languages| to reduce dependency (no need to call PrefService). | 373 // |languages| to reduce dependency (no need to call PrefService). |
376 base::string16 ascii = base::ASCIIToUTF16(gurl.host()); | 374 base::string16 ascii = base::ASCIIToUTF16(gurl.host()); |
377 base::string16 utf = net::IDNToUnicode(gurl.host(), std::string()); | 375 base::string16 utf = net::IDNToUnicode(gurl.host(), std::string()); |
378 if (ascii != utf) | 376 if (ascii != utf) |
379 query_parser_.ExtractQueryWords(utf, &query_words); | 377 query_parser_.ExtractQueryWords(utf, &query_words); |
380 } | 378 } |
381 base::string16 title = base::i18n::ToLower(statement.ColumnString16(2)); | 379 base::string16 title = base::i18n::ToLower(statement.ColumnString16(2)); |
382 query_parser_.ExtractQueryWords(title, &query_words); | 380 query_parser_.ExtractQueryWords(title, &query_words); |
383 | 381 |
384 if (query_parser_.DoesQueryMatch(query_words, query_nodes.get())) { | 382 if (query_parser_.DoesQueryMatch(query_words, query_nodes.get())) { |
385 history::URLResult info; | 383 URLResult info; |
386 FillURLRow(statement, &info); | 384 FillURLRow(statement, &info); |
387 if (info.url().is_valid()) | 385 if (info.url().is_valid()) |
388 results->push_back(info); | 386 results->push_back(info); |
389 } | 387 } |
390 } | 388 } |
391 return !results->empty(); | 389 return !results->empty(); |
392 } | 390 } |
393 | 391 |
394 bool URLDatabase::InitKeywordSearchTermsTable() { | 392 bool URLDatabase::InitKeywordSearchTermsTable() { |
395 has_keyword_search_terms_ = true; | 393 has_keyword_search_terms_ = true; |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
628 bool RowQualifiesAsSignificant(const URLRow& row, | 626 bool RowQualifiesAsSignificant(const URLRow& row, |
629 const base::Time& threshold) { | 627 const base::Time& threshold) { |
630 const base::Time& real_threshold = | 628 const base::Time& real_threshold = |
631 threshold.is_null() ? AutocompleteAgeThreshold() : threshold; | 629 threshold.is_null() ? AutocompleteAgeThreshold() : threshold; |
632 return (row.typed_count() >= kLowQualityMatchTypedLimit) || | 630 return (row.typed_count() >= kLowQualityMatchTypedLimit) || |
633 (row.visit_count() >= kLowQualityMatchVisitLimit) || | 631 (row.visit_count() >= kLowQualityMatchVisitLimit) || |
634 (row.last_visit() >= real_threshold); | 632 (row.last_visit() >= real_threshold); |
635 } | 633 } |
636 | 634 |
637 } // namespace history | 635 } // namespace history |
OLD | NEW |