summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/autofill/core/browser/webdata/autofill_table.cc708
-rw-r--r--components/autofill/core/browser/webdata/autofill_table.h78
-rw-r--r--components/autofill/core/browser/webdata/autofill_table_unittest.cc251
-rw-r--r--components/test/data/web_database/version_21.sql40
-rw-r--r--components/test/data/web_database/version_54.sql40
-rw-r--r--components/webdata/common/web_database.cc4
-rw-r--r--components/webdata/common/web_database_migration_unittest.cc280
7 files changed, 522 insertions, 879 deletions
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc
index 23c5b05..039942f 100644
--- a/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -5,7 +5,6 @@
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include <algorithm>
-#include <cmath>
#include <limits>
#include <map>
#include <set>
@@ -15,7 +14,6 @@
#include "base/guid.h"
#include "base/i18n/case_conversion.h"
#include "base/logging.h"
-#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
@@ -40,27 +38,14 @@ using base::Time;
namespace autofill {
namespace {
+typedef std::vector<Tuple3<int64, base::string16, base::string16> >
+ AutofillElementList;
+
template<typename T>
T* address_of(T& v) {
return &v;
}
-// Helper struct for AutofillTable::RemoveFormElementsAddedBetween().
-// Contains all the necessary fields to update a row in the 'autofill' table.
-struct AutofillUpdate {
- base::string16 name;
- base::string16 value;
- time_t date_created;
- time_t date_last_used;
- int count;
-};
-
-// Rounds a positive floating point number to the nearest integer.
-int Round(float f) {
- DCHECK_GE(f, 0.f);
- return base::checked_cast<int>(std::floor(f + 0.5f));
-}
-
// Returns the |data_model|'s value corresponding to the |type|, trimmed to the
// maximum length that can be stored in a column of the Autofill database.
base::string16 GetInfo(const AutofillDataModel& data_model,
@@ -379,9 +364,10 @@ WebDatabaseTable::TypeKey AutofillTable::GetTypeKey() const {
bool AutofillTable::Init(sql::Connection* db, sql::MetaTable* meta_table) {
WebDatabaseTable::Init(db, meta_table);
- return (InitMainTable() && InitCreditCardsTable() && InitProfilesTable() &&
- InitProfileNamesTable() && InitProfileEmailsTable() &&
- InitProfilePhonesTable() && InitProfileTrashTable());
+ return (InitMainTable() && InitCreditCardsTable() && InitDatesTable() &&
+ InitProfilesTable() && InitProfileNamesTable() &&
+ InitProfileEmailsTable() && InitProfilePhonesTable() &&
+ InitProfileTrashTable());
}
bool AutofillTable::IsSyncable() {
@@ -393,7 +379,7 @@ bool AutofillTable::MigrateToVersion(int version,
// Migrate if necessary.
switch (version) {
case 22:
- return MigrateToVersion22ClearAutofillEmptyValueElements();
+ return ClearAutofillEmptyValueElements();
case 23:
return MigrateToVersion23AddCardNumberEncryptedColumn();
case 24:
@@ -437,9 +423,6 @@ bool AutofillTable::MigrateToVersion(int version,
case 54:
*update_compatible_version = true;
return MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields();
- case 55:
- *update_compatible_version = true;
- return MigrateToVersion55MergeAutofillDatesTable();
}
return true;
}
@@ -496,7 +479,8 @@ bool AutofillTable::GetFormValuesForElementName(
}
bool AutofillTable::HasFormElements() {
- sql::Statement s(db_->GetUniqueStatement("SELECT COUNT(*) FROM autofill"));
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT COUNT(*) FROM autofill"));
if (!s.Step()) {
NOTREACHED();
return false;
@@ -508,139 +492,264 @@ bool AutofillTable::RemoveFormElementsAddedBetween(
const Time& delete_begin,
const Time& delete_end,
std::vector<AutofillChange>* changes) {
- const time_t delete_begin_time_t = delete_begin.ToTimeT();
- const time_t delete_end_time_t = GetEndTime(delete_end);
-
- // Query for the name, value, count, and access dates of all form elements
- // that were used between the given times.
+ DCHECK(changes);
+ // Query for the pair_id, name, and value of all form elements that
+ // were used between the given times.
sql::Statement s(db_->GetUniqueStatement(
- "SELECT name, value, count, date_created, date_last_used FROM autofill "
- "WHERE (date_created >= ? AND date_created < ?) OR "
- " (date_last_used >= ? AND date_last_used < ?)"));
- s.BindInt64(0, delete_begin_time_t);
- s.BindInt64(1, delete_end_time_t);
- s.BindInt64(2, delete_begin_time_t);
- s.BindInt64(3, delete_end_time_t);
-
- std::vector<AutofillUpdate> updates;
- std::vector<AutofillChange> tentative_changes;
+ "SELECT DISTINCT a.pair_id, a.name, a.value "
+ "FROM autofill_dates ad JOIN autofill a ON ad.pair_id = a.pair_id "
+ "WHERE ad.date_created >= ? AND ad.date_created < ?"));
+ s.BindInt64(0, delete_begin.ToTimeT());
+ s.BindInt64(1,
+ (delete_end.is_null() || delete_end == base::Time::Max()) ?
+ std::numeric_limits<int64>::max() :
+ delete_end.ToTimeT());
+
+ AutofillElementList elements;
while (s.Step()) {
- base::string16 name = s.ColumnString16(0);
- base::string16 value = s.ColumnString16(1);
- int count = s.ColumnInt(2);
- time_t date_created_time_t = s.ColumnInt64(3);
- time_t date_last_used_time_t = s.ColumnInt64(4);
-
- // If *all* uses of the element were between |delete_begin| and
- // |delete_end|, then delete the element. Otherwise, update the use
- // timestamps and use count.
- AutofillChange::Type change_type;
- if (date_created_time_t >= delete_begin_time_t &&
- date_last_used_time_t < delete_end_time_t) {
- change_type = AutofillChange::REMOVE;
- } else {
- change_type = AutofillChange::UPDATE;
-
- // For all updated elements, set either date_created or date_last_used so
- // that the range [date_created, date_last_used] no longer overlaps with
- // [delete_begin, delete_end). Update the count by interpolating.
- // Precisely, compute the average amount of time between increments to the
- // count in the original range [date_created, date_last_used]:
- // avg_delta = (date_last_used_orig - date_created_orig) / (count - 1)
- // The count can be exressed as
- // count = 1 + (date_last_used - date_created) / avg_delta
- // Hence, update the count to
- // count_new = 1 + (date_last_used_new - date_created_new) / avg_delta
- // = 1 + ((count - 1) *
- // (date_last_used_new - date_created_new) /
- // (date_last_used_orig - date_created_orig))
- // Interpolating might not give a result that completely accurately
- // reflects the user's history, but it's the best that can be done given
- // the information in the database.
- AutofillUpdate updated_entry;
- updated_entry.name = name;
- updated_entry.value = value;
- updated_entry.date_created =
- date_created_time_t < delete_begin_time_t ?
- date_created_time_t :
- delete_end_time_t;
- updated_entry.date_last_used =
- date_last_used_time_t >= delete_end_time_t ?
- date_last_used_time_t :
- delete_begin_time_t - 1;
- updated_entry.count =
- 1 +
- Round(1.0 * (count - 1) *
- (updated_entry.date_last_used - updated_entry.date_created) /
- (date_last_used_time_t - date_created_time_t));
- updates.push_back(updated_entry);
- }
-
- tentative_changes.push_back(
- AutofillChange(change_type, AutofillKey(name, value)));
+ elements.push_back(MakeTuple(s.ColumnInt64(0),
+ s.ColumnString16(1),
+ s.ColumnString16(2)));
}
if (!s.Succeeded())
return false;
- // As a single transaction, remove or update the elements appropriately.
- sql::Statement s_delete(db_->GetUniqueStatement(
- "DELETE FROM autofill WHERE date_created >= ? AND date_last_used < ?"));
- s_delete.BindInt64(0, delete_begin_time_t);
- s_delete.BindInt64(1, delete_end_time_t);
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
- if (!s_delete.Run())
- return false;
- for (size_t i = 0; i < updates.size(); ++i) {
- sql::Statement s_update(db_->GetUniqueStatement(
- "UPDATE autofill SET date_created = ?, date_last_used = ?, count = ?"
- "WHERE name = ? AND value = ?"));
- s_update.BindInt64(0, updates[i].date_created);
- s_update.BindInt64(1, updates[i].date_last_used);
- s_update.BindInt(2, updates[i].count);
- s_update.BindString16(3, updates[i].name);
- s_update.BindString16(4, updates[i].value);
- if (!s_update.Run())
+ for (AutofillElementList::iterator itr = elements.begin();
+ itr != elements.end(); ++itr) {
+ int how_many = 0;
+ if (!RemoveFormElementForTimeRange(itr->a, delete_begin, delete_end,
+ &how_many)) {
return false;
+ }
+ // We store at most 2 time stamps. If we remove both of them we should
+ // delete the corresponding data. If we delete only one it could still be
+ // the last timestamp for the data, so check how many timestamps do remain.
+ bool should_remove = (CountTimestampsData(itr->a) == 0);
+ if (should_remove) {
+ if (!RemoveFormElementForID(itr->a))
+ return false;
+ } else {
+ if (!AddToCountOfFormElement(itr->a, -how_many))
+ return false;
+ }
+ AutofillChange::Type change_type =
+ should_remove ? AutofillChange::REMOVE : AutofillChange::UPDATE;
+ changes->push_back(AutofillChange(change_type,
+ AutofillKey(itr->b, itr->c)));
}
- if (!transaction.Commit())
- return false;
- *changes = tentative_changes;
return true;
}
bool AutofillTable::RemoveExpiredFormElements(
std::vector<AutofillChange>* changes) {
- base::Time expiration_time = AutofillEntry::ExpirationTime();
+ DCHECK(changes);
- // Query for the name and value of all form elements that were last used
- // before the |expiration_time|.
+ base::Time delete_end = AutofillEntry::ExpirationTime();
+ // Query for the pair_id, name, and value of all form elements that
+ // were last used before the |delete_end|.
sql::Statement select_for_delete(db_->GetUniqueStatement(
- "SELECT name, value FROM autofill WHERE date_last_used < ?"));
- select_for_delete.BindInt64(0, expiration_time.ToTimeT());
- std::vector<AutofillChange> tentative_changes;
+ "SELECT DISTINCT pair_id, name, value "
+ "FROM autofill WHERE pair_id NOT IN "
+ "(SELECT DISTINCT pair_id "
+ "FROM autofill_dates WHERE date_created >= ?)"));
+ select_for_delete.BindInt64(0, delete_end.ToTimeT());
+ AutofillElementList entries_to_delete;
while (select_for_delete.Step()) {
- base::string16 name = select_for_delete.ColumnString16(0);
- base::string16 value = select_for_delete.ColumnString16(1);
- tentative_changes.push_back(
- AutofillChange(AutofillChange::REMOVE, AutofillKey(name, value)));
+ entries_to_delete.push_back(MakeTuple(select_for_delete.ColumnInt64(0),
+ select_for_delete.ColumnString16(1),
+ select_for_delete.ColumnString16(2)));
}
if (!select_for_delete.Succeeded())
return false;
sql::Statement delete_data_statement(db_->GetUniqueStatement(
- "DELETE FROM autofill WHERE date_last_used < ?"));
- delete_data_statement.BindInt64(0, expiration_time.ToTimeT());
+ "DELETE FROM autofill WHERE pair_id NOT IN ("
+ "SELECT pair_id FROM autofill_dates WHERE date_created >= ?)"));
+ delete_data_statement.BindInt64(0, delete_end.ToTimeT());
if (!delete_data_statement.Run())
return false;
- *changes = tentative_changes;
+ sql::Statement delete_times_statement(db_->GetUniqueStatement(
+ "DELETE FROM autofill_dates WHERE pair_id NOT IN ("
+ "SELECT pair_id FROM autofill_dates WHERE date_created >= ?)"));
+ delete_times_statement.BindInt64(0, delete_end.ToTimeT());
+ if (!delete_times_statement.Run())
+ return false;
+
+ // Cull remaining entries' timestamps.
+ std::vector<AutofillEntry> entries;
+ if (!GetAllAutofillEntries(&entries))
+ return false;
+ sql::Statement cull_date_entry(db_->GetUniqueStatement(
+ "DELETE FROM autofill_dates "
+ "WHERE pair_id == (SELECT pair_id FROM autofill "
+ "WHERE name = ? and value = ?)"
+ "AND date_created != ? AND date_created != ?"));
+ for (size_t i = 0; i < entries.size(); ++i) {
+ cull_date_entry.BindString16(0, entries[i].key().name());
+ cull_date_entry.BindString16(1, entries[i].key().value());
+ cull_date_entry.BindInt64(2,
+ entries[i].timestamps().empty() ? 0 :
+ entries[i].timestamps().front().ToTimeT());
+ cull_date_entry.BindInt64(3,
+ entries[i].timestamps().empty() ? 0 :
+ entries[i].timestamps().back().ToTimeT());
+ if (!cull_date_entry.Run())
+ return false;
+ cull_date_entry.Reset(true);
+ }
+
+ changes->clear();
+ changes->reserve(entries_to_delete.size());
+
+ for (AutofillElementList::iterator it = entries_to_delete.begin();
+ it != entries_to_delete.end(); ++it) {
+ changes->push_back(AutofillChange(
+ AutofillChange::REMOVE, AutofillKey(it->b, it->c)));
+ }
return true;
}
+bool AutofillTable::RemoveFormElementForTimeRange(int64 pair_id,
+ const Time& delete_begin,
+ const Time& delete_end,
+ int* how_many) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "DELETE FROM autofill_dates WHERE pair_id = ? AND "
+ "date_created >= ? AND date_created < ?"));
+ s.BindInt64(0, pair_id);
+ s.BindInt64(1, delete_begin.is_null() ? 0 : delete_begin.ToTimeT());
+ s.BindInt64(2, delete_end.is_null() ? std::numeric_limits<int64>::max() :
+ delete_end.ToTimeT());
+
+ bool result = s.Run();
+ if (how_many)
+ *how_many = db_->GetLastChangeCount();
+
+ return result;
+}
+
+int AutofillTable::CountTimestampsData(int64 pair_id) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT COUNT(*) FROM autofill_dates WHERE pair_id = ?"));
+ s.BindInt64(0, pair_id);
+ if (!s.Step()) {
+ NOTREACHED();
+ return 0;
+ } else {
+ return s.ColumnInt(0);
+ }
+}
+
+bool AutofillTable::AddToCountOfFormElement(int64 pair_id,
+ int delta) {
+ int count = 0;
+
+ if (!GetCountOfFormElement(pair_id, &count))
+ return false;
+
+ if (count + delta == 0) {
+ // Should remove the element earlier in the code.
+ NOTREACHED();
+ return false;
+ } else {
+ if (!SetCountOfFormElement(pair_id, count + delta))
+ return false;
+ }
+ return true;
+}
+
+bool AutofillTable::GetIDAndCountOfFormElement(
+ const FormFieldData& element,
+ int64* pair_id,
+ int* count) {
+ DCHECK(pair_id);
+ DCHECK(count);
+
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT pair_id, count FROM autofill "
+ "WHERE name = ? AND value = ?"));
+ s.BindString16(0, element.name);
+ s.BindString16(1, element.value);
+
+ if (!s.is_valid())
+ return false;
+
+ *pair_id = 0;
+ *count = 0;
+
+ if (s.Step()) {
+ *pair_id = s.ColumnInt64(0);
+ *count = s.ColumnInt(1);
+ }
+
+ return true;
+}
+
+bool AutofillTable::GetCountOfFormElement(int64 pair_id, int* count) {
+ DCHECK(count);
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT count FROM autofill WHERE pair_id = ?"));
+ s.BindInt64(0, pair_id);
+
+ if (s.Step()) {
+ *count = s.ColumnInt(0);
+ return true;
+ }
+ return false;
+}
+
+bool AutofillTable::SetCountOfFormElement(int64 pair_id, int count) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "UPDATE autofill SET count = ? WHERE pair_id = ?"));
+ s.BindInt(0, count);
+ s.BindInt64(1, pair_id);
+
+ return s.Run();
+}
+
+bool AutofillTable::InsertFormElement(const FormFieldData& element,
+ int64* pair_id) {
+ DCHECK(pair_id);
+ sql::Statement s(db_->GetUniqueStatement(
+ "INSERT INTO autofill (name, value, value_lower) VALUES (?,?,?)"));
+ s.BindString16(0, element.name);
+ s.BindString16(1, element.value);
+ s.BindString16(2, base::i18n::ToLower(element.value));
+
+ if (!s.Run())
+ return false;
+
+ *pair_id = db_->GetLastInsertRowId();
+ return true;
+}
+
+bool AutofillTable::InsertPairIDAndDate(int64 pair_id,
+ const Time& date_created) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "INSERT INTO autofill_dates "
+ "(pair_id, date_created) VALUES (?, ?)"));
+ s.BindInt64(0, pair_id);
+ s.BindInt64(1, date_created.ToTimeT());
+
+ return s.Run();
+}
+
+bool AutofillTable::DeleteLastAccess(int64 pair_id) {
+ // Inner SELECT selects the newest |date_created| for a given |pair_id|.
+ // DELETE deletes only that entry.
+ sql::Statement s(db_->GetUniqueStatement(
+ "DELETE FROM autofill_dates WHERE pair_id = ? and date_created IN "
+ "(SELECT date_created FROM autofill_dates WHERE pair_id = ? "
+ "ORDER BY date_created DESC LIMIT 1)"));
+ s.BindInt64(0, pair_id);
+ s.BindInt64(1, pair_id);
+
+ return s.Run();
+}
+
bool AutofillTable::AddFormFieldValuesTime(
const std::vector<FormFieldData>& elements,
std::vector<AutofillChange>* changes,
@@ -662,20 +771,75 @@ bool AutofillTable::AddFormFieldValuesTime(
return result;
}
-bool AutofillTable::GetAllAutofillEntries(std::vector<AutofillEntry>* entries) {
+bool AutofillTable::ClearAutofillEmptyValueElements() {
sql::Statement s(db_->GetUniqueStatement(
- "SELECT name, value, date_created, date_last_used FROM autofill"));
+ "SELECT pair_id FROM autofill WHERE TRIM(value)= \"\""));
+ if (!s.is_valid())
+ return false;
+ std::set<int64> ids;
+ while (s.Step())
+ ids.insert(s.ColumnInt64(0));
+ if (!s.Succeeded())
+ return false;
+
+ bool success = true;
+ for (std::set<int64>::const_iterator iter = ids.begin(); iter != ids.end();
+ ++iter) {
+ if (!RemoveFormElementForID(*iter))
+ success = false;
+ }
+
+ return success;
+}
+
+bool AutofillTable::GetAllAutofillEntries(std::vector<AutofillEntry>* entries) {
+ DCHECK(entries);
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT name, value, date_created FROM autofill a JOIN "
+ "autofill_dates ad ON a.pair_id=ad.pair_id"));
+
+ bool first_entry = true;
+ AutofillKey* current_key_ptr = NULL;
+ std::vector<Time>* timestamps_ptr = NULL;
+ base::string16 name, value;
+ Time time;
while (s.Step()) {
- base::string16 name = s.ColumnString16(0);
- base::string16 value = s.ColumnString16(1);
+ name = s.ColumnString16(0);
+ value = s.ColumnString16(1);
+ time = Time::FromTimeT(s.ColumnInt64(2));
+
+ if (first_entry) {
+ current_key_ptr = new AutofillKey(name, value);
+
+ timestamps_ptr = new std::vector<Time>;
+ timestamps_ptr->push_back(time);
+
+ first_entry = false;
+ } else {
+ // we've encountered the next entry
+ if (current_key_ptr->name().compare(name) != 0 ||
+ current_key_ptr->value().compare(value) != 0) {
+ AutofillEntry entry(*current_key_ptr, *timestamps_ptr);
+ entries->push_back(entry);
+
+ delete current_key_ptr;
+ delete timestamps_ptr;
+
+ current_key_ptr = new AutofillKey(name, value);
+ timestamps_ptr = new std::vector<Time>;
+ }
+ timestamps_ptr->push_back(time);
+ }
+ }
- std::vector<Time> timestamps;
- timestamps.push_back(Time::FromTimeT(s.ColumnInt64(2)));
- timestamps.push_back(Time::FromTimeT(s.ColumnInt64(3)));
- if (timestamps.front() == timestamps.back())
- timestamps.pop_back();
- entries->push_back(AutofillEntry(AutofillKey(name, value), timestamps));
+ // If there is at least one result returned, first_entry will be false.
+ // For this case we need to do a final cleanup step.
+ if (!first_entry) {
+ AutofillEntry entry(*current_key_ptr, *timestamps_ptr);
+ entries->push_back(entry);
+ delete current_key_ptr;
+ delete timestamps_ptr;
}
return s.Succeeded();
@@ -684,22 +848,18 @@ bool AutofillTable::GetAllAutofillEntries(std::vector<AutofillEntry>* entries) {
bool AutofillTable::GetAutofillTimestamps(const base::string16& name,
const base::string16& value,
std::vector<Time>* timestamps) {
+ DCHECK(timestamps);
sql::Statement s(db_->GetUniqueStatement(
- "SELECT date_created, date_last_used FROM autofill "
- "WHERE name = ? AND value = ?"));
+ "SELECT date_created FROM autofill a JOIN "
+ "autofill_dates ad ON a.pair_id=ad.pair_id "
+ "WHERE a.name = ? AND a.value = ?"));
s.BindString16(0, name);
s.BindString16(1, value);
- if (!s.Step())
- return false;
- timestamps->clear();
- timestamps->push_back(Time::FromTimeT(s.ColumnInt64(0)));
- timestamps->push_back(Time::FromTimeT(s.ColumnInt64(1)));
- if (timestamps->front() == timestamps->back())
- timestamps->pop_back();
+ while (s.Step())
+ timestamps->push_back(Time::FromTimeT(s.ColumnInt64(0)));
- DCHECK(!s.Step());
- return true;
+ return s.Succeeded();
}
bool AutofillTable::UpdateAutofillEntries(
@@ -708,17 +868,24 @@ bool AutofillTable::UpdateAutofillEntries(
return true;
// Remove all existing entries.
- for (size_t i = 0; i < entries.size(); ++i) {
- sql::Statement s(db_->GetUniqueStatement(
- "DELETE FROM autofill WHERE name = ? AND value = ?"));
+ for (size_t i = 0; i < entries.size(); i++) {
+ std::string sql = "SELECT pair_id FROM autofill "
+ "WHERE name = ? AND value = ?";
+ sql::Statement s(db_->GetUniqueStatement(sql.c_str()));
s.BindString16(0, entries[i].key().name());
s.BindString16(1, entries[i].key().value());
- if (!s.Run())
+
+ if (!s.is_valid())
return false;
+
+ if (s.Step()) {
+ if (!RemoveFormElementForID(s.ColumnInt64(0)))
+ return false;
+ }
}
// Insert all the supplied autofill entries.
- for (size_t i = 0; i < entries.size(); ++i) {
+ for (size_t i = 0; i < entries.size(); i++) {
if (!InsertAutofillEntry(entries[i]))
return false;
}
@@ -727,86 +894,69 @@ bool AutofillTable::UpdateAutofillEntries(
}
bool AutofillTable::InsertAutofillEntry(const AutofillEntry& entry) {
- if (entry.timestamps().empty())
- return false;
-
- Time date_created = entry.timestamps().front();
- Time date_last_used = date_created;
- for (size_t i = 1; i < entry.timestamps().size(); ++i) {
- const Time& timestamp = entry.timestamps()[i];
- date_created = std::min(date_created, timestamp);
- date_last_used = std::max(date_last_used, timestamp);
- }
-
- std::string sql =
- "INSERT INTO autofill "
- "(name, value, value_lower, date_created, date_last_used, count) "
- "VALUES (?, ?, ?, ?, ?, ?)";
+ std::string sql = "INSERT INTO autofill (name, value, value_lower, count) "
+ "VALUES (?, ?, ?, ?)";
sql::Statement s(db_->GetUniqueStatement(sql.c_str()));
s.BindString16(0, entry.key().name());
s.BindString16(1, entry.key().value());
s.BindString16(2, base::i18n::ToLower(entry.key().value()));
- s.BindInt64(3, date_created.ToTimeT());
- s.BindInt64(4, date_last_used.ToTimeT());
- // TODO(isherman): The counts column is currently synced implicitly as the
- // number of timestamps. Sync the value explicitly instead, since the DB now
- // only saves the first and last timestamp, which makes counting timestamps
- // completely meaningless as a way to track frequency of usage.
- s.BindInt(5, entry.timestamps().size());
- return s.Run();
+ s.BindInt(3, entry.timestamps().size());
+
+ if (!s.Run())
+ return false;
+
+ int64 pair_id = db_->GetLastInsertRowId();
+ for (size_t i = 0; i < entry.timestamps().size(); i++) {
+ if (!InsertPairIDAndDate(pair_id, entry.timestamps()[i]))
+ return false;
+ }
+
+ return true;
}
bool AutofillTable::AddFormFieldValueTime(const FormFieldData& element,
std::vector<AutofillChange>* changes,
Time time) {
- sql::Statement s_exists(db_->GetUniqueStatement(
- "SELECT COUNT(*) FROM autofill WHERE name = ? AND value = ?"));
- s_exists.BindString16(0, element.name);
- s_exists.BindString16(1, element.value);
- if (!s_exists.Step())
+ int count = 0;
+ int64 pair_id;
+
+ if (!GetIDAndCountOfFormElement(element, &pair_id, &count))
return false;
- bool already_exists = s_exists.ColumnInt(0) > 0;
- if (already_exists) {
- sql::Statement s(db_->GetUniqueStatement(
- "UPDATE autofill SET date_last_used = ?, count = count + 1 "
- "WHERE name = ? AND value = ?"));
- s.BindInt64(0, time.ToTimeT());
- s.BindString16(1, element.name);
- s.BindString16(2, element.value);
- if (!s.Run())
- return false;
- } else {
- time_t time_as_time_t = time.ToTimeT();
- sql::Statement s(db_->GetUniqueStatement(
- "INSERT INTO autofill "
- "(name, value, value_lower, date_created, date_last_used, count) "
- "VALUES (?, ?, ?, ?, ?, ?)"));
- s.BindString16(0, element.name);
- s.BindString16(1, element.value);
- s.BindString16(2, base::i18n::ToLower(element.value));
- s.BindInt64(3, time_as_time_t);
- s.BindInt64(4, time_as_time_t);
- s.BindInt(5, 1);
- if (!s.Run())
- return false;
- }
+ if (count == 0 && !InsertFormElement(element, &pair_id))
+ return false;
+
+ if (!SetCountOfFormElement(pair_id, count + 1))
+ return false;
+
+ // If we already have more than 2 times delete last one, before adding new
+ // one.
+ if (count >= 2 && !DeleteLastAccess(pair_id))
+ return false;
+
+ if (!InsertPairIDAndDate(pair_id, time))
+ return false;
AutofillChange::Type change_type =
- already_exists ? AutofillChange::UPDATE : AutofillChange::ADD;
+ count == 0 ? AutofillChange::ADD : AutofillChange::UPDATE;
changes->push_back(
- AutofillChange(change_type, AutofillKey(element.name, element.value)));
+ AutofillChange(change_type,
+ AutofillKey(element.name, element.value)));
return true;
}
bool AutofillTable::RemoveFormElement(const base::string16& name,
const base::string16& value) {
+ // Find the id for that pair.
sql::Statement s(db_->GetUniqueStatement(
- "DELETE FROM autofill WHERE name = ? AND value= ?"));
+ "SELECT pair_id FROM autofill WHERE name = ? AND value= ?"));
s.BindString16(0, name);
s.BindString16(1, value);
- return s.Run();
+
+ if (s.Step())
+ return RemoveFormElementForID(s.ColumnInt64(0));
+ return false;
}
bool AutofillTable::AddAutofillProfile(const AutofillProfile& profile) {
@@ -1205,6 +1355,17 @@ bool AutofillTable::EmptyAutofillProfilesTrash() {
}
+bool AutofillTable::RemoveFormElementForID(int64 pair_id) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "DELETE FROM autofill WHERE pair_id = ?"));
+ s.BindInt64(0, pair_id);
+
+ if (s.Run())
+ return RemoveFormElementForTimeRange(pair_id, Time(), Time(), NULL);
+
+ return false;
+}
+
bool AutofillTable::AddAutofillGUIDToTrash(const std::string& guid) {
sql::Statement s(db_->GetUniqueStatement(
"INSERT INTO autofill_profiles_trash"
@@ -1239,12 +1400,16 @@ bool AutofillTable::InitMainTable() {
"name VARCHAR, "
"value VARCHAR, "
"value_lower VARCHAR, "
- "date_created INTEGER DEFAULT 0, "
- "date_last_used INTEGER DEFAULT 0, "
- "count INTEGER DEFAULT 1, "
- "PRIMARY KEY (name, value))") ||
- !db_->Execute("CREATE INDEX autofill_name ON autofill (name)") ||
- !db_->Execute("CREATE INDEX autofill_name_value_lower ON "
+ "pair_id INTEGER PRIMARY KEY, "
+ "count INTEGER DEFAULT 1)")) {
+ NOTREACHED();
+ return false;
+ }
+ if (!db_->Execute("CREATE INDEX autofill_name ON autofill (name)")) {
+ NOTREACHED();
+ return false;
+ }
+ if (!db_->Execute("CREATE INDEX autofill_name_value_lower ON "
"autofill (name, value_lower)")) {
NOTREACHED();
return false;
@@ -1271,6 +1436,23 @@ bool AutofillTable::InitCreditCardsTable() {
return true;
}
+bool AutofillTable::InitDatesTable() {
+ if (!db_->DoesTableExist("autofill_dates")) {
+ if (!db_->Execute("CREATE TABLE autofill_dates ( "
+ "pair_id INTEGER DEFAULT 0, "
+ "date_created INTEGER DEFAULT 0)")) {
+ NOTREACHED();
+ return false;
+ }
+ if (!db_->Execute("CREATE INDEX autofill_dates_pair_id ON "
+ "autofill_dates (pair_id)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
bool AutofillTable::InitProfilesTable() {
if (!db_->DoesTableExist("autofill_profiles")) {
if (!db_->Execute("CREATE TABLE autofill_profiles ( "
@@ -1341,33 +1523,6 @@ bool AutofillTable::InitProfileTrashTable() {
return true;
}
-bool AutofillTable::MigrateToVersion22ClearAutofillEmptyValueElements() {
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT pair_id FROM autofill WHERE TRIM(value) = \"\""));
- if (!s.is_valid())
- return false;
-
- std::set<int64> ids;
- while (s.Step())
- ids.insert(s.ColumnInt64(0));
- if (!s.Succeeded())
- return false;
-
- if (!db_->Execute("DELETE FROM autofill WHERE TRIM(value) = \"\""))
- return false;
-
- for (std::set<int64>::const_iterator it = ids.begin(); it != ids.end();
- ++it) {
- sql::Statement s(db_->GetUniqueStatement(
- "DELETE FROM autofill_dates WHERE pair_id = ?"));
- s.BindInt64(0, *it);
- if (!s.Run())
- return false;
- }
-
- return true;
-}
-
// Add the card_number_encrypted column if credit card table was not
// created in this build (otherwise the column already exists).
// WARNING: Do not change the order of the execution of the SQL
@@ -2136,65 +2291,4 @@ bool AutofillTable::MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields() {
return transaction.Commit();
}
-bool AutofillTable::MigrateToVersion55MergeAutofillDatesTable() {
- sql::Transaction transaction(db_);
- if (!transaction.Begin())
- return false;
-
- if (db_->DoesTableExist("autofill_temp") ||
- !db_->Execute("CREATE TABLE autofill_temp ("
- "name VARCHAR, "
- "value VARCHAR, "
- "value_lower VARCHAR, "
- "date_created INTEGER DEFAULT 0, "
- "date_last_used INTEGER DEFAULT 0, "
- "count INTEGER DEFAULT 1, "
- "PRIMARY KEY (name, value))")) {
- return false;
- }
-
- // Slurp up the data from the existing table and write it to the new table.
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT name, value, value_lower, count, MIN(date_created),"
- " MAX(date_created) "
- "FROM autofill a JOIN autofill_dates ad ON a.pair_id=ad.pair_id "
- "GROUP BY name, value, value_lower, count"));
- while (s.Step()) {
- sql::Statement s_insert(db_->GetUniqueStatement(
- "INSERT INTO autofill_temp "
- "(name, value, value_lower, count, date_created, date_last_used) "
- "VALUES (?, ?, ?, ?, ?, ?)"));
- s_insert.BindString16(0, s.ColumnString16(0));
- s_insert.BindString16(1, s.ColumnString16(1));
- s_insert.BindString16(2, s.ColumnString16(2));
- s_insert.BindInt(3, s.ColumnInt(3));
- s_insert.BindInt64(4, s.ColumnInt64(4));
- s_insert.BindInt64(5, s.ColumnInt64(5));
- if (!s_insert.Run())
- return false;
- }
-
- if (!s.Succeeded())
- return false;
-
- // Delete the existing (version 54) tables and replace them with the contents
- // of the temporary table.
- if (!db_->Execute("DROP TABLE autofill") ||
- !db_->Execute("DROP TABLE autofill_dates") ||
- !db_->Execute("ALTER TABLE autofill_temp "
- "RENAME TO autofill")) {
- return false;
- }
-
- // Create indices on the new table, for fast lookups.
- if (!db_->Execute("CREATE INDEX autofill_name ON autofill (name)") ||
- !db_->Execute("CREATE INDEX autofill_name_value_lower ON "
- "autofill (name, value_lower)")) {
- return false;
- }
-
-
- return transaction.Commit();
-}
-
} // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_table.h b/components/autofill/core/browser/webdata/autofill_table.h
index 83aded5..bcacdcd 100644
--- a/components/autofill/core/browser/webdata/autofill_table.h
+++ b/components/autofill/core/browser/webdata/autofill_table.h
@@ -38,13 +38,17 @@ struct FormFieldData;
// name The name of the input as specified in the html.
// value The literal contents of the text field.
// value_lower The contents of the text field made lower_case.
-// date_created The date on which the user first entered the string
-// |value| into a field of name |name|.
-// date_last_used The date on which the user last entered the string
-// |value| into a field of name |name|.
+// pair_id An ID number unique to the row in the table.
// count How many times the user has entered the string |value|
// in a field of name |name|.
//
+// autofill_dates This table associates a row to each separate time the
+// user submits a form containing a certain name/value
+// pair. The |pair_id| should match the |pair_id| field
+// in the appropriate row of the autofill table.
+// pair_id
+// date_created
+//
// autofill_profiles This table contains Autofill profile data added by the
// user with the Autofill dialog. Most of the columns are
// standard entries in a contact information form.
@@ -172,6 +176,48 @@ class AutofillTable : public WebDatabaseTable {
// culling in future versions.
bool RemoveExpiredFormElements(std::vector<AutofillChange>* changes);
+ // Removes from autofill_dates rows with given pair_id where date_created lies
+ // between |delete_begin| and |delete_end|.
+ bool RemoveFormElementForTimeRange(int64 pair_id,
+ const base::Time& delete_begin,
+ const base::Time& delete_end,
+ int* how_many);
+
+ // Increments the count in the row corresponding to |pair_id| by |delta|.
+ bool AddToCountOfFormElement(int64 pair_id, int delta);
+
+ // Counts how many timestamp data rows are in the |autofill_dates| table for
+ // a given |pair_id|. GetCountOfFormElement() on the other hand gives the
+ // |count| property for a given id.
+ int CountTimestampsData(int64 pair_id);
+
+ // Gets the pair_id and count entries from name and value specified in
+ // |element|. Sets *pair_id and *count to 0 if there is no such row in
+ // the table.
+ bool GetIDAndCountOfFormElement(const FormFieldData& element,
+ int64* pair_id,
+ int* count);
+
+ // Gets the count only given the pair_id.
+ bool GetCountOfFormElement(int64 pair_id, int* count);
+
+ // Updates the count entry in the row corresponding to |pair_id| to |count|.
+ bool SetCountOfFormElement(int64 pair_id, int count);
+
+ // Adds a new row to the autofill table with name and value given in
+ // |element|. Sets *pair_id to the pair_id of the new row.
+ bool InsertFormElement(const FormFieldData& element,
+ int64* pair_id);
+
+ // Adds a new row to the autofill_dates table.
+ bool InsertPairIDAndDate(int64 pair_id, const base::Time& date_created);
+
+ // Deletes last access to the Autofill data from the autofill_dates table.
+ bool DeleteLastAccess(int64 pair_id);
+
+ // Removes row from the autofill tables given |pair_id|.
+ bool RemoveFormElementForID(int64 pair_id);
+
// Removes row from the autofill tables for the given |name| |value| pair.
virtual bool RemoveFormElement(const base::string16& name,
const base::string16& value);
@@ -253,6 +299,10 @@ class AutofillTable : public WebDatabaseTable {
// Empties the Autofill profiles "trash can".
bool EmptyAutofillProfilesTrash();
+ // Removes empty values for autofill that were incorrectly stored in the DB
+ // See bug http://crbug.com/6111
+ bool ClearAutofillEmptyValueElements();
+
// Retrieves all profiles in the database that have been deleted since last
// "empty" of the trash.
bool AddAutofillGUIDToTrash(const std::string& guid);
@@ -261,9 +311,6 @@ class AutofillTable : public WebDatabaseTable {
bool ClearAutofillProfiles();
// Table migration functions.
- // Removes empty values for autofill that were incorrectly stored in the DB
- // See bug http://crbug.com/6111
- bool MigrateToVersion22ClearAutofillEmptyValueElements();
bool MigrateToVersion23AddCardNumberEncryptedColumn();
bool MigrateToVersion24CleanupOversizedStringFields();
bool MigrateToVersion27UpdateLegacyCreditCards();
@@ -276,7 +323,6 @@ class AutofillTable : public WebDatabaseTable {
bool MigrateToVersion37MergeAndCullOlderProfiles();
bool MigrateToVersion51AddOriginColumn();
bool MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields();
- bool MigrateToVersion55MergeAutofillDatesTable();
// Max data length saved in the table;
static const size_t kMaxDataLength;
@@ -285,22 +331,8 @@ class AutofillTable : public WebDatabaseTable {
FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill);
FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_AddChanges);
FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_RemoveBetweenChanges);
+
FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_UpdateDontReplace);
- FRIEND_TEST_ALL_PREFIXES(
- AutofillTableTest,
- Autofill_RemoveFormElementsAddedBetween_UsedOnlyBefore);
- FRIEND_TEST_ALL_PREFIXES(
- AutofillTableTest,
- Autofill_RemoveFormElementsAddedBetween_UsedOnlyAfter);
- FRIEND_TEST_ALL_PREFIXES(
- AutofillTableTest,
- Autofill_RemoveFormElementsAddedBetween_UsedOnlyDuring);
- FRIEND_TEST_ALL_PREFIXES(
- AutofillTableTest,
- Autofill_RemoveFormElementsAddedBetween_UsedBeforeAndDuring);
- FRIEND_TEST_ALL_PREFIXES(
- AutofillTableTest,
- Autofill_RemoveFormElementsAddedBetween_UsedDuringAndAfter);
FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_AddFormFieldValues);
FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, AutofillProfile);
FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, UpdateAutofillProfile);
diff --git a/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/components/autofill/core/browser/webdata/autofill_table_unittest.cc
index daa0a63..649eec3 100644
--- a/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -108,17 +108,6 @@ void CompareAutofillEntrySets(const AutofillEntrySet& actual,
EXPECT_EQ(actual.size(), count);
}
-int GetAutofillEntryCount(const base::string16& name,
- const base::string16& value,
- WebDatabase* db) {
- sql::Statement s(db->GetSQLConnection()->GetUniqueStatement(
- "SELECT count FROM autofill WHERE name = ? AND value = ?"));
- s.BindString16(0, name);
- s.BindString16(1, value);
- s.Step();
- return s.ColumnInt(0);
-}
-
} // namespace
class AutofillTableTest : public testing::Test {
@@ -181,17 +170,27 @@ TEST_F(AutofillTableTest, Autofill) {
now + i * two_seconds));
}
- // We have added the name Clark Kent 5 times, so count should be 5.
- EXPECT_EQ(5, GetAutofillEntryCount(ASCIIToUTF16("Name"),
- ASCIIToUTF16("Clark Kent"), db_.get()));
+ int count = 0;
+ int64 pair_id = 0;
+
+ // We have added the name Clark Kent 5 times, so count should be 5 and pair_id
+ // should be somthing non-zero.
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16("Clark Kent");
+ EXPECT_TRUE(table_->GetIDAndCountOfFormElement(field, &pair_id, &count));
+ EXPECT_EQ(5, count);
+ EXPECT_NE(0, pair_id);
// Storing in the data base should be case sensitive, so there should be no
// database entry for clark kent lowercase.
- EXPECT_EQ(0, GetAutofillEntryCount(ASCIIToUTF16("Name"),
- ASCIIToUTF16("clark kent"), db_.get()));
+ field.value = ASCIIToUTF16("clark kent");
+ EXPECT_TRUE(table_->GetIDAndCountOfFormElement(field, &pair_id, &count));
+ EXPECT_EQ(0, count);
- EXPECT_EQ(2, GetAutofillEntryCount(ASCIIToUTF16("Favorite Color"),
- ASCIIToUTF16("Green"), db_.get()));
+ field.name = ASCIIToUTF16("Favorite Color");
+ field.value = ASCIIToUTF16("Green");
+ EXPECT_TRUE(table_->GetIDAndCountOfFormElement(field, &pair_id, &count));
+ EXPECT_EQ(2, count);
// This is meant to get a list of suggestions for Name. The empty prefix
// in the second argument means it should return all suggestions for a name
@@ -249,8 +248,10 @@ TEST_F(AutofillTableTest, Autofill) {
EXPECT_EQ(kExpectedChanges[i], changes[i]);
}
- EXPECT_EQ(0, GetAutofillEntryCount(ASCIIToUTF16("Name"),
- ASCIIToUTF16("Clark Kent"), db_.get()));
+ field.name = ASCIIToUTF16("Name");
+ field.value = ASCIIToUTF16("Clark Kent");
+ EXPECT_TRUE(table_->GetIDAndCountOfFormElement(field, &pair_id, &count));
+ EXPECT_EQ(0, count);
EXPECT_TRUE(table_->GetFormValuesForElementName(
ASCIIToUTF16("Name"), base::string16(), &v, 6));
@@ -277,6 +278,16 @@ TEST_F(AutofillTableTest, Autofill) {
EXPECT_TRUE(table_->GetFormValuesForElementName(
ASCIIToUTF16("blank"), base::string16(), &v, 10));
EXPECT_EQ(4U, v.size());
+
+ // Now we'll check that ClearAutofillEmptyValueElements() works as expected.
+ table_->ClearAutofillEmptyValueElements();
+
+ v.clear();
+ EXPECT_TRUE(table_->GetFormValuesForElementName(
+ ASCIIToUTF16("blank"), base::string16(), &v, 10));
+ ASSERT_EQ(1U, v.size());
+
+ EXPECT_EQ(kValue, v[0]);
}
TEST_F(AutofillTableTest, Autofill_RemoveBetweenChanges) {
@@ -341,8 +352,14 @@ TEST_F(AutofillTableTest, Autofill_UpdateOneWithOneTimestamp) {
entries.push_back(entry);
ASSERT_TRUE(table_->UpdateAutofillEntries(entries));
- EXPECT_EQ(1, GetAutofillEntryCount(ASCIIToUTF16("foo"), ASCIIToUTF16("bar"),
- db_.get()));
+ FormFieldData field;
+ field.name = ASCIIToUTF16("foo");
+ field.value = ASCIIToUTF16("bar");
+ int64 pair_id;
+ int count;
+ ASSERT_TRUE(table_->GetIDAndCountOfFormElement(field, &pair_id, &count));
+ EXPECT_LE(0, pair_id);
+ EXPECT_EQ(1, count);
std::vector<AutofillEntry> all_entries;
ASSERT_TRUE(table_->GetAllAutofillEntries(&all_entries));
@@ -356,8 +373,14 @@ TEST_F(AutofillTableTest, Autofill_UpdateOneWithTwoTimestamps) {
entries.push_back(entry);
ASSERT_TRUE(table_->UpdateAutofillEntries(entries));
- EXPECT_EQ(2, GetAutofillEntryCount(ASCIIToUTF16("foo"), ASCIIToUTF16("bar"),
- db_.get()));
+ FormFieldData field;
+ field.name = ASCIIToUTF16("foo");
+ field.value = ASCIIToUTF16("bar");
+ int64 pair_id;
+ int count;
+ ASSERT_TRUE(table_->GetIDAndCountOfFormElement(field, &pair_id, &count));
+ EXPECT_LE(0, pair_id);
+ EXPECT_EQ(2, count);
std::vector<AutofillEntry> all_entries;
ASSERT_TRUE(table_->GetAllAutofillEntries(&all_entries));
@@ -388,10 +411,21 @@ TEST_F(AutofillTableTest, Autofill_UpdateTwo) {
entries.push_back(entry1);
ASSERT_TRUE(table_->UpdateAutofillEntries(entries));
- EXPECT_EQ(1, GetAutofillEntryCount(ASCIIToUTF16("foo"), ASCIIToUTF16("bar0"),
- db_.get()));
- EXPECT_EQ(2, GetAutofillEntryCount(ASCIIToUTF16("foo"), ASCIIToUTF16("bar1"),
- db_.get()));
+ FormFieldData field0;
+ field0.name = ASCIIToUTF16("foo");
+ field0.value = ASCIIToUTF16("bar0");
+ int64 pair_id;
+ int count;
+ ASSERT_TRUE(table_->GetIDAndCountOfFormElement(field0, &pair_id, &count));
+ EXPECT_LE(0, pair_id);
+ EXPECT_EQ(1, count);
+
+ FormFieldData field1;
+ field1.name = ASCIIToUTF16("foo");
+ field1.value = ASCIIToUTF16("bar1");
+ ASSERT_TRUE(table_->GetIDAndCountOfFormElement(field1, &pair_id, &count));
+ EXPECT_LE(0, pair_id);
+ EXPECT_EQ(2, count);
}
TEST_F(AutofillTableTest, Autofill_UpdateReplace) {
@@ -479,167 +513,6 @@ TEST_F(AutofillTableTest, Autofill_AddFormFieldValues) {
ASSERT_EQ(2U, all_entries.size());
}
-TEST_F(AutofillTableTest,
- Autofill_RemoveFormElementsAddedBetween_UsedOnlyBefore) {
- // Add an entry used only before the targetted range.
- AutofillChangeList changes;
- FormFieldData field;
- field.name = ASCIIToUTF16("Name");
- field.value = ASCIIToUTF16("Superman");
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(10)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(20)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(30)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(40)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(50)));
-
- EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get()));
-
- changes.clear();
- EXPECT_TRUE(table_->RemoveFormElementsAddedBetween(base::Time::FromTimeT(51),
- base::Time::FromTimeT(60),
- &changes));
- EXPECT_TRUE(changes.empty());
- EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get()));
-}
-
-TEST_F(AutofillTableTest,
- Autofill_RemoveFormElementsAddedBetween_UsedOnlyAfter) {
- // Add an entry used only after the targetted range.
- AutofillChangeList changes;
- FormFieldData field;
- field.name = ASCIIToUTF16("Name");
- field.value = ASCIIToUTF16("Superman");
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(50)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(60)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(70)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(80)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(90)));
-
- EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get()));
-
- changes.clear();
- EXPECT_TRUE(table_->RemoveFormElementsAddedBetween(base::Time::FromTimeT(40),
- base::Time::FromTimeT(50),
- &changes));
- EXPECT_TRUE(changes.empty());
- EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get()));
-}
-
-TEST_F(AutofillTableTest,
- Autofill_RemoveFormElementsAddedBetween_UsedOnlyDuring) {
- // Add an entry used entirely during the targetted range.
- AutofillChangeList changes;
- FormFieldData field;
- field.name = ASCIIToUTF16("Name");
- field.value = ASCIIToUTF16("Superman");
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(10)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(20)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(30)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(40)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(50)));
-
- EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get()));
-
- changes.clear();
- EXPECT_TRUE(table_->RemoveFormElementsAddedBetween(base::Time::FromTimeT(10),
- base::Time::FromTimeT(51),
- &changes));
- ASSERT_EQ(1U, changes.size());
- EXPECT_EQ(AutofillChange(AutofillChange::REMOVE,
- AutofillKey(field.name, field.value)),
- changes[0]);
- EXPECT_EQ(0, GetAutofillEntryCount(field.name, field.value, db_.get()));
-}
-
-TEST_F(AutofillTableTest,
- Autofill_RemoveFormElementsAddedBetween_UsedBeforeAndDuring) {
- // Add an entry used both before and during the targetted range.
- AutofillChangeList changes;
- FormFieldData field;
- field.name = ASCIIToUTF16("Name");
- field.value = ASCIIToUTF16("Superman");
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(10)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(20)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(30)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(40)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(50)));
-
- EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get()));
-
- changes.clear();
- EXPECT_TRUE(table_->RemoveFormElementsAddedBetween(base::Time::FromTimeT(40),
- base::Time::FromTimeT(60),
- &changes));
- ASSERT_EQ(1U, changes.size());
- EXPECT_EQ(AutofillChange(AutofillChange::UPDATE,
- AutofillKey(field.name, field.value)),
- changes[0]);
- EXPECT_EQ(4, GetAutofillEntryCount(field.name, field.value, db_.get()));
- std::vector<base::Time> timestamps;
- EXPECT_TRUE(
- table_->GetAutofillTimestamps(field.name, field.value, &timestamps));
- ASSERT_EQ(2U, timestamps.size());
- EXPECT_EQ(base::Time::FromTimeT(10), timestamps[0]);
- EXPECT_EQ(base::Time::FromTimeT(39), timestamps[1]);
-}
-
-TEST_F(AutofillTableTest,
- Autofill_RemoveFormElementsAddedBetween_UsedDuringAndAfter) {
- // Add an entry used both during and after the targetted range.
- AutofillChangeList changes;
- FormFieldData field;
- field.name = ASCIIToUTF16("Name");
- field.value = ASCIIToUTF16("Superman");
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(50)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(60)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(70)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(80)));
- EXPECT_TRUE(table_->AddFormFieldValueTime(field, &changes,
- base::Time::FromTimeT(90)));
-
- EXPECT_EQ(5, GetAutofillEntryCount(field.name, field.value, db_.get()));
-
- changes.clear();
- EXPECT_TRUE(table_->RemoveFormElementsAddedBetween(base::Time::FromTimeT(40),
- base::Time::FromTimeT(80),
- &changes));
- ASSERT_EQ(1U, changes.size());
- EXPECT_EQ(AutofillChange(AutofillChange::UPDATE,
- AutofillKey(field.name, field.value)),
- changes[0]);
- EXPECT_EQ(2, GetAutofillEntryCount(field.name, field.value, db_.get()));
- std::vector<base::Time> timestamps;
- EXPECT_TRUE(
- table_->GetAutofillTimestamps(field.name, field.value, &timestamps));
- ASSERT_EQ(2U, timestamps.size());
- EXPECT_EQ(base::Time::FromTimeT(80), timestamps[0]);
- EXPECT_EQ(base::Time::FromTimeT(90), timestamps[1]);
-}
-
TEST_F(AutofillTableTest, AutofillProfile) {
// Add a 'Home' profile.
AutofillProfile home_profile;
diff --git a/components/test/data/web_database/version_21.sql b/components/test/data/web_database/version_21.sql
deleted file mode 100644
index a77ab7e..0000000
--- a/components/test/data/web_database/version_21.sql
+++ /dev/null
@@ -1,40 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','21');
-INSERT INTO "meta" VALUES('last_compatible_version','21');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','27');
-INSERT INTO "meta" VALUES('Default Search Provider ID','7');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL, keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1);
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0);
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0);
-INSERT INTO "keywords" VALUES(5,'Wikipedia (en)','en.wikipedia.org','','http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}',1,0,'',1283287335,0,'','',0,0);
-INSERT INTO "keywords" VALUES(6,'NYTimes','query.nytimes.com','','http://query.nytimes.com/gst/handler.html?query={searchTerms}&opensearch=1',1,0,'',1283287335,0,'','',0,0);
-INSERT INTO "keywords" VALUES(7,'eBay','rover.ebay.com','','http://rover.ebay.com/rover/1/711-43047-14818-1/4?satitle={searchTerms}',1,0,'',1283287335,0,'','',0,0);
-INSERT INTO "keywords" VALUES(8,'ff','ff','','http://ff{searchTerms}',0,0,'',1283287356,0,'','',0,0);
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR,signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-INSERT INTO "autofill" VALUES('Name','John Doe','john doe',10,1);
-INSERT INTO "autofill" VALUES('Name','','',11,1);
-INSERT INTO "autofill" VALUES('Email','jane@example.com','jane@example.com',20,3);
-INSERT INTO "autofill" VALUES('Email','','',21,4);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,date_created INTEGER DEFAULT 0);
-INSERT INTO "autofill_dates" VALUES(10,1384299100);
-INSERT INTO "autofill_dates" VALUES(11,1384299200);
-INSERT INTO "autofill_dates" VALUES(20,1384299300);
-INSERT INTO "autofill_dates" VALUES(20,1384299301);
-INSERT INTO "autofill_dates" VALUES(21,1384299401);
-INSERT INTO "autofill_dates" VALUES(21,1384299400);
-INSERT INTO "autofill_dates" VALUES(21,1384299403);
-INSERT INTO "autofill_dates" VALUES(21,1384299402);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
diff --git a/components/test/data/web_database/version_54.sql b/components/test/data/web_database/version_54.sql
deleted file mode 100644
index 17e5b68..0000000
--- a/components/test/data/web_database/version_54.sql
+++ /dev/null
@@ -1,40 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','54');
-INSERT INTO "meta" VALUES('last_compatible_version','54');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','69');
-INSERT INTO "meta" VALUES('Default Search Provider ID','7');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,search_terms_replacement_key VARCHAR,image_url VARCHAR,search_url_post_params VARCHAR,suggest_url_post_params VARCHAR,instant_url_post_params VARCHAR,image_url_post_params VARCHAR,new_tab_url VARCHAR);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE web_intents ( service_url LONGVARCHAR, action VARCHAR, type VARCHAR, title LONGVARCHAR, disposition VARCHAR, scheme VARCHAR, UNIQUE (service_url, action, scheme, type));
-CREATE TABLE web_intents_defaults ( action VARCHAR, type VARCHAR, url_pattern LONGVARCHAR, user_date INTEGER, suppression INTEGER, service_url LONGVARCHAR, scheme VARCHAR, UNIQUE (action, scheme, type, url_pattern));
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-INSERT INTO "autofill" VALUES('Name','John Doe','john doe',10,1);
-INSERT INTO "autofill" VALUES('Name','john doe','john doe',11,1);
-INSERT INTO "autofill" VALUES('Email','jane@example.com','jane@example.com',20,3);
-INSERT INTO "autofill" VALUES('Email','jane.doe@example.org','jane.doe@example.org',21,4);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '');
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-INSERT INTO "autofill_dates" VALUES(10,1384299100);
-INSERT INTO "autofill_dates" VALUES(11,1384299200);
-INSERT INTO "autofill_dates" VALUES(20,1384299300);
-INSERT INTO "autofill_dates" VALUES(20,1384299301);
-INSERT INTO "autofill_dates" VALUES(21,1384299401);
-INSERT INTO "autofill_dates" VALUES(21,1384299400);
-INSERT INTO "autofill_dates" VALUES(21,1384299403);
-INSERT INTO "autofill_dates" VALUES(21,1384299402);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '');
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX web_intents_index ON web_intents (action);
-CREATE INDEX web_intents_default_index ON web_intents_defaults (action);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
diff --git a/components/webdata/common/web_database.cc b/components/webdata/common/web_database.cc
index 230eae1..44b6790 100644
--- a/components/webdata/common/web_database.cc
+++ b/components/webdata/common/web_database.cc
@@ -14,11 +14,11 @@
// corresponding changes must happen in the unit tests, and new migration test
// added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
// static
-const int WebDatabase::kCurrentVersionNumber = 55;
+const int WebDatabase::kCurrentVersionNumber = 54;
namespace {
-const int kCompatibleVersionNumber = 55;
+const int kCompatibleVersionNumber = 54;
// Change the version number and possibly the compatibility version of
// |meta_table_|.
diff --git a/components/webdata/common/web_database_migration_unittest.cc b/components/webdata/common/web_database_migration_unittest.cc
index a72140c..0f22cb5 100644
--- a/components/webdata/common/web_database_migration_unittest.cc
+++ b/components/webdata/common/web_database_migration_unittest.cc
@@ -248,7 +248,7 @@ class WebDatabaseMigrationTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest);
};
-const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 55;
+const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 54;
void WebDatabaseMigrationTest::LoadDatabase(
const base::FilePath::StringType& file) {
@@ -275,9 +275,7 @@ TEST_F(WebDatabaseMigrationTest, MigrateEmptyToCurrent) {
// Check that expected tables are present.
EXPECT_TRUE(connection.DoesTableExist("autofill"));
- // The autofill_dates table is obsolete. (It's been merged into the autofill
- // table.)
- EXPECT_FALSE(connection.DoesTableExist("autofill_dates"));
+ EXPECT_TRUE(connection.DoesTableExist("autofill_dates"));
EXPECT_TRUE(connection.DoesTableExist("autofill_profiles"));
EXPECT_TRUE(connection.DoesTableExist("credit_cards"));
EXPECT_TRUE(connection.DoesTableExist("keywords"));
@@ -292,125 +290,6 @@ TEST_F(WebDatabaseMigrationTest, MigrateEmptyToCurrent) {
}
}
-// Tests that rows with empty values get removed from the autofill tables.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion21ToCurrent) {
- ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_21.sql")));
-
- // Verify pre-conditions.
- {
- sql::Connection connection;
- ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
- // Both empty and non-empty values are allowed in a version 21 database.
- sql::Statement s_autofill(connection.GetUniqueStatement(
- "SELECT name, value, value_lower, pair_id, count FROM autofill"));
- sql::Statement s_dates(connection.GetUniqueStatement(
- "SELECT pair_id, date_created FROM autofill_dates"));
-
- // An entry with a non-empty value.
- ASSERT_TRUE(s_autofill.Step());
- EXPECT_EQ(ASCIIToUTF16("Name"), s_autofill.ColumnString16(0));
- EXPECT_EQ(ASCIIToUTF16("John Doe"), s_autofill.ColumnString16(1));
- EXPECT_EQ(ASCIIToUTF16("john doe"), s_autofill.ColumnString16(2));
- EXPECT_EQ(10, s_autofill.ColumnInt(3));
- EXPECT_EQ(1, s_autofill.ColumnInt(4));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(10, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299100, s_dates.ColumnInt64(1));
-
- // An entry with an empty value.
- ASSERT_TRUE(s_autofill.Step());
- EXPECT_EQ(ASCIIToUTF16("Name"), s_autofill.ColumnString16(0));
- EXPECT_EQ(base::string16(), s_autofill.ColumnString16(1));
- EXPECT_EQ(base::string16(), s_autofill.ColumnString16(2));
- EXPECT_EQ(11, s_autofill.ColumnInt(3));
- EXPECT_EQ(1, s_autofill.ColumnInt(4));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(11, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299200, s_dates.ColumnInt64(1));
-
- // Another entry with a non-empty value.
- ASSERT_TRUE(s_autofill.Step());
- EXPECT_EQ(ASCIIToUTF16("Email"), s_autofill.ColumnString16(0));
- EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s_autofill.ColumnString16(1));
- EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s_autofill.ColumnString16(2));
- EXPECT_EQ(20, s_autofill.ColumnInt(3));
- EXPECT_EQ(3, s_autofill.ColumnInt(4));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(20, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299300, s_dates.ColumnInt64(1));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(20, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299301, s_dates.ColumnInt64(1));
-
- // Another entry with an empty value.
- ASSERT_TRUE(s_autofill.Step());
- EXPECT_EQ(ASCIIToUTF16("Email"), s_autofill.ColumnString16(0));
- EXPECT_EQ(base::string16(), s_autofill.ColumnString16(1));
- EXPECT_EQ(base::string16(), s_autofill.ColumnString16(2));
- EXPECT_EQ(21, s_autofill.ColumnInt(3));
- EXPECT_EQ(4, s_autofill.ColumnInt(4));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(21, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299401, s_dates.ColumnInt64(1));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(21, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299400, s_dates.ColumnInt64(1));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(21, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299403, s_dates.ColumnInt64(1));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(21, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299402, s_dates.ColumnInt64(1));
-
- // No more entries expected.
- ASSERT_FALSE(s_autofill.Step());
- ASSERT_FALSE(s_dates.Step());
- }
-
- DoMigration();
-
- // Verify post-conditions. These are expectations for current version of the
- // database.
- {
- sql::Connection connection;
- ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
- // Check version.
- EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
- // Entries with empty values should have been dropped. The remaining
- // entries should have been preserved.
- sql::Statement s(
- connection.GetUniqueStatement(
- "SELECT name, value, value_lower, date_created, date_last_used,"
- " count "
- "FROM autofill "
- "ORDER BY name, value ASC"));
-
- // "jane@example.com"
- ASSERT_TRUE(s.Step());
- EXPECT_EQ(ASCIIToUTF16("Email"), s.ColumnString16(0));
- EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s.ColumnString16(1));
- EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s.ColumnString16(2));
- EXPECT_EQ(1384299300, s.ColumnInt64(3));
- EXPECT_EQ(1384299301, s.ColumnInt64(4));
- EXPECT_EQ(3, s.ColumnInt(5));
-
- // "John Doe"
- ASSERT_TRUE(s.Step());
- EXPECT_EQ(ASCIIToUTF16("Name"), s.ColumnString16(0));
- EXPECT_EQ(ASCIIToUTF16("John Doe"), s.ColumnString16(1));
- EXPECT_EQ(ASCIIToUTF16("john doe"), s.ColumnString16(2));
- EXPECT_EQ(1384299100, s.ColumnInt64(3));
- EXPECT_EQ(1384299100, s.ColumnInt64(4));
- EXPECT_EQ(1, s.ColumnInt(5));
-
- // No more entries expected.
- ASSERT_FALSE(s.Step());
- }
-}
-
// Tests that the |credit_card| table gets added to the schema for a version 22
// database.
TEST_F(WebDatabaseMigrationTest, MigrateVersion22ToCurrent) {
@@ -2391,158 +2270,3 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion53ToCurrent) {
EXPECT_FALSE(s_phones.Step());
}
}
-
-// Tests that migrating from version 54 to version 55 drops the autofill_dates
-// table, and merges the appropriate dates into the autofill table.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion54ToCurrent) {
- ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_54.sql")));
-
- // Verify pre-conditions. These are expectations for version 54 of the
- // database.
- {
- sql::Connection connection;
- ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
- EXPECT_TRUE(connection.DoesTableExist("autofill_dates"));
- EXPECT_FALSE(connection.DoesColumnExist("autofill", "date_created"));
- EXPECT_FALSE(connection.DoesColumnExist("autofill", "date_last_used"));
-
- // Verify the incoming data.
- sql::Statement s_autofill(connection.GetUniqueStatement(
- "SELECT name, value, value_lower, pair_id, count FROM autofill"));
- sql::Statement s_dates(connection.GetUniqueStatement(
- "SELECT pair_id, date_created FROM autofill_dates"));
-
- // An entry with one timestamp.
- ASSERT_TRUE(s_autofill.Step());
- EXPECT_EQ(ASCIIToUTF16("Name"), s_autofill.ColumnString16(0));
- EXPECT_EQ(ASCIIToUTF16("John Doe"), s_autofill.ColumnString16(1));
- EXPECT_EQ(ASCIIToUTF16("john doe"), s_autofill.ColumnString16(2));
- EXPECT_EQ(10, s_autofill.ColumnInt(3));
- EXPECT_EQ(1, s_autofill.ColumnInt(4));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(10, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299100, s_dates.ColumnInt64(1));
-
- // Another entry with one timestamp, differing from the previous one in case
- // only.
- ASSERT_TRUE(s_autofill.Step());
- EXPECT_EQ(ASCIIToUTF16("Name"), s_autofill.ColumnString16(0));
- EXPECT_EQ(ASCIIToUTF16("john doe"), s_autofill.ColumnString16(1));
- EXPECT_EQ(ASCIIToUTF16("john doe"), s_autofill.ColumnString16(2));
- EXPECT_EQ(11, s_autofill.ColumnInt(3));
- EXPECT_EQ(1, s_autofill.ColumnInt(4));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(11, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299200, s_dates.ColumnInt64(1));
-
- // An entry with two timestamps (with count > 2; this is realistic).
- ASSERT_TRUE(s_autofill.Step());
- EXPECT_EQ(ASCIIToUTF16("Email"), s_autofill.ColumnString16(0));
- EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s_autofill.ColumnString16(1));
- EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s_autofill.ColumnString16(2));
- EXPECT_EQ(20, s_autofill.ColumnInt(3));
- EXPECT_EQ(3, s_autofill.ColumnInt(4));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(20, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299300, s_dates.ColumnInt64(1));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(20, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299301, s_dates.ColumnInt64(1));
-
- // An entry with more than two timestamps, which are stored out of order.
- ASSERT_TRUE(s_autofill.Step());
- EXPECT_EQ(ASCIIToUTF16("Email"), s_autofill.ColumnString16(0));
- EXPECT_EQ(ASCIIToUTF16("jane.doe@example.org"),
- s_autofill.ColumnString16(1));
- EXPECT_EQ(ASCIIToUTF16("jane.doe@example.org"),
- s_autofill.ColumnString16(2));
- EXPECT_EQ(21, s_autofill.ColumnInt(3));
- EXPECT_EQ(4, s_autofill.ColumnInt(4));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(21, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299401, s_dates.ColumnInt64(1));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(21, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299400, s_dates.ColumnInt64(1));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(21, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299403, s_dates.ColumnInt64(1));
- ASSERT_TRUE(s_dates.Step());
- EXPECT_EQ(21, s_dates.ColumnInt(0));
- EXPECT_EQ(1384299402, s_dates.ColumnInt64(1));
-
- // No more entries expected.
- ASSERT_FALSE(s_autofill.Step());
- ASSERT_FALSE(s_dates.Step());
- }
-
- DoMigration();
-
- // Verify post-conditions. These are expectations for current version of the
- // database.
- {
- sql::Connection connection;
- ASSERT_TRUE(connection.Open(GetDatabasePath()));
- ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
- // Check version.
- EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
- // The autofill_dates table should have been dropped, and its columns should
- // have been migrated to the autofill table.
- EXPECT_FALSE(connection.DoesTableExist("autofill_dates"));
- EXPECT_TRUE(connection.DoesColumnExist("autofill", "date_created"));
- EXPECT_TRUE(connection.DoesColumnExist("autofill", "date_last_used"));
-
- // Data should have been preserved. Note that it appears out of order
- // relative to the previous table, as it's been alphabetized. That's ok.
- sql::Statement s(
- connection.GetUniqueStatement(
- "SELECT name, value, value_lower, date_created, date_last_used,"
- " count "
- "FROM autofill "
- "ORDER BY name, value ASC"));
-
- // "jane.doe@example.org": Timestamps should be parsed correctly, and only
- // the first and last should be kept.
- ASSERT_TRUE(s.Step());
- EXPECT_EQ(ASCIIToUTF16("Email"), s.ColumnString16(0));
- EXPECT_EQ(ASCIIToUTF16("jane.doe@example.org"), s.ColumnString16(1));
- EXPECT_EQ(ASCIIToUTF16("jane.doe@example.org"), s.ColumnString16(2));
- EXPECT_EQ(1384299400, s.ColumnInt64(3));
- EXPECT_EQ(1384299403, s.ColumnInt64(4));
- EXPECT_EQ(4, s.ColumnInt(5));
-
- // "jane@example.com": Timestamps should be parsed correctly.
- ASSERT_TRUE(s.Step());
- EXPECT_EQ(ASCIIToUTF16("Email"), s.ColumnString16(0));
- EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s.ColumnString16(1));
- EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s.ColumnString16(2));
- EXPECT_EQ(1384299300, s.ColumnInt64(3));
- EXPECT_EQ(1384299301, s.ColumnInt64(4));
- EXPECT_EQ(3, s.ColumnInt(5));
-
- // "John Doe": The single timestamp should be assigned as both the creation
- // and the last use timestamp.
- ASSERT_TRUE(s.Step());
- EXPECT_EQ(ASCIIToUTF16("Name"), s.ColumnString16(0));
- EXPECT_EQ(ASCIIToUTF16("John Doe"), s.ColumnString16(1));
- EXPECT_EQ(ASCIIToUTF16("john doe"), s.ColumnString16(2));
- EXPECT_EQ(1384299100, s.ColumnInt64(3));
- EXPECT_EQ(1384299100, s.ColumnInt64(4));
- EXPECT_EQ(1, s.ColumnInt(5));
-
- // "john doe": Should not be merged with "John Doe" (case-sensitivity).
- ASSERT_TRUE(s.Step());
- EXPECT_EQ(ASCIIToUTF16("Name"), s.ColumnString16(0));
- EXPECT_EQ(ASCIIToUTF16("john doe"), s.ColumnString16(1));
- EXPECT_EQ(ASCIIToUTF16("john doe"), s.ColumnString16(2));
- EXPECT_EQ(1384299200, s.ColumnInt64(3));
- EXPECT_EQ(1384299200, s.ColumnInt64(4));
- EXPECT_EQ(1, s.ColumnInt(5));
-
- // No more entries expected.
- ASSERT_FALSE(s.Step());
- }
-}