summaryrefslogtreecommitdiffstats
path: root/chrome/browser/webdata
diff options
context:
space:
mode:
authorandybons@chromium.org <andybons@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-30 15:52:34 +0000
committerandybons@chromium.org <andybons@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-30 15:52:34 +0000
commit23e152e917c70e0399770433d564fe2f54c5ea95 (patch)
tree8bc4584d15b8bafe7b019448e79e81f1d74be9e5 /chrome/browser/webdata
parent8549a7c039c6db1f1ab9dcf529a97c9262faf227 (diff)
downloadchromium_src-23e152e917c70e0399770433d564fe2f54c5ea95.zip
chromium_src-23e152e917c70e0399770433d564fe2f54c5ea95.tar.gz
chromium_src-23e152e917c70e0399770433d564fe2f54c5ea95.tar.bz2
Split out Keywords and Autofill logic from WebDatabase.
This is simply moving things around. No underlying logic has changed. Since the new class AutofillTable actually encapsulates more than one table within the schema, I'm open to naming suggestions. No plans yet for the migration code. BUG=none TEST=WebDatabaseTest*,AutofillTableTest*,KeywordTableTest*,ProfileSyncServiceAutofillTest.* Review URL: http://codereview.chromium.org/6708110 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@79834 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/webdata')
-rw-r--r--chrome/browser/webdata/autofill_table.cc1146
-rw-r--r--chrome/browser/webdata/autofill_table.h315
-rw-r--r--chrome/browser/webdata/autofill_table_unittest.cc1578
-rw-r--r--chrome/browser/webdata/autofill_util.cc358
-rw-r--r--chrome/browser/webdata/autofill_util.h68
-rw-r--r--chrome/browser/webdata/keyword_table.cc224
-rw-r--r--chrome/browser/webdata/keyword_table.h88
-rw-r--r--chrome/browser/webdata/keyword_table_unittest.cc247
-rw-r--r--chrome/browser/webdata/web_data_service.cc65
-rw-r--r--chrome/browser/webdata/web_database.cc1826
-rw-r--r--chrome/browser/webdata/web_database.h259
-rw-r--r--chrome/browser/webdata/web_database_table.h41
-rw-r--r--chrome/browser/webdata/web_database_unittest.cc1730
13 files changed, 4154 insertions, 3791 deletions
diff --git a/chrome/browser/webdata/autofill_table.cc b/chrome/browser/webdata/autofill_table.cc
new file mode 100644
index 0000000..0433b44
--- /dev/null
+++ b/chrome/browser/webdata/autofill_table.cc
@@ -0,0 +1,1146 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/webdata/autofill_table.h"
+
+#include "app/sql/statement.h"
+#include "base/time.h"
+#include "base/tuple.h"
+#include "chrome/browser/autofill/autofill_country.h"
+#include "chrome/browser/autofill/autofill_profile.h"
+#include "chrome/browser/autofill/autofill_type.h"
+#include "chrome/browser/autofill/credit_card.h"
+#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/webdata/autofill_change.h"
+#include "chrome/browser/webdata/autofill_util.h"
+#include "chrome/common/guid.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "webkit/glue/form_field.h"
+
+using base::Time;
+using webkit_glue::FormField;
+
+namespace {
+typedef std::vector<Tuple3<int64, string16, string16> > AutofillElementList;
+} // anonymous namespace
+
+bool AutofillTable::Init() {
+ return (InitMainTable() && InitCreditCardsTable() && InitDatesTable() &&
+ InitProfilesTable() && InitProfileNamesTable() &&
+ InitProfileEmailsTable() && InitProfilePhonesTable() &&
+ InitProfileTrashTable());
+}
+
+bool AutofillTable::AddFormFieldValues(const std::vector<FormField>& elements,
+ std::vector<AutofillChange>* changes) {
+ return AddFormFieldValuesTime(elements, changes, Time::Now());
+}
+
+bool AutofillTable::AddFormFieldValue(const FormField& element,
+ std::vector<AutofillChange>* changes) {
+ return AddFormFieldValueTime(element, changes, base::Time::Now());
+}
+
+bool AutofillTable::GetFormValuesForElementName(const string16& name,
+ const string16& prefix,
+ std::vector<string16>* values,
+ int limit) {
+ DCHECK(values);
+ sql::Statement s;
+
+ if (prefix.empty()) {
+ s.Assign(db_->GetUniqueStatement(
+ "SELECT value FROM autofill "
+ "WHERE name = ? "
+ "ORDER BY count DESC "
+ "LIMIT ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString16(0, name);
+ s.BindInt(1, limit);
+ } else {
+ string16 prefix_lower = l10n_util::ToLower(prefix);
+ string16 next_prefix = prefix_lower;
+ next_prefix[next_prefix.length() - 1]++;
+
+ s.Assign(db_->GetUniqueStatement(
+ "SELECT value FROM autofill "
+ "WHERE name = ? AND "
+ "value_lower >= ? AND "
+ "value_lower < ? "
+ "ORDER BY count DESC "
+ "LIMIT ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString16(0, name);
+ s.BindString16(1, prefix_lower);
+ s.BindString16(2, next_prefix);
+ s.BindInt(3, limit);
+ }
+
+ values->clear();
+ while (s.Step())
+ values->push_back(s.ColumnString16(0));
+ return s.Succeeded();
+}
+
+bool AutofillTable::RemoveFormElementsAddedBetween(
+ base::Time delete_begin,
+ base::Time delete_end,
+ std::vector<AutofillChange>* changes) {
+ 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 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 < ?"));
+ if (!s) {
+ NOTREACHED() << "Statement 1 prepare failed";
+ return false;
+ }
+ s.BindInt64(0, delete_begin.ToTimeT());
+ s.BindInt64(1,
+ delete_end.is_null() ?
+ std::numeric_limits<int64>::max() :
+ delete_end.ToTimeT());
+
+ AutofillElementList elements;
+ while (s.Step()) {
+ elements.push_back(MakeTuple(s.ColumnInt64(0),
+ s.ColumnString16(1),
+ s.ColumnString16(2)));
+ }
+
+ if (!s.Succeeded()) {
+ NOTREACHED();
+ return false;
+ }
+
+ 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;
+ }
+ bool was_removed = false;
+ if (!AddToCountOfFormElement(itr->a, -how_many, &was_removed))
+ return false;
+ AutofillChange::Type change_type =
+ was_removed ? AutofillChange::REMOVE : AutofillChange::UPDATE;
+ changes->push_back(AutofillChange(change_type,
+ AutofillKey(itr->b, itr->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 < ?"));
+ if (!s) {
+ NOTREACHED() << "Statement 1 prepare failed";
+ return false;
+ }
+ 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;
+}
+
+bool AutofillTable::AddToCountOfFormElement(int64 pair_id,
+ int delta,
+ bool* was_removed) {
+ DCHECK(was_removed);
+ int count = 0;
+ *was_removed = false;
+
+ if (!GetCountOfFormElement(pair_id, &count))
+ return false;
+
+ if (count + delta == 0) {
+ if (!RemoveFormElementForID(pair_id))
+ return false;
+ *was_removed = true;
+ } else {
+ if (!SetCountOfFormElement(pair_id, count + delta))
+ return false;
+ }
+ return true;
+}
+
+bool AutofillTable::GetIDAndCountOfFormElement(
+ const FormField& element,
+ int64* pair_id,
+ int* count) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT pair_id, count FROM autofill "
+ "WHERE name = ? AND value = ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString16(0, element.name);
+ s.BindString16(1, element.value);
+
+ *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) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT count FROM autofill WHERE pair_id = ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ 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 = ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindInt(0, count);
+ s.BindInt64(1, pair_id);
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+
+ return true;
+}
+
+bool AutofillTable::InsertFormElement(const FormField& element,
+ int64* pair_id) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "INSERT INTO autofill (name, value, value_lower) VALUES (?,?,?)"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString16(0, element.name);
+ s.BindString16(1, element.value);
+ s.BindString16(2, l10n_util::ToLower(element.value));
+
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+
+ *pair_id = db_->GetLastInsertRowId();
+ return true;
+}
+
+bool AutofillTable::InsertPairIDAndDate(int64 pair_id,
+ base::Time date_created) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "INSERT INTO autofill_dates "
+ "(pair_id, date_created) VALUES (?, ?)"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindInt64(0, pair_id);
+ s.BindInt64(1, date_created.ToTimeT());
+
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+
+ return true;
+}
+
+bool AutofillTable::AddFormFieldValuesTime(
+ const std::vector<FormField>& elements,
+ std::vector<AutofillChange>* changes,
+ base::Time time) {
+ // Only add one new entry for each unique element name. Use |seen_names| to
+ // track this. Add up to |kMaximumUniqueNames| unique entries per form.
+ const size_t kMaximumUniqueNames = 256;
+ std::set<string16> seen_names;
+ bool result = true;
+ for (std::vector<FormField>::const_iterator
+ itr = elements.begin();
+ itr != elements.end();
+ itr++) {
+ if (seen_names.size() >= kMaximumUniqueNames)
+ break;
+ if (seen_names.find(itr->name) != seen_names.end())
+ continue;
+ result = result && AddFormFieldValueTime(*itr, changes, time);
+ seen_names.insert(itr->name);
+ }
+ return result;
+}
+
+bool AutofillTable::ClearAutofillEmptyValueElements() {
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT pair_id FROM autofill WHERE TRIM(value)= \"\""));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ std::set<int64> ids;
+ while (s.Step())
+ ids.insert(s.ColumnInt64(0));
+
+ 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"));
+
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ bool first_entry = true;
+ AutofillKey* current_key_ptr = NULL;
+ std::vector<base::Time>* timestamps_ptr = NULL;
+ string16 name, value;
+ base::Time time;
+ while (s.Step()) {
+ 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<base::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<base::Time>;
+ }
+ timestamps_ptr->push_back(time);
+ }
+ }
+ // 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();
+}
+
+bool AutofillTable::GetAutofillTimestamps(const string16& name,
+ const string16& value,
+ std::vector<base::Time>* timestamps) {
+ DCHECK(timestamps);
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT date_created FROM autofill a JOIN "
+ "autofill_dates ad ON a.pair_id=ad.pair_id "
+ "WHERE a.name = ? AND a.value = ?"));
+
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString16(0, name);
+ s.BindString16(1, value);
+ while (s.Step()) {
+ timestamps->push_back(Time::FromTimeT(s.ColumnInt64(0)));
+ }
+
+ return s.Succeeded();
+}
+
+bool AutofillTable::UpdateAutofillEntries(
+ const std::vector<AutofillEntry>& entries) {
+ if (!entries.size())
+ return true;
+
+ // Remove all existing entries.
+ 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()));
+ if (!s.is_valid()) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString16(0, entries[i].key().name());
+ s.BindString16(1, entries[i].key().value());
+ 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++) {
+ if (!InsertAutofillEntry(entries[i]))
+ return false;
+ }
+
+ return true;
+}
+
+bool AutofillTable::InsertAutofillEntry(const AutofillEntry& entry) {
+ std::string sql = "INSERT INTO autofill (name, value, value_lower, count) "
+ "VALUES (?, ?, ?, ?)";
+ sql::Statement s(db_->GetUniqueStatement(sql.c_str()));
+ if (!s.is_valid()) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString16(0, entry.key().name());
+ s.BindString16(1, entry.key().value());
+ s.BindString16(2, l10n_util::ToLower(entry.key().value()));
+ s.BindInt(3, entry.timestamps().size());
+
+ if (!s.Run()) {
+ NOTREACHED();
+ 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 FormField& element,
+ std::vector<AutofillChange>* changes,
+ base::Time time) {
+ int count = 0;
+ int64 pair_id;
+
+ if (!GetIDAndCountOfFormElement(element, &pair_id, &count))
+ return false;
+
+ if (count == 0 && !InsertFormElement(element, &pair_id))
+ return false;
+
+ if (!SetCountOfFormElement(pair_id, count + 1))
+ return false;
+
+ if (!InsertPairIDAndDate(pair_id, time))
+ return false;
+
+ AutofillChange::Type change_type =
+ count == 0 ? AutofillChange::ADD : AutofillChange::UPDATE;
+ changes->push_back(
+ AutofillChange(change_type,
+ AutofillKey(element.name, element.value)));
+ return true;
+}
+
+
+bool AutofillTable::RemoveFormElement(const string16& name,
+ const string16& value) {
+ // Find the id for that pair.
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT pair_id FROM autofill WHERE name = ? AND value= ?"));
+ if (!s) {
+ NOTREACHED() << "Statement 1 prepare failed";
+ return false;
+ }
+ s.BindString16(0, name);
+ s.BindString16(1, value);
+
+ if (s.Step())
+ return RemoveFormElementForID(s.ColumnInt64(0));
+ return false;
+}
+
+bool AutofillTable::AddAutofillProfile(const AutofillProfile& profile) {
+ if (IsAutofillGUIDInTrash(profile.guid()))
+ return true;
+
+ sql::Statement s(db_->GetUniqueStatement(
+ "INSERT INTO autofill_profiles"
+ "(guid, company_name, address_line_1, address_line_2, city, state,"
+ " zipcode, country, country_code, date_modified)"
+ "VALUES (?,?,?,?,?,?,?,?,?,?)"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ autofill_util::BindAutofillProfileToStatement(profile, &s);
+
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (!s.Succeeded())
+ return false;
+
+ return autofill_util::AddAutofillProfilePieces(profile, db_);
+}
+
+bool AutofillTable::GetAutofillProfile(const std::string& guid,
+ AutofillProfile** profile) {
+ DCHECK(guid::IsValidGUID(guid));
+ DCHECK(profile);
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT guid, company_name, address_line_1, address_line_2, city, state,"
+ " zipcode, country, country_code, date_modified "
+ "FROM autofill_profiles "
+ "WHERE guid=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString(0, guid);
+ if (!s.Step())
+ return false;
+
+ if (!s.Succeeded())
+ return false;
+
+ scoped_ptr<AutofillProfile> p(autofill_util::AutofillProfileFromStatement(s));
+
+ // Get associated name info.
+ autofill_util::AddAutofillProfileNamesToProfile(db_, p.get());
+
+ // Get associated email info.
+ autofill_util::AddAutofillProfileEmailsToProfile(db_, p.get());
+
+ // Get associated phone info.
+ autofill_util::AddAutofillProfilePhonesToProfile(db_, p.get());
+
+ // Get associated fax info.
+ autofill_util::AddAutofillProfileFaxesToProfile(db_, p.get());
+
+ *profile = p.release();
+ return true;
+}
+
+bool AutofillTable::GetAutofillProfiles(
+ std::vector<AutofillProfile*>* profiles) {
+ DCHECK(profiles);
+ profiles->clear();
+
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT guid "
+ "FROM autofill_profiles"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ while (s.Step()) {
+ std::string guid = s.ColumnString(0);
+ AutofillProfile* profile = NULL;
+ if (!GetAutofillProfile(guid, &profile))
+ return false;
+ profiles->push_back(profile);
+ }
+
+ return s.Succeeded();
+}
+
+bool AutofillTable::UpdateAutofillProfile(const AutofillProfile& profile) {
+ DCHECK(guid::IsValidGUID(profile.guid()));
+
+ // Don't update anything until the trash has been emptied. There may be
+ // pending modifications to process.
+ if (!IsAutofillProfilesTrashEmpty())
+ return true;
+
+ AutofillProfile* tmp_profile = NULL;
+ if (!GetAutofillProfile(profile.guid(), &tmp_profile))
+ return false;
+
+ // Preserve appropriate modification dates by not updating unchanged profiles.
+ scoped_ptr<AutofillProfile> old_profile(tmp_profile);
+ if (old_profile->Compare(profile) == 0)
+ return true;
+
+ AutofillProfile new_profile(profile);
+ std::vector<string16> values;
+
+ old_profile->GetMultiInfo(NAME_FULL, &values);
+ values[0] = new_profile.GetInfo(NAME_FULL);
+ new_profile.SetMultiInfo(NAME_FULL, values);
+
+ old_profile->GetMultiInfo(EMAIL_ADDRESS, &values);
+ values[0] = new_profile.GetInfo(EMAIL_ADDRESS);
+ new_profile.SetMultiInfo(EMAIL_ADDRESS, values);
+
+ old_profile->GetMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values);
+ values[0] = new_profile.GetInfo(PHONE_HOME_WHOLE_NUMBER);
+ new_profile.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, values);
+
+ old_profile->GetMultiInfo(PHONE_FAX_WHOLE_NUMBER, &values);
+ values[0] = new_profile.GetInfo(PHONE_FAX_WHOLE_NUMBER);
+ new_profile.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, values);
+
+ return UpdateAutofillProfileMulti(new_profile);
+}
+
+bool AutofillTable::UpdateAutofillProfileMulti(const AutofillProfile& profile) {
+ DCHECK(guid::IsValidGUID(profile.guid()));
+
+ // Don't update anything until the trash has been emptied. There may be
+ // pending modifications to process.
+ if (!IsAutofillProfilesTrashEmpty())
+ return true;
+
+ AutofillProfile* tmp_profile = NULL;
+ if (!GetAutofillProfile(profile.guid(), &tmp_profile))
+ return false;
+
+ // Preserve appropriate modification dates by not updating unchanged profiles.
+ scoped_ptr<AutofillProfile> old_profile(tmp_profile);
+ if (old_profile->CompareMulti(profile) == 0)
+ return true;
+
+ sql::Statement s(db_->GetUniqueStatement(
+ "UPDATE autofill_profiles "
+ "SET guid=?, company_name=?, address_line_1=?, address_line_2=?, "
+ " city=?, state=?, zipcode=?, country=?, country_code=?, "
+ " date_modified=? "
+ "WHERE guid=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ autofill_util::BindAutofillProfileToStatement(profile, &s);
+ s.BindString(10, profile.guid());
+ bool result = s.Run();
+ DCHECK_GT(db_->GetLastChangeCount(), 0);
+ if (!result)
+ return result;
+
+ // Remove the old names, emails, and phone/fax numbers.
+ if (!autofill_util::RemoveAutofillProfilePieces(profile.guid(), db_))
+ return false;
+
+ return autofill_util::AddAutofillProfilePieces(profile, db_);
+}
+
+bool AutofillTable::RemoveAutofillProfile(const std::string& guid) {
+ DCHECK(guid::IsValidGUID(guid));
+
+ if (IsAutofillGUIDInTrash(guid)) {
+ sql::Statement s_trash(db_->GetUniqueStatement(
+ "DELETE FROM autofill_profiles_trash WHERE guid = ?"));
+ if (!s_trash) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s_trash.BindString(0, guid);
+ if (!s_trash.Run()) {
+ NOTREACHED() << "Expected item in trash.";
+ return false;
+ }
+
+ return true;
+ }
+
+ sql::Statement s(db_->GetUniqueStatement(
+ "DELETE FROM autofill_profiles WHERE guid = ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString(0, guid);
+ if (!s.Run())
+ return false;
+
+ return autofill_util::RemoveAutofillProfilePieces(guid, db_);
+}
+
+bool AutofillTable::ClearAutofillProfiles() {
+ sql::Statement s1(db_->GetUniqueStatement(
+ "DELETE FROM autofill_profiles"));
+ if (!s1) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ if (!s1.Run())
+ return false;
+
+ sql::Statement s2(db_->GetUniqueStatement(
+ "DELETE FROM autofill_profile_names"));
+ if (!s2) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ if (!s2.Run())
+ return false;
+
+ sql::Statement s3(db_->GetUniqueStatement(
+ "DELETE FROM autofill_profile_emails"));
+ if (!s3) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ if (!s3.Run())
+ return false;
+
+ sql::Statement s4(db_->GetUniqueStatement(
+ "DELETE FROM autofill_profile_phones"));
+ if (!s4) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ if (!s4.Run())
+ return false;
+
+ return true;
+}
+
+bool AutofillTable::AddCreditCard(const CreditCard& credit_card) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "INSERT INTO credit_cards"
+ "(guid, name_on_card, expiration_month, expiration_year, "
+ "card_number_encrypted, date_modified)"
+ "VALUES (?,?,?,?,?,?)"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ autofill_util::BindCreditCardToStatement(credit_card, &s);
+
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+
+ DCHECK_GT(db_->GetLastChangeCount(), 0);
+ return s.Succeeded();
+}
+
+bool AutofillTable::GetCreditCard(const std::string& guid,
+ CreditCard** credit_card) {
+ DCHECK(guid::IsValidGUID(guid));
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT guid, name_on_card, expiration_month, expiration_year, "
+ "card_number_encrypted, date_modified "
+ "FROM credit_cards "
+ "WHERE guid = ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString(0, guid);
+ if (!s.Step())
+ return false;
+
+ *credit_card = autofill_util::CreditCardFromStatement(s);
+
+ return s.Succeeded();
+}
+
+bool AutofillTable::GetCreditCards(
+ std::vector<CreditCard*>* credit_cards) {
+ DCHECK(credit_cards);
+ credit_cards->clear();
+
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT guid "
+ "FROM credit_cards"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ while (s.Step()) {
+ std::string guid = s.ColumnString(0);
+ CreditCard* credit_card = NULL;
+ if (!GetCreditCard(guid, &credit_card))
+ return false;
+ credit_cards->push_back(credit_card);
+ }
+
+ return s.Succeeded();
+}
+
+bool AutofillTable::UpdateCreditCard(const CreditCard& credit_card) {
+ DCHECK(guid::IsValidGUID(credit_card.guid()));
+
+ CreditCard* tmp_credit_card = NULL;
+ if (!GetCreditCard(credit_card.guid(), &tmp_credit_card))
+ return false;
+
+ // Preserve appropriate modification dates by not updating unchanged cards.
+ scoped_ptr<CreditCard> old_credit_card(tmp_credit_card);
+ if (*old_credit_card == credit_card)
+ return true;
+
+ sql::Statement s(db_->GetUniqueStatement(
+ "UPDATE credit_cards "
+ "SET guid=?, name_on_card=?, expiration_month=?, "
+ " expiration_year=?, card_number_encrypted=?, date_modified=? "
+ "WHERE guid=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ autofill_util::BindCreditCardToStatement(credit_card, &s);
+ s.BindString(6, credit_card.guid());
+ bool result = s.Run();
+ DCHECK_GT(db_->GetLastChangeCount(), 0);
+ return result;
+}
+
+bool AutofillTable::RemoveCreditCard(const std::string& guid) {
+ DCHECK(guid::IsValidGUID(guid));
+ sql::Statement s(db_->GetUniqueStatement(
+ "DELETE FROM credit_cards WHERE guid = ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString(0, guid);
+ return s.Run();
+}
+
+bool AutofillTable::RemoveAutofillProfilesAndCreditCardsModifiedBetween(
+ base::Time delete_begin,
+ base::Time delete_end) {
+ DCHECK(delete_end.is_null() || delete_begin < delete_end);
+
+ time_t delete_begin_t = delete_begin.ToTimeT();
+ time_t delete_end_t = delete_end.is_null() ?
+ std::numeric_limits<time_t>::max() :
+ delete_end.ToTimeT();
+
+ // Remove Autofill profiles in the time range.
+ sql::Statement s_profiles(db_->GetUniqueStatement(
+ "DELETE FROM autofill_profiles "
+ "WHERE date_modified >= ? AND date_modified < ?"));
+ if (!s_profiles) {
+ NOTREACHED() << "Autofill profiles statement prepare failed";
+ return false;
+ }
+
+ s_profiles.BindInt64(0, delete_begin_t);
+ s_profiles.BindInt64(1, delete_end_t);
+ s_profiles.Run();
+
+ if (!s_profiles.Succeeded()) {
+ NOTREACHED();
+ return false;
+ }
+
+ // Remove Autofill profiles in the time range.
+ sql::Statement s_credit_cards(db_->GetUniqueStatement(
+ "DELETE FROM credit_cards "
+ "WHERE date_modified >= ? AND date_modified < ?"));
+ if (!s_credit_cards) {
+ NOTREACHED() << "Autofill credit cards statement prepare failed";
+ return false;
+ }
+
+ s_credit_cards.BindInt64(0, delete_begin_t);
+ s_credit_cards.BindInt64(1, delete_end_t);
+ s_credit_cards.Run();
+
+ if (!s_credit_cards.Succeeded()) {
+ NOTREACHED();
+ return false;
+ }
+
+ return true;
+}
+
+bool AutofillTable::GetAutofillProfilesInTrash(
+ std::vector<std::string>* guids) {
+ guids->clear();
+
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT guid "
+ "FROM autofill_profiles_trash"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ while (s.Step()) {
+ std::string guid = s.ColumnString(0);
+ guids->push_back(guid);
+ }
+
+ return s.Succeeded();
+}
+
+bool AutofillTable::EmptyAutofillProfilesTrash() {
+ sql::Statement s(db_->GetUniqueStatement(
+ "DELETE FROM autofill_profiles_trash"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ return s.Run();
+}
+
+
+bool AutofillTable::RemoveFormElementForID(int64 pair_id) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "DELETE FROM autofill WHERE pair_id = ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindInt64(0, pair_id);
+ if (s.Run()) {
+ return RemoveFormElementForTimeRange(pair_id, base::Time(), base::Time(),
+ NULL);
+ }
+ return false;
+}
+
+bool AutofillTable::AddAutofillGUIDToTrash(const std::string& guid) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "INSERT INTO autofill_profiles_trash"
+ " (guid) "
+ "VALUES (?)"));
+ if (!s) {
+ NOTREACHED();
+ return sql::INIT_FAILURE;
+ }
+
+ s.BindString(0, guid);
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+ return true;
+}
+
+bool AutofillTable::IsAutofillProfilesTrashEmpty() {
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT guid "
+ "FROM autofill_profiles_trash"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ return !s.Step();
+}
+
+bool AutofillTable::IsAutofillGUIDInTrash(const std::string& guid) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT guid "
+ "FROM autofill_profiles_trash "
+ "WHERE guid = ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s.BindString(0, guid);
+ return s.Step();
+}
+
+bool AutofillTable::InitMainTable() {
+ if (!db_->DoesTableExist("autofill")) {
+ if (!db_->Execute("CREATE TABLE autofill ("
+ "name VARCHAR, "
+ "value VARCHAR, "
+ "value_lower VARCHAR, "
+ "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;
+ }
+ }
+ return true;
+}
+
+bool AutofillTable::InitCreditCardsTable() {
+ if (!db_->DoesTableExist("credit_cards")) {
+ if (!db_->Execute("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)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+
+ 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 ( "
+ "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)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool AutofillTable::InitProfileNamesTable() {
+ if (!db_->DoesTableExist("autofill_profile_names")) {
+ if (!db_->Execute("CREATE TABLE autofill_profile_names ( "
+ "guid VARCHAR, "
+ "first_name VARCHAR, "
+ "middle_name VARCHAR, "
+ "last_name VARCHAR)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool AutofillTable::InitProfileEmailsTable() {
+ if (!db_->DoesTableExist("autofill_profile_emails")) {
+ if (!db_->Execute("CREATE TABLE autofill_profile_emails ( "
+ "guid VARCHAR, "
+ "email VARCHAR)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool AutofillTable::InitProfilePhonesTable() {
+ if (!db_->DoesTableExist("autofill_profile_phones")) {
+ if (!db_->Execute("CREATE TABLE autofill_profile_phones ( "
+ "guid VARCHAR, "
+ "type INTEGER DEFAULT 0, "
+ "number VARCHAR)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool AutofillTable::InitProfileTrashTable() {
+ if (!db_->DoesTableExist("autofill_profiles_trash")) {
+ if (!db_->Execute("CREATE TABLE autofill_profiles_trash ( "
+ "guid VARCHAR)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/chrome/browser/webdata/autofill_table.h b/chrome/browser/webdata/autofill_table.h
new file mode 100644
index 0000000..584b949
--- /dev/null
+++ b/chrome/browser/webdata/autofill_table.h
@@ -0,0 +1,315 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEBDATA_AUTOFILL_TABLE_H_
+#define CHROME_BROWSER_WEBDATA_AUTOFILL_TABLE_H_
+#pragma once
+
+#include "base/gtest_prod_util.h"
+#include "base/string16.h"
+#include "chrome/browser/webdata/web_database_table.h"
+
+#include <vector>
+
+class AutofillChange;
+class AutofillEntry;
+class AutofillProfile;
+class AutofillTableTest;
+class CreditCard;
+
+namespace webkit_glue {
+struct FormField;
+}
+
+// This class manages the various autofill tables within the SQLite database
+// passed to the constructor. It expects the following schemas:
+//
+// Note: The database stores time in seconds, UTC.
+//
+// autofill
+// 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.
+// 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.
+//
+// guid A guid string to uniquely identify the profile.
+// Added in version 31.
+// company_name
+// address_line_1
+// address_line_2
+// city
+// state
+// zipcode
+// country The country name. Deprecated, should be removed once
+// the stable channel reaches version 11.
+// country_code
+// date_modified The date on which this profile was last modified.
+// Added in version 30.
+//
+// autofill_profile_names
+// This table contains the multi-valued name fields
+// associated with a profile.
+//
+// guid The guid string that identifies the profile to which
+// the name belongs.
+// first_name
+// middle_name
+// last_name
+//
+// autofill_profile_emails
+// This table contains the multi-valued email fields
+// associated with a profile.
+//
+// guid The guid string that identifies the profile to which
+// the email belongs.
+// email
+//
+// autofill_profile_phones
+// This table contains the multi-valued phone fields
+// associated with a profile.
+//
+// guid The guid string that identifies the profile to which
+// the phone or fax number belongs.
+// type An integer constant designating either phone or fax type
+// of the number.
+// number
+//
+// autofill_profiles_trash
+// This table contains guids of "trashed" autofill
+// profiles. When a profile is removed its guid is added
+// to this table so that Sync can perform deferred removal.
+//
+// guid The guid string that identifies the trashed profile.
+//
+// credit_cards This table contains credit card data added by the user
+// with the Autofill dialog. Most of the columns are
+// standard entries in a credit card form.
+//
+// guid A guid string to uniquely identify the profile.
+// Added in version 31.
+// name_on_card
+// expiration_month
+// expiration_year
+// card_number_encrypted Stores encrypted credit card number.
+// date_modified The date on which this entry was last modified.
+// Added in version 30.
+//
+class AutofillTable : public WebDatabaseTable {
+ public:
+ AutofillTable(sql::Connection* db, sql::MetaTable* meta_table)
+ : WebDatabaseTable(db, meta_table) {}
+ virtual ~AutofillTable() {}
+ virtual bool Init();
+ virtual bool IsSyncable() { return true; }
+
+ // Records the form elements in |elements| in the database in the
+ // autofill table. A list of all added and updated autofill entries
+ // is returned in the changes out parameter.
+ bool AddFormFieldValues(const std::vector<webkit_glue::FormField>& elements,
+ std::vector<AutofillChange>* changes);
+
+ // Records a single form element in the database in the autofill table. A list
+ // of all added and updated autofill entries is returned in the changes out
+ // parameter.
+ bool AddFormFieldValue(const webkit_glue::FormField& element,
+ std::vector<AutofillChange>* changes);
+
+ // Retrieves a vector of all values which have been recorded in the autofill
+ // table as the value in a form element with name |name| and which start with
+ // |prefix|. The comparison of the prefix is case insensitive.
+ bool GetFormValuesForElementName(const string16& name,
+ const string16& prefix,
+ std::vector<string16>* values,
+ int limit);
+
+ // Removes rows from autofill_dates if they were created on or after
+ // |delete_begin| and strictly before |delete_end|. Decrements the
+ // count of the corresponding rows in the autofill table, and
+ // removes those rows if the count goes to 0. A list of all changed
+ // keys and whether each was updater or removed is returned in the
+ // changes out parameter.
+ bool RemoveFormElementsAddedBetween(base::Time delete_begin,
+ base::Time delete_end,
+ std::vector<AutofillChange>* changes);
+
+ // Removes from autofill_dates rows with given pair_id where date_created lies
+ // between delte_begin and delte_end.
+ bool RemoveFormElementForTimeRange(int64 pair_id,
+ base::Time delete_begin,
+ base::Time delete_end,
+ int* how_many);
+
+ // Increments the count in the row corresponding to |pair_id| by
+ // |delta|. Removes the row from the table and sets the
+ // |was_removed| out parameter to true if the count becomes 0.
+ bool AddToCountOfFormElement(int64 pair_id, int delta, bool* was_removed);
+
+ // 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 webkit_glue::FormField& 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 webkit_glue::FormField& element, int64* pair_id);
+
+ // Adds a new row to the autofill_dates table.
+ bool InsertPairIDAndDate(int64 pair_id, base::Time date_created);
+
+ // 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 string16& name, const string16& value);
+
+ // Retrieves all of the entries in the autofill table.
+ virtual bool GetAllAutofillEntries(std::vector<AutofillEntry>* entries);
+
+ // Retrieves a single entry from the autofill table.
+ virtual bool GetAutofillTimestamps(const string16& name,
+ const string16& value,
+ std::vector<base::Time>* timestamps);
+
+ // Replaces existing autofill entries with the entries supplied in
+ // the argument. If the entry does not already exist, it will be
+ // added.
+ virtual bool UpdateAutofillEntries(const std::vector<AutofillEntry>& entries);
+
+ // Records a single Autofill profile in the autofill_profiles table.
+ virtual bool AddAutofillProfile(const AutofillProfile& profile);
+
+ // Updates the database values for the specified profile.
+ // DEPRECATED: Use |UpdateAutofillProfileMulti| instead.
+ virtual bool UpdateAutofillProfile(const AutofillProfile& profile);
+
+ // Updates the database values for the specified profile. Mulit-value aware.
+ virtual bool UpdateAutofillProfileMulti(const AutofillProfile& profile);
+
+ // Removes a row from the autofill_profiles table. |guid| is the identifier
+ // of the profile to remove.
+ virtual bool RemoveAutofillProfile(const std::string& guid);
+
+ // Retrieves a profile with guid |guid|. The caller owns |profile|.
+ bool GetAutofillProfile(const std::string& guid, AutofillProfile** profile);
+
+ // Retrieves all profiles in the database. Caller owns the returned profiles.
+ virtual bool GetAutofillProfiles(std::vector<AutofillProfile*>* profiles);
+
+ // Records a single credit card in the credit_cards table.
+ bool AddCreditCard(const CreditCard& credit_card);
+
+ // Updates the database values for the specified credit card.
+ bool UpdateCreditCard(const CreditCard& credit_card);
+
+ // Removes a row from the credit_cards table. |guid| is the identifer of the
+ // credit card to remove.
+ bool RemoveCreditCard(const std::string& guid);
+
+ // Retrieves a credit card with guid |guid|. The caller owns
+ // |credit_card_id|.
+ bool GetCreditCard(const std::string& guid, CreditCard** credit_card);
+
+ // Retrieves all credit cards in the database. Caller owns the returned
+ // credit cards.
+ virtual bool GetCreditCards(std::vector<CreditCard*>* credit_cards);
+
+ // Removes rows from autofill_profiles and credit_cards if they were created
+ // on or after |delete_begin| and strictly before |delete_end|.
+ bool RemoveAutofillProfilesAndCreditCardsModifiedBetween(
+ base::Time delete_begin,
+ base::Time delete_end);
+
+ // Retrieves all profiles in the database that have been deleted since last
+ // "empty" of the trash.
+ bool GetAutofillProfilesInTrash(std::vector<std::string>* guids);
+
+ // 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);
+
+ // Clear all profiles.
+ bool ClearAutofillProfiles();
+
+ private:
+ 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_AddFormFieldValues);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, AutofillProfile);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, UpdateAutofillProfile);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, AutofillProfileTrash);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, AutofillProfileTrashInteraction);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest,
+ RemoveAutofillProfilesAndCreditCardsModifiedBetween);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, CreditCard);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, UpdateCreditCard);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest,
+ Autofill_GetAllAutofillEntries_OneResult);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest,
+ Autofill_GetAllAutofillEntries_TwoDistinct);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest,
+ Autofill_GetAllAutofillEntries_TwoSame);
+
+ // Methods for adding autofill entries at a specified time. For
+ // testing only.
+ bool AddFormFieldValuesTime(
+ const std::vector<webkit_glue::FormField>& elements,
+ std::vector<AutofillChange>* changes,
+ base::Time time);
+ bool AddFormFieldValueTime(const webkit_glue::FormField& element,
+ std::vector<AutofillChange>* changes,
+ base::Time time);
+
+ // Insert a single AutofillEntry into the autofill/autofill_dates tables.
+ bool InsertAutofillEntry(const AutofillEntry& entry);
+
+ // Checks if the trash is empty.
+ bool IsAutofillProfilesTrashEmpty();
+
+ // Checks if the guid is in the trash.
+ bool IsAutofillGUIDInTrash(const std::string& guid);
+
+ bool InitMainTable();
+ bool InitCreditCardsTable();
+ bool InitDatesTable();
+ bool InitProfilesTable();
+ bool InitProfileNamesTable();
+ bool InitProfileEmailsTable();
+ bool InitProfilePhonesTable();
+ bool InitProfileTrashTable();
+
+ DISALLOW_COPY_AND_ASSIGN(AutofillTable);
+};
+
+#endif // CHROME_BROWSER_WEBDATA_AUTOFILL_TABLE_H_
diff --git a/chrome/browser/webdata/autofill_table_unittest.cc b/chrome/browser/webdata/autofill_table_unittest.cc
new file mode 100644
index 0000000..22d2ad5
--- /dev/null
+++ b/chrome/browser/webdata/autofill_table_unittest.cc
@@ -0,0 +1,1578 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "app/sql/statement.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/string_number_conversions.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/browser/autofill/autofill_profile.h"
+#include "chrome/browser/autofill/autofill_type.h"
+#include "chrome/browser/autofill/credit_card.h"
+#include "chrome/browser/password_manager/encryptor.h"
+#include "chrome/browser/webdata/autofill_change.h"
+#include "chrome/browser/webdata/autofill_entry.h"
+#include "chrome/browser/webdata/web_database.h"
+#include "chrome/common/guid.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/glue/form_field.h"
+
+using base::Time;
+using base::TimeDelta;
+using webkit_glue::FormField;
+
+// So we can compare AutofillKeys with EXPECT_EQ().
+std::ostream& operator<<(std::ostream& os, const AutofillKey& key) {
+ return os << UTF16ToASCII(key.name()) << ", " << UTF16ToASCII(key.value());
+}
+
+// So we can compare AutofillChanges with EXPECT_EQ().
+std::ostream& operator<<(std::ostream& os, const AutofillChange& change) {
+ switch (change.type()) {
+ case AutofillChange::ADD: {
+ os << "ADD";
+ break;
+ }
+ case AutofillChange::UPDATE: {
+ os << "UPDATE";
+ break;
+ }
+ case AutofillChange::REMOVE: {
+ os << "REMOVE";
+ break;
+ }
+ }
+ return os << " " << change.key();
+}
+
+namespace {
+
+bool CompareAutofillEntries(const AutofillEntry& a, const AutofillEntry& b) {
+ std::set<Time> timestamps1(a.timestamps().begin(), a.timestamps().end());
+ std::set<Time> timestamps2(b.timestamps().begin(), b.timestamps().end());
+
+ int compVal = a.key().name().compare(b.key().name());
+ if (compVal != 0) {
+ return compVal < 0;
+ }
+
+ compVal = a.key().value().compare(b.key().value());
+ if (compVal != 0) {
+ return compVal < 0;
+ }
+
+ if (timestamps1.size() != timestamps2.size()) {
+ return timestamps1.size() < timestamps2.size();
+ }
+
+ std::set<Time>::iterator it;
+ for (it = timestamps1.begin(); it != timestamps1.end(); it++) {
+ timestamps2.erase(*it);
+ }
+
+ return !timestamps2.empty();
+}
+
+} // anonymous namespace
+
+class AutofillTableTest : public testing::Test {
+ public:
+ AutofillTableTest() {}
+ virtual ~AutofillTableTest() {}
+
+ protected:
+ typedef std::vector<AutofillChange> AutofillChangeList;
+ typedef std::set<AutofillEntry,
+ bool (*)(const AutofillEntry&, const AutofillEntry&)> AutofillEntrySet;
+ typedef std::set<AutofillEntry, bool (*)(const AutofillEntry&,
+ const AutofillEntry&)>::iterator AutofillEntrySetIterator;
+
+ virtual void SetUp() {
+#if defined(OS_MACOSX)
+ Encryptor::UseMockKeychain(true);
+#endif
+ PathService::Get(chrome::DIR_TEST_DATA, &file_);
+ const std::string test_db = "TestWebDatabase" +
+ base::Int64ToString(Time::Now().ToTimeT()) +
+ ".db";
+ file_ = file_.AppendASCII(test_db);
+ file_util::Delete(file_, false);
+ }
+
+ virtual void TearDown() {
+ file_util::Delete(file_, false);
+ }
+
+ static AutofillEntry MakeAutofillEntry(const char* name,
+ const char* value,
+ time_t timestamp0,
+ time_t timestamp1) {
+ std::vector<Time> timestamps;
+ if (timestamp0 >= 0)
+ timestamps.push_back(Time::FromTimeT(timestamp0));
+ if (timestamp1 >= 0)
+ timestamps.push_back(Time::FromTimeT(timestamp1));
+ return AutofillEntry(
+ AutofillKey(ASCIIToUTF16(name), ASCIIToUTF16(value)), timestamps);
+ }
+
+ FilePath file_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AutofillTableTest);
+};
+
+TEST_F(AutofillTableTest, Autofill) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ Time t1 = Time::Now();
+
+ // Simulate the submission of a handful of entries in a field called "Name",
+ // some more often than others.
+ AutofillChangeList changes;
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValue(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"),
+ string16(),
+ 0,
+ false),
+ &changes));
+ std::vector<string16> v;
+ for (int i = 0; i < 5; i++) {
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValue(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Clark Kent"),
+ string16(),
+ 0,
+ false),
+ &changes));
+ }
+ for (int i = 0; i < 3; i++) {
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValue(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Clark Sutter"),
+ string16(),
+ 0,
+ false),
+ &changes));
+ }
+ for (int i = 0; i < 2; i++) {
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValue(
+ FormField(string16(),
+ ASCIIToUTF16("Favorite Color"),
+ ASCIIToUTF16("Green"),
+ string16(),
+ 0,
+ false),
+ &changes));
+ }
+
+ 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.
+ EXPECT_TRUE(db.GetAutofillTable()->GetIDAndCountOfFormElement(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Clark Kent"),
+ string16(),
+ 0,
+ false),
+ &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_TRUE(db.GetAutofillTable()->GetIDAndCountOfFormElement(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("clark kent"),
+ string16(),
+ 0,
+ false),
+ &pair_id, &count));
+ EXPECT_EQ(0, count);
+
+ EXPECT_TRUE(db.GetAutofillTable()->GetIDAndCountOfFormElement(
+ FormField(string16(),
+ ASCIIToUTF16("Favorite Color"),
+ ASCIIToUTF16("Green"),
+ string16(),
+ 0,
+ false),
+ &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
+ // no matter what they start with. The order that the names occur in the list
+ // should be decreasing order by count.
+ EXPECT_TRUE(db.GetAutofillTable()->GetFormValuesForElementName(
+ ASCIIToUTF16("Name"), string16(), &v, 6));
+ EXPECT_EQ(3U, v.size());
+ if (v.size() == 3) {
+ EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0]);
+ EXPECT_EQ(ASCIIToUTF16("Clark Sutter"), v[1]);
+ EXPECT_EQ(ASCIIToUTF16("Superman"), v[2]);
+ }
+
+ // If we query again limiting the list size to 1, we should only get the most
+ // frequent entry.
+ EXPECT_TRUE(db.GetAutofillTable()->GetFormValuesForElementName(
+ ASCIIToUTF16("Name"), string16(), &v, 1));
+ EXPECT_EQ(1U, v.size());
+ if (v.size() == 1) {
+ EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0]);
+ }
+
+ // Querying for suggestions given a prefix is case-insensitive, so the prefix
+ // "cLa" shoud get suggestions for both Clarks.
+ EXPECT_TRUE(db.GetAutofillTable()->GetFormValuesForElementName(
+ ASCIIToUTF16("Name"), ASCIIToUTF16("cLa"), &v, 6));
+ EXPECT_EQ(2U, v.size());
+ if (v.size() == 2) {
+ EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0]);
+ EXPECT_EQ(ASCIIToUTF16("Clark Sutter"), v[1]);
+ }
+
+ // Removing all elements since the beginning of this function should remove
+ // everything from the database.
+ changes.clear();
+ EXPECT_TRUE(db.GetAutofillTable()->RemoveFormElementsAddedBetween(
+ t1, Time(), &changes));
+
+ const AutofillChange expected_changes[] = {
+ AutofillChange(AutofillChange::REMOVE,
+ AutofillKey(ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"))),
+ AutofillChange(AutofillChange::REMOVE,
+ AutofillKey(ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Clark Kent"))),
+ AutofillChange(AutofillChange::REMOVE,
+ AutofillKey(ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Clark Sutter"))),
+ AutofillChange(AutofillChange::REMOVE,
+ AutofillKey(ASCIIToUTF16("Favorite Color"),
+ ASCIIToUTF16("Green"))),
+ };
+ EXPECT_EQ(arraysize(expected_changes), changes.size());
+ for (size_t i = 0; i < arraysize(expected_changes); i++) {
+ EXPECT_EQ(expected_changes[i], changes[i]);
+ }
+
+ EXPECT_TRUE(db.GetAutofillTable()->GetIDAndCountOfFormElement(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Clark Kent"),
+ string16(),
+ 0,
+ false),
+ &pair_id, &count));
+ EXPECT_EQ(0, count);
+
+ EXPECT_TRUE(db.GetAutofillTable()->GetFormValuesForElementName(
+ ASCIIToUTF16("Name"), string16(), &v, 6));
+ EXPECT_EQ(0U, v.size());
+
+ // Now add some values with empty strings.
+ const string16 kValue = ASCIIToUTF16(" toto ");
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValue(
+ FormField(string16(),
+ ASCIIToUTF16("blank"),
+ string16(),
+ string16(),
+ 0,
+ false),
+ &changes));
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValue(
+ FormField(string16(),
+ ASCIIToUTF16("blank"),
+ ASCIIToUTF16(" "),
+ string16(),
+ 0,
+ false),
+ &changes));
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValue(
+ FormField(string16(),
+ ASCIIToUTF16("blank"),
+ ASCIIToUTF16(" "),
+ string16(),
+ 0,
+ false),
+ &changes));
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValue(
+ FormField(string16(),
+ ASCIIToUTF16("blank"),
+ kValue,
+ string16(),
+ 0,
+ false),
+ &changes));
+
+ // They should be stored normally as the DB layer does not check for empty
+ // values.
+ v.clear();
+ EXPECT_TRUE(db.GetAutofillTable()->GetFormValuesForElementName(
+ ASCIIToUTF16("blank"), string16(), &v, 10));
+ EXPECT_EQ(4U, v.size());
+
+ // Now we'll check that ClearAutofillEmptyValueElements() works as expected.
+ db.GetAutofillTable()->ClearAutofillEmptyValueElements();
+
+ v.clear();
+ EXPECT_TRUE(db.GetAutofillTable()->GetFormValuesForElementName(
+ ASCIIToUTF16("blank"), string16(), &v, 10));
+ ASSERT_EQ(1U, v.size());
+
+ EXPECT_EQ(kValue, v[0]);
+}
+
+TEST_F(AutofillTableTest, Autofill_RemoveBetweenChanges) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ TimeDelta one_day(TimeDelta::FromDays(1));
+ Time t1 = Time::Now();
+ Time t2 = t1 + one_day;
+
+ AutofillChangeList changes;
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValueTime(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"),
+ string16(),
+ 0,
+ false),
+ &changes,
+ t1));
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValueTime(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"),
+ string16(),
+ 0,
+ false),
+ &changes,
+ t2));
+
+ changes.clear();
+ EXPECT_TRUE(db.GetAutofillTable()->RemoveFormElementsAddedBetween(
+ t1, t2, &changes));
+ ASSERT_EQ(1U, changes.size());
+ EXPECT_EQ(AutofillChange(AutofillChange::UPDATE,
+ AutofillKey(ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"))),
+ changes[0]);
+ changes.clear();
+
+ EXPECT_TRUE(db.GetAutofillTable()->RemoveFormElementsAddedBetween(
+ t2, t2 + one_day, &changes));
+ ASSERT_EQ(1U, changes.size());
+ EXPECT_EQ(AutofillChange(AutofillChange::REMOVE,
+ AutofillKey(ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"))),
+ changes[0]);
+}
+
+TEST_F(AutofillTableTest, Autofill_AddChanges) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ TimeDelta one_day(TimeDelta::FromDays(1));
+ Time t1 = Time::Now();
+ Time t2 = t1 + one_day;
+
+ AutofillChangeList changes;
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValueTime(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"),
+ string16(),
+ 0,
+ false),
+ &changes,
+ t1));
+ ASSERT_EQ(1U, changes.size());
+ EXPECT_EQ(AutofillChange(AutofillChange::ADD,
+ AutofillKey(ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"))),
+ changes[0]);
+
+ changes.clear();
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValueTime(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"),
+ string16(),
+ 0,
+ false),
+ &changes,
+ t2));
+ ASSERT_EQ(1U, changes.size());
+ EXPECT_EQ(AutofillChange(AutofillChange::UPDATE,
+ AutofillKey(ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"))),
+ changes[0]);
+}
+
+TEST_F(AutofillTableTest, Autofill_UpdateOneWithOneTimestamp) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, -1));
+ std::vector<AutofillEntry> entries;
+ entries.push_back(entry);
+ ASSERT_TRUE(db.GetAutofillTable()->UpdateAutofillEntries(entries));
+
+ FormField field(string16(),
+ ASCIIToUTF16("foo"),
+ ASCIIToUTF16("bar"),
+ string16(),
+ 0,
+ false);
+ int64 pair_id;
+ int count;
+ ASSERT_TRUE(db.GetAutofillTable()->GetIDAndCountOfFormElement(
+ field, &pair_id, &count));
+ EXPECT_LE(0, pair_id);
+ EXPECT_EQ(1, count);
+
+ std::vector<AutofillEntry> all_entries;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAllAutofillEntries(&all_entries));
+ ASSERT_EQ(1U, all_entries.size());
+ EXPECT_TRUE(entry == all_entries[0]);
+}
+
+TEST_F(AutofillTableTest, Autofill_UpdateOneWithTwoTimestamps) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, 2));
+ std::vector<AutofillEntry> entries;
+ entries.push_back(entry);
+ ASSERT_TRUE(db.GetAutofillTable()->UpdateAutofillEntries(entries));
+
+ FormField field(string16(),
+ ASCIIToUTF16("foo"),
+ ASCIIToUTF16("bar"),
+ string16(),
+ 0,
+ false);
+ int64 pair_id;
+ int count;
+ ASSERT_TRUE(db.GetAutofillTable()->GetIDAndCountOfFormElement(
+ field, &pair_id, &count));
+ EXPECT_LE(0, pair_id);
+ EXPECT_EQ(2, count);
+
+ std::vector<AutofillEntry> all_entries;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAllAutofillEntries(&all_entries));
+ ASSERT_EQ(1U, all_entries.size());
+ EXPECT_TRUE(entry == all_entries[0]);
+}
+
+TEST_F(AutofillTableTest, Autofill_GetAutofillTimestamps) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, 2));
+ std::vector<AutofillEntry> entries;
+ entries.push_back(entry);
+ ASSERT_TRUE(db.GetAutofillTable()->UpdateAutofillEntries(entries));
+
+ std::vector<Time> timestamps;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillTimestamps(ASCIIToUTF16("foo"),
+ ASCIIToUTF16("bar"),
+ &timestamps));
+ ASSERT_EQ(2U, timestamps.size());
+ EXPECT_TRUE(Time::FromTimeT(1) == timestamps[0]);
+ EXPECT_TRUE(Time::FromTimeT(2) == timestamps[1]);
+}
+
+TEST_F(AutofillTableTest, Autofill_UpdateTwo) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillEntry entry0(MakeAutofillEntry("foo", "bar0", 1, -1));
+ AutofillEntry entry1(MakeAutofillEntry("foo", "bar1", 2, 3));
+ std::vector<AutofillEntry> entries;
+ entries.push_back(entry0);
+ entries.push_back(entry1);
+ ASSERT_TRUE(db.GetAutofillTable()->UpdateAutofillEntries(entries));
+
+ FormField field0(string16(),
+ ASCIIToUTF16("foo"),
+ ASCIIToUTF16("bar0"),
+ string16(),
+ 0,
+ false);
+ int64 pair_id;
+ int count;
+ ASSERT_TRUE(db.GetAutofillTable()->GetIDAndCountOfFormElement(
+ field0, &pair_id, &count));
+ EXPECT_LE(0, pair_id);
+ EXPECT_EQ(1, count);
+
+ FormField field1(string16(),
+ ASCIIToUTF16("foo"),
+ ASCIIToUTF16("bar1"),
+ string16(),
+ 0,
+ false);
+ ASSERT_TRUE(db.GetAutofillTable()->GetIDAndCountOfFormElement(
+ field1, &pair_id, &count));
+ EXPECT_LE(0, pair_id);
+ EXPECT_EQ(2, count);
+}
+
+TEST_F(AutofillTableTest, Autofill_UpdateReplace) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillChangeList changes;
+ // Add a form field. This will be replaced.
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValue(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"),
+ string16(),
+ 0,
+ false),
+ &changes));
+
+ AutofillEntry entry(MakeAutofillEntry("Name", "Superman", 1, 2));
+ std::vector<AutofillEntry> entries;
+ entries.push_back(entry);
+ ASSERT_TRUE(db.GetAutofillTable()->UpdateAutofillEntries(entries));
+
+ std::vector<AutofillEntry> all_entries;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAllAutofillEntries(&all_entries));
+ ASSERT_EQ(1U, all_entries.size());
+ EXPECT_TRUE(entry == all_entries[0]);
+}
+
+TEST_F(AutofillTableTest, Autofill_UpdateDontReplace) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ Time t = Time::Now();
+ AutofillEntry existing(
+ MakeAutofillEntry("Name", "Superman", t.ToTimeT(), -1));
+
+ AutofillChangeList changes;
+ // Add a form field. This will NOT be replaced.
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValueTime(
+ FormField(string16(),
+ existing.key().name(),
+ existing.key().value(),
+ string16(),
+ 0,
+ false),
+ &changes,
+ t));
+ AutofillEntry entry(MakeAutofillEntry("Name", "Clark Kent", 1, 2));
+ std::vector<AutofillEntry> entries;
+ entries.push_back(entry);
+ ASSERT_TRUE(db.GetAutofillTable()->UpdateAutofillEntries(entries));
+
+ std::vector<AutofillEntry> all_entries;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAllAutofillEntries(&all_entries));
+ ASSERT_EQ(2U, all_entries.size());
+ AutofillEntrySet expected_entries(all_entries.begin(),
+ all_entries.end(),
+ CompareAutofillEntries);
+ EXPECT_EQ(1U, expected_entries.count(existing));
+ EXPECT_EQ(1U, expected_entries.count(entry));
+}
+
+TEST_F(AutofillTableTest, Autofill_AddFormFieldValues) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ Time t = Time::Now();
+
+ // Add multiple values for "firstname" and "lastname" names. Test that only
+ // first value of each gets added. Related to security issue:
+ // http://crbug.com/51727.
+ std::vector<FormField> elements;
+ elements.push_back(FormField(string16(),
+ ASCIIToUTF16("firstname"),
+ ASCIIToUTF16("Joe"),
+ string16(),
+ 0,
+ false));
+ elements.push_back(FormField(string16(),
+ ASCIIToUTF16("firstname"),
+ ASCIIToUTF16("Jane"),
+ string16(),
+ 0,
+ false));
+ elements.push_back(FormField(string16(),
+ ASCIIToUTF16("lastname"),
+ ASCIIToUTF16("Smith"),
+ string16(),
+ 0,
+ false));
+ elements.push_back(FormField(string16(),
+ ASCIIToUTF16("lastname"),
+ ASCIIToUTF16("Jones"),
+ string16(),
+ 0,
+ false));
+
+ std::vector<AutofillChange> changes;
+ db.GetAutofillTable()->AddFormFieldValuesTime(elements, &changes, t);
+
+ ASSERT_EQ(2U, changes.size());
+ EXPECT_EQ(changes[0], AutofillChange(AutofillChange::ADD,
+ AutofillKey(ASCIIToUTF16("firstname"),
+ ASCIIToUTF16("Joe"))));
+ EXPECT_EQ(changes[1], AutofillChange(AutofillChange::ADD,
+ AutofillKey(ASCIIToUTF16("lastname"),
+ ASCIIToUTF16("Smith"))));
+
+ std::vector<AutofillEntry> all_entries;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAllAutofillEntries(&all_entries));
+ ASSERT_EQ(2U, all_entries.size());
+}
+
+TEST_F(AutofillTableTest, AutofillProfile) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ // Add a 'Home' profile.
+ AutofillProfile home_profile;
+ home_profile.SetInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ home_profile.SetInfo(NAME_MIDDLE, ASCIIToUTF16("Q."));
+ home_profile.SetInfo(NAME_LAST, ASCIIToUTF16("Smith"));
+ home_profile.SetInfo(EMAIL_ADDRESS, ASCIIToUTF16("js@smith.xyz"));
+ home_profile.SetInfo(COMPANY_NAME, ASCIIToUTF16("Google"));
+ home_profile.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Apple Way"));
+ home_profile.SetInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("unit 5"));
+ home_profile.SetInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Los Angeles"));
+ home_profile.SetInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA"));
+ home_profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("90025"));
+ home_profile.SetInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
+ home_profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("18181234567"));
+ home_profile.SetInfo(PHONE_FAX_WHOLE_NUMBER, ASCIIToUTF16("1915243678"));
+
+ Time pre_creation_time = Time::Now();
+ EXPECT_TRUE(db.GetAutofillTable()->AddAutofillProfile(home_profile));
+ Time post_creation_time = Time::Now();
+
+ // Get the 'Home' profile.
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(
+ home_profile.guid(), &db_profile));
+ EXPECT_EQ(home_profile, *db_profile);
+ sql::Statement s_home(db.db_.GetUniqueStatement(
+ "SELECT date_modified "
+ "FROM autofill_profiles WHERE guid=?"));
+ s_home.BindString(0, home_profile.guid());
+ ASSERT_TRUE(s_home);
+ ASSERT_TRUE(s_home.Step());
+ EXPECT_GE(s_home.ColumnInt64(0), pre_creation_time.ToTimeT());
+ EXPECT_LE(s_home.ColumnInt64(0), post_creation_time.ToTimeT());
+ EXPECT_FALSE(s_home.Step());
+ delete db_profile;
+
+ // Add a 'Billing' profile.
+ AutofillProfile billing_profile = home_profile;
+ billing_profile.set_guid(guid::GenerateGUID());
+ billing_profile.SetInfo(ADDRESS_HOME_LINE1,
+ ASCIIToUTF16("5678 Bottom Street"));
+ billing_profile.SetInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("suite 3"));
+
+ pre_creation_time = Time::Now();
+ EXPECT_TRUE(db.GetAutofillTable()->AddAutofillProfile(billing_profile));
+ post_creation_time = Time::Now();
+
+ // Get the 'Billing' profile.
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(
+ billing_profile.guid(), &db_profile));
+ EXPECT_EQ(billing_profile, *db_profile);
+ sql::Statement s_billing(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles WHERE guid=?"));
+ s_billing.BindString(0, billing_profile.guid());
+ ASSERT_TRUE(s_billing);
+ ASSERT_TRUE(s_billing.Step());
+ EXPECT_GE(s_billing.ColumnInt64(0), pre_creation_time.ToTimeT());
+ EXPECT_LE(s_billing.ColumnInt64(0), post_creation_time.ToTimeT());
+ EXPECT_FALSE(s_billing.Step());
+ delete db_profile;
+
+ // Update the 'Billing' profile, name only.
+ billing_profile.SetInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
+ Time pre_modification_time = Time::Now();
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateAutofillProfileMulti(
+ billing_profile));
+ Time post_modification_time = Time::Now();
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(
+ billing_profile.guid(), &db_profile));
+ EXPECT_EQ(billing_profile, *db_profile);
+ sql::Statement s_billing_updated(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles WHERE guid=?"));
+ s_billing_updated.BindString(0, billing_profile.guid());
+ ASSERT_TRUE(s_billing_updated);
+ ASSERT_TRUE(s_billing_updated.Step());
+ EXPECT_GE(s_billing_updated.ColumnInt64(0),
+ pre_modification_time.ToTimeT());
+ EXPECT_LE(s_billing_updated.ColumnInt64(0),
+ post_modification_time.ToTimeT());
+ EXPECT_FALSE(s_billing_updated.Step());
+ delete db_profile;
+
+ // Update the 'Billing' profile.
+ billing_profile.SetInfo(NAME_FIRST, ASCIIToUTF16("Janice"));
+ billing_profile.SetInfo(NAME_MIDDLE, ASCIIToUTF16("C."));
+ billing_profile.SetInfo(NAME_FIRST, ASCIIToUTF16("Joplin"));
+ billing_profile.SetInfo(EMAIL_ADDRESS, ASCIIToUTF16("jane@singer.com"));
+ billing_profile.SetInfo(COMPANY_NAME, ASCIIToUTF16("Indy"));
+ billing_profile.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("Open Road"));
+ billing_profile.SetInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("Route 66"));
+ billing_profile.SetInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("NFA"));
+ billing_profile.SetInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("NY"));
+ billing_profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("10011"));
+ billing_profile.SetInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("United States"));
+ billing_profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("18181230000"));
+ billing_profile.SetInfo(PHONE_FAX_WHOLE_NUMBER, ASCIIToUTF16("1915240000"));
+ Time pre_modification_time_2 = Time::Now();
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateAutofillProfileMulti(
+ billing_profile));
+ Time post_modification_time_2 = Time::Now();
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(
+ billing_profile.guid(), &db_profile));
+ EXPECT_EQ(billing_profile, *db_profile);
+ sql::Statement s_billing_updated_2(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles WHERE guid=?"));
+ s_billing_updated_2.BindString(0, billing_profile.guid());
+ ASSERT_TRUE(s_billing_updated_2);
+ ASSERT_TRUE(s_billing_updated_2.Step());
+ EXPECT_GE(s_billing_updated_2.ColumnInt64(0),
+ pre_modification_time_2.ToTimeT());
+ EXPECT_LE(s_billing_updated_2.ColumnInt64(0),
+ post_modification_time_2.ToTimeT());
+ EXPECT_FALSE(s_billing_updated_2.Step());
+ delete db_profile;
+
+ // Remove the 'Billing' profile.
+ EXPECT_TRUE(db.GetAutofillTable()->RemoveAutofillProfile(
+ billing_profile.guid()));
+ EXPECT_FALSE(db.GetAutofillTable()->GetAutofillProfile(
+ billing_profile.guid(), &db_profile));
+}
+
+TEST_F(AutofillTableTest, AutofillProfileMultiValueNames) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("John Doe"));
+ const string16 kJohnPDoe(ASCIIToUTF16("John P. Doe"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(NAME_FULL, set_values);
+
+ EXPECT_TRUE(db.GetAutofillTable()->AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Update the values.
+ const string16 kNoOne(ASCIIToUTF16("No One"));
+ set_values[1] = kNoOne;
+ p.SetMultiInfo(NAME_FULL, set_values);
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Delete values.
+ set_values.clear();
+ p.SetMultiInfo(NAME_FULL, set_values);
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ EXPECT_EQ(string16(), db_profile->GetInfo(NAME_FULL));
+ delete db_profile;
+}
+
+TEST_F(AutofillTableTest, AutofillProfileSingleValue) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("John Doe"));
+ const string16 kJohnPDoe(ASCIIToUTF16("John P. Doe"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(NAME_FULL, set_values);
+
+ EXPECT_TRUE(db.GetAutofillTable()->AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Update the values. This update is the "single value" update, it should
+ // not perturb the multi-values following the zeroth entry. This simulates
+ // the Sync use-case until Sync can be changed to be multi-value aware.
+ const string16 kNoOne(ASCIIToUTF16("No One"));
+ set_values.resize(1);
+ set_values[0] = kNoOne;
+ p.SetMultiInfo(NAME_FULL, set_values);
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateAutofillProfile(p));
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_NE(0, p.CompareMulti(*db_profile));
+ db_profile->GetMultiInfo(NAME_FULL, &set_values);
+ ASSERT_EQ(2UL, set_values.size());
+ EXPECT_EQ(kNoOne, set_values[0]);
+ EXPECT_EQ(kJohnPDoe, set_values[1]);
+ delete db_profile;
+}
+
+TEST_F(AutofillTableTest, AutofillProfileMultiValueEmails) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("john@doe.com"));
+ const string16 kJohnPDoe(ASCIIToUTF16("john_p@doe.com"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(EMAIL_ADDRESS, set_values);
+
+ EXPECT_TRUE(db.GetAutofillTable()->AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Update the values.
+ const string16 kNoOne(ASCIIToUTF16("no@one.com"));
+ set_values[1] = kNoOne;
+ p.SetMultiInfo(EMAIL_ADDRESS, set_values);
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Delete values.
+ set_values.clear();
+ p.SetMultiInfo(EMAIL_ADDRESS, set_values);
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ EXPECT_EQ(string16(), db_profile->GetInfo(EMAIL_ADDRESS));
+ delete db_profile;
+}
+
+TEST_F(AutofillTableTest, AutofillProfileMultiValuePhone) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("4151112222"));
+ const string16 kJohnPDoe(ASCIIToUTF16("4151113333"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
+
+ EXPECT_TRUE(db.GetAutofillTable()->AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Update the values.
+ const string16 kNoOne(ASCIIToUTF16("4151110000"));
+ set_values[1] = kNoOne;
+ p.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Delete values.
+ set_values.clear();
+ p.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ EXPECT_EQ(string16(), db_profile->GetInfo(EMAIL_ADDRESS));
+ delete db_profile;
+}
+
+TEST_F(AutofillTableTest, AutofillProfileMultiValueFax) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillProfile p;
+ const string16 kJohnDoe(ASCIIToUTF16("4151112222"));
+ const string16 kJohnPDoe(ASCIIToUTF16("4151113333"));
+ std::vector<string16> set_values;
+ set_values.push_back(kJohnDoe);
+ set_values.push_back(kJohnPDoe);
+ p.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, set_values);
+
+ EXPECT_TRUE(db.GetAutofillTable()->AddAutofillProfile(p));
+
+ AutofillProfile* db_profile;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Update the values.
+ const string16 kNoOne(ASCIIToUTF16("4151110000"));
+ set_values[1] = kNoOne;
+ p.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, set_values);
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ delete db_profile;
+
+ // Delete values.
+ set_values.clear();
+ p.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, set_values);
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateAutofillProfileMulti(p));
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(p.guid(), &db_profile));
+ EXPECT_EQ(p, *db_profile);
+ EXPECT_EQ(0, p.CompareMulti(*db_profile));
+ EXPECT_EQ(string16(), db_profile->GetInfo(EMAIL_ADDRESS));
+ delete db_profile;
+}
+
+TEST_F(AutofillTableTest, AutofillProfileTrash) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ std::vector<std::string> guids;
+ db.GetAutofillTable()->GetAutofillProfilesInTrash(&guids);
+ EXPECT_TRUE(guids.empty());
+
+ ASSERT_TRUE(db.GetAutofillTable()->AddAutofillGUIDToTrash(
+ "00000000-0000-0000-0000-000000000000"));
+ ASSERT_TRUE(db.GetAutofillTable()->AddAutofillGUIDToTrash(
+ "00000000-0000-0000-0000-000000000001"));
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfilesInTrash(&guids));
+ EXPECT_EQ(2UL, guids.size());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000000", guids[0]);
+ EXPECT_EQ("00000000-0000-0000-0000-000000000001", guids[1]);
+
+ ASSERT_TRUE(db.GetAutofillTable()->EmptyAutofillProfilesTrash());
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfilesInTrash(&guids));
+ EXPECT_TRUE(guids.empty());
+}
+
+TEST_F(AutofillTableTest, AutofillProfileTrashInteraction) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ std::vector<std::string> guids;
+ db.GetAutofillTable()->GetAutofillProfilesInTrash(&guids);
+ EXPECT_TRUE(guids.empty());
+
+ AutofillProfile profile;
+ profile.SetInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ profile.SetInfo(NAME_MIDDLE, ASCIIToUTF16("Q."));
+ profile.SetInfo(NAME_LAST, ASCIIToUTF16("Smith"));
+ profile.SetInfo(EMAIL_ADDRESS,ASCIIToUTF16("js@smith.xyz"));
+ profile.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1 Main St"));
+ profile.SetInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Los Angeles"));
+ profile.SetInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA"));
+ profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("90025"));
+ profile.SetInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
+
+ // Mark this profile as in the trash. This stops |AddAutofillProfile| from
+ // adding it.
+ EXPECT_TRUE(db.GetAutofillTable()->AddAutofillGUIDToTrash(profile.guid()));
+ EXPECT_TRUE(db.GetAutofillTable()->AddAutofillProfile(profile));
+ AutofillProfile* added_profile = NULL;
+ EXPECT_FALSE(db.GetAutofillTable()->GetAutofillProfile(
+ profile.guid(), &added_profile));
+ EXPECT_EQ(static_cast<AutofillProfile*>(NULL), added_profile);
+
+ // Add the profile for real this time.
+ EXPECT_TRUE(db.GetAutofillTable()->EmptyAutofillProfilesTrash());
+ EXPECT_TRUE(db.GetAutofillTable()->GetAutofillProfilesInTrash(&guids));
+ EXPECT_TRUE(guids.empty());
+ EXPECT_TRUE(db.GetAutofillTable()->AddAutofillProfile(profile));
+ EXPECT_TRUE(db.GetAutofillTable()->GetAutofillProfile(profile.guid(),
+ &added_profile));
+ ASSERT_NE(static_cast<AutofillProfile*>(NULL), added_profile);
+ delete added_profile;
+
+ // Mark this profile as in the trash. This stops |UpdateAutofillProfileMulti|
+ // from updating it. In normal operation a profile should not be both in the
+ // trash and in the profiles table simultaneously.
+ EXPECT_TRUE(db.GetAutofillTable()->AddAutofillGUIDToTrash(profile.guid()));
+ profile.SetInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateAutofillProfileMulti(profile));
+ AutofillProfile* updated_profile = NULL;
+ EXPECT_TRUE(db.GetAutofillTable()->GetAutofillProfile(
+ profile.guid(), &updated_profile));
+ ASSERT_NE(static_cast<AutofillProfile*>(NULL), added_profile);
+ EXPECT_EQ(ASCIIToUTF16("John"), updated_profile->GetInfo(NAME_FIRST));
+ delete updated_profile;
+
+ // Try to delete the trashed profile. This stops |RemoveAutofillProfile| from
+ // deleting it. In normal operation deletion is done by migration step, and
+ // removal from trash is done by |WebDataService|. |RemoveAutofillProfile|
+ // does remove the item from the trash if it is found however, so that if
+ // other clients remove it (via Sync say) then it is gone and doesn't need to
+ // be processed further by |WebDataService|.
+ EXPECT_TRUE(db.GetAutofillTable()->RemoveAutofillProfile(profile.guid()));
+ AutofillProfile* removed_profile = NULL;
+ EXPECT_TRUE(db.GetAutofillTable()->GetAutofillProfile(profile.guid(),
+ &removed_profile));
+ EXPECT_FALSE(db.GetAutofillTable()->IsAutofillGUIDInTrash(profile.guid()));
+ ASSERT_NE(static_cast<AutofillProfile*>(NULL), removed_profile);
+ delete removed_profile;
+
+ // Check that emptying the trash now allows removal to occur.
+ EXPECT_TRUE(db.GetAutofillTable()->EmptyAutofillProfilesTrash());
+ EXPECT_TRUE(db.GetAutofillTable()->RemoveAutofillProfile(profile.guid()));
+ removed_profile = NULL;
+ EXPECT_FALSE(db.GetAutofillTable()->GetAutofillProfile(profile.guid(),
+ &removed_profile));
+ EXPECT_EQ(static_cast<AutofillProfile*>(NULL), removed_profile);
+}
+
+TEST_F(AutofillTableTest, CreditCard) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ // Add a 'Work' credit card.
+ CreditCard work_creditcard;
+ work_creditcard.SetInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Jack Torrance"));
+ work_creditcard.SetInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("1234567890123456"));
+ work_creditcard.SetInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("04"));
+ work_creditcard.SetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2013"));
+
+ Time pre_creation_time = Time::Now();
+ EXPECT_TRUE(db.GetAutofillTable()->AddCreditCard(work_creditcard));
+ Time post_creation_time = Time::Now();
+
+ // Get the 'Work' credit card.
+ CreditCard* db_creditcard;
+ ASSERT_TRUE(db.GetAutofillTable()->GetCreditCard(work_creditcard.guid(),
+ &db_creditcard));
+ EXPECT_EQ(work_creditcard, *db_creditcard);
+ sql::Statement s_work(db.db_.GetUniqueStatement(
+ "SELECT guid, name_on_card, expiration_month, expiration_year, "
+ "card_number_encrypted, date_modified "
+ "FROM credit_cards WHERE guid=?"));
+ s_work.BindString(0, work_creditcard.guid());
+ ASSERT_TRUE(s_work);
+ ASSERT_TRUE(s_work.Step());
+ EXPECT_GE(s_work.ColumnInt64(5), pre_creation_time.ToTimeT());
+ EXPECT_LE(s_work.ColumnInt64(5), post_creation_time.ToTimeT());
+ EXPECT_FALSE(s_work.Step());
+ delete db_creditcard;
+
+ // Add a 'Target' credit card.
+ CreditCard target_creditcard;
+ target_creditcard.SetInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Jack Torrance"));
+ target_creditcard.SetInfo(CREDIT_CARD_NUMBER,
+ ASCIIToUTF16("1111222233334444"));
+ target_creditcard.SetInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("06"));
+ target_creditcard.SetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2012"));
+
+ pre_creation_time = Time::Now();
+ EXPECT_TRUE(db.GetAutofillTable()->AddCreditCard(target_creditcard));
+ post_creation_time = Time::Now();
+ ASSERT_TRUE(db.GetAutofillTable()->GetCreditCard(target_creditcard.guid(),
+ &db_creditcard));
+ EXPECT_EQ(target_creditcard, *db_creditcard);
+ sql::Statement s_target(db.db_.GetUniqueStatement(
+ "SELECT guid, name_on_card, expiration_month, expiration_year, "
+ "card_number_encrypted, date_modified "
+ "FROM credit_cards WHERE guid=?"));
+ s_target.BindString(0, target_creditcard.guid());
+ ASSERT_TRUE(s_target);
+ ASSERT_TRUE(s_target.Step());
+ EXPECT_GE(s_target.ColumnInt64(5), pre_creation_time.ToTimeT());
+ EXPECT_LE(s_target.ColumnInt64(5), post_creation_time.ToTimeT());
+ EXPECT_FALSE(s_target.Step());
+ delete db_creditcard;
+
+ // Update the 'Target' credit card.
+ target_creditcard.SetInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Charles Grady"));
+ Time pre_modification_time = Time::Now();
+ EXPECT_TRUE(db.GetAutofillTable()->UpdateCreditCard(target_creditcard));
+ Time post_modification_time = Time::Now();
+ ASSERT_TRUE(db.GetAutofillTable()->GetCreditCard(target_creditcard.guid(),
+ &db_creditcard));
+ EXPECT_EQ(target_creditcard, *db_creditcard);
+ sql::Statement s_target_updated(db.db_.GetUniqueStatement(
+ "SELECT guid, name_on_card, expiration_month, expiration_year, "
+ "card_number_encrypted, date_modified "
+ "FROM credit_cards WHERE guid=?"));
+ s_target_updated.BindString(0, target_creditcard.guid());
+ ASSERT_TRUE(s_target_updated);
+ ASSERT_TRUE(s_target_updated.Step());
+ EXPECT_GE(s_target_updated.ColumnInt64(5), pre_modification_time.ToTimeT());
+ EXPECT_LE(s_target_updated.ColumnInt64(5), post_modification_time.ToTimeT());
+ EXPECT_FALSE(s_target_updated.Step());
+ delete db_creditcard;
+
+ // Remove the 'Target' credit card.
+ EXPECT_TRUE(db.GetAutofillTable()->RemoveCreditCard(
+ target_creditcard.guid()));
+ EXPECT_FALSE(db.GetAutofillTable()->GetCreditCard(target_creditcard.guid(),
+ &db_creditcard));
+}
+
+TEST_F(AutofillTableTest, UpdateAutofillProfile) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ // Add a profile to the db.
+ AutofillProfile profile;
+ profile.SetInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ profile.SetInfo(NAME_MIDDLE, ASCIIToUTF16("Q."));
+ profile.SetInfo(NAME_LAST, ASCIIToUTF16("Smith"));
+ profile.SetInfo(EMAIL_ADDRESS, ASCIIToUTF16("js@example.com"));
+ profile.SetInfo(COMPANY_NAME, ASCIIToUTF16("Google"));
+ profile.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Apple Way"));
+ profile.SetInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("unit 5"));
+ profile.SetInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Los Angeles"));
+ profile.SetInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA"));
+ profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("90025"));
+ profile.SetInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
+ profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("18181234567"));
+ profile.SetInfo(PHONE_FAX_WHOLE_NUMBER, ASCIIToUTF16("1915243678"));
+ db.GetAutofillTable()->AddAutofillProfile(profile);
+
+ // Set a mocked value for the profile's creation time.
+ const time_t mock_creation_date = Time::Now().ToTimeT() - 13;
+ sql::Statement s_mock_creation_date(db.db_.GetUniqueStatement(
+ "UPDATE autofill_profiles SET date_modified = ?"));
+ ASSERT_TRUE(s_mock_creation_date);
+ s_mock_creation_date.BindInt64(0, mock_creation_date);
+ ASSERT_TRUE(s_mock_creation_date.Run());
+
+ // Get the profile.
+ AutofillProfile* tmp_profile;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(profile.guid(),
+ &tmp_profile));
+ scoped_ptr<AutofillProfile> db_profile(tmp_profile);
+ EXPECT_EQ(profile, *db_profile);
+ sql::Statement s_original(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
+ ASSERT_TRUE(s_original);
+ ASSERT_TRUE(s_original.Step());
+ EXPECT_EQ(mock_creation_date, s_original.ColumnInt64(0));
+ EXPECT_FALSE(s_original.Step());
+
+ // Now, update the profile and save the update to the database.
+ // The modification date should change to reflect the update.
+ profile.SetInfo(EMAIL_ADDRESS, ASCIIToUTF16("js@smith.xyz"));
+ db.GetAutofillTable()->UpdateAutofillProfileMulti(profile);
+
+ // Get the profile.
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(profile.guid(),
+ &tmp_profile));
+ db_profile.reset(tmp_profile);
+ EXPECT_EQ(profile, *db_profile);
+ sql::Statement s_updated(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
+ ASSERT_TRUE(s_updated);
+ ASSERT_TRUE(s_updated.Step());
+ EXPECT_LT(mock_creation_date, s_updated.ColumnInt64(0));
+ EXPECT_FALSE(s_updated.Step());
+
+ // Set a mocked value for the profile's modification time.
+ const time_t mock_modification_date = Time::Now().ToTimeT() - 7;
+ sql::Statement s_mock_modification_date(db.db_.GetUniqueStatement(
+ "UPDATE autofill_profiles SET date_modified = ?"));
+ ASSERT_TRUE(s_mock_modification_date);
+ s_mock_modification_date.BindInt64(0, mock_modification_date);
+ ASSERT_TRUE(s_mock_modification_date.Run());
+
+ // Finally, call into |UpdateAutofillProfileMulti()| without changing the
+ // profile. The modification date should not change.
+ db.GetAutofillTable()->UpdateAutofillProfileMulti(profile);
+
+ // Get the profile.
+ ASSERT_TRUE(db.GetAutofillTable()->GetAutofillProfile(profile.guid(),
+ &tmp_profile));
+ db_profile.reset(tmp_profile);
+ EXPECT_EQ(profile, *db_profile);
+ sql::Statement s_unchanged(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
+ ASSERT_TRUE(s_unchanged);
+ ASSERT_TRUE(s_unchanged.Step());
+ EXPECT_EQ(mock_modification_date, s_unchanged.ColumnInt64(0));
+ EXPECT_FALSE(s_unchanged.Step());
+}
+
+TEST_F(AutofillTableTest, UpdateCreditCard) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ // Add a credit card to the db.
+ CreditCard credit_card;
+ credit_card.SetInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Jack Torrance"));
+ credit_card.SetInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("1234567890123456"));
+ credit_card.SetInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("04"));
+ credit_card.SetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2013"));
+ db.GetAutofillTable()->AddCreditCard(credit_card);
+
+ // Set a mocked value for the credit card's creation time.
+ const time_t mock_creation_date = Time::Now().ToTimeT() - 13;
+ sql::Statement s_mock_creation_date(db.db_.GetUniqueStatement(
+ "UPDATE credit_cards SET date_modified = ?"));
+ ASSERT_TRUE(s_mock_creation_date);
+ s_mock_creation_date.BindInt64(0, mock_creation_date);
+ ASSERT_TRUE(s_mock_creation_date.Run());
+
+ // Get the credit card.
+ CreditCard* tmp_credit_card;
+ ASSERT_TRUE(db.GetAutofillTable()->GetCreditCard(credit_card.guid(),
+ &tmp_credit_card));
+ scoped_ptr<CreditCard> db_credit_card(tmp_credit_card);
+ EXPECT_EQ(credit_card, *db_credit_card);
+ sql::Statement s_original(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
+ ASSERT_TRUE(s_original);
+ ASSERT_TRUE(s_original.Step());
+ EXPECT_EQ(mock_creation_date, s_original.ColumnInt64(0));
+ EXPECT_FALSE(s_original.Step());
+
+ // Now, update the credit card and save the update to the database.
+ // The modification date should change to reflect the update.
+ credit_card.SetInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01"));
+ db.GetAutofillTable()->UpdateCreditCard(credit_card);
+
+ // Get the credit card.
+ ASSERT_TRUE(db.GetAutofillTable()->GetCreditCard(credit_card.guid(),
+ &tmp_credit_card));
+ db_credit_card.reset(tmp_credit_card);
+ EXPECT_EQ(credit_card, *db_credit_card);
+ sql::Statement s_updated(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
+ ASSERT_TRUE(s_updated);
+ ASSERT_TRUE(s_updated.Step());
+ EXPECT_LT(mock_creation_date, s_updated.ColumnInt64(0));
+ EXPECT_FALSE(s_updated.Step());
+
+ // Set a mocked value for the credit card's modification time.
+ const time_t mock_modification_date = Time::Now().ToTimeT() - 7;
+ sql::Statement s_mock_modification_date(db.db_.GetUniqueStatement(
+ "UPDATE credit_cards SET date_modified = ?"));
+ ASSERT_TRUE(s_mock_modification_date);
+ s_mock_modification_date.BindInt64(0, mock_modification_date);
+ ASSERT_TRUE(s_mock_modification_date.Run());
+
+ // Finally, call into |UpdateCreditCard()| without changing the credit card.
+ // The modification date should not change.
+ db.GetAutofillTable()->UpdateCreditCard(credit_card);
+
+ // Get the profile.
+ ASSERT_TRUE(db.GetAutofillTable()->GetCreditCard(credit_card.guid(),
+ &tmp_credit_card));
+ db_credit_card.reset(tmp_credit_card);
+ EXPECT_EQ(credit_card, *db_credit_card);
+ sql::Statement s_unchanged(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
+ ASSERT_TRUE(s_unchanged);
+ ASSERT_TRUE(s_unchanged.Step());
+ EXPECT_EQ(mock_modification_date, s_unchanged.ColumnInt64(0));
+ EXPECT_FALSE(s_unchanged.Step());
+}
+
+TEST_F(AutofillTableTest, RemoveAutofillProfilesAndCreditCardsModifiedBetween) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ // Populate the autofill_profiles and credit_cards tables.
+ ASSERT_TRUE(db.db_.Execute(
+ "INSERT INTO autofill_profiles (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000000', 11);"
+ "INSERT INTO autofill_profiles (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000001', 21);"
+ "INSERT INTO autofill_profiles (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000002', 31);"
+ "INSERT INTO autofill_profiles (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000003', 41);"
+ "INSERT INTO autofill_profiles (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000004', 51);"
+ "INSERT INTO autofill_profiles (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000005', 61);"
+ "INSERT INTO credit_cards (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000006', 17);"
+ "INSERT INTO credit_cards (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000007', 27);"
+ "INSERT INTO credit_cards (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000008', 37);"
+ "INSERT INTO credit_cards (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000009', 47);"
+ "INSERT INTO credit_cards (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000010', 57);"
+ "INSERT INTO credit_cards (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000011', 67);"));
+
+ // Remove all entries modified in the bounded time range [17,41).
+ db.GetAutofillTable()->RemoveAutofillProfilesAndCreditCardsModifiedBetween(
+ Time::FromTimeT(17), Time::FromTimeT(41));
+ sql::Statement s_autofill_profiles_bounded(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
+ ASSERT_TRUE(s_autofill_profiles_bounded);
+ ASSERT_TRUE(s_autofill_profiles_bounded.Step());
+ EXPECT_EQ(11, s_autofill_profiles_bounded.ColumnInt64(0));
+ ASSERT_TRUE(s_autofill_profiles_bounded.Step());
+ EXPECT_EQ(41, s_autofill_profiles_bounded.ColumnInt64(0));
+ ASSERT_TRUE(s_autofill_profiles_bounded.Step());
+ EXPECT_EQ(51, s_autofill_profiles_bounded.ColumnInt64(0));
+ ASSERT_TRUE(s_autofill_profiles_bounded.Step());
+ EXPECT_EQ(61, s_autofill_profiles_bounded.ColumnInt64(0));
+ EXPECT_FALSE(s_autofill_profiles_bounded.Step());
+ sql::Statement s_credit_cards_bounded(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
+ ASSERT_TRUE(s_credit_cards_bounded);
+ ASSERT_TRUE(s_credit_cards_bounded.Step());
+ EXPECT_EQ(47, s_credit_cards_bounded.ColumnInt64(0));
+ ASSERT_TRUE(s_credit_cards_bounded.Step());
+ EXPECT_EQ(57, s_credit_cards_bounded.ColumnInt64(0));
+ ASSERT_TRUE(s_credit_cards_bounded.Step());
+ EXPECT_EQ(67, s_credit_cards_bounded.ColumnInt64(0));
+ EXPECT_FALSE(s_credit_cards_bounded.Step());
+
+ // Remove all entries modified on or after time 51 (unbounded range).
+ db.GetAutofillTable()->RemoveAutofillProfilesAndCreditCardsModifiedBetween(
+ Time::FromTimeT(51), Time());
+ sql::Statement s_autofill_profiles_unbounded(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
+ ASSERT_TRUE(s_autofill_profiles_unbounded);
+ ASSERT_TRUE(s_autofill_profiles_unbounded.Step());
+ EXPECT_EQ(11, s_autofill_profiles_unbounded.ColumnInt64(0));
+ ASSERT_TRUE(s_autofill_profiles_unbounded.Step());
+ EXPECT_EQ(41, s_autofill_profiles_unbounded.ColumnInt64(0));
+ EXPECT_FALSE(s_autofill_profiles_unbounded.Step());
+ sql::Statement s_credit_cards_unbounded(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
+ ASSERT_TRUE(s_credit_cards_unbounded);
+ ASSERT_TRUE(s_credit_cards_unbounded.Step());
+ EXPECT_EQ(47, s_credit_cards_unbounded.ColumnInt64(0));
+ EXPECT_FALSE(s_credit_cards_unbounded.Step());
+
+ // Remove all remaining entries.
+ db.GetAutofillTable()->RemoveAutofillProfilesAndCreditCardsModifiedBetween(
+ Time(), Time());
+ sql::Statement s_autofill_profiles_empty(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM autofill_profiles"));
+ ASSERT_TRUE(s_autofill_profiles_empty);
+ EXPECT_FALSE(s_autofill_profiles_empty.Step());
+ sql::Statement s_credit_cards_empty(db.db_.GetUniqueStatement(
+ "SELECT date_modified FROM credit_cards"));
+ ASSERT_TRUE(s_credit_cards_empty);
+ EXPECT_FALSE(s_credit_cards_empty.Step());
+}
+
+TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_NoResults) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ std::vector<AutofillEntry> entries;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAllAutofillEntries(&entries));
+
+ EXPECT_EQ(0U, entries.size());
+}
+
+TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_OneResult) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillChangeList changes;
+ std::map<std::string, std::vector<Time> > name_value_times_map;
+
+ time_t start = 0;
+ std::vector<Time> timestamps1;
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValueTime(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"),
+ string16(),
+ 0,
+ false),
+ &changes,
+ Time::FromTimeT(start)));
+ timestamps1.push_back(Time::FromTimeT(start));
+ std::string key1("NameSuperman");
+ name_value_times_map.insert(std::pair<std::string,
+ std::vector<Time> > (key1, timestamps1));
+
+ AutofillEntrySet expected_entries(CompareAutofillEntries);
+ AutofillKey ak1(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"));
+ AutofillEntry ae1(ak1, timestamps1);
+
+ expected_entries.insert(ae1);
+
+ std::vector<AutofillEntry> entries;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAllAutofillEntries(&entries));
+ AutofillEntrySet entry_set(entries.begin(), entries.end(),
+ CompareAutofillEntries);
+
+ // make sure the lists of entries match
+ ASSERT_EQ(expected_entries.size(), entry_set.size());
+ AutofillEntrySetIterator it;
+ for (it = entry_set.begin(); it != entry_set.end(); it++) {
+ expected_entries.erase(*it);
+ }
+
+ EXPECT_EQ(0U, expected_entries.size());
+}
+
+TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_TwoDistinct) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillChangeList changes;
+ std::map<std::string, std::vector<Time> > name_value_times_map;
+ time_t start = 0;
+
+ std::vector<Time> timestamps1;
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValueTime(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"),
+ string16(),
+ 0,
+ false),
+ &changes,
+ Time::FromTimeT(start)));
+ timestamps1.push_back(Time::FromTimeT(start));
+ std::string key1("NameSuperman");
+ name_value_times_map.insert(std::pair<std::string,
+ std::vector<Time> > (key1, timestamps1));
+
+ start++;
+ std::vector<Time> timestamps2;
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValueTime(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Clark Kent"),
+ string16(),
+ 0,
+ false),
+ &changes,
+ Time::FromTimeT(start)));
+ timestamps2.push_back(Time::FromTimeT(start));
+ std::string key2("NameClark Kent");
+ name_value_times_map.insert(std::pair<std::string,
+ std::vector<Time> > (key2, timestamps2));
+
+ AutofillEntrySet expected_entries(CompareAutofillEntries);
+ AutofillKey ak1(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"));
+ AutofillKey ak2(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Kent"));
+ AutofillEntry ae1(ak1, timestamps1);
+ AutofillEntry ae2(ak2, timestamps2);
+
+ expected_entries.insert(ae1);
+ expected_entries.insert(ae2);
+
+ std::vector<AutofillEntry> entries;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAllAutofillEntries(&entries));
+ AutofillEntrySet entry_set(entries.begin(), entries.end(),
+ CompareAutofillEntries);
+
+ // make sure the lists of entries match
+ ASSERT_EQ(expected_entries.size(), entry_set.size());
+ AutofillEntrySetIterator it;
+ for (it = entry_set.begin(); it != entry_set.end(); it++) {
+ expected_entries.erase(*it);
+ }
+
+ EXPECT_EQ(0U, expected_entries.size());
+}
+
+TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_TwoSame) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ AutofillChangeList changes;
+ std::map<std::string, std::vector<Time> > name_value_times_map;
+
+ time_t start = 0;
+ std::vector<Time> timestamps;
+ for (int i = 0; i < 2; i++) {
+ EXPECT_TRUE(db.GetAutofillTable()->AddFormFieldValueTime(
+ FormField(string16(),
+ ASCIIToUTF16("Name"),
+ ASCIIToUTF16("Superman"),
+ string16(),
+ 0,
+ false),
+ &changes,
+ Time::FromTimeT(start)));
+ timestamps.push_back(Time::FromTimeT(start));
+ start++;
+ }
+
+ std::string key("NameSuperman");
+ name_value_times_map.insert(std::pair<std::string,
+ std::vector<Time> > (key, timestamps));
+
+ AutofillEntrySet expected_entries(CompareAutofillEntries);
+ AutofillKey ak1(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"));
+ AutofillEntry ae1(ak1, timestamps);
+
+ expected_entries.insert(ae1);
+
+ std::vector<AutofillEntry> entries;
+ ASSERT_TRUE(db.GetAutofillTable()->GetAllAutofillEntries(&entries));
+ AutofillEntrySet entry_set(entries.begin(), entries.end(),
+ CompareAutofillEntries);
+
+ // make sure the lists of entries match
+ ASSERT_EQ(expected_entries.size(), entry_set.size());
+ AutofillEntrySetIterator it;
+ for (it = entry_set.begin(); it != entry_set.end(); it++) {
+ expected_entries.erase(*it);
+ }
+
+ EXPECT_EQ(0U, expected_entries.size());
+}
diff --git a/chrome/browser/webdata/autofill_util.cc b/chrome/browser/webdata/autofill_util.cc
new file mode 100644
index 0000000..1b3c74e
--- /dev/null
+++ b/chrome/browser/webdata/autofill_util.cc
@@ -0,0 +1,358 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/webdata/autofill_util.h"
+
+#include "app/sql/statement.h"
+#include "base/logging.h"
+#include "base/time.h"
+#include "chrome/browser/autofill/autofill_profile.h"
+#include "chrome/browser/autofill/autofill_type.h"
+#include "chrome/browser/autofill/credit_card.h"
+#include "chrome/browser/password_manager/encryptor.h"
+#include "chrome/common/guid.h"
+
+using base::Time;
+
+namespace autofill_util {
+
+// The maximum length allowed for form data.
+const size_t kMaxDataLength = 1024;
+
+string16 LimitDataSize(const string16& data) {
+ if (data.size() > kMaxDataLength)
+ return data.substr(0, kMaxDataLength);
+
+ return data;
+}
+
+void BindAutofillProfileToStatement(const AutofillProfile& profile,
+ sql::Statement* s) {
+ DCHECK(guid::IsValidGUID(profile.guid()));
+ s->BindString(0, profile.guid());
+
+ string16 text = profile.GetInfo(COMPANY_NAME);
+ s->BindString16(1, LimitDataSize(text));
+ text = profile.GetInfo(ADDRESS_HOME_LINE1);
+ s->BindString16(2, LimitDataSize(text));
+ text = profile.GetInfo(ADDRESS_HOME_LINE2);
+ s->BindString16(3, LimitDataSize(text));
+ text = profile.GetInfo(ADDRESS_HOME_CITY);
+ s->BindString16(4, LimitDataSize(text));
+ text = profile.GetInfo(ADDRESS_HOME_STATE);
+ s->BindString16(5, LimitDataSize(text));
+ text = profile.GetInfo(ADDRESS_HOME_ZIP);
+ s->BindString16(6, LimitDataSize(text));
+ text = profile.GetInfo(ADDRESS_HOME_COUNTRY);
+ s->BindString16(7, LimitDataSize(text));
+ std::string country_code = profile.CountryCode();
+ s->BindString(8, country_code);
+ s->BindInt64(9, Time::Now().ToTimeT());
+}
+
+AutofillProfile* AutofillProfileFromStatement(const sql::Statement& s) {
+ AutofillProfile* profile = new AutofillProfile;
+ profile->set_guid(s.ColumnString(0));
+ DCHECK(guid::IsValidGUID(profile->guid()));
+
+ profile->SetInfo(COMPANY_NAME, s.ColumnString16(1));
+ profile->SetInfo(ADDRESS_HOME_LINE1, s.ColumnString16(2));
+ profile->SetInfo(ADDRESS_HOME_LINE2, s.ColumnString16(3));
+ profile->SetInfo(ADDRESS_HOME_CITY, s.ColumnString16(4));
+ profile->SetInfo(ADDRESS_HOME_STATE, s.ColumnString16(5));
+ profile->SetInfo(ADDRESS_HOME_ZIP, s.ColumnString16(6));
+ // Intentionally skip column 7, which stores the localized country name.
+ profile->SetCountryCode(s.ColumnString(8));
+ // Intentionally skip column 9, which stores the profile's modification date.
+
+ return profile;
+}
+
+void BindCreditCardToStatement(const CreditCard& credit_card,
+ sql::Statement* s) {
+ DCHECK(guid::IsValidGUID(credit_card.guid()));
+ s->BindString(0, credit_card.guid());
+
+ string16 text = credit_card.GetInfo(CREDIT_CARD_NAME);
+ s->BindString16(1, LimitDataSize(text));
+ text = credit_card.GetInfo(CREDIT_CARD_EXP_MONTH);
+ s->BindString16(2, LimitDataSize(text));
+ text = credit_card.GetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR);
+ s->BindString16(3, LimitDataSize(text));
+ text = credit_card.GetInfo(CREDIT_CARD_NUMBER);
+ std::string encrypted_data;
+ Encryptor::EncryptString16(text, &encrypted_data);
+ s->BindBlob(4, encrypted_data.data(),
+ static_cast<int>(encrypted_data.length()));
+ s->BindInt64(5, Time::Now().ToTimeT());
+}
+
+CreditCard* CreditCardFromStatement(const sql::Statement& s) {
+ CreditCard* credit_card = new CreditCard;
+
+ credit_card->set_guid(s.ColumnString(0));
+ DCHECK(guid::IsValidGUID(credit_card->guid()));
+
+ credit_card->SetInfo(CREDIT_CARD_NAME, s.ColumnString16(1));
+ credit_card->SetInfo(CREDIT_CARD_EXP_MONTH,
+ s.ColumnString16(2));
+ credit_card->SetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR,
+ s.ColumnString16(3));
+ int encrypted_number_len = s.ColumnByteLength(4);
+ string16 credit_card_number;
+ if (encrypted_number_len) {
+ std::string encrypted_number;
+ encrypted_number.resize(encrypted_number_len);
+ memcpy(&encrypted_number[0], s.ColumnBlob(4), encrypted_number_len);
+ Encryptor::DecryptString16(encrypted_number, &credit_card_number);
+ }
+ credit_card->SetInfo(CREDIT_CARD_NUMBER, credit_card_number);
+ // Intentionally skip column 5, which stores the modification date.
+
+ return credit_card;
+}
+
+bool AddAutofillProfileNamesToProfile(sql::Connection* db,
+ AutofillProfile* profile) {
+ sql::Statement s(db->GetUniqueStatement(
+ "SELECT guid, first_name, middle_name, last_name "
+ "FROM autofill_profile_names "
+ "WHERE guid=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindString(0, profile->guid());
+
+ std::vector<string16> first_names;
+ std::vector<string16> middle_names;
+ std::vector<string16> last_names;
+ while (s.Step()) {
+ DCHECK_EQ(profile->guid(), s.ColumnString(0));
+ first_names.push_back(s.ColumnString16(1));
+ middle_names.push_back(s.ColumnString16(2));
+ last_names.push_back(s.ColumnString16(3));
+ }
+ profile->SetMultiInfo(NAME_FIRST, first_names);
+ profile->SetMultiInfo(NAME_MIDDLE, middle_names);
+ profile->SetMultiInfo(NAME_LAST, last_names);
+ return true;
+}
+
+bool AddAutofillProfileEmailsToProfile(sql::Connection* db,
+ AutofillProfile* profile) {
+ sql::Statement s(db->GetUniqueStatement(
+ "SELECT guid, email "
+ "FROM autofill_profile_emails "
+ "WHERE guid=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindString(0, profile->guid());
+
+ std::vector<string16> emails;
+ while (s.Step()) {
+ DCHECK_EQ(profile->guid(), s.ColumnString(0));
+ emails.push_back(s.ColumnString16(1));
+ }
+ profile->SetMultiInfo(EMAIL_ADDRESS, emails);
+ return true;
+}
+
+bool AddAutofillProfilePhonesToProfile(sql::Connection* db,
+ AutofillProfile* profile) {
+ sql::Statement s(db->GetUniqueStatement(
+ "SELECT guid, type, number "
+ "FROM autofill_profile_phones "
+ "WHERE guid=? AND type=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindString(0, profile->guid());
+ s.BindInt(1, kAutofillPhoneNumber);
+
+ std::vector<string16> numbers;
+ while (s.Step()) {
+ DCHECK_EQ(profile->guid(), s.ColumnString(0));
+ numbers.push_back(s.ColumnString16(2));
+ }
+ profile->SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, numbers);
+ return true;
+}
+
+bool AddAutofillProfileFaxesToProfile(sql::Connection* db,
+ AutofillProfile* profile) {
+ sql::Statement s(db->GetUniqueStatement(
+ "SELECT guid, type, number "
+ "FROM autofill_profile_phones "
+ "WHERE guid=? AND type=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindString(0, profile->guid());
+ s.BindInt(1, kAutofillFaxNumber);
+
+ std::vector<string16> numbers;
+ while (s.Step()) {
+ DCHECK_EQ(profile->guid(), s.ColumnString(0));
+ numbers.push_back(s.ColumnString16(2));
+ }
+ profile->SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, numbers);
+ return true;
+}
+
+
+bool AddAutofillProfileNames(const AutofillProfile& profile,
+ sql::Connection* db) {
+ std::vector<string16> first_names;
+ profile.GetMultiInfo(NAME_FIRST, &first_names);
+ std::vector<string16> middle_names;
+ profile.GetMultiInfo(NAME_MIDDLE, &middle_names);
+ std::vector<string16> last_names;
+ profile.GetMultiInfo(NAME_LAST, &last_names);
+ DCHECK_EQ(first_names.size(), middle_names.size());
+ DCHECK_EQ(middle_names.size(), last_names.size());
+
+ for (size_t i = 0; i < first_names.size(); ++i) {
+ // Add the new name.
+ sql::Statement s(db->GetUniqueStatement(
+ "INSERT INTO autofill_profile_names"
+ " (guid, first_name, middle_name, last_name) "
+ "VALUES (?,?,?,?)"));
+ if (!s) {
+ NOTREACHED();
+ return false;
+ }
+ s.BindString(0, profile.guid());
+ s.BindString16(1, first_names[i]);
+ s.BindString16(2, middle_names[i]);
+ s.BindString16(3, last_names[i]);
+
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool AddAutofillProfileEmails(const AutofillProfile& profile,
+ sql::Connection* db) {
+ std::vector<string16> emails;
+ profile.GetMultiInfo(EMAIL_ADDRESS, &emails);
+
+ for (size_t i = 0; i < emails.size(); ++i) {
+ // Add the new email.
+ sql::Statement s(db->GetUniqueStatement(
+ "INSERT INTO autofill_profile_emails"
+ " (guid, email) "
+ "VALUES (?,?)"));
+ if (!s) {
+ NOTREACHED();
+ return false;
+ }
+ s.BindString(0, profile.guid());
+ s.BindString16(1, emails[i]);
+
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool AddAutofillProfilePhones(const AutofillProfile& profile,
+ AutofillPhoneType phone_type,
+ sql::Connection* db) {
+ AutofillFieldType field_type;
+ if (phone_type == kAutofillPhoneNumber) {
+ field_type = PHONE_HOME_WHOLE_NUMBER;
+ } else if (phone_type == kAutofillFaxNumber) {
+ field_type = PHONE_FAX_WHOLE_NUMBER;
+ } else {
+ NOTREACHED();
+ return false;
+ }
+
+ std::vector<string16> numbers;
+ profile.GetMultiInfo(field_type, &numbers);
+
+ for (size_t i = 0; i < numbers.size(); ++i) {
+ // Add the new number.
+ sql::Statement s(db->GetUniqueStatement(
+ "INSERT INTO autofill_profile_phones"
+ " (guid, type, number) "
+ "VALUES (?,?,?)"));
+ if (!s) {
+ NOTREACHED();
+ return false;
+ }
+ s.BindString(0, profile.guid());
+ s.BindInt(1, phone_type);
+ s.BindString16(2, numbers[i]);
+
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool AddAutofillProfilePieces(const AutofillProfile& profile,
+ sql::Connection* db) {
+ if (!AddAutofillProfileNames(profile, db))
+ return false;
+
+ if (!AddAutofillProfileEmails(profile, db))
+ return false;
+
+ if (!AddAutofillProfilePhones(profile, kAutofillPhoneNumber, db))
+ return false;
+
+ if (!AddAutofillProfilePhones(profile, kAutofillFaxNumber, db))
+ return false;
+
+ return true;
+}
+
+bool RemoveAutofillProfilePieces(const std::string& guid, sql::Connection* db) {
+ sql::Statement s1(db->GetUniqueStatement(
+ "DELETE FROM autofill_profile_names WHERE guid = ?"));
+ if (!s1) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s1.BindString(0, guid);
+ if (!s1.Run())
+ return false;
+
+ sql::Statement s2(db->GetUniqueStatement(
+ "DELETE FROM autofill_profile_emails WHERE guid = ?"));
+ if (!s2) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s2.BindString(0, guid);
+ if (!s2.Run())
+ return false;
+
+ sql::Statement s3(db->GetUniqueStatement(
+ "DELETE FROM autofill_profile_phones WHERE guid = ?"));
+ if (!s3) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ s3.BindString(0, guid);
+ return s3.Run();
+}
+
+} // namespace autofill_util
diff --git a/chrome/browser/webdata/autofill_util.h b/chrome/browser/webdata/autofill_util.h
new file mode 100644
index 0000000..8436001
--- /dev/null
+++ b/chrome/browser/webdata/autofill_util.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEBDATA_AUTOFILL_UTIL_H_
+#define CHROME_BROWSER_WEBDATA_AUTOFILL_UTIL_H_
+#pragma once
+
+#include "app/sql/statement.h"
+#include "base/string16.h"
+
+class AutofillProfile;
+class CreditCard;
+
+// Constants for the |autofill_profile_phones| |type| column.
+enum AutofillPhoneType {
+ kAutofillPhoneNumber = 0,
+ kAutofillFaxNumber = 1
+};
+
+namespace autofill_util {
+
+// TODO(jhawkins): This is a temporary stop-gap measure designed to prevent
+// a malicious site from DOS'ing the browser with extremely large profile
+// data. The correct solution is to parse this data asynchronously.
+// See http://crbug.com/49332.
+string16 LimitDataSize(const string16& data);
+
+void BindAutofillProfileToStatement(const AutofillProfile& profile,
+ sql::Statement* s);
+
+AutofillProfile* AutofillProfileFromStatement(const sql::Statement& s);
+
+void BindCreditCardToStatement(const CreditCard& credit_card,
+ sql::Statement* s);
+
+CreditCard* CreditCardFromStatement(const sql::Statement& s);
+
+bool AddAutofillProfileNamesToProfile(sql::Connection* db,
+ AutofillProfile* profile);
+
+bool AddAutofillProfileEmailsToProfile(sql::Connection* db,
+ AutofillProfile* profile);
+
+bool AddAutofillProfilePhonesToProfile(sql::Connection* db,
+ AutofillProfile* profile);
+
+bool AddAutofillProfileFaxesToProfile(sql::Connection* db,
+ AutofillProfile* profile);
+
+bool AddAutofillProfileNames(const AutofillProfile& profile,
+ sql::Connection* db);
+
+bool AddAutofillProfileEmails(const AutofillProfile& profile,
+ sql::Connection* db);
+
+bool AddAutofillProfilePhones(const AutofillProfile& profile,
+ AutofillPhoneType phone_type,
+ sql::Connection* db);
+
+bool AddAutofillProfilePieces(const AutofillProfile& profile,
+ sql::Connection* db);
+
+bool RemoveAutofillProfilePieces(const std::string& guid, sql::Connection* db);
+
+} // namespace autofill_util
+
+#endif // CHROME_BROWSER_WEBDATA_AUTOFILL_UTIL_H_
diff --git a/chrome/browser/webdata/keyword_table.cc b/chrome/browser/webdata/keyword_table.cc
new file mode 100644
index 0000000..f0d30e4
--- /dev/null
+++ b/chrome/browser/webdata/keyword_table.cc
@@ -0,0 +1,224 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/webdata/keyword_table.h"
+
+#include "app/sql/statement.h"
+#include "base/logging.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/history/history_database.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "googleurl/src/gurl.h"
+
+using base::Time;
+
+namespace {
+
+// ID of the url column in keywords.
+const int kUrlIdPosition = 16;
+
+// Keys used in the meta table.
+const char* kDefaultSearchProviderKey = "Default Search Provider ID";
+const char* kBuiltinKeywordVersion = "Builtin Keyword Version";
+
+void BindURLToStatement(const TemplateURL& url, sql::Statement* s) {
+ s->BindString(0, UTF16ToUTF8(url.short_name()));
+ s->BindString(1, UTF16ToUTF8(url.keyword()));
+ GURL favicon_url = url.GetFaviconURL();
+ if (!favicon_url.is_valid()) {
+ s->BindString(2, std::string());
+ } else {
+ s->BindString(2, history::HistoryDatabase::GURLToDatabaseURL(
+ url.GetFaviconURL()));
+ }
+ s->BindString(3, url.url() ? url.url()->url() : std::string());
+ s->BindInt(4, url.safe_for_autoreplace() ? 1 : 0);
+ if (!url.originating_url().is_valid()) {
+ s->BindString(5, std::string());
+ } else {
+ s->BindString(5, history::HistoryDatabase::GURLToDatabaseURL(
+ url.originating_url()));
+ }
+ s->BindInt64(6, url.date_created().ToTimeT());
+ s->BindInt(7, url.usage_count());
+ s->BindString(8, JoinString(url.input_encodings(), ';'));
+ s->BindInt(9, url.show_in_default_list() ? 1 : 0);
+ s->BindString(10, url.suggestions_url() ? url.suggestions_url()->url() :
+ std::string());
+ s->BindInt(11, url.prepopulate_id());
+ s->BindInt(12, url.autogenerate_keyword() ? 1 : 0);
+ s->BindInt(13, url.logo_id());
+ s->BindBool(14, url.created_by_policy());
+ s->BindString(15, url.instant_url() ? url.instant_url()->url() :
+ std::string());
+}
+} // anonymous namespace
+
+KeywordTable::~KeywordTable() {}
+
+bool KeywordTable::Init() {
+ if (!db_->DoesTableExist("keywords")) {
+ if (!db_->Execute("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,"
+ "logo_id INTEGER DEFAULT 0,"
+ "created_by_policy INTEGER DEFAULT 0,"
+ "instant_url VARCHAR)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool KeywordTable::AddKeyword(const TemplateURL& url) {
+ DCHECK(url.id());
+ // Be sure to change kUrlIdPosition if you add columns
+ sql::Statement s(db_->GetCachedStatement(SQL_FROM_HERE,
+ "INSERT INTO keywords "
+ "(short_name, keyword, favicon_url, url, safe_for_autoreplace, "
+ "originating_url, date_created, usage_count, input_encodings, "
+ "show_in_default_list, suggest_url, prepopulate_id, "
+ "autogenerate_keyword, logo_id, created_by_policy, instant_url, "
+ "id) VALUES "
+ "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ BindURLToStatement(url, &s);
+ s.BindInt64(kUrlIdPosition, url.id());
+ if (!s.Run()) {
+ NOTREACHED();
+ return false;
+ }
+ return true;
+}
+
+bool KeywordTable::RemoveKeyword(TemplateURLID id) {
+ DCHECK(id);
+ sql::Statement s(
+ db_->GetUniqueStatement("DELETE FROM keywords WHERE id = ?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ s.BindInt64(0, id);
+ return s.Run();
+}
+
+bool KeywordTable::GetKeywords(std::vector<TemplateURL*>* urls) {
+ sql::Statement s(db_->GetUniqueStatement(
+ "SELECT id, short_name, keyword, favicon_url, url, "
+ "safe_for_autoreplace, originating_url, date_created, "
+ "usage_count, input_encodings, show_in_default_list, "
+ "suggest_url, prepopulate_id, autogenerate_keyword, logo_id, "
+ "created_by_policy, instant_url "
+ "FROM keywords ORDER BY id ASC"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ while (s.Step()) {
+ TemplateURL* template_url = new TemplateURL();
+ template_url->set_id(s.ColumnInt64(0));
+
+ std::string tmp;
+ tmp = s.ColumnString(1);
+ DCHECK(!tmp.empty());
+ template_url->set_short_name(UTF8ToUTF16(tmp));
+
+ template_url->set_keyword(UTF8ToUTF16(s.ColumnString(2)));
+
+ tmp = s.ColumnString(3);
+ if (!tmp.empty())
+ template_url->SetFaviconURL(GURL(tmp));
+
+ template_url->SetURL(s.ColumnString(4), 0, 0);
+
+ template_url->set_safe_for_autoreplace(s.ColumnInt(5) == 1);
+
+ tmp = s.ColumnString(6);
+ if (!tmp.empty())
+ template_url->set_originating_url(GURL(tmp));
+
+ template_url->set_date_created(Time::FromTimeT(s.ColumnInt64(7)));
+
+ template_url->set_usage_count(s.ColumnInt(8));
+
+ std::vector<std::string> encodings;
+ base::SplitString(s.ColumnString(9), ';', &encodings);
+ template_url->set_input_encodings(encodings);
+
+ template_url->set_show_in_default_list(s.ColumnInt(10) == 1);
+
+ template_url->SetSuggestionsURL(s.ColumnString(11), 0, 0);
+
+ template_url->set_prepopulate_id(s.ColumnInt(12));
+
+ template_url->set_autogenerate_keyword(s.ColumnInt(13) == 1);
+
+ template_url->set_logo_id(s.ColumnInt(14));
+
+ template_url->set_created_by_policy(s.ColumnBool(15));
+
+ template_url->SetInstantURL(s.ColumnString(16), 0, 0);
+
+ urls->push_back(template_url);
+ }
+ return s.Succeeded();
+}
+
+bool KeywordTable::UpdateKeyword(const TemplateURL& url) {
+ DCHECK(url.id());
+ // Be sure to change kUrlIdPosition if you add columns
+ sql::Statement s(db_->GetUniqueStatement(
+ "UPDATE keywords "
+ "SET short_name=?, keyword=?, favicon_url=?, url=?, "
+ "safe_for_autoreplace=?, originating_url=?, date_created=?, "
+ "usage_count=?, input_encodings=?, show_in_default_list=?, "
+ "suggest_url=?, prepopulate_id=?, autogenerate_keyword=?, "
+ "logo_id=?, created_by_policy=?, instant_url=? WHERE id=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+ BindURLToStatement(url, &s);
+ s.BindInt64(kUrlIdPosition, url.id());
+ return s.Run();
+}
+
+bool KeywordTable::SetDefaultSearchProviderID(int64 id) {
+ return meta_table_->SetValue(kDefaultSearchProviderKey, id);
+}
+
+int64 KeywordTable::GetDefaulSearchProviderID() {
+ int64 value = 0;
+ meta_table_->GetValue(kDefaultSearchProviderKey, &value);
+ return value;
+}
+
+bool KeywordTable::SetBuitinKeywordVersion(int version) {
+ return meta_table_->SetValue(kBuiltinKeywordVersion, version);
+}
+
+int KeywordTable::GetBuitinKeywordVersion() {
+ int version = 0;
+ meta_table_->GetValue(kBuiltinKeywordVersion, &version);
+ return version;
+}
diff --git a/chrome/browser/webdata/keyword_table.h b/chrome/browser/webdata/keyword_table.h
new file mode 100644
index 0000000..5b43ea6
--- /dev/null
+++ b/chrome/browser/webdata/keyword_table.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEBDATA_KEYWORD_TABLE_H_
+#define CHROME_BROWSER_WEBDATA_KEYWORD_TABLE_H_
+#pragma once
+
+#include <vector>
+
+#include "chrome/browser/webdata/web_database_table.h"
+#include "chrome/browser/search_engines/template_url_id.h"
+
+class GURL;
+class TemplateURL;
+
+namespace base {
+class Time;
+}
+
+// This class manages the |keywords| MetaTable within the SQLite database
+// passed to the constructor. It expects the following schema:
+//
+// Note: The database stores time in seconds, UTC.
+//
+// keywords Most of the columns mirror that of a field in
+// TemplateURL. See TemplateURL for more details.
+// id
+// short_name
+// keyword
+// favicon_url
+// url
+// show_in_default_list
+// safe_for_autoreplace
+// originating_url
+// date_created This column was added after we allowed keywords.
+// Keywords created before we started tracking
+// creation date have a value of 0 for this.
+// usage_count
+// input_encodings Semicolon separated list of supported input
+// encodings, may be empty.
+// suggest_url
+// prepopulate_id See TemplateURL::prepopulate_id.
+// autogenerate_keyword
+// logo_id See TemplateURL::logo_id
+// created_by_policy See TemplateURL::created_by_policy. This was added
+// in version 26.
+// instant_url See TemplateURL::instant_url. This was added
+// in version 29.
+//
+class KeywordTable : public WebDatabaseTable {
+ public:
+ KeywordTable(sql::Connection* db, sql::MetaTable* meta_table)
+ : WebDatabaseTable(db, meta_table) {}
+ virtual ~KeywordTable();
+ virtual bool Init();
+ virtual bool IsSyncable() { return true; }
+
+ // Adds a new keyword, updating the id field on success.
+ // Returns true if successful.
+ bool AddKeyword(const TemplateURL& url);
+
+ // Removes the specified keyword.
+ // Returns true if successful.
+ bool RemoveKeyword(TemplateURLID id);
+
+ // Loads the keywords into the specified vector. It's up to the caller to
+ // delete the returned objects.
+ // Returns true on success.
+ bool GetKeywords(std::vector<TemplateURL*>* urls);
+
+ // Updates the database values for the specified url.
+ // Returns true on success.
+ bool UpdateKeyword(const TemplateURL& url);
+
+ // ID (TemplateURL->id) of the default search provider.
+ bool SetDefaultSearchProviderID(int64 id);
+ int64 GetDefaulSearchProviderID();
+
+ // Version of the built-in keywords.
+ bool SetBuitinKeywordVersion(int version);
+ int GetBuitinKeywordVersion();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(KeywordTable);
+};
+
+#endif // CHROME_BROWSER_WEBDATA_KEYWORD_TABLE_H_
diff --git a/chrome/browser/webdata/keyword_table_unittest.cc b/chrome/browser/webdata/keyword_table_unittest.cc
new file mode 100644
index 0000000..e2ae690
--- /dev/null
+++ b/chrome/browser/webdata/keyword_table_unittest.cc
@@ -0,0 +1,247 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/string_number_conversions.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/webdata/web_database.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+
+class KeywordTableTest : public testing::Test {
+ public:
+ KeywordTableTest() {}
+ virtual ~KeywordTableTest() {}
+
+ protected:
+ virtual void SetUp() {
+ PathService::Get(chrome::DIR_TEST_DATA, &file_);
+ const std::string test_db = "TestWebDatabase" +
+ base::Int64ToString(Time::Now().ToTimeT()) +
+ ".db";
+ file_ = file_.AppendASCII(test_db);
+ file_util::Delete(file_, false);
+ }
+
+ virtual void TearDown() {
+ file_util::Delete(file_, false);
+ }
+
+ static int64 GetID(const TemplateURL* url) {
+ return url->id();
+ }
+
+ static void SetID(int64 new_id, TemplateURL* url) {
+ url->set_id(new_id);
+ }
+
+ static void set_prepopulate_id(TemplateURL* url, int id) {
+ url->set_prepopulate_id(id);
+ }
+
+ static void set_logo_id(TemplateURL* url, int id) {
+ url->set_logo_id(id);
+ }
+
+ FilePath file_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(KeywordTableTest);
+};
+
+
+TEST_F(KeywordTableTest, Keywords) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ TemplateURL template_url;
+ template_url.set_short_name(ASCIIToUTF16("short_name"));
+ template_url.set_keyword(ASCIIToUTF16("keyword"));
+ GURL favicon_url("http://favicon.url/");
+ GURL originating_url("http://google.com/");
+ template_url.SetFaviconURL(favicon_url);
+ template_url.SetURL("http://url/", 0, 0);
+ template_url.set_safe_for_autoreplace(true);
+ Time created_time = Time::Now();
+ template_url.set_date_created(created_time);
+ template_url.set_show_in_default_list(true);
+ template_url.set_originating_url(originating_url);
+ template_url.set_usage_count(32);
+ template_url.add_input_encoding("UTF-8");
+ template_url.add_input_encoding("UTF-16");
+ set_prepopulate_id(&template_url, 10);
+ set_logo_id(&template_url, 1000);
+ template_url.set_created_by_policy(true);
+ template_url.SetInstantURL("http://instant/", 0, 0);
+ SetID(1, &template_url);
+
+ EXPECT_TRUE(db.GetKeywordTable()->AddKeyword(template_url));
+
+ std::vector<TemplateURL*> template_urls;
+ EXPECT_TRUE(db.GetKeywordTable()->GetKeywords(&template_urls));
+
+ EXPECT_EQ(1U, template_urls.size());
+ const TemplateURL* restored_url = template_urls.front();
+
+ EXPECT_EQ(template_url.short_name(), restored_url->short_name());
+
+ EXPECT_EQ(template_url.keyword(), restored_url->keyword());
+
+ EXPECT_FALSE(restored_url->autogenerate_keyword());
+
+ EXPECT_TRUE(favicon_url == restored_url->GetFaviconURL());
+
+ EXPECT_TRUE(restored_url->safe_for_autoreplace());
+
+ // The database stores time only at the resolution of a second.
+ EXPECT_EQ(created_time.ToTimeT(), restored_url->date_created().ToTimeT());
+
+ EXPECT_TRUE(restored_url->show_in_default_list());
+
+ EXPECT_EQ(GetID(&template_url), GetID(restored_url));
+
+ EXPECT_TRUE(originating_url == restored_url->originating_url());
+
+ EXPECT_EQ(32, restored_url->usage_count());
+
+ ASSERT_EQ(2U, restored_url->input_encodings().size());
+ EXPECT_EQ("UTF-8", restored_url->input_encodings()[0]);
+ EXPECT_EQ("UTF-16", restored_url->input_encodings()[1]);
+
+ EXPECT_EQ(10, restored_url->prepopulate_id());
+
+ EXPECT_EQ(1000, restored_url->logo_id());
+
+ EXPECT_TRUE(restored_url->created_by_policy());
+
+ ASSERT_TRUE(restored_url->instant_url());
+ EXPECT_EQ("http://instant/", restored_url->instant_url()->url());
+
+ EXPECT_TRUE(db.GetKeywordTable()->RemoveKeyword(restored_url->id()));
+
+ template_urls.clear();
+ EXPECT_TRUE(db.GetKeywordTable()->GetKeywords(&template_urls));
+
+ EXPECT_EQ(0U, template_urls.size());
+
+ delete restored_url;
+}
+
+TEST_F(KeywordTableTest, KeywordMisc) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ ASSERT_EQ(0, db.GetKeywordTable()->GetDefaulSearchProviderID());
+ ASSERT_EQ(0, db.GetKeywordTable()->GetBuitinKeywordVersion());
+
+ db.GetKeywordTable()->SetDefaultSearchProviderID(10);
+ db.GetKeywordTable()->SetBuitinKeywordVersion(11);
+
+ ASSERT_EQ(10, db.GetKeywordTable()->GetDefaulSearchProviderID());
+ ASSERT_EQ(11, db.GetKeywordTable()->GetBuitinKeywordVersion());
+}
+
+TEST_F(KeywordTableTest, UpdateKeyword) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ TemplateURL template_url;
+ template_url.set_short_name(ASCIIToUTF16("short_name"));
+ template_url.set_keyword(ASCIIToUTF16("keyword"));
+ GURL favicon_url("http://favicon.url/");
+ GURL originating_url("http://originating.url/");
+ template_url.SetFaviconURL(favicon_url);
+ template_url.SetURL("http://url/", 0, 0);
+ template_url.set_safe_for_autoreplace(true);
+ template_url.set_show_in_default_list(true);
+ template_url.SetSuggestionsURL("url2", 0, 0);
+ SetID(1, &template_url);
+
+ EXPECT_TRUE(db.GetKeywordTable()->AddKeyword(template_url));
+
+ GURL originating_url2("http://originating.url/");
+ template_url.set_originating_url(originating_url2);
+ template_url.set_autogenerate_keyword(true);
+ EXPECT_EQ(ASCIIToUTF16("url"), template_url.keyword());
+ template_url.add_input_encoding("Shift_JIS");
+ set_prepopulate_id(&template_url, 5);
+ set_logo_id(&template_url, 2000);
+ template_url.SetInstantURL("http://instant2/", 0, 0);
+ EXPECT_TRUE(db.GetKeywordTable()->UpdateKeyword(template_url));
+
+ std::vector<TemplateURL*> template_urls;
+ EXPECT_TRUE(db.GetKeywordTable()->GetKeywords(&template_urls));
+
+ EXPECT_EQ(1U, template_urls.size());
+ const TemplateURL* restored_url = template_urls.front();
+
+ EXPECT_EQ(template_url.short_name(), restored_url->short_name());
+
+ EXPECT_EQ(template_url.keyword(), restored_url->keyword());
+
+ EXPECT_TRUE(restored_url->autogenerate_keyword());
+
+ EXPECT_TRUE(favicon_url == restored_url->GetFaviconURL());
+
+ EXPECT_TRUE(restored_url->safe_for_autoreplace());
+
+ EXPECT_TRUE(restored_url->show_in_default_list());
+
+ EXPECT_EQ(GetID(&template_url), GetID(restored_url));
+
+ EXPECT_TRUE(originating_url2 == restored_url->originating_url());
+
+ ASSERT_EQ(1U, restored_url->input_encodings().size());
+ ASSERT_EQ("Shift_JIS", restored_url->input_encodings()[0]);
+
+ EXPECT_EQ(template_url.suggestions_url()->url(),
+ restored_url->suggestions_url()->url());
+
+ EXPECT_EQ(template_url.id(), restored_url->id());
+
+ EXPECT_EQ(template_url.prepopulate_id(), restored_url->prepopulate_id());
+
+ EXPECT_EQ(template_url.logo_id(), restored_url->logo_id());
+
+ EXPECT_TRUE(restored_url->instant_url());
+ EXPECT_EQ(template_url.instant_url()->url(),
+ restored_url->instant_url()->url());
+
+ delete restored_url;
+}
+
+TEST_F(KeywordTableTest, KeywordWithNoFavicon) {
+ WebDatabase db;
+
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ TemplateURL template_url;
+ template_url.set_short_name(ASCIIToUTF16("short_name"));
+ template_url.set_keyword(ASCIIToUTF16("keyword"));
+ template_url.SetURL("http://url/", 0, 0);
+ template_url.set_safe_for_autoreplace(true);
+ SetID(-100, &template_url);
+
+ EXPECT_TRUE(db.GetKeywordTable()->AddKeyword(template_url));
+
+ std::vector<TemplateURL*> template_urls;
+ EXPECT_TRUE(db.GetKeywordTable()->GetKeywords(&template_urls));
+ EXPECT_EQ(1U, template_urls.size());
+ const TemplateURL* restored_url = template_urls.front();
+
+ EXPECT_EQ(template_url.short_name(), restored_url->short_name());
+ EXPECT_EQ(template_url.keyword(), restored_url->keyword());
+ EXPECT_TRUE(!restored_url->GetFaviconURL().is_valid());
+ EXPECT_TRUE(restored_url->safe_for_autoreplace());
+ EXPECT_EQ(GetID(&template_url), GetID(restored_url));
+ delete restored_url;
+}
diff --git a/chrome/browser/webdata/web_data_service.cc b/chrome/browser/webdata/web_data_service.cc
index e334a03..8e4483c 100644
--- a/chrome/browser/webdata/web_data_service.cc
+++ b/chrome/browser/webdata/web_data_service.cc
@@ -661,7 +661,7 @@ int WebDataService::GetNextRequestHandle() {
void WebDataService::AddKeywordImpl(GenericRequest<TemplateURL>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- db_->AddKeyword(request->GetArgument());
+ db_->GetKeywordTable()->AddKeyword(request->GetArgument());
ScheduleCommit();
}
request->RequestComplete();
@@ -672,7 +672,7 @@ void WebDataService::RemoveKeywordImpl(
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
DCHECK(request->GetArgument());
- db_->RemoveKeyword(request->GetArgument());
+ db_->GetKeywordTable()->RemoveKeyword(request->GetArgument());
ScheduleCommit();
}
request->RequestComplete();
@@ -681,7 +681,7 @@ void WebDataService::RemoveKeywordImpl(
void WebDataService::UpdateKeywordImpl(GenericRequest<TemplateURL>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- if (!db_->UpdateKeyword(request->GetArgument())) {
+ if (!db_->GetKeywordTable()->UpdateKeyword(request->GetArgument())) {
NOTREACHED();
return;
}
@@ -694,9 +694,11 @@ void WebDataService::GetKeywordsImpl(WebDataRequest* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
WDKeywordsResult result;
- db_->GetKeywords(&result.keywords);
- result.default_search_provider_id = db_->GetDefaulSearchProviderID();
- result.builtin_keyword_version = db_->GetBuitinKeywordVersion();
+ db_->GetKeywordTable()->GetKeywords(&result.keywords);
+ result.default_search_provider_id =
+ db_->GetKeywordTable()->GetDefaulSearchProviderID();
+ result.builtin_keyword_version =
+ db_->GetKeywordTable()->GetBuitinKeywordVersion();
request->SetResult(
new WDResult<WDKeywordsResult>(KEYWORDS_RESULT, result));
}
@@ -707,7 +709,8 @@ void WebDataService::SetDefaultSearchProviderImpl(
GenericRequest<TemplateURLID>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- if (!db_->SetDefaultSearchProviderID(request->GetArgument())) {
+ if (!db_->GetKeywordTable()->SetDefaultSearchProviderID(
+ request->GetArgument())) {
NOTREACHED();
return;
}
@@ -720,7 +723,8 @@ void WebDataService::SetBuiltinKeywordVersionImpl(
GenericRequest<int>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- if (!db_->SetBuitinKeywordVersion(request->GetArgument())) {
+ if (!db_->GetKeywordTable()->SetBuitinKeywordVersion(
+ request->GetArgument())) {
NOTREACHED();
return;
}
@@ -919,7 +923,7 @@ void WebDataService::AddFormElementsImpl(
const std::vector<FormField>& form_fields = request->GetArgument();
if (db_ && !request->IsCancelled()) {
AutofillChangeList changes;
- if (!db_->AddFormFieldValues(form_fields, &changes)) {
+ if (!db_->GetAutofillTable()->AddFormFieldValues(form_fields, &changes)) {
NOTREACHED();
return;
}
@@ -944,7 +948,8 @@ void WebDataService::GetFormValuesForElementNameImpl(WebDataRequest* request,
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<string16> values;
- db_->GetFormValuesForElementName(name, prefix, &values, limit);
+ db_->GetAutofillTable()->GetFormValuesForElementName(
+ name, prefix, &values, limit);
request->SetResult(
new WDResult<std::vector<string16> >(AUTOFILL_VALUE_RESULT, values));
}
@@ -956,9 +961,8 @@ void WebDataService::RemoveFormElementsAddedBetweenImpl(
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
AutofillChangeList changes;
- if (db_->RemoveFormElementsAddedBetween(request->GetArgument1(),
- request->GetArgument2(),
- &changes)) {
+ if (db_->GetAutofillTable()->RemoveFormElementsAddedBetween(
+ request->GetArgument1(), request->GetArgument2(), &changes)) {
if (!changes.empty()) {
request->SetResult(
new WDResult<AutofillChangeList>(AUTOFILL_CHANGES, changes));
@@ -984,7 +988,7 @@ void WebDataService::RemoveFormValueForElementNameImpl(
const string16& name = request->GetArgument1();
const string16& value = request->GetArgument2();
- if (db_->RemoveFormElement(name, value)) {
+ if (db_->GetAutofillTable()->RemoveFormElement(name, value)) {
AutofillChangeList changes;
changes.push_back(AutofillChange(AutofillChange::REMOVE,
AutofillKey(name, value)));
@@ -1007,7 +1011,7 @@ void WebDataService::AddAutofillProfileImpl(
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
const AutofillProfile& profile = request->GetArgument();
- if (!db_->AddAutofillProfile(profile)) {
+ if (!db_->GetAutofillTable()->AddAutofillProfile(profile)) {
NOTREACHED();
return;
}
@@ -1034,13 +1038,14 @@ void WebDataService::UpdateAutofillProfileImpl(
// valid to try to update a missing profile. We simply drop the write and
// the caller will detect this on the next refresh.
AutofillProfile* original_profile = NULL;
- if (!db_->GetAutofillProfile(profile.guid(), &original_profile)) {
+ if (!db_->GetAutofillTable()->GetAutofillProfile(profile.guid(),
+ &original_profile)) {
request->RequestComplete();
return;
}
scoped_ptr<AutofillProfile> scoped_profile(original_profile);
- if (!db_->UpdateAutofillProfileMulti(profile)) {
+ if (!db_->GetAutofillTable()->UpdateAutofillProfileMulti(profile)) {
NOTREACHED();
return;
}
@@ -1064,13 +1069,13 @@ void WebDataService::RemoveAutofillProfileImpl(
std::string guid = request->GetArgument();
AutofillProfile* profile = NULL;
- if (!db_->GetAutofillProfile(guid, &profile)) {
+ if (!db_->GetAutofillTable()->GetAutofillProfile(guid, &profile)) {
NOTREACHED();
return;
}
scoped_ptr<AutofillProfile> scoped_profile(profile);
- if (!db_->RemoveAutofillProfile(guid)) {
+ if (!db_->GetAutofillTable()->RemoveAutofillProfile(guid)) {
NOTREACHED();
return;
}
@@ -1090,7 +1095,7 @@ void WebDataService::GetAutofillProfilesImpl(WebDataRequest* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<AutofillProfile*> profiles;
- db_->GetAutofillProfiles(&profiles);
+ db_->GetAutofillTable()->GetAutofillProfiles(&profiles);
request->SetResult(
new WDResult<std::vector<AutofillProfile*> >(AUTOFILL_PROFILES_RESULT,
profiles));
@@ -1105,7 +1110,7 @@ void WebDataService::EmptyMigrationTrashImpl(
bool notify_sync = request->GetArgument();
if (notify_sync) {
std::vector<std::string> guids;
- if (!db_->GetAutofillProfilesInTrash(&guids)) {
+ if (!db_->GetAutofillTable()->GetAutofillProfilesInTrash(&guids)) {
NOTREACHED();
return;
}
@@ -1125,7 +1130,7 @@ void WebDataService::EmptyMigrationTrashImpl(
// update notifications as well.
if (!guids.empty()) {
std::vector<AutofillProfile*> profiles;
- db_->GetAutofillProfiles(&profiles);
+ db_->GetAutofillTable()->GetAutofillProfiles(&profiles);
for (std::vector<AutofillProfile*>::const_iterator
iter = profiles.begin();
iter != profiles.end(); ++iter) {
@@ -1140,7 +1145,7 @@ void WebDataService::EmptyMigrationTrashImpl(
}
}
- if (!db_->EmptyAutofillProfilesTrash()) {
+ if (!db_->GetAutofillTable()->EmptyAutofillProfilesTrash()) {
NOTREACHED();
return;
}
@@ -1154,7 +1159,7 @@ void WebDataService::AddCreditCardImpl(
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
const CreditCard& credit_card = request->GetArgument();
- if (!db_->AddCreditCard(credit_card)) {
+ if (!db_->GetAutofillTable()->AddCreditCard(credit_card)) {
NOTREACHED();
return;
}
@@ -1180,13 +1185,14 @@ void WebDataService::UpdateCreditCardImpl(
// It is currently valid to try to update a missing profile. We simply drop
// the write and the caller will detect this on the next refresh.
CreditCard* original_credit_card = NULL;
- if (!db_->GetCreditCard(credit_card.guid(), &original_credit_card)) {
+ if (!db_->GetAutofillTable()->GetCreditCard(credit_card.guid(),
+ &original_credit_card)) {
request->RequestComplete();
return;
}
scoped_ptr<CreditCard> scoped_credit_card(original_credit_card);
- if (!db_->UpdateCreditCard(credit_card)) {
+ if (!db_->GetAutofillTable()->UpdateCreditCard(credit_card)) {
NOTREACHED();
return;
}
@@ -1208,7 +1214,7 @@ void WebDataService::RemoveCreditCardImpl(
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::string guid = request->GetArgument();
- if (!db_->RemoveCreditCard(guid)) {
+ if (!db_->GetAutofillTable()->RemoveCreditCard(guid)) {
NOTREACHED();
return;
}
@@ -1229,7 +1235,7 @@ void WebDataService::GetCreditCardsImpl(WebDataRequest* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
std::vector<CreditCard*> credit_cards;
- db_->GetCreditCards(&credit_cards);
+ db_->GetAutofillTable()->GetCreditCards(&credit_cards);
request->SetResult(
new WDResult<std::vector<CreditCard*> >(AUTOFILL_CREDITCARDS_RESULT,
credit_cards));
@@ -1241,7 +1247,8 @@ void WebDataService::RemoveAutofillProfilesAndCreditCardsModifiedBetweenImpl(
GenericRequest2<Time, Time>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- if (db_->RemoveAutofillProfilesAndCreditCardsModifiedBetween(
+ if (db_->GetAutofillTable()->
+ RemoveAutofillProfilesAndCreditCardsModifiedBetween(
request->GetArgument1(),
request->GetArgument2())) {
// Note: It is the caller's responsibility to post notifications for any
diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc
index ea6b6ec..5fa4413 100644
--- a/chrome/browser/webdata/web_database.cc
+++ b/chrome/browser/webdata/web_database.cc
@@ -12,26 +12,19 @@
#include "app/sql/statement.h"
#include "app/sql/transaction.h"
#include "base/string_number_conversions.h"
-#include "base/string_split.h"
-#include "base/string_util.h"
-#include "base/tuple.h"
-#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_country.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/autofill_type.h"
-#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
#include "chrome/browser/history/history_database.h"
#include "chrome/browser/password_manager/encryptor.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/webdata/autofill_change.h"
+#include "chrome/browser/webdata/autofill_util.h"
+#include "chrome/browser/webdata/keyword_table.h"
#include "chrome/common/guid.h"
#include "content/common/notification_service.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/codec/png_codec.h"
-#include "webkit/glue/form_field.h"
#include "webkit/glue/password_form.h"
// Encryptor is now in place for Windows and Mac. The Linux implementation
@@ -40,46 +33,12 @@
// details.
// For details on the Linux work see:
// http://crbug.com/25404
-
-using webkit_glue::FormField;
-using webkit_glue::PasswordForm;
-
-// Constants for the |autofill_profile_phones| |type| column.
-enum AutofillPhoneType {
- kAutofillPhoneNumber = 0,
- kAutofillFaxNumber = 1
-};
-
+//
////////////////////////////////////////////////////////////////////////////////
//
// Schema
// Note: The database stores time in seconds, UTC.
//
-// keywords Most of the columns mirror that of a field in
-// TemplateURL. See TemplateURL for more details.
-// id
-// short_name
-// keyword
-// favicon_url
-// url
-// show_in_default_list
-// safe_for_autoreplace
-// originating_url
-// date_created This column was added after we allowed keywords.
-// Keywords created before we started tracking
-// creation date have a value of 0 for this.
-// usage_count
-// input_encodings Semicolon separated list of supported input
-// encodings, may be empty.
-// suggest_url
-// prepopulate_id See TemplateURL::prepopulate_id.
-// autogenerate_keyword
-// logo_id See TemplateURL::logo_id
-// created_by_policy See TemplateURL::created_by_policy. This was added
-// in version 26.
-// instant_url See TemplateURL::instant_url. This was added
-// in version 29.
-//
// logins
// origin_url
// action_url
@@ -98,87 +57,6 @@ enum AutofillPhoneType {
// remember'
// passwords for this site.
//
-// autofill
-// 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.
-// 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.
-//
-// guid A guid string to uniquely identify the profile.
-// Added in version 31.
-// company_name
-// address_line_1
-// address_line_2
-// city
-// state
-// zipcode
-// country The country name. Deprecated, should be removed once
-// the stable channel reaches version 11.
-// country_code
-// date_modified The date on which this profile was last modified.
-// Added in version 30.
-//
-// autofill_profile_names
-// This table contains the multi-valued name fields
-// associated with a profile.
-//
-// guid The guid string that identifies the profile to which
-// the name belongs.
-// first_name
-// middle_name
-// last_name
-//
-// autofill_profile_emails
-// This table contains the multi-valued email fields
-// associated with a profile.
-//
-// guid The guid string that identifies the profile to which
-// the email belongs.
-// email
-//
-// autofill_profile_phones
-// This table contains the multi-valued phone fields
-// associated with a profile.
-//
-// guid The guid string that identifies the profile to which
-// the phone or fax number belongs.
-// type An integer constant designating either phone or fax type
-// of the number.
-// number
-//
-// autofill_profiles_trash
-// This table contains guids of "trashed" autofill
-// profiles. When a profile is removed its guid is added
-// to this table so that Sync can perform deferred removal.
-//
-// guid The guid string that identifies the trashed profile.
-//
-// credit_cards This table contains credit card data added by the user
-// with the Autofill dialog. Most of the columns are
-// standard entries in a credit card form.
-//
-// guid A guid string to uniquely identify the profile.
-// Added in version 31.
-// name_on_card
-// expiration_month
-// expiration_year
-// card_number_encrypted Stores encrypted credit card number.
-// date_modified The date on which this entry was last modified.
-// Added in version 30.
-//
// web_app_icons
// url URL of the web app.
// width Width of the image.
@@ -192,59 +70,16 @@ enum AutofillPhoneType {
////////////////////////////////////////////////////////////////////////////////
using base::Time;
+using webkit_glue::PasswordForm;
namespace {
-typedef std::vector<Tuple3<int64, string16, string16> > AutofillElementList;
-
// Current version number. Note: when changing the current version number,
// corresponding changes must happen in the unit tests, and new migration test
// added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
const int kCurrentVersionNumber = 36;
const int kCompatibleVersionNumber = 36;
-// ID of the url column in keywords.
-const int kUrlIdPosition = 16;
-
-// Keys used in the meta table.
-const char* kDefaultSearchProviderKey = "Default Search Provider ID";
-const char* kBuiltinKeywordVersion = "Builtin Keyword Version";
-
-// The maximum length allowed for form data.
-const size_t kMaxDataLength = 1024;
-
-void BindURLToStatement(const TemplateURL& url, sql::Statement* s) {
- s->BindString(0, UTF16ToUTF8(url.short_name()));
- s->BindString(1, UTF16ToUTF8(url.keyword()));
- GURL favicon_url = url.GetFaviconURL();
- if (!favicon_url.is_valid()) {
- s->BindString(2, std::string());
- } else {
- s->BindString(2, history::HistoryDatabase::GURLToDatabaseURL(
- url.GetFaviconURL()));
- }
- s->BindString(3, url.url() ? url.url()->url() : std::string());
- s->BindInt(4, url.safe_for_autoreplace() ? 1 : 0);
- if (!url.originating_url().is_valid()) {
- s->BindString(5, std::string());
- } else {
- s->BindString(5, history::HistoryDatabase::GURLToDatabaseURL(
- url.originating_url()));
- }
- s->BindInt64(6, url.date_created().ToTimeT());
- s->BindInt(7, url.usage_count());
- s->BindString(8, JoinString(url.input_encodings(), ';'));
- s->BindInt(9, url.show_in_default_list() ? 1 : 0);
- s->BindString(10, url.suggestions_url() ? url.suggestions_url()->url() :
- std::string());
- s->BindInt(11, url.prepopulate_id());
- s->BindInt(12, url.autogenerate_keyword() ? 1 : 0);
- s->BindInt(13, url.logo_id());
- s->BindBool(14, url.created_by_policy());
- s->BindString(15, url.instant_url() ? url.instant_url()->url() :
- std::string());
-}
-
void InitPasswordFormFromStatement(PasswordForm* form, sql::Statement* s) {
std::string tmp;
string16 decrypted_password;
@@ -277,344 +112,6 @@ void InitPasswordFormFromStatement(PasswordForm* form, sql::Statement* s) {
form->scheme = static_cast<PasswordForm::Scheme>(scheme_int);
}
-// TODO(jhawkins): This is a temporary stop-gap measure designed to prevent
-// a malicious site from DOS'ing the browser with extremely large profile
-// data. The correct solution is to parse this data asynchronously.
-// See http://crbug.com/49332.
-string16 LimitDataSize(const string16& data) {
- if (data.size() > kMaxDataLength)
- return data.substr(0, kMaxDataLength);
-
- return data;
-}
-
-void BindAutofillProfileToStatement(const AutofillProfile& profile,
- sql::Statement* s) {
- DCHECK(guid::IsValidGUID(profile.guid()));
- s->BindString(0, profile.guid());
-
- string16 text = profile.GetInfo(COMPANY_NAME);
- s->BindString16(1, LimitDataSize(text));
- text = profile.GetInfo(ADDRESS_HOME_LINE1);
- s->BindString16(2, LimitDataSize(text));
- text = profile.GetInfo(ADDRESS_HOME_LINE2);
- s->BindString16(3, LimitDataSize(text));
- text = profile.GetInfo(ADDRESS_HOME_CITY);
- s->BindString16(4, LimitDataSize(text));
- text = profile.GetInfo(ADDRESS_HOME_STATE);
- s->BindString16(5, LimitDataSize(text));
- text = profile.GetInfo(ADDRESS_HOME_ZIP);
- s->BindString16(6, LimitDataSize(text));
- text = profile.GetInfo(ADDRESS_HOME_COUNTRY);
- s->BindString16(7, LimitDataSize(text));
- std::string country_code = profile.CountryCode();
- s->BindString(8, country_code);
- s->BindInt64(9, Time::Now().ToTimeT());
-}
-
-AutofillProfile* AutofillProfileFromStatement(const sql::Statement& s) {
- AutofillProfile* profile = new AutofillProfile;
- profile->set_guid(s.ColumnString(0));
- DCHECK(guid::IsValidGUID(profile->guid()));
-
- profile->SetInfo(COMPANY_NAME, s.ColumnString16(1));
- profile->SetInfo(ADDRESS_HOME_LINE1, s.ColumnString16(2));
- profile->SetInfo(ADDRESS_HOME_LINE2, s.ColumnString16(3));
- profile->SetInfo(ADDRESS_HOME_CITY, s.ColumnString16(4));
- profile->SetInfo(ADDRESS_HOME_STATE, s.ColumnString16(5));
- profile->SetInfo(ADDRESS_HOME_ZIP, s.ColumnString16(6));
- // Intentionally skip column 7, which stores the localized country name.
- profile->SetCountryCode(s.ColumnString(8));
- // Intentionally skip column 9, which stores the profile's modification date.
-
- return profile;
-}
-
-bool AddAutofillProfileNamesToProfile(sql::Connection* db,
- AutofillProfile* profile) {
- sql::Statement s(db->GetUniqueStatement(
- "SELECT guid, first_name, middle_name, last_name "
- "FROM autofill_profile_names "
- "WHERE guid=?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s.BindString(0, profile->guid());
-
- std::vector<string16> first_names;
- std::vector<string16> middle_names;
- std::vector<string16> last_names;
- while (s.Step()) {
- DCHECK_EQ(profile->guid(), s.ColumnString(0));
- first_names.push_back(s.ColumnString16(1));
- middle_names.push_back(s.ColumnString16(2));
- last_names.push_back(s.ColumnString16(3));
- }
- profile->SetMultiInfo(NAME_FIRST, first_names);
- profile->SetMultiInfo(NAME_MIDDLE, middle_names);
- profile->SetMultiInfo(NAME_LAST, last_names);
- return true;
-}
-
-bool AddAutofillProfileEmailsToProfile(sql::Connection* db,
- AutofillProfile* profile) {
- sql::Statement s(db->GetUniqueStatement(
- "SELECT guid, email "
- "FROM autofill_profile_emails "
- "WHERE guid=?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s.BindString(0, profile->guid());
-
- std::vector<string16> emails;
- while (s.Step()) {
- DCHECK_EQ(profile->guid(), s.ColumnString(0));
- emails.push_back(s.ColumnString16(1));
- }
- profile->SetMultiInfo(EMAIL_ADDRESS, emails);
- return true;
-}
-
-bool AddAutofillProfilePhonesToProfile(sql::Connection* db,
- AutofillProfile* profile) {
- sql::Statement s(db->GetUniqueStatement(
- "SELECT guid, type, number "
- "FROM autofill_profile_phones "
- "WHERE guid=? AND type=?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s.BindString(0, profile->guid());
- s.BindInt(1, kAutofillPhoneNumber);
-
- std::vector<string16> numbers;
- while (s.Step()) {
- DCHECK_EQ(profile->guid(), s.ColumnString(0));
- numbers.push_back(s.ColumnString16(2));
- }
- profile->SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, numbers);
- return true;
-}
-
-bool AddAutofillProfileFaxesToProfile(sql::Connection* db,
- AutofillProfile* profile) {
- sql::Statement s(db->GetUniqueStatement(
- "SELECT guid, type, number "
- "FROM autofill_profile_phones "
- "WHERE guid=? AND type=?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s.BindString(0, profile->guid());
- s.BindInt(1, kAutofillFaxNumber);
-
- std::vector<string16> numbers;
- while (s.Step()) {
- DCHECK_EQ(profile->guid(), s.ColumnString(0));
- numbers.push_back(s.ColumnString16(2));
- }
- profile->SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, numbers);
- return true;
-}
-
-void BindCreditCardToStatement(const CreditCard& credit_card,
- sql::Statement* s) {
- DCHECK(guid::IsValidGUID(credit_card.guid()));
- s->BindString(0, credit_card.guid());
-
- string16 text = credit_card.GetInfo(CREDIT_CARD_NAME);
- s->BindString16(1, LimitDataSize(text));
- text = credit_card.GetInfo(CREDIT_CARD_EXP_MONTH);
- s->BindString16(2, LimitDataSize(text));
- text = credit_card.GetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR);
- s->BindString16(3, LimitDataSize(text));
- text = credit_card.GetInfo(CREDIT_CARD_NUMBER);
- std::string encrypted_data;
- Encryptor::EncryptString16(text, &encrypted_data);
- s->BindBlob(4, encrypted_data.data(),
- static_cast<int>(encrypted_data.length()));
- s->BindInt64(5, Time::Now().ToTimeT());
-}
-
-CreditCard* CreditCardFromStatement(const sql::Statement& s) {
- CreditCard* credit_card = new CreditCard;
-
- credit_card->set_guid(s.ColumnString(0));
- DCHECK(guid::IsValidGUID(credit_card->guid()));
-
- credit_card->SetInfo(CREDIT_CARD_NAME, s.ColumnString16(1));
- credit_card->SetInfo(CREDIT_CARD_EXP_MONTH,
- s.ColumnString16(2));
- credit_card->SetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- s.ColumnString16(3));
- int encrypted_number_len = s.ColumnByteLength(4);
- string16 credit_card_number;
- if (encrypted_number_len) {
- std::string encrypted_number;
- encrypted_number.resize(encrypted_number_len);
- memcpy(&encrypted_number[0], s.ColumnBlob(4), encrypted_number_len);
- Encryptor::DecryptString16(encrypted_number, &credit_card_number);
- }
- credit_card->SetInfo(CREDIT_CARD_NUMBER, credit_card_number);
- // Intentionally skip column 5, which stores the modification date.
-
- return credit_card;
-}
-
-bool AddAutofillProfileNames(const AutofillProfile& profile,
- sql::Connection* db) {
- std::vector<string16> first_names;
- profile.GetMultiInfo(NAME_FIRST, &first_names);
- std::vector<string16> middle_names;
- profile.GetMultiInfo(NAME_MIDDLE, &middle_names);
- std::vector<string16> last_names;
- profile.GetMultiInfo(NAME_LAST, &last_names);
- DCHECK_EQ(first_names.size(), middle_names.size());
- DCHECK_EQ(middle_names.size(), last_names.size());
-
- for (size_t i = 0; i < first_names.size(); ++i) {
- // Add the new name.
- sql::Statement s(db->GetUniqueStatement(
- "INSERT INTO autofill_profile_names"
- " (guid, first_name, middle_name, last_name) "
- "VALUES (?,?,?,?)"));
- if (!s) {
- NOTREACHED();
- return false;
- }
- s.BindString(0, profile.guid());
- s.BindString16(1, first_names[i]);
- s.BindString16(2, middle_names[i]);
- s.BindString16(3, last_names[i]);
-
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
-bool AddAutofillProfileEmails(const AutofillProfile& profile,
- sql::Connection* db) {
- std::vector<string16> emails;
- profile.GetMultiInfo(EMAIL_ADDRESS, &emails);
-
- for (size_t i = 0; i < emails.size(); ++i) {
- // Add the new email.
- sql::Statement s(db->GetUniqueStatement(
- "INSERT INTO autofill_profile_emails"
- " (guid, email) "
- "VALUES (?,?)"));
- if (!s) {
- NOTREACHED();
- return false;
- }
- s.BindString(0, profile.guid());
- s.BindString16(1, emails[i]);
-
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
-bool AddAutofillProfilePhones(const AutofillProfile& profile,
- AutofillPhoneType phone_type,
- sql::Connection* db) {
- AutofillFieldType field_type;
- if (phone_type == kAutofillPhoneNumber) {
- field_type = PHONE_HOME_WHOLE_NUMBER;
- } else if (phone_type == kAutofillFaxNumber) {
- field_type = PHONE_FAX_WHOLE_NUMBER;
- } else {
- NOTREACHED();
- return false;
- }
-
- std::vector<string16> numbers;
- profile.GetMultiInfo(field_type, &numbers);
-
- for (size_t i = 0; i < numbers.size(); ++i) {
- // Add the new number.
- sql::Statement s(db->GetUniqueStatement(
- "INSERT INTO autofill_profile_phones"
- " (guid, type, number) "
- "VALUES (?,?,?)"));
- if (!s) {
- NOTREACHED();
- return false;
- }
- s.BindString(0, profile.guid());
- s.BindInt(1, phone_type);
- s.BindString16(2, numbers[i]);
-
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
-bool AddAutofillProfilePieces(const AutofillProfile& profile,
- sql::Connection* db) {
- if (!AddAutofillProfileNames(profile, db))
- return false;
-
- if (!AddAutofillProfileEmails(profile, db))
- return false;
-
- if (!AddAutofillProfilePhones(profile, kAutofillPhoneNumber, db))
- return false;
-
- if (!AddAutofillProfilePhones(profile, kAutofillFaxNumber, db))
- return false;
-
- return true;
-}
-
-bool RemoveAutofillProfilePieces(const std::string& guid, sql::Connection* db) {
- sql::Statement s1(db->GetUniqueStatement(
- "DELETE FROM autofill_profile_names WHERE guid = ?"));
- if (!s1) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s1.BindString(0, guid);
- if (!s1.Run())
- return false;
-
- sql::Statement s2(db->GetUniqueStatement(
- "DELETE FROM autofill_profile_emails WHERE guid = ?"));
- if (!s2) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s2.BindString(0, guid);
- if (!s2.Run())
- return false;
-
- sql::Statement s3(db->GetUniqueStatement(
- "DELETE FROM autofill_profile_phones WHERE guid = ?"));
- if (!s3) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s3.BindString(0, guid);
- return s3.Run();
-}
-
// TODO(dhollowa): Find a common place for this. It is duplicated in
// personal_data_manager.cc.
template<typename T>
@@ -624,11 +121,9 @@ T* address_of(T& v) {
} // namespace
-WebDatabase::WebDatabase() {
-}
+WebDatabase::WebDatabase() {}
-WebDatabase::~WebDatabase() {
-}
+WebDatabase::~WebDatabase() {}
void WebDatabase::BeginTransaction() {
db_.BeginTransaction();
@@ -638,6 +133,14 @@ void WebDatabase::CommitTransaction() {
db_.CommitTransaction();
}
+AutofillTable* WebDatabase::GetAutofillTable() {
+ return autofill_table_.get();
+}
+
+KeywordTable* WebDatabase::GetKeywordTable() {
+ return keyword_table_.get();
+}
+
sql::InitStatus WebDatabase::Init(const FilePath& db_name) {
// When running in unit tests, there is already a NotificationService object.
// Since only one can exist at a time per thread, check first.
@@ -676,13 +179,14 @@ sql::InitStatus WebDatabase::Init(const FilePath& db_name) {
return sql::INIT_TOO_NEW;
}
+ // Create the tables.
+ autofill_table_.reset(new AutofillTable(&db_, &meta_table_));
+ keyword_table_.reset(new KeywordTable(&db_, &meta_table_));
+
// Initialize the tables.
- if (!InitKeywordsTable() || !InitLoginsTable() || !InitWebAppIconsTable() ||
- !InitWebAppsTable() || !InitAutofillTable() ||
- !InitAutofillDatesTable() || !InitAutofillProfilesTable() ||
- !InitAutofillProfileNamesTable() || !InitAutofillProfileEmailsTable() ||
- !InitAutofillProfilePhonesTable() || !InitAutofillProfileTrashTable() ||
- !InitCreditCardsTable() || !InitTokenServiceTable()) {
+ if (!keyword_table_->Init() || !autofill_table_->Init() ||
+ !InitLoginsTable() || !InitWebAppIconsTable() || !InitWebAppsTable() ||
+ !InitTokenServiceTable()) {
LOG(WARNING) << "Unable to initialize the web database.";
return sql::INIT_FAILURE;
}
@@ -849,33 +353,6 @@ bool WebDatabase::GetAllTokens(std::map<std::string, std::string>* tokens) {
return true;
}
-bool WebDatabase::InitKeywordsTable() {
- if (!db_.DoesTableExist("keywords")) {
- if (!db_.Execute("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,"
- "logo_id INTEGER DEFAULT 0,"
- "created_by_policy INTEGER DEFAULT 0,"
- "instant_url VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
bool WebDatabase::InitLoginsTable() {
if (!db_.DoesTableExist("logins")) {
if (!db_.Execute("CREATE TABLE logins ("
@@ -927,134 +404,6 @@ bool WebDatabase::InitLoginsTable() {
return true;
}
-bool WebDatabase::InitAutofillTable() {
- if (!db_.DoesTableExist("autofill")) {
- if (!db_.Execute("CREATE TABLE autofill ("
- "name VARCHAR, "
- "value VARCHAR, "
- "value_lower VARCHAR, "
- "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;
- }
- }
- return true;
-}
-
-bool WebDatabase::InitAutofillDatesTable() {
- 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 WebDatabase::InitAutofillProfilesTable() {
- if (!db_.DoesTableExist("autofill_profiles")) {
- if (!db_.Execute("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)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
-bool WebDatabase::InitAutofillProfileNamesTable() {
- if (!db_.DoesTableExist("autofill_profile_names")) {
- if (!db_.Execute("CREATE TABLE autofill_profile_names ( "
- "guid VARCHAR, "
- "first_name VARCHAR, "
- "middle_name VARCHAR, "
- "last_name VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
-bool WebDatabase::InitAutofillProfileEmailsTable() {
- if (!db_.DoesTableExist("autofill_profile_emails")) {
- if (!db_.Execute("CREATE TABLE autofill_profile_emails ( "
- "guid VARCHAR, "
- "email VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
-bool WebDatabase::InitAutofillProfilePhonesTable() {
- if (!db_.DoesTableExist("autofill_profile_phones")) {
- if (!db_.Execute("CREATE TABLE autofill_profile_phones ( "
- "guid VARCHAR, "
- "type INTEGER DEFAULT 0, "
- "number VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
-bool WebDatabase::InitAutofillProfileTrashTable() {
- if (!db_.DoesTableExist("autofill_profiles_trash")) {
- if (!db_.Execute("CREATE TABLE autofill_profiles_trash ( "
- "guid VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
-bool WebDatabase::InitCreditCardsTable() {
- if (!db_.DoesTableExist("credit_cards")) {
- if (!db_.Execute("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)")) {
- NOTREACHED();
- return false;
- }
- }
-
- return true;
-}
-
bool WebDatabase::InitWebAppIconsTable() {
if (!db_.DoesTableExist("web_app_icons")) {
if (!db_.Execute("CREATE TABLE web_app_icons ("
@@ -1097,142 +446,6 @@ bool WebDatabase::InitTokenServiceTable() {
return true;
}
-bool WebDatabase::AddKeyword(const TemplateURL& url) {
- DCHECK(url.id());
- // Be sure to change kUrlIdPosition if you add columns
- sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
- "INSERT INTO keywords "
- "(short_name, keyword, favicon_url, url, safe_for_autoreplace, "
- "originating_url, date_created, usage_count, input_encodings, "
- "show_in_default_list, suggest_url, prepopulate_id, "
- "autogenerate_keyword, logo_id, created_by_policy, instant_url, "
- "id) VALUES "
- "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- BindURLToStatement(url, &s);
- s.BindInt64(kUrlIdPosition, url.id());
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
- return true;
-}
-
-bool WebDatabase::RemoveKeyword(TemplateURLID id) {
- DCHECK(id);
- sql::Statement s(db_.GetUniqueStatement("DELETE FROM keywords WHERE id = ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s.BindInt64(0, id);
- return s.Run();
-}
-
-bool WebDatabase::GetKeywords(std::vector<TemplateURL*>* urls) {
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT id, short_name, keyword, favicon_url, url, "
- "safe_for_autoreplace, originating_url, date_created, "
- "usage_count, input_encodings, show_in_default_list, "
- "suggest_url, prepopulate_id, autogenerate_keyword, logo_id, "
- "created_by_policy, instant_url "
- "FROM keywords ORDER BY id ASC"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- while (s.Step()) {
- TemplateURL* template_url = new TemplateURL();
- template_url->set_id(s.ColumnInt64(0));
-
- std::string tmp;
- tmp = s.ColumnString(1);
- DCHECK(!tmp.empty());
- template_url->set_short_name(UTF8ToUTF16(tmp));
-
- template_url->set_keyword(UTF8ToUTF16(s.ColumnString(2)));
-
- tmp = s.ColumnString(3);
- if (!tmp.empty())
- template_url->SetFaviconURL(GURL(tmp));
-
- template_url->SetURL(s.ColumnString(4), 0, 0);
-
- template_url->set_safe_for_autoreplace(s.ColumnInt(5) == 1);
-
- tmp = s.ColumnString(6);
- if (!tmp.empty())
- template_url->set_originating_url(GURL(tmp));
-
- template_url->set_date_created(Time::FromTimeT(s.ColumnInt64(7)));
-
- template_url->set_usage_count(s.ColumnInt(8));
-
- std::vector<std::string> encodings;
- base::SplitString(s.ColumnString(9), ';', &encodings);
- template_url->set_input_encodings(encodings);
-
- template_url->set_show_in_default_list(s.ColumnInt(10) == 1);
-
- template_url->SetSuggestionsURL(s.ColumnString(11), 0, 0);
-
- template_url->set_prepopulate_id(s.ColumnInt(12));
-
- template_url->set_autogenerate_keyword(s.ColumnInt(13) == 1);
-
- template_url->set_logo_id(s.ColumnInt(14));
-
- template_url->set_created_by_policy(s.ColumnBool(15));
-
- template_url->SetInstantURL(s.ColumnString(16), 0, 0);
-
- urls->push_back(template_url);
- }
- return s.Succeeded();
-}
-
-bool WebDatabase::UpdateKeyword(const TemplateURL& url) {
- DCHECK(url.id());
- // Be sure to change kUrlIdPosition if you add columns
- sql::Statement s(db_.GetUniqueStatement(
- "UPDATE keywords "
- "SET short_name=?, keyword=?, favicon_url=?, url=?, "
- "safe_for_autoreplace=?, originating_url=?, date_created=?, "
- "usage_count=?, input_encodings=?, show_in_default_list=?, "
- "suggest_url=?, prepopulate_id=?, autogenerate_keyword=?, "
- "logo_id=?, created_by_policy=?, instant_url=? WHERE id=?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- BindURLToStatement(url, &s);
- s.BindInt64(kUrlIdPosition, url.id());
- return s.Run();
-}
-
-bool WebDatabase::SetDefaultSearchProviderID(int64 id) {
- return meta_table_.SetValue(kDefaultSearchProviderKey, id);
-}
-
-int64 WebDatabase::GetDefaulSearchProviderID() {
- int64 value = 0;
- meta_table_.GetValue(kDefaultSearchProviderKey, &value);
- return value;
-}
-
-bool WebDatabase::SetBuitinKeywordVersion(int version) {
- return meta_table_.SetValue(kBuiltinKeywordVersion, version);
-}
-
-int WebDatabase::GetBuitinKeywordVersion() {
- int version = 0;
- meta_table_.GetValue(kBuiltinKeywordVersion, &version);
- return version;
-}
-
bool WebDatabase::AddLogin(const PasswordForm& form) {
sql::Statement s(db_.GetUniqueStatement(
"INSERT OR REPLACE INTO logins "
@@ -1423,988 +636,7 @@ bool WebDatabase::GetAllLogins(std::vector<PasswordForm*>* forms,
return s.Succeeded();
}
-bool WebDatabase::AddFormFieldValues(const std::vector<FormField>& elements,
- std::vector<AutofillChange>* changes) {
- return AddFormFieldValuesTime(elements, changes, Time::Now());
-}
-
-bool WebDatabase::AddFormFieldValuesTime(const std::vector<FormField>& elements,
- std::vector<AutofillChange>* changes,
- base::Time time) {
- // Only add one new entry for each unique element name. Use |seen_names| to
- // track this. Add up to |kMaximumUniqueNames| unique entries per form.
- const size_t kMaximumUniqueNames = 256;
- std::set<string16> seen_names;
- bool result = true;
- for (std::vector<FormField>::const_iterator
- itr = elements.begin();
- itr != elements.end();
- itr++) {
- if (seen_names.size() >= kMaximumUniqueNames)
- break;
- if (seen_names.find(itr->name) != seen_names.end())
- continue;
- result = result && AddFormFieldValueTime(*itr, changes, time);
- seen_names.insert(itr->name);
- }
- return result;
-}
-
-bool WebDatabase::ClearAutofillEmptyValueElements() {
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT pair_id FROM autofill WHERE TRIM(value)= \"\""));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- std::set<int64> ids;
- while (s.Step())
- ids.insert(s.ColumnInt64(0));
-
- bool success = true;
- for (std::set<int64>::const_iterator iter = ids.begin(); iter != ids.end();
- ++iter) {
- if (!RemoveFormElementForID(*iter))
- success = false;
- }
-
- return success;
-}
-
-bool WebDatabase::GetIDAndCountOfFormElement(
- const FormField& element,
- int64* pair_id,
- int* count) {
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT pair_id, count FROM autofill "
- "WHERE name = ? AND value = ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString16(0, element.name);
- s.BindString16(1, element.value);
-
- *pair_id = 0;
- *count = 0;
-
- if (s.Step()) {
- *pair_id = s.ColumnInt64(0);
- *count = s.ColumnInt(1);
- }
-
- return true;
-}
-
-bool WebDatabase::GetCountOfFormElement(int64 pair_id, int* count) {
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT count FROM autofill WHERE pair_id = ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindInt64(0, pair_id);
-
- if (s.Step()) {
- *count = s.ColumnInt(0);
- return true;
- }
- return false;
-}
-
-bool WebDatabase::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"));
-
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- bool first_entry = true;
- AutofillKey* current_key_ptr = NULL;
- std::vector<base::Time>* timestamps_ptr = NULL;
- string16 name, value;
- base::Time time;
- while (s.Step()) {
- 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<base::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<base::Time>;
- }
- timestamps_ptr->push_back(time);
- }
- }
- // 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();
-}
-
-bool WebDatabase::GetAutofillTimestamps(const string16& name,
- const string16& value,
- std::vector<base::Time>* timestamps) {
- DCHECK(timestamps);
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT date_created FROM autofill a JOIN "
- "autofill_dates ad ON a.pair_id=ad.pair_id "
- "WHERE a.name = ? AND a.value = ?"));
-
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString16(0, name);
- s.BindString16(1, value);
- while (s.Step()) {
- timestamps->push_back(Time::FromTimeT(s.ColumnInt64(0)));
- }
-
- return s.Succeeded();
-}
-
-bool WebDatabase::UpdateAutofillEntries(
- const std::vector<AutofillEntry>& entries) {
- if (!entries.size())
- return true;
-
- // Remove all existing entries.
- 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()));
- if (!s.is_valid()) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString16(0, entries[i].key().name());
- s.BindString16(1, entries[i].key().value());
- 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++) {
- if (!InsertAutofillEntry(entries[i]))
- return false;
- }
-
- return true;
-}
-
-bool WebDatabase::InsertAutofillEntry(const AutofillEntry& entry) {
- std::string sql = "INSERT INTO autofill (name, value, value_lower, count) "
- "VALUES (?, ?, ?, ?)";
- sql::Statement s(db_.GetUniqueStatement(sql.c_str()));
- if (!s.is_valid()) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString16(0, entry.key().name());
- s.BindString16(1, entry.key().value());
- s.BindString16(2, l10n_util::ToLower(entry.key().value()));
- s.BindInt(3, entry.timestamps().size());
-
- if (!s.Run()) {
- NOTREACHED();
- 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 WebDatabase::InsertFormElement(const FormField& element,
- int64* pair_id) {
- sql::Statement s(db_.GetUniqueStatement(
- "INSERT INTO autofill (name, value, value_lower) VALUES (?,?,?)"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString16(0, element.name);
- s.BindString16(1, element.value);
- s.BindString16(2, l10n_util::ToLower(element.value));
-
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
-
- *pair_id = db_.GetLastInsertRowId();
- return true;
-}
-
-bool WebDatabase::InsertPairIDAndDate(int64 pair_id,
- base::Time date_created) {
- sql::Statement s(db_.GetUniqueStatement(
- "INSERT INTO autofill_dates "
- "(pair_id, date_created) VALUES (?, ?)"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindInt64(0, pair_id);
- s.BindInt64(1, date_created.ToTimeT());
-
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
-
- return true;
-}
-
-bool WebDatabase::SetCountOfFormElement(int64 pair_id, int count) {
- sql::Statement s(db_.GetUniqueStatement(
- "UPDATE autofill SET count = ? WHERE pair_id = ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindInt(0, count);
- s.BindInt64(1, pair_id);
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
-
- return true;
-}
-
-bool WebDatabase::AddFormFieldValue(const FormField& element,
- std::vector<AutofillChange>* changes) {
- return AddFormFieldValueTime(element, changes, base::Time::Now());
-}
-
-bool WebDatabase::AddFormFieldValueTime(const FormField& element,
- std::vector<AutofillChange>* changes,
- base::Time time) {
- int count = 0;
- int64 pair_id;
-
- if (!GetIDAndCountOfFormElement(element, &pair_id, &count))
- return false;
-
- if (count == 0 && !InsertFormElement(element, &pair_id))
- return false;
-
- if (!SetCountOfFormElement(pair_id, count + 1))
- return false;
-
- if (!InsertPairIDAndDate(pair_id, time))
- return false;
-
- AutofillChange::Type change_type =
- count == 0 ? AutofillChange::ADD : AutofillChange::UPDATE;
- changes->push_back(
- AutofillChange(change_type,
- AutofillKey(element.name, element.value)));
- return true;
-}
-
-bool WebDatabase::GetFormValuesForElementName(const string16& name,
- const string16& prefix,
- std::vector<string16>* values,
- int limit) {
- DCHECK(values);
- sql::Statement s;
-
- if (prefix.empty()) {
- s.Assign(db_.GetUniqueStatement(
- "SELECT value FROM autofill "
- "WHERE name = ? "
- "ORDER BY count DESC "
- "LIMIT ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString16(0, name);
- s.BindInt(1, limit);
- } else {
- string16 prefix_lower = l10n_util::ToLower(prefix);
- string16 next_prefix = prefix_lower;
- next_prefix[next_prefix.length() - 1]++;
-
- s.Assign(db_.GetUniqueStatement(
- "SELECT value FROM autofill "
- "WHERE name = ? AND "
- "value_lower >= ? AND "
- "value_lower < ? "
- "ORDER BY count DESC "
- "LIMIT ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString16(0, name);
- s.BindString16(1, prefix_lower);
- s.BindString16(2, next_prefix);
- s.BindInt(3, limit);
- }
-
- values->clear();
- while (s.Step())
- values->push_back(s.ColumnString16(0));
- return s.Succeeded();
-}
-
-bool WebDatabase::RemoveFormElementsAddedBetween(
- base::Time delete_begin,
- base::Time delete_end,
- std::vector<AutofillChange>* changes) {
- 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 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 < ?"));
- if (!s) {
- NOTREACHED() << "Statement 1 prepare failed";
- return false;
- }
- s.BindInt64(0, delete_begin.ToTimeT());
- s.BindInt64(1,
- delete_end.is_null() ?
- std::numeric_limits<int64>::max() :
- delete_end.ToTimeT());
-
- AutofillElementList elements;
- while (s.Step()) {
- elements.push_back(MakeTuple(s.ColumnInt64(0),
- s.ColumnString16(1),
- s.ColumnString16(2)));
- }
-
- if (!s.Succeeded()) {
- NOTREACHED();
- return false;
- }
-
- 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;
- }
- bool was_removed = false;
- if (!AddToCountOfFormElement(itr->a, -how_many, &was_removed))
- return false;
- AutofillChange::Type change_type =
- was_removed ? AutofillChange::REMOVE : AutofillChange::UPDATE;
- changes->push_back(AutofillChange(change_type,
- AutofillKey(itr->b, itr->c)));
- }
-
- return true;
-}
-
-bool WebDatabase::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 < ?"));
- if (!s) {
- NOTREACHED() << "Statement 1 prepare failed";
- return false;
- }
- 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;
-}
-
-bool WebDatabase::RemoveFormElement(const string16& name,
- const string16& value) {
- // Find the id for that pair.
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT pair_id FROM autofill WHERE name = ? AND value= ?"));
- if (!s) {
- NOTREACHED() << "Statement 1 prepare failed";
- return false;
- }
- s.BindString16(0, name);
- s.BindString16(1, value);
-
- if (s.Step())
- return RemoveFormElementForID(s.ColumnInt64(0));
- return false;
-}
-
-bool WebDatabase::AddAutofillProfile(const AutofillProfile& profile) {
- if (IsAutofillGUIDInTrash(profile.guid()))
- return true;
-
- sql::Statement s(db_.GetUniqueStatement(
- "INSERT INTO autofill_profiles"
- "(guid, company_name, address_line_1, address_line_2, city, state,"
- " zipcode, country, country_code, date_modified)"
- "VALUES (?,?,?,?,?,?,?,?,?,?)"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- BindAutofillProfileToStatement(profile, &s);
-
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
-
- if (!s.Succeeded())
- return false;
-
- return AddAutofillProfilePieces(profile, &db_);
-}
-
-bool WebDatabase::GetAutofillProfile(const std::string& guid,
- AutofillProfile** profile) {
- DCHECK(guid::IsValidGUID(guid));
- DCHECK(profile);
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT guid, company_name, address_line_1, address_line_2, city, state,"
- " zipcode, country, country_code, date_modified "
- "FROM autofill_profiles "
- "WHERE guid=?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString(0, guid);
- if (!s.Step())
- return false;
-
- if (!s.Succeeded())
- return false;
-
- scoped_ptr<AutofillProfile> p(AutofillProfileFromStatement(s));
-
- // Get associated name info.
- AddAutofillProfileNamesToProfile(&db_, p.get());
-
- // Get associated email info.
- AddAutofillProfileEmailsToProfile(&db_, p.get());
-
- // Get associated phone info.
- AddAutofillProfilePhonesToProfile(&db_, p.get());
-
- // Get associated fax info.
- AddAutofillProfileFaxesToProfile(&db_, p.get());
-
- *profile = p.release();
- return true;
-}
-
-bool WebDatabase::GetAutofillProfiles(
- std::vector<AutofillProfile*>* profiles) {
- DCHECK(profiles);
- profiles->clear();
-
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT guid "
- "FROM autofill_profiles"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- while (s.Step()) {
- std::string guid = s.ColumnString(0);
- AutofillProfile* profile = NULL;
- if (!GetAutofillProfile(guid, &profile))
- return false;
- profiles->push_back(profile);
- }
-
- return s.Succeeded();
-}
-
-bool WebDatabase::UpdateAutofillProfile(const AutofillProfile& profile) {
- DCHECK(guid::IsValidGUID(profile.guid()));
-
- // Don't update anything until the trash has been emptied. There may be
- // pending modifications to process.
- if (!IsAutofillProfilesTrashEmpty())
- return true;
-
- AutofillProfile* tmp_profile = NULL;
- if (!GetAutofillProfile(profile.guid(), &tmp_profile))
- return false;
-
- // Preserve appropriate modification dates by not updating unchanged profiles.
- scoped_ptr<AutofillProfile> old_profile(tmp_profile);
- if (old_profile->Compare(profile) == 0)
- return true;
-
- AutofillProfile new_profile(profile);
- std::vector<string16> values;
-
- old_profile->GetMultiInfo(NAME_FULL, &values);
- values[0] = new_profile.GetInfo(NAME_FULL);
- new_profile.SetMultiInfo(NAME_FULL, values);
-
- old_profile->GetMultiInfo(EMAIL_ADDRESS, &values);
- values[0] = new_profile.GetInfo(EMAIL_ADDRESS);
- new_profile.SetMultiInfo(EMAIL_ADDRESS, values);
-
- old_profile->GetMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values);
- values[0] = new_profile.GetInfo(PHONE_HOME_WHOLE_NUMBER);
- new_profile.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, values);
-
- old_profile->GetMultiInfo(PHONE_FAX_WHOLE_NUMBER, &values);
- values[0] = new_profile.GetInfo(PHONE_FAX_WHOLE_NUMBER);
- new_profile.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, values);
-
- return UpdateAutofillProfileMulti(new_profile);
-}
-
-bool WebDatabase::UpdateAutofillProfileMulti(const AutofillProfile& profile) {
- DCHECK(guid::IsValidGUID(profile.guid()));
-
- // Don't update anything until the trash has been emptied. There may be
- // pending modifications to process.
- if (!IsAutofillProfilesTrashEmpty())
- return true;
-
- AutofillProfile* tmp_profile = NULL;
- if (!GetAutofillProfile(profile.guid(), &tmp_profile))
- return false;
-
- // Preserve appropriate modification dates by not updating unchanged profiles.
- scoped_ptr<AutofillProfile> old_profile(tmp_profile);
- if (old_profile->CompareMulti(profile) == 0)
- return true;
-
- sql::Statement s(db_.GetUniqueStatement(
- "UPDATE autofill_profiles "
- "SET guid=?, company_name=?, address_line_1=?, address_line_2=?, "
- " city=?, state=?, zipcode=?, country=?, country_code=?, "
- " date_modified=? "
- "WHERE guid=?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- BindAutofillProfileToStatement(profile, &s);
- s.BindString(10, profile.guid());
- bool result = s.Run();
- DCHECK_GT(db_.GetLastChangeCount(), 0);
- if (!result)
- return result;
-
- // Remove the old names, emails, and phone/fax numbers.
- if (!RemoveAutofillProfilePieces(profile.guid(), &db_))
- return false;
-
- return AddAutofillProfilePieces(profile, &db_);
-}
-
-bool WebDatabase::RemoveAutofillProfile(const std::string& guid) {
- DCHECK(guid::IsValidGUID(guid));
-
- if (IsAutofillGUIDInTrash(guid)) {
- sql::Statement s_trash(db_.GetUniqueStatement(
- "DELETE FROM autofill_profiles_trash WHERE guid = ?"));
- if (!s_trash) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s_trash.BindString(0, guid);
- if (!s_trash.Run()) {
- NOTREACHED() << "Expected item in trash.";
- return false;
- }
-
- return true;
- }
-
- sql::Statement s(db_.GetUniqueStatement(
- "DELETE FROM autofill_profiles WHERE guid = ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString(0, guid);
- if (!s.Run())
- return false;
-
- return RemoveAutofillProfilePieces(guid, &db_);
-}
-
-bool WebDatabase::ClearAutofillProfiles() {
- sql::Statement s1(db_.GetUniqueStatement(
- "DELETE FROM autofill_profiles"));
- if (!s1) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- if (!s1.Run())
- return false;
-
- sql::Statement s2(db_.GetUniqueStatement(
- "DELETE FROM autofill_profile_names"));
- if (!s2) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- if (!s2.Run())
- return false;
-
- sql::Statement s3(db_.GetUniqueStatement(
- "DELETE FROM autofill_profile_emails"));
- if (!s3) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- if (!s3.Run())
- return false;
-
- sql::Statement s4(db_.GetUniqueStatement(
- "DELETE FROM autofill_profile_phones"));
- if (!s4) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- if (!s4.Run())
- return false;
-
- return true;
-}
-
-bool WebDatabase::AddCreditCard(const CreditCard& credit_card) {
- sql::Statement s(db_.GetUniqueStatement(
- "INSERT INTO credit_cards"
- "(guid, name_on_card, expiration_month, expiration_year, "
- "card_number_encrypted, date_modified)"
- "VALUES (?,?,?,?,?,?)"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- BindCreditCardToStatement(credit_card, &s);
-
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
-
- DCHECK_GT(db_.GetLastChangeCount(), 0);
- return s.Succeeded();
-}
-
-bool WebDatabase::GetCreditCard(const std::string& guid,
- CreditCard** credit_card) {
- DCHECK(guid::IsValidGUID(guid));
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT guid, name_on_card, expiration_month, expiration_year, "
- "card_number_encrypted, date_modified "
- "FROM credit_cards "
- "WHERE guid = ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString(0, guid);
- if (!s.Step())
- return false;
-
- *credit_card = CreditCardFromStatement(s);
-
- return s.Succeeded();
-}
-
-bool WebDatabase::GetCreditCards(
- std::vector<CreditCard*>* credit_cards) {
- DCHECK(credit_cards);
- credit_cards->clear();
-
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT guid "
- "FROM credit_cards"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- while (s.Step()) {
- std::string guid = s.ColumnString(0);
- CreditCard* credit_card = NULL;
- if (!GetCreditCard(guid, &credit_card))
- return false;
- credit_cards->push_back(credit_card);
- }
-
- return s.Succeeded();
-}
-
-bool WebDatabase::UpdateCreditCard(const CreditCard& credit_card) {
- DCHECK(guid::IsValidGUID(credit_card.guid()));
-
- CreditCard* tmp_credit_card = NULL;
- if (!GetCreditCard(credit_card.guid(), &tmp_credit_card))
- return false;
-
- // Preserve appropriate modification dates by not updating unchanged cards.
- scoped_ptr<CreditCard> old_credit_card(tmp_credit_card);
- if (*old_credit_card == credit_card)
- return true;
-
- sql::Statement s(db_.GetUniqueStatement(
- "UPDATE credit_cards "
- "SET guid=?, name_on_card=?, expiration_month=?, "
- " expiration_year=?, card_number_encrypted=?, date_modified=? "
- "WHERE guid=?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- BindCreditCardToStatement(credit_card, &s);
- s.BindString(6, credit_card.guid());
- bool result = s.Run();
- DCHECK_GT(db_.GetLastChangeCount(), 0);
- return result;
-}
-
-bool WebDatabase::RemoveCreditCard(const std::string& guid) {
- DCHECK(guid::IsValidGUID(guid));
- sql::Statement s(db_.GetUniqueStatement(
- "DELETE FROM credit_cards WHERE guid = ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString(0, guid);
- return s.Run();
-}
-
-bool WebDatabase::RemoveAutofillProfilesAndCreditCardsModifiedBetween(
- base::Time delete_begin,
- base::Time delete_end) {
- DCHECK(delete_end.is_null() || delete_begin < delete_end);
-
- time_t delete_begin_t = delete_begin.ToTimeT();
- time_t delete_end_t = delete_end.is_null() ?
- std::numeric_limits<time_t>::max() :
- delete_end.ToTimeT();
-
- // Remove Autofill profiles in the time range.
- sql::Statement s_profiles(db_.GetUniqueStatement(
- "DELETE FROM autofill_profiles "
- "WHERE date_modified >= ? AND date_modified < ?"));
- if (!s_profiles) {
- NOTREACHED() << "Autofill profiles statement prepare failed";
- return false;
- }
-
- s_profiles.BindInt64(0, delete_begin_t);
- s_profiles.BindInt64(1, delete_end_t);
- s_profiles.Run();
-
- if (!s_profiles.Succeeded()) {
- NOTREACHED();
- return false;
- }
-
- // Remove Autofill profiles in the time range.
- sql::Statement s_credit_cards(db_.GetUniqueStatement(
- "DELETE FROM credit_cards "
- "WHERE date_modified >= ? AND date_modified < ?"));
- if (!s_credit_cards) {
- NOTREACHED() << "Autofill credit cards statement prepare failed";
- return false;
- }
-
- s_credit_cards.BindInt64(0, delete_begin_t);
- s_credit_cards.BindInt64(1, delete_end_t);
- s_credit_cards.Run();
-
- if (!s_credit_cards.Succeeded()) {
- NOTREACHED();
- return false;
- }
-
- return true;
-}
-
-bool WebDatabase::GetAutofillProfilesInTrash(std::vector<std::string>* guids) {
- guids->clear();
-
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT guid "
- "FROM autofill_profiles_trash"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- while (s.Step()) {
- std::string guid = s.ColumnString(0);
- guids->push_back(guid);
- }
-
- return s.Succeeded();
-}
-
-bool WebDatabase::EmptyAutofillProfilesTrash() {
- sql::Statement s(db_.GetUniqueStatement(
- "DELETE FROM autofill_profiles_trash"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- return s.Run();
-}
-
-bool WebDatabase::AddToCountOfFormElement(int64 pair_id,
- int delta,
- bool* was_removed) {
- DCHECK(was_removed);
- int count = 0;
- *was_removed = false;
-
- if (!GetCountOfFormElement(pair_id, &count))
- return false;
-
- if (count + delta == 0) {
- if (!RemoveFormElementForID(pair_id))
- return false;
- *was_removed = true;
- } else {
- if (!SetCountOfFormElement(pair_id, count + delta))
- return false;
- }
- return true;
-}
-
-bool WebDatabase::RemoveFormElementForID(int64 pair_id) {
- sql::Statement s(db_.GetUniqueStatement(
- "DELETE FROM autofill WHERE pair_id = ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
- s.BindInt64(0, pair_id);
- if (s.Run()) {
- return RemoveFormElementForTimeRange(pair_id, base::Time(), base::Time(),
- NULL);
- }
- return false;
-}
-
-bool WebDatabase::AddAutofillGUIDToTrash(const std::string& guid) {
- sql::Statement s(db_.GetUniqueStatement(
- "INSERT INTO autofill_profiles_trash"
- " (guid) "
- "VALUES (?)"));
- if (!s) {
- NOTREACHED();
- return sql::INIT_FAILURE;
- }
-
- s.BindString(0, guid);
- if (!s.Run()) {
- NOTREACHED();
- return false;
- }
- return true;
-}
-
-bool WebDatabase::IsAutofillProfilesTrashEmpty() {
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT guid "
- "FROM autofill_profiles_trash"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- return !s.Step();
-}
-
-bool WebDatabase::IsAutofillGUIDInTrash(const std::string& guid) {
- sql::Statement s(db_.GetUniqueStatement(
- "SELECT guid "
- "FROM autofill_profiles_trash "
- "WHERE guid = ?"));
- if (!s) {
- NOTREACHED() << "Statement prepare failed";
- return false;
- }
-
- s.BindString(0, guid);
- return s.Step();
-}
-
-sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded(){
+sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded() {
// Migrate if necessary.
int current_version = meta_table_.GetVersionNumber();
switch (current_version) {
@@ -2436,7 +668,7 @@ sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded(){
// FALL THROUGH
case 21:
- if (!ClearAutofillEmptyValueElements()) {
+ if (!autofill_table_->ClearAutofillEmptyValueElements()) {
LOG(WARNING) << "Failed to clean-up autofill DB.";
NOTREACHED();
return sql::INIT_FAILURE;
@@ -3109,7 +1341,7 @@ sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded(){
}
// Add the other bits: names, emails, and phone/fax.
- if (!AddAutofillProfilePieces(profile, &db_)) {
+ if (!autofill_util::AddAutofillProfilePieces(profile, &db_)) {
NOTREACHED();
return sql::INIT_FAILURE;
}
@@ -3271,7 +1503,7 @@ sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded(){
modification_map.insert(
std::pair<std::string, int64>(guid, date_modified));
AutofillProfile* profile = NULL;
- if (!GetAutofillProfile(guid, &profile)) {
+ if (!autofill_table_->GetAutofillProfile(guid, &profile)) {
NOTREACHED() << "Bad read of profile.";
return sql::INIT_FAILURE;
}
@@ -3293,15 +1525,15 @@ sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded(){
// If the profile got merged trash the original.
if (merged)
- AddAutofillGUIDToTrash(p->guid());
+ autofill_table_->AddAutofillGUIDToTrash(p->guid());
} else {
// An invalid profile, so trash it.
- AddAutofillGUIDToTrash(p->guid());
+ autofill_table_->AddAutofillGUIDToTrash(p->guid());
}
}
// Drop the current profiles.
- if (!ClearAutofillProfiles()) {
+ if (!autofill_table_->ClearAutofillProfiles()) {
LOG(WARNING) << "Unable to update web database to version 36.";
NOTREACHED();
return sql::INIT_FAILURE;
@@ -3312,7 +1544,7 @@ sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded(){
iter = accumulated_profiles.begin();
iter != accumulated_profiles.end();
++iter) {
- if (!AddAutofillProfile(*iter)) {
+ if (!autofill_table_->AddAutofillProfile(*iter)) {
LOG(WARNING) << "Unable to update web database to version 36.";
NOTREACHED();
return sql::INIT_FAILURE;
diff --git a/chrome/browser/webdata/web_database.h b/chrome/browser/webdata/web_database.h
index 71138cd..ee69165 100644
--- a/chrome/browser/webdata/web_database.h
+++ b/chrome/browser/webdata/web_database.h
@@ -11,28 +11,21 @@
#include "app/sql/connection.h"
#include "app/sql/init_status.h"
#include "app/sql/meta_table.h"
-#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
-#include "base/string16.h"
-#include "chrome/browser/search_engines/template_url_id.h"
+#include "chrome/browser/webdata/autofill_table.h"
+#include "chrome/browser/webdata/keyword_table.h"
-class AutofillChange;
-class AutofillEntry;
-class AutofillProfile;
-class CreditCard;
+class AutofillTableTest;
class FilePath;
class GURL;
class NotificationService;
class SkBitmap;
-class TemplateURL;
-class WebDatabaseTest;
namespace base {
class Time;
}
namespace webkit_glue {
-struct FormField;
struct PasswordForm;
}
@@ -58,36 +51,8 @@ class WebDatabase {
void BeginTransaction();
void CommitTransaction();
- //////////////////////////////////////////////////////////////////////////////
- //
- // Keywords
- //
- //////////////////////////////////////////////////////////////////////////////
-
- // Adds a new keyword, updating the id field on success.
- // Returns true if successful.
- bool AddKeyword(const TemplateURL& url);
-
- // Removes the specified keyword.
- // Returns true if successful.
- bool RemoveKeyword(TemplateURLID id);
-
- // Loads the keywords into the specified vector. It's up to the caller to
- // delete the returned objects.
- // Returns true on success.
- bool GetKeywords(std::vector<TemplateURL*>* urls);
-
- // Updates the database values for the specified url.
- // Returns true on success.
- bool UpdateKeyword(const TemplateURL& url);
-
- // ID (TemplateURL->id) of the default search provider.
- bool SetDefaultSearchProviderID(int64 id);
- int64 GetDefaulSearchProviderID();
-
- // Version of the builtin keywords.
- bool SetBuitinKeywordVersion(int version);
- int GetBuitinKeywordVersion();
+ virtual AutofillTable* GetAutofillTable();
+ virtual KeywordTable* GetKeywordTable();
//////////////////////////////////////////////////////////////////////////////
//
@@ -136,144 +101,6 @@ class WebDatabase {
//////////////////////////////////////////////////////////////////////////////
//
- // Autofill
- //
- //////////////////////////////////////////////////////////////////////////////
-
- // Records the form elements in |elements| in the database in the
- // autofill table. A list of all added and updated autofill entries
- // is returned in the changes out parameter.
- bool AddFormFieldValues(const std::vector<webkit_glue::FormField>& elements,
- std::vector<AutofillChange>* changes);
-
- // Records a single form element in the database in the autofill table. A list
- // of all added and updated autofill entries is returned in the changes out
- // parameter.
- bool AddFormFieldValue(const webkit_glue::FormField& element,
- std::vector<AutofillChange>* changes);
-
- // Retrieves a vector of all values which have been recorded in the autofill
- // table as the value in a form element with name |name| and which start with
- // |prefix|. The comparison of the prefix is case insensitive.
- bool GetFormValuesForElementName(const string16& name,
- const string16& prefix,
- std::vector<string16>* values,
- int limit);
-
- // Removes rows from autofill_dates if they were created on or after
- // |delete_begin| and strictly before |delete_end|. Decrements the
- // count of the corresponding rows in the autofill table, and
- // removes those rows if the count goes to 0. A list of all changed
- // keys and whether each was updater or removed is returned in the
- // changes out parameter.
- bool RemoveFormElementsAddedBetween(base::Time delete_begin,
- base::Time delete_end,
- std::vector<AutofillChange>* changes);
-
- // Removes from autofill_dates rows with given pair_id where date_created lies
- // between delte_begin and delte_end.
- bool RemoveFormElementForTimeRange(int64 pair_id,
- base::Time delete_begin,
- base::Time delete_end,
- int* how_many);
-
- // Increments the count in the row corresponding to |pair_id| by
- // |delta|. Removes the row from the table and sets the
- // |was_removed| out parameter to true if the count becomes 0.
- bool AddToCountOfFormElement(int64 pair_id, int delta, bool* was_removed);
-
- // 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 webkit_glue::FormField& 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 webkit_glue::FormField& element, int64* pair_id);
-
- // Adds a new row to the autofill_dates table.
- bool InsertPairIDAndDate(int64 pair_id, base::Time date_created);
-
- // 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 string16& name, const string16& value);
-
- // Retrieves all of the entries in the autofill table.
- virtual bool GetAllAutofillEntries(std::vector<AutofillEntry>* entries);
-
- // Retrieves a single entry from the autofill table.
- virtual bool GetAutofillTimestamps(const string16& name,
- const string16& value,
- std::vector<base::Time>* timestamps);
-
- // Replaces existing autofill entries with the entries supplied in
- // the argument. If the entry does not already exist, it will be
- // added.
- virtual bool UpdateAutofillEntries(const std::vector<AutofillEntry>& entries);
-
- // Records a single Autofill profile in the autofill_profiles table.
- virtual bool AddAutofillProfile(const AutofillProfile& profile);
-
- // Updates the database values for the specified profile.
- // DEPRECATED: Use |UpdateAutofillProfileMulti| instead.
- virtual bool UpdateAutofillProfile(const AutofillProfile& profile);
-
- // Updates the database values for the specified profile. Mulit-value aware.
- virtual bool UpdateAutofillProfileMulti(const AutofillProfile& profile);
-
- // Removes a row from the autofill_profiles table. |guid| is the identifier
- // of the profile to remove.
- virtual bool RemoveAutofillProfile(const std::string& guid);
-
- // Retrieves a profile with guid |guid|. The caller owns |profile|.
- bool GetAutofillProfile(const std::string& guid, AutofillProfile** profile);
-
- // Retrieves all profiles in the database. Caller owns the returned profiles.
- virtual bool GetAutofillProfiles(std::vector<AutofillProfile*>* profiles);
-
- // Records a single credit card in the credit_cards table.
- bool AddCreditCard(const CreditCard& credit_card);
-
- // Updates the database values for the specified credit card.
- bool UpdateCreditCard(const CreditCard& credit_card);
-
- // Removes a row from the credit_cards table. |guid| is the identifer of the
- // credit card to remove.
- bool RemoveCreditCard(const std::string& guid);
-
- // Retrieves a credit card with guid |guid|. The caller owns
- // |credit_card_id|.
- bool GetCreditCard(const std::string& guid, CreditCard** credit_card);
-
- // Retrieves all credit cards in the database. Caller owns the returned
- // credit cards.
- virtual bool GetCreditCards(std::vector<CreditCard*>* credit_cards);
-
- // Removes rows from autofill_profiles and credit_cards if they were created
- // on or after |delete_begin| and strictly before |delete_end|.
- bool RemoveAutofillProfilesAndCreditCardsModifiedBetween(
- base::Time delete_begin,
- base::Time delete_end);
-
- // Retrieves all profiles in the database that have been deleted since last
- // "empty" of the trash.
- bool GetAutofillProfilesInTrash(std::vector<std::string>* guids);
-
- // Empties the Autofill profiles "trash can".
- bool EmptyAutofillProfilesTrash();
-
- //////////////////////////////////////////////////////////////////////////////
- //
// Web Apps
//
//////////////////////////////////////////////////////////////////////////////
@@ -307,68 +134,23 @@ class WebDatabase {
const std::string& token);
private:
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, Autofill);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, Autofill_AddChanges);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, Autofill_RemoveBetweenChanges);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest,
- Autofill_GetAllAutofillEntries_OneResult);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest,
- Autofill_GetAllAutofillEntries_TwoDistinct);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest,
- Autofill_GetAllAutofillEntries_TwoSame);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, Autofill_UpdateDontReplace);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, Autofill_AddFormFieldValues);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, AutofillProfile);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, CreditCard);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, UpdateAutofillProfile);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, UpdateCreditCard);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, AutofillProfileTrash);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, AutofillProfileTrashInteraction);
- FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest,
+ // TODO(andybons): Remove this in the next refactor round.
+ 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_AddFormFieldValues);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, AutofillProfile);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, UpdateAutofillProfile);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, AutofillProfileTrash);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, AutofillProfileTrashInteraction);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest,
RemoveAutofillProfilesAndCreditCardsModifiedBetween);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, CreditCard);
+ FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, UpdateCreditCard);
- // Methods for adding autofill entries at a specified time. For
- // testing only.
- bool AddFormFieldValuesTime(
- const std::vector<webkit_glue::FormField>& elements,
- std::vector<AutofillChange>* changes,
- base::Time time);
- bool AddFormFieldValueTime(const webkit_glue::FormField& element,
- std::vector<AutofillChange>* changes,
- base::Time time);
-
- // Removes empty values for autofill that were incorrectly stored in the DB
- // (see bug http://crbug.com/6111).
- // TODO(jcampan): http://crbug.com/7564 remove when we think all users have
- // run this code.
- bool ClearAutofillEmptyValueElements();
-
- // Insert a single AutofillEntry into the autofill/autofill_dates tables.
- bool InsertAutofillEntry(const AutofillEntry& entry);
-
- // Retrieves all profiles in the database that have been deleted since last
- // "empty" of the trash.
- bool AddAutofillGUIDToTrash(const std::string& guid);
-
- // Checks if the trash is empty.
- bool IsAutofillProfilesTrashEmpty();
-
- // Checks if the guid is in the trash.
- bool IsAutofillGUIDInTrash(const std::string& guid);
-
- // Clear all profiles.
- bool ClearAutofillProfiles();
-
- bool InitKeywordsTable();
bool InitLoginsTable();
- bool InitAutofillTable();
- bool InitAutofillDatesTable();
- bool InitAutofillProfilesTable();
- bool InitAutofillProfileNamesTable();
- bool InitAutofillProfileEmailsTable();
- bool InitAutofillProfilePhonesTable();
- bool InitAutofillProfileTrashTable();
- bool InitCreditCardsTable();
bool InitTokenServiceTable();
bool InitWebAppIconsTable();
bool InitWebAppsTable();
@@ -380,6 +162,9 @@ class WebDatabase {
sql::Connection db_;
sql::MetaTable meta_table_;
+ scoped_ptr<AutofillTable> autofill_table_;
+ scoped_ptr<KeywordTable> keyword_table_;
+
scoped_ptr<NotificationService> notification_service_;
DISALLOW_COPY_AND_ASSIGN(WebDatabase);
diff --git a/chrome/browser/webdata/web_database_table.h b/chrome/browser/webdata/web_database_table.h
new file mode 100644
index 0000000..5bb95b9
--- /dev/null
+++ b/chrome/browser/webdata/web_database_table.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEBDATA_WEB_DATABASE_TABLE_H_
+#define CHROME_BROWSER_WEBDATA_WEB_DATABASE_TABLE_H_
+#pragma once
+
+#include "app/sql/connection.h"
+#include "app/sql/init_status.h"
+#include "app/sql/meta_table.h"
+
+// An abstract base class representing a table within a WebDatabase.
+// Each table should subclass this, adding type-specific methods as needed.
+class WebDatabaseTable {
+ protected:
+ explicit WebDatabaseTable(sql::Connection* db, sql::MetaTable* meta_table)
+ : db_(db), meta_table_(meta_table) {}
+ virtual ~WebDatabaseTable() {
+ db_ = NULL;
+ meta_table_ = NULL;
+ };
+
+ // Attempts to initialize the table and returns true if successful.
+ virtual bool Init() = 0;
+
+ // In order to encourage developers to think about sync when adding or
+ // or altering new tables, this method must be implemented. Please get in
+ // contact with the sync team if you believe you're making a change that they
+ // should be aware of (or if you could break something).
+ // TODO(andybons): Implement something more robust.
+ virtual bool IsSyncable() = 0;
+
+ sql::Connection* db_;
+ sql::MetaTable* meta_table_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebDatabaseTable);
+};
+
+#endif // CHROME_BROWSER_WEBDATA_WEB_DATABASE_TABLE_H_
diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc
index 0601954..9939284 100644
--- a/chrome/browser/webdata/web_database_unittest.cc
+++ b/chrome/browser/webdata/web_database_unittest.cc
@@ -23,7 +23,6 @@
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/password_manager/encryptor.h"
-#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/webdata/autofill_change.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_database.h"
@@ -32,68 +31,14 @@
#include "chrome/test/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "webkit/glue/form_field.h"
#include "webkit/glue/password_form.h"
using base::Time;
using base::TimeDelta;
-using webkit_glue::FormField;
using webkit_glue::PasswordForm;
-// So we can compare AutofillKeys with EXPECT_EQ().
-std::ostream& operator<<(std::ostream& os, const AutofillKey& key) {
- return os << UTF16ToASCII(key.name()) << ", " << UTF16ToASCII(key.value());
-}
-
-// So we can compare AutofillChanges with EXPECT_EQ().
-std::ostream& operator<<(std::ostream& os, const AutofillChange& change) {
- switch (change.type()) {
- case AutofillChange::ADD: {
- os << "ADD";
- break;
- }
- case AutofillChange::UPDATE: {
- os << "UPDATE";
- break;
- }
- case AutofillChange::REMOVE: {
- os << "REMOVE";
- break;
- }
- }
- return os << " " << change.key();
-}
-
namespace {
-bool CompareAutofillEntries(const AutofillEntry& a, const AutofillEntry& b) {
- std::set<base::Time> timestamps1(a.timestamps().begin(),
- a.timestamps().end());
- std::set<base::Time> timestamps2(b.timestamps().begin(),
- b.timestamps().end());
-
- int compVal = a.key().name().compare(b.key().name());
- if (compVal != 0) {
- return compVal < 0;
- }
-
- compVal = a.key().value().compare(b.key().value());
- if (compVal != 0) {
- return compVal < 0;
- }
-
- if (timestamps1.size() != timestamps2.size()) {
- return timestamps1.size() < timestamps2.size();
- }
-
- std::set<base::Time>::iterator it;
- for (it = timestamps1.begin(); it != timestamps1.end(); it++) {
- timestamps2.erase(*it);
- }
-
- return !timestamps2.empty();
-}
-
void AutofillProfile31FromStatement(const sql::Statement& s,
AutofillProfile* profile,
string16* label,
@@ -213,7 +158,7 @@ void CreditCard32FromStatement(const sql::Statement& s,
*date_modified = s.ColumnInt64(5);
}
-} // namespace
+} // anonymous namespace
class WebDatabaseTest : public testing::Test {
public:
@@ -221,18 +166,13 @@ class WebDatabaseTest : public testing::Test {
virtual ~WebDatabaseTest() {}
protected:
- typedef std::vector<AutofillChange> AutofillChangeList;
- typedef std::set<AutofillEntry,
- bool (*)(const AutofillEntry&, const AutofillEntry&)> AutofillEntrySet;
- typedef std::set<AutofillEntry, bool (*)(const AutofillEntry&,
- const AutofillEntry&)>::iterator AutofillEntrySetIterator;
virtual void SetUp() {
#if defined(OS_MACOSX)
Encryptor::UseMockKeychain(true);
#endif
PathService::Get(chrome::DIR_TEST_DATA, &file_);
const std::string test_db = "TestWebDatabase" +
- base::Int64ToString(base::Time::Now().ToTimeT()) +
+ base::Int64ToString(Time::Now().ToTimeT()) +
".db";
file_ = file_.AppendASCII(test_db);
file_util::Delete(file_, false);
@@ -242,263 +182,12 @@ class WebDatabaseTest : public testing::Test {
file_util::Delete(file_, false);
}
- static int GetKeyCount(const DictionaryValue& d) {
- DictionaryValue::key_iterator i(d.begin_keys());
- DictionaryValue::key_iterator e(d.end_keys());
-
- int r = 0;
- while (i != e) {
- ++i;
- ++r;
- }
- return r;
- }
-
- static bool StringDictionaryValueEquals(const DictionaryValue& a,
- const DictionaryValue& b) {
- int a_count = 0;
- int b_count = GetKeyCount(b);
- DictionaryValue::key_iterator i(a.begin_keys());
- DictionaryValue::key_iterator e(a.end_keys());
- std::string av, bv;
- while (i != e) {
- if (!(a.GetStringWithoutPathExpansion(*i, &av)) ||
- !(b.GetStringWithoutPathExpansion(*i, &bv)) ||
- av != bv)
- return false;
-
- a_count++;
- ++i;
- }
-
- return (a_count == b_count);
- }
-
- static int64 GetID(const TemplateURL* url) {
- return url->id();
- }
-
- static void SetID(int64 new_id, TemplateURL* url) {
- url->set_id(new_id);
- }
-
- static void set_prepopulate_id(TemplateURL* url, int id) {
- url->set_prepopulate_id(id);
- }
-
- static void set_logo_id(TemplateURL* url, int id) {
- url->set_logo_id(id);
- }
-
- static AutofillEntry MakeAutofillEntry(const char* name,
- const char* value,
- time_t timestamp0,
- time_t timestamp1) {
- std::vector<base::Time> timestamps;
- if (timestamp0 >= 0)
- timestamps.push_back(Time::FromTimeT(timestamp0));
- if (timestamp1 >= 0)
- timestamps.push_back(Time::FromTimeT(timestamp1));
- return AutofillEntry(
- AutofillKey(ASCIIToUTF16(name), ASCIIToUTF16(value)), timestamps);
- }
-
FilePath file_;
private:
DISALLOW_COPY_AND_ASSIGN(WebDatabaseTest);
};
-TEST_F(WebDatabaseTest, Keywords) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- TemplateURL template_url;
- template_url.set_short_name(ASCIIToUTF16("short_name"));
- template_url.set_keyword(ASCIIToUTF16("keyword"));
- GURL favicon_url("http://favicon.url/");
- GURL originating_url("http://google.com/");
- template_url.SetFaviconURL(favicon_url);
- template_url.SetURL("http://url/", 0, 0);
- template_url.set_safe_for_autoreplace(true);
- base::Time created_time = Time::Now();
- template_url.set_date_created(created_time);
- template_url.set_show_in_default_list(true);
- template_url.set_originating_url(originating_url);
- template_url.set_usage_count(32);
- template_url.add_input_encoding("UTF-8");
- template_url.add_input_encoding("UTF-16");
- set_prepopulate_id(&template_url, 10);
- set_logo_id(&template_url, 1000);
- template_url.set_created_by_policy(true);
- template_url.SetInstantURL("http://instant/", 0, 0);
- SetID(1, &template_url);
-
- EXPECT_TRUE(db.AddKeyword(template_url));
-
- std::vector<TemplateURL*> template_urls;
- EXPECT_TRUE(db.GetKeywords(&template_urls));
-
- EXPECT_EQ(1U, template_urls.size());
- const TemplateURL* restored_url = template_urls.front();
-
- EXPECT_EQ(template_url.short_name(), restored_url->short_name());
-
- EXPECT_EQ(template_url.keyword(), restored_url->keyword());
-
- EXPECT_FALSE(restored_url->autogenerate_keyword());
-
- EXPECT_TRUE(favicon_url == restored_url->GetFaviconURL());
-
- EXPECT_TRUE(restored_url->safe_for_autoreplace());
-
- // The database stores time only at the resolution of a second.
- EXPECT_EQ(created_time.ToTimeT(), restored_url->date_created().ToTimeT());
-
- EXPECT_TRUE(restored_url->show_in_default_list());
-
- EXPECT_EQ(GetID(&template_url), GetID(restored_url));
-
- EXPECT_TRUE(originating_url == restored_url->originating_url());
-
- EXPECT_EQ(32, restored_url->usage_count());
-
- ASSERT_EQ(2U, restored_url->input_encodings().size());
- EXPECT_EQ("UTF-8", restored_url->input_encodings()[0]);
- EXPECT_EQ("UTF-16", restored_url->input_encodings()[1]);
-
- EXPECT_EQ(10, restored_url->prepopulate_id());
-
- EXPECT_EQ(1000, restored_url->logo_id());
-
- EXPECT_TRUE(restored_url->created_by_policy());
-
- ASSERT_TRUE(restored_url->instant_url());
- EXPECT_EQ("http://instant/", restored_url->instant_url()->url());
-
- EXPECT_TRUE(db.RemoveKeyword(restored_url->id()));
-
- template_urls.clear();
- EXPECT_TRUE(db.GetKeywords(&template_urls));
-
- EXPECT_EQ(0U, template_urls.size());
-
- delete restored_url;
-}
-
-TEST_F(WebDatabaseTest, KeywordMisc) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- ASSERT_EQ(0, db.GetDefaulSearchProviderID());
- ASSERT_EQ(0, db.GetBuitinKeywordVersion());
-
- db.SetDefaultSearchProviderID(10);
- db.SetBuitinKeywordVersion(11);
-
- ASSERT_EQ(10, db.GetDefaulSearchProviderID());
- ASSERT_EQ(11, db.GetBuitinKeywordVersion());
-}
-
-TEST_F(WebDatabaseTest, UpdateKeyword) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- TemplateURL template_url;
- template_url.set_short_name(ASCIIToUTF16("short_name"));
- template_url.set_keyword(ASCIIToUTF16("keyword"));
- GURL favicon_url("http://favicon.url/");
- GURL originating_url("http://originating.url/");
- template_url.SetFaviconURL(favicon_url);
- template_url.SetURL("http://url/", 0, 0);
- template_url.set_safe_for_autoreplace(true);
- template_url.set_show_in_default_list(true);
- template_url.SetSuggestionsURL("url2", 0, 0);
- SetID(1, &template_url);
-
- EXPECT_TRUE(db.AddKeyword(template_url));
-
- GURL originating_url2("http://originating.url/");
- template_url.set_originating_url(originating_url2);
- template_url.set_autogenerate_keyword(true);
- EXPECT_EQ(ASCIIToUTF16("url"), template_url.keyword());
- template_url.add_input_encoding("Shift_JIS");
- set_prepopulate_id(&template_url, 5);
- set_logo_id(&template_url, 2000);
- template_url.SetInstantURL("http://instant2/", 0, 0);
- EXPECT_TRUE(db.UpdateKeyword(template_url));
-
- std::vector<TemplateURL*> template_urls;
- EXPECT_TRUE(db.GetKeywords(&template_urls));
-
- EXPECT_EQ(1U, template_urls.size());
- const TemplateURL* restored_url = template_urls.front();
-
- EXPECT_EQ(template_url.short_name(), restored_url->short_name());
-
- EXPECT_EQ(template_url.keyword(), restored_url->keyword());
-
- EXPECT_TRUE(restored_url->autogenerate_keyword());
-
- EXPECT_TRUE(favicon_url == restored_url->GetFaviconURL());
-
- EXPECT_TRUE(restored_url->safe_for_autoreplace());
-
- EXPECT_TRUE(restored_url->show_in_default_list());
-
- EXPECT_EQ(GetID(&template_url), GetID(restored_url));
-
- EXPECT_TRUE(originating_url2 == restored_url->originating_url());
-
- ASSERT_EQ(1U, restored_url->input_encodings().size());
- ASSERT_EQ("Shift_JIS", restored_url->input_encodings()[0]);
-
- EXPECT_EQ(template_url.suggestions_url()->url(),
- restored_url->suggestions_url()->url());
-
- EXPECT_EQ(template_url.id(), restored_url->id());
-
- EXPECT_EQ(template_url.prepopulate_id(), restored_url->prepopulate_id());
-
- EXPECT_EQ(template_url.logo_id(), restored_url->logo_id());
-
- EXPECT_TRUE(restored_url->instant_url());
- EXPECT_EQ(template_url.instant_url()->url(),
- restored_url->instant_url()->url());
-
- delete restored_url;
-}
-
-TEST_F(WebDatabaseTest, KeywordWithNoFavicon) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- TemplateURL template_url;
- template_url.set_short_name(ASCIIToUTF16("short_name"));
- template_url.set_keyword(ASCIIToUTF16("keyword"));
- template_url.SetURL("http://url/", 0, 0);
- template_url.set_safe_for_autoreplace(true);
- SetID(-100, &template_url);
-
- EXPECT_TRUE(db.AddKeyword(template_url));
-
- std::vector<TemplateURL*> template_urls;
- EXPECT_TRUE(db.GetKeywords(&template_urls));
- EXPECT_EQ(1U, template_urls.size());
- const TemplateURL* restored_url = template_urls.front();
-
- EXPECT_EQ(template_url.short_name(), restored_url->short_name());
- EXPECT_EQ(template_url.keyword(), restored_url->keyword());
- EXPECT_TRUE(!restored_url->GetFaviconURL().is_valid());
- EXPECT_TRUE(restored_url->safe_for_autoreplace());
- EXPECT_EQ(GetID(&template_url), GetID(restored_url));
- delete restored_url;
-}
-
TEST_F(WebDatabaseTest, Logins) {
WebDatabase db;
@@ -632,516 +321,6 @@ TEST_F(WebDatabaseTest, Logins) {
EXPECT_EQ(0U, result.size());
}
-TEST_F(WebDatabaseTest, Autofill) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- Time t1 = Time::Now();
-
- // Simulate the submission of a handful of entries in a field called "Name",
- // some more often than others.
- AutofillChangeList changes;
- EXPECT_TRUE(db.AddFormFieldValue(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"),
- string16(),
- 0,
- false),
- &changes));
- std::vector<string16> v;
- for (int i = 0; i < 5; i++) {
- EXPECT_TRUE(db.AddFormFieldValue(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Clark Kent"),
- string16(),
- 0,
- false),
- &changes));
- }
- for (int i = 0; i < 3; i++) {
- EXPECT_TRUE(db.AddFormFieldValue(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Clark Sutter"),
- string16(),
- 0,
- false),
- &changes));
- }
- for (int i = 0; i < 2; i++) {
- EXPECT_TRUE(db.AddFormFieldValue(
- FormField(string16(),
- ASCIIToUTF16("Favorite Color"),
- ASCIIToUTF16("Green"),
- string16(),
- 0,
- false),
- &changes));
- }
-
- 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.
- EXPECT_TRUE(db.GetIDAndCountOfFormElement(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Clark Kent"),
- string16(),
- 0,
- false),
- &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_TRUE(db.GetIDAndCountOfFormElement(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("clark kent"),
- string16(),
- 0,
- false),
- &pair_id, &count));
- EXPECT_EQ(0, count);
-
- EXPECT_TRUE(db.GetIDAndCountOfFormElement(
- FormField(string16(),
- ASCIIToUTF16("Favorite Color"),
- ASCIIToUTF16("Green"),
- string16(),
- 0,
- false),
- &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
- // no matter what they start with. The order that the names occur in the list
- // should be decreasing order by count.
- EXPECT_TRUE(db.GetFormValuesForElementName(
- ASCIIToUTF16("Name"), string16(), &v, 6));
- EXPECT_EQ(3U, v.size());
- if (v.size() == 3) {
- EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0]);
- EXPECT_EQ(ASCIIToUTF16("Clark Sutter"), v[1]);
- EXPECT_EQ(ASCIIToUTF16("Superman"), v[2]);
- }
-
- // If we query again limiting the list size to 1, we should only get the most
- // frequent entry.
- EXPECT_TRUE(db.GetFormValuesForElementName(
- ASCIIToUTF16("Name"), string16(), &v, 1));
- EXPECT_EQ(1U, v.size());
- if (v.size() == 1) {
- EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0]);
- }
-
- // Querying for suggestions given a prefix is case-insensitive, so the prefix
- // "cLa" shoud get suggestions for both Clarks.
- EXPECT_TRUE(db.GetFormValuesForElementName(
- ASCIIToUTF16("Name"), ASCIIToUTF16("cLa"), &v, 6));
- EXPECT_EQ(2U, v.size());
- if (v.size() == 2) {
- EXPECT_EQ(ASCIIToUTF16("Clark Kent"), v[0]);
- EXPECT_EQ(ASCIIToUTF16("Clark Sutter"), v[1]);
- }
-
- // Removing all elements since the beginning of this function should remove
- // everything from the database.
- changes.clear();
- EXPECT_TRUE(db.RemoveFormElementsAddedBetween(t1, Time(), &changes));
-
- const AutofillChange expected_changes[] = {
- AutofillChange(AutofillChange::REMOVE,
- AutofillKey(ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"))),
- AutofillChange(AutofillChange::REMOVE,
- AutofillKey(ASCIIToUTF16("Name"),
- ASCIIToUTF16("Clark Kent"))),
- AutofillChange(AutofillChange::REMOVE,
- AutofillKey(ASCIIToUTF16("Name"),
- ASCIIToUTF16("Clark Sutter"))),
- AutofillChange(AutofillChange::REMOVE,
- AutofillKey(ASCIIToUTF16("Favorite Color"),
- ASCIIToUTF16("Green"))),
- };
- EXPECT_EQ(arraysize(expected_changes), changes.size());
- for (size_t i = 0; i < arraysize(expected_changes); i++) {
- EXPECT_EQ(expected_changes[i], changes[i]);
- }
-
- EXPECT_TRUE(db.GetIDAndCountOfFormElement(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Clark Kent"),
- string16(),
- 0,
- false),
- &pair_id, &count));
- EXPECT_EQ(0, count);
-
- EXPECT_TRUE(
- db.GetFormValuesForElementName(ASCIIToUTF16("Name"), string16(), &v, 6));
- EXPECT_EQ(0U, v.size());
-
- // Now add some values with empty strings.
- const string16 kValue = ASCIIToUTF16(" toto ");
- EXPECT_TRUE(db.AddFormFieldValue(FormField(string16(),
- ASCIIToUTF16("blank"),
- string16(),
- string16(),
- 0,
- false),
- &changes));
- EXPECT_TRUE(db.AddFormFieldValue(FormField(string16(),
- ASCIIToUTF16("blank"),
- ASCIIToUTF16(" "),
- string16(),
- 0,
- false),
- &changes));
- EXPECT_TRUE(db.AddFormFieldValue(FormField(string16(),
- ASCIIToUTF16("blank"),
- ASCIIToUTF16(" "),
- string16(),
- 0,
- false),
- &changes));
- EXPECT_TRUE(db.AddFormFieldValue(FormField(string16(),
- ASCIIToUTF16("blank"),
- kValue,
- string16(),
- 0,
- false),
- &changes));
-
- // They should be stored normally as the DB layer does not check for empty
- // values.
- v.clear();
- EXPECT_TRUE(db.GetFormValuesForElementName(
- ASCIIToUTF16("blank"), string16(), &v, 10));
- EXPECT_EQ(4U, v.size());
-
- // Now we'll check that ClearAutofillEmptyValueElements() works as expected.
- db.ClearAutofillEmptyValueElements();
-
- v.clear();
- EXPECT_TRUE(db.GetFormValuesForElementName(ASCIIToUTF16("blank"),
- string16(), &v, 10));
- ASSERT_EQ(1U, v.size());
-
- EXPECT_EQ(kValue, v[0]);
-}
-
-TEST_F(WebDatabaseTest, Autofill_RemoveBetweenChanges) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- TimeDelta one_day(TimeDelta::FromDays(1));
- Time t1 = Time::Now();
- Time t2 = t1 + one_day;
-
- AutofillChangeList changes;
- EXPECT_TRUE(db.AddFormFieldValueTime(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"),
- string16(),
- 0,
- false),
- &changes,
- t1));
- EXPECT_TRUE(db.AddFormFieldValueTime(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"),
- string16(),
- 0,
- false),
- &changes,
- t2));
-
- changes.clear();
- EXPECT_TRUE(db.RemoveFormElementsAddedBetween(t1, t2, &changes));
- ASSERT_EQ(1U, changes.size());
- EXPECT_EQ(AutofillChange(AutofillChange::UPDATE,
- AutofillKey(ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"))),
- changes[0]);
- changes.clear();
-
- EXPECT_TRUE(db.RemoveFormElementsAddedBetween(t2, t2 + one_day, &changes));
- ASSERT_EQ(1U, changes.size());
- EXPECT_EQ(AutofillChange(AutofillChange::REMOVE,
- AutofillKey(ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"))),
- changes[0]);
-}
-
-TEST_F(WebDatabaseTest, Autofill_AddChanges) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- TimeDelta one_day(TimeDelta::FromDays(1));
- Time t1 = Time::Now();
- Time t2 = t1 + one_day;
-
- AutofillChangeList changes;
- EXPECT_TRUE(db.AddFormFieldValueTime(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"),
- string16(),
- 0,
- false),
- &changes,
- t1));
- ASSERT_EQ(1U, changes.size());
- EXPECT_EQ(AutofillChange(AutofillChange::ADD,
- AutofillKey(ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"))),
- changes[0]);
-
- changes.clear();
- EXPECT_TRUE(db.AddFormFieldValueTime(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"),
- string16(),
- 0,
- false),
- &changes,
- t2));
- ASSERT_EQ(1U, changes.size());
- EXPECT_EQ(AutofillChange(AutofillChange::UPDATE,
- AutofillKey(ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"))),
- changes[0]);
-}
-
-TEST_F(WebDatabaseTest, Autofill_UpdateOneWithOneTimestamp) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, -1));
- std::vector<AutofillEntry> entries;
- entries.push_back(entry);
- ASSERT_TRUE(db.UpdateAutofillEntries(entries));
-
- FormField field(string16(),
- ASCIIToUTF16("foo"),
- ASCIIToUTF16("bar"),
- string16(),
- 0,
- false);
- int64 pair_id;
- int count;
- ASSERT_TRUE(db.GetIDAndCountOfFormElement(field, &pair_id, &count));
- EXPECT_LE(0, pair_id);
- EXPECT_EQ(1, count);
-
- std::vector<AutofillEntry> all_entries;
- ASSERT_TRUE(db.GetAllAutofillEntries(&all_entries));
- ASSERT_EQ(1U, all_entries.size());
- EXPECT_TRUE(entry == all_entries[0]);
-}
-
-TEST_F(WebDatabaseTest, Autofill_UpdateOneWithTwoTimestamps) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, 2));
- std::vector<AutofillEntry> entries;
- entries.push_back(entry);
- ASSERT_TRUE(db.UpdateAutofillEntries(entries));
-
- FormField field(string16(),
- ASCIIToUTF16("foo"),
- ASCIIToUTF16("bar"),
- string16(),
- 0,
- false);
- int64 pair_id;
- int count;
- ASSERT_TRUE(db.GetIDAndCountOfFormElement(field, &pair_id, &count));
- EXPECT_LE(0, pair_id);
- EXPECT_EQ(2, count);
-
- std::vector<AutofillEntry> all_entries;
- ASSERT_TRUE(db.GetAllAutofillEntries(&all_entries));
- ASSERT_EQ(1U, all_entries.size());
- EXPECT_TRUE(entry == all_entries[0]);
-}
-
-TEST_F(WebDatabaseTest, Autofill_GetAutofillTimestamps) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, 2));
- std::vector<AutofillEntry> entries;
- entries.push_back(entry);
- ASSERT_TRUE(db.UpdateAutofillEntries(entries));
-
- std::vector<base::Time> timestamps;
- ASSERT_TRUE(db.GetAutofillTimestamps(ASCIIToUTF16("foo"),
- ASCIIToUTF16("bar"),
- &timestamps));
- ASSERT_EQ(2U, timestamps.size());
- EXPECT_TRUE(Time::FromTimeT(1) == timestamps[0]);
- EXPECT_TRUE(Time::FromTimeT(2) == timestamps[1]);
-}
-
-TEST_F(WebDatabaseTest, Autofill_UpdateTwo) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillEntry entry0(MakeAutofillEntry("foo", "bar0", 1, -1));
- AutofillEntry entry1(MakeAutofillEntry("foo", "bar1", 2, 3));
- std::vector<AutofillEntry> entries;
- entries.push_back(entry0);
- entries.push_back(entry1);
- ASSERT_TRUE(db.UpdateAutofillEntries(entries));
-
- FormField field0(string16(),
- ASCIIToUTF16("foo"),
- ASCIIToUTF16("bar0"),
- string16(),
- 0,
- false);
- int64 pair_id;
- int count;
- ASSERT_TRUE(db.GetIDAndCountOfFormElement(field0, &pair_id, &count));
- EXPECT_LE(0, pair_id);
- EXPECT_EQ(1, count);
-
- FormField field1(string16(),
- ASCIIToUTF16("foo"),
- ASCIIToUTF16("bar1"),
- string16(),
- 0,
- false);
- ASSERT_TRUE(db.GetIDAndCountOfFormElement(field1, &pair_id, &count));
- EXPECT_LE(0, pair_id);
- EXPECT_EQ(2, count);
-}
-
-TEST_F(WebDatabaseTest, Autofill_UpdateReplace) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillChangeList changes;
- // Add a form field. This will be replaced.
- EXPECT_TRUE(db.AddFormFieldValue(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"),
- string16(),
- 0,
- false),
- &changes));
-
- AutofillEntry entry(MakeAutofillEntry("Name", "Superman", 1, 2));
- std::vector<AutofillEntry> entries;
- entries.push_back(entry);
- ASSERT_TRUE(db.UpdateAutofillEntries(entries));
-
- std::vector<AutofillEntry> all_entries;
- ASSERT_TRUE(db.GetAllAutofillEntries(&all_entries));
- ASSERT_EQ(1U, all_entries.size());
- EXPECT_TRUE(entry == all_entries[0]);
-}
-
-TEST_F(WebDatabaseTest, Autofill_UpdateDontReplace) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- Time t = Time::Now();
- AutofillEntry existing(
- MakeAutofillEntry("Name", "Superman", t.ToTimeT(), -1));
-
- AutofillChangeList changes;
- // Add a form field. This will NOT be replaced.
- EXPECT_TRUE(db.AddFormFieldValueTime(
- FormField(string16(),
- existing.key().name(),
- existing.key().value(),
- string16(),
- 0,
- false),
- &changes,
- t));
- AutofillEntry entry(MakeAutofillEntry("Name", "Clark Kent", 1, 2));
- std::vector<AutofillEntry> entries;
- entries.push_back(entry);
- ASSERT_TRUE(db.UpdateAutofillEntries(entries));
-
- std::vector<AutofillEntry> all_entries;
- ASSERT_TRUE(db.GetAllAutofillEntries(&all_entries));
- ASSERT_EQ(2U, all_entries.size());
- AutofillEntrySet expected_entries(all_entries.begin(),
- all_entries.end(),
- CompareAutofillEntries);
- EXPECT_EQ(1U, expected_entries.count(existing));
- EXPECT_EQ(1U, expected_entries.count(entry));
-}
-
-TEST_F(WebDatabaseTest, Autofill_AddFormFieldValues) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- Time t = Time::Now();
-
- // Add multiple values for "firstname" and "lastname" names. Test that only
- // first value of each gets added. Related to security issue:
- // http://crbug.com/51727.
- std::vector<FormField> elements;
- elements.push_back(FormField(string16(),
- ASCIIToUTF16("firstname"),
- ASCIIToUTF16("Joe"),
- string16(),
- 0,
- false));
- elements.push_back(FormField(string16(),
- ASCIIToUTF16("firstname"),
- ASCIIToUTF16("Jane"),
- string16(),
- 0,
- false));
- elements.push_back(FormField(string16(),
- ASCIIToUTF16("lastname"),
- ASCIIToUTF16("Smith"),
- string16(),
- 0,
- false));
- elements.push_back(FormField(string16(),
- ASCIIToUTF16("lastname"),
- ASCIIToUTF16("Jones"),
- string16(),
- 0,
- false));
-
- std::vector<AutofillChange> changes;
- db.AddFormFieldValuesTime(elements, &changes, t);
-
- ASSERT_EQ(2U, changes.size());
- EXPECT_EQ(changes[0], AutofillChange(AutofillChange::ADD,
- AutofillKey(ASCIIToUTF16("firstname"),
- ASCIIToUTF16("Joe"))));
- EXPECT_EQ(changes[1], AutofillChange(AutofillChange::ADD,
- AutofillKey(ASCIIToUTF16("lastname"),
- ASCIIToUTF16("Smith"))));
-
- std::vector<AutofillEntry> all_entries;
- ASSERT_TRUE(db.GetAllAutofillEntries(&all_entries));
- ASSERT_EQ(2U, all_entries.size());
-}
-
static bool AddTimestampedLogin(WebDatabase* db, std::string url,
const std::string& unique_string,
const Time& time) {
@@ -1397,911 +576,6 @@ TEST_F(WebDatabaseTest, TokenServiceGetSet) {
EXPECT_EQ(out_map.find(service)->second, "ham");
}
-TEST_F(WebDatabaseTest, AutofillProfile) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- // Add a 'Home' profile.
- AutofillProfile home_profile;
- home_profile.SetInfo(NAME_FIRST, ASCIIToUTF16("John"));
- home_profile.SetInfo(NAME_MIDDLE, ASCIIToUTF16("Q."));
- home_profile.SetInfo(NAME_LAST, ASCIIToUTF16("Smith"));
- home_profile.SetInfo(EMAIL_ADDRESS, ASCIIToUTF16("js@smith.xyz"));
- home_profile.SetInfo(COMPANY_NAME, ASCIIToUTF16("Google"));
- home_profile.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Apple Way"));
- home_profile.SetInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("unit 5"));
- home_profile.SetInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Los Angeles"));
- home_profile.SetInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA"));
- home_profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("90025"));
- home_profile.SetInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
- home_profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("18181234567"));
- home_profile.SetInfo(PHONE_FAX_WHOLE_NUMBER, ASCIIToUTF16("1915243678"));
-
- Time pre_creation_time = Time::Now();
- EXPECT_TRUE(db.AddAutofillProfile(home_profile));
- Time post_creation_time = Time::Now();
-
- // Get the 'Home' profile.
- AutofillProfile* db_profile;
- ASSERT_TRUE(db.GetAutofillProfile(home_profile.guid(), &db_profile));
- EXPECT_EQ(home_profile, *db_profile);
- sql::Statement s_home(db.db_.GetUniqueStatement(
- "SELECT date_modified "
- "FROM autofill_profiles WHERE guid=?"));
- s_home.BindString(0, home_profile.guid());
- ASSERT_TRUE(s_home);
- ASSERT_TRUE(s_home.Step());
- EXPECT_GE(s_home.ColumnInt64(0), pre_creation_time.ToTimeT());
- EXPECT_LE(s_home.ColumnInt64(0), post_creation_time.ToTimeT());
- EXPECT_FALSE(s_home.Step());
- delete db_profile;
-
- // Add a 'Billing' profile.
- AutofillProfile billing_profile = home_profile;
- billing_profile.set_guid(guid::GenerateGUID());
- billing_profile.SetInfo(ADDRESS_HOME_LINE1,
- ASCIIToUTF16("5678 Bottom Street"));
- billing_profile.SetInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("suite 3"));
-
- pre_creation_time = Time::Now();
- EXPECT_TRUE(db.AddAutofillProfile(billing_profile));
- post_creation_time = Time::Now();
-
- // Get the 'Billing' profile.
- ASSERT_TRUE(db.GetAutofillProfile(billing_profile.guid(), &db_profile));
- EXPECT_EQ(billing_profile, *db_profile);
- sql::Statement s_billing(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM autofill_profiles WHERE guid=?"));
- s_billing.BindString(0, billing_profile.guid());
- ASSERT_TRUE(s_billing);
- ASSERT_TRUE(s_billing.Step());
- EXPECT_GE(s_billing.ColumnInt64(0), pre_creation_time.ToTimeT());
- EXPECT_LE(s_billing.ColumnInt64(0), post_creation_time.ToTimeT());
- EXPECT_FALSE(s_billing.Step());
- delete db_profile;
-
- // Update the 'Billing' profile, name only.
- billing_profile.SetInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
- Time pre_modification_time = Time::Now();
- EXPECT_TRUE(db.UpdateAutofillProfileMulti(billing_profile));
- Time post_modification_time = Time::Now();
- ASSERT_TRUE(db.GetAutofillProfile(billing_profile.guid(), &db_profile));
- EXPECT_EQ(billing_profile, *db_profile);
- sql::Statement s_billing_updated(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM autofill_profiles WHERE guid=?"));
- s_billing_updated.BindString(0, billing_profile.guid());
- ASSERT_TRUE(s_billing_updated);
- ASSERT_TRUE(s_billing_updated.Step());
- EXPECT_GE(s_billing_updated.ColumnInt64(0),
- pre_modification_time.ToTimeT());
- EXPECT_LE(s_billing_updated.ColumnInt64(0),
- post_modification_time.ToTimeT());
- EXPECT_FALSE(s_billing_updated.Step());
- delete db_profile;
-
- // Update the 'Billing' profile.
- billing_profile.SetInfo(NAME_FIRST, ASCIIToUTF16("Janice"));
- billing_profile.SetInfo(NAME_MIDDLE, ASCIIToUTF16("C."));
- billing_profile.SetInfo(NAME_FIRST, ASCIIToUTF16("Joplin"));
- billing_profile.SetInfo(EMAIL_ADDRESS, ASCIIToUTF16("jane@singer.com"));
- billing_profile.SetInfo(COMPANY_NAME, ASCIIToUTF16("Indy"));
- billing_profile.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("Open Road"));
- billing_profile.SetInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("Route 66"));
- billing_profile.SetInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("NFA"));
- billing_profile.SetInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("NY"));
- billing_profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("10011"));
- billing_profile.SetInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("United States"));
- billing_profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("18181230000"));
- billing_profile.SetInfo(PHONE_FAX_WHOLE_NUMBER, ASCIIToUTF16("1915240000"));
- Time pre_modification_time_2 = Time::Now();
- EXPECT_TRUE(db.UpdateAutofillProfileMulti(billing_profile));
- Time post_modification_time_2 = Time::Now();
- ASSERT_TRUE(db.GetAutofillProfile(billing_profile.guid(), &db_profile));
- EXPECT_EQ(billing_profile, *db_profile);
- sql::Statement s_billing_updated_2(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM autofill_profiles WHERE guid=?"));
- s_billing_updated_2.BindString(0, billing_profile.guid());
- ASSERT_TRUE(s_billing_updated_2);
- ASSERT_TRUE(s_billing_updated_2.Step());
- EXPECT_GE(s_billing_updated_2.ColumnInt64(0),
- pre_modification_time_2.ToTimeT());
- EXPECT_LE(s_billing_updated_2.ColumnInt64(0),
- post_modification_time_2.ToTimeT());
- EXPECT_FALSE(s_billing_updated_2.Step());
- delete db_profile;
-
- // Remove the 'Billing' profile.
- EXPECT_TRUE(db.RemoveAutofillProfile(billing_profile.guid()));
- EXPECT_FALSE(db.GetAutofillProfile(billing_profile.guid(), &db_profile));
-}
-
-TEST_F(WebDatabaseTest, AutofillProfileMultiValueNames) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillProfile p;
- const string16 kJohnDoe(ASCIIToUTF16("John Doe"));
- const string16 kJohnPDoe(ASCIIToUTF16("John P. Doe"));
- std::vector<string16> set_values;
- set_values.push_back(kJohnDoe);
- set_values.push_back(kJohnPDoe);
- p.SetMultiInfo(NAME_FULL, set_values);
-
- EXPECT_TRUE(db.AddAutofillProfile(p));
-
- AutofillProfile* db_profile;
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- delete db_profile;
-
- // Update the values.
- const string16 kNoOne(ASCIIToUTF16("No One"));
- set_values[1] = kNoOne;
- p.SetMultiInfo(NAME_FULL, set_values);
- EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- delete db_profile;
-
- // Delete values.
- set_values.clear();
- p.SetMultiInfo(NAME_FULL, set_values);
- EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- EXPECT_EQ(string16(), db_profile->GetInfo(NAME_FULL));
- delete db_profile;
-}
-
-TEST_F(WebDatabaseTest, AutofillProfileSingleValue) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillProfile p;
- const string16 kJohnDoe(ASCIIToUTF16("John Doe"));
- const string16 kJohnPDoe(ASCIIToUTF16("John P. Doe"));
- std::vector<string16> set_values;
- set_values.push_back(kJohnDoe);
- set_values.push_back(kJohnPDoe);
- p.SetMultiInfo(NAME_FULL, set_values);
-
- EXPECT_TRUE(db.AddAutofillProfile(p));
-
- AutofillProfile* db_profile;
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- delete db_profile;
-
- // Update the values. This update is the "single value" update, it should
- // not perturb the multi-values following the zeroth entry. This simulates
- // the Sync use-case until Sync can be changed to be multi-value aware.
- const string16 kNoOne(ASCIIToUTF16("No One"));
- set_values.resize(1);
- set_values[0] = kNoOne;
- p.SetMultiInfo(NAME_FULL, set_values);
- EXPECT_TRUE(db.UpdateAutofillProfile(p));
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_NE(0, p.CompareMulti(*db_profile));
- db_profile->GetMultiInfo(NAME_FULL, &set_values);
- ASSERT_EQ(2UL, set_values.size());
- EXPECT_EQ(kNoOne, set_values[0]);
- EXPECT_EQ(kJohnPDoe, set_values[1]);
- delete db_profile;
-}
-
-TEST_F(WebDatabaseTest, AutofillProfileMultiValueEmails) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillProfile p;
- const string16 kJohnDoe(ASCIIToUTF16("john@doe.com"));
- const string16 kJohnPDoe(ASCIIToUTF16("john_p@doe.com"));
- std::vector<string16> set_values;
- set_values.push_back(kJohnDoe);
- set_values.push_back(kJohnPDoe);
- p.SetMultiInfo(EMAIL_ADDRESS, set_values);
-
- EXPECT_TRUE(db.AddAutofillProfile(p));
-
- AutofillProfile* db_profile;
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- delete db_profile;
-
- // Update the values.
- const string16 kNoOne(ASCIIToUTF16("no@one.com"));
- set_values[1] = kNoOne;
- p.SetMultiInfo(EMAIL_ADDRESS, set_values);
- EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- delete db_profile;
-
- // Delete values.
- set_values.clear();
- p.SetMultiInfo(EMAIL_ADDRESS, set_values);
- EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- EXPECT_EQ(string16(), db_profile->GetInfo(EMAIL_ADDRESS));
- delete db_profile;
-}
-
-TEST_F(WebDatabaseTest, AutofillProfileMultiValuePhone) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillProfile p;
- const string16 kJohnDoe(ASCIIToUTF16("4151112222"));
- const string16 kJohnPDoe(ASCIIToUTF16("4151113333"));
- std::vector<string16> set_values;
- set_values.push_back(kJohnDoe);
- set_values.push_back(kJohnPDoe);
- p.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
-
- EXPECT_TRUE(db.AddAutofillProfile(p));
-
- AutofillProfile* db_profile;
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- delete db_profile;
-
- // Update the values.
- const string16 kNoOne(ASCIIToUTF16("4151110000"));
- set_values[1] = kNoOne;
- p.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
- EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- delete db_profile;
-
- // Delete values.
- set_values.clear();
- p.SetMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
- EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- EXPECT_EQ(string16(), db_profile->GetInfo(EMAIL_ADDRESS));
- delete db_profile;
-}
-
-TEST_F(WebDatabaseTest, AutofillProfileMultiValueFax) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillProfile p;
- const string16 kJohnDoe(ASCIIToUTF16("4151112222"));
- const string16 kJohnPDoe(ASCIIToUTF16("4151113333"));
- std::vector<string16> set_values;
- set_values.push_back(kJohnDoe);
- set_values.push_back(kJohnPDoe);
- p.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, set_values);
-
- EXPECT_TRUE(db.AddAutofillProfile(p));
-
- AutofillProfile* db_profile;
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- delete db_profile;
-
- // Update the values.
- const string16 kNoOne(ASCIIToUTF16("4151110000"));
- set_values[1] = kNoOne;
- p.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, set_values);
- EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- delete db_profile;
-
- // Delete values.
- set_values.clear();
- p.SetMultiInfo(PHONE_FAX_WHOLE_NUMBER, set_values);
- EXPECT_TRUE(db.UpdateAutofillProfileMulti(p));
- ASSERT_TRUE(db.GetAutofillProfile(p.guid(), &db_profile));
- EXPECT_EQ(p, *db_profile);
- EXPECT_EQ(0, p.CompareMulti(*db_profile));
- EXPECT_EQ(string16(), db_profile->GetInfo(EMAIL_ADDRESS));
- delete db_profile;
-}
-
-TEST_F(WebDatabaseTest, AutofillProfileTrash) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- std::vector<std::string> guids;
- db.GetAutofillProfilesInTrash(&guids);
- EXPECT_TRUE(guids.empty());
-
- ASSERT_TRUE(
- db.AddAutofillGUIDToTrash("00000000-0000-0000-0000-000000000000"));
- ASSERT_TRUE(
- db.AddAutofillGUIDToTrash("00000000-0000-0000-0000-000000000001"));
- ASSERT_TRUE(db.GetAutofillProfilesInTrash(&guids));
- EXPECT_EQ(2UL, guids.size());
- EXPECT_EQ("00000000-0000-0000-0000-000000000000", guids[0]);
- EXPECT_EQ("00000000-0000-0000-0000-000000000001", guids[1]);
-
- ASSERT_TRUE(db.EmptyAutofillProfilesTrash());
- ASSERT_TRUE(db.GetAutofillProfilesInTrash(&guids));
- EXPECT_TRUE(guids.empty());
-}
-
-TEST_F(WebDatabaseTest, AutofillProfileTrashInteraction) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- std::vector<std::string> guids;
- db.GetAutofillProfilesInTrash(&guids);
- EXPECT_TRUE(guids.empty());
-
- AutofillProfile profile;
- profile.SetInfo(NAME_FIRST, ASCIIToUTF16("John"));
- profile.SetInfo(NAME_MIDDLE, ASCIIToUTF16("Q."));
- profile.SetInfo(NAME_LAST, ASCIIToUTF16("Smith"));
- profile.SetInfo(EMAIL_ADDRESS,ASCIIToUTF16("js@smith.xyz"));
- profile.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1 Main St"));
- profile.SetInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Los Angeles"));
- profile.SetInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA"));
- profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("90025"));
- profile.SetInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
-
- // Mark this profile as in the trash. This stops |AddAutofillProfile| from
- // adding it.
- EXPECT_TRUE(db.AddAutofillGUIDToTrash(profile.guid()));
- EXPECT_TRUE(db.AddAutofillProfile(profile));
- AutofillProfile* added_profile = NULL;
- EXPECT_FALSE(db.GetAutofillProfile(profile.guid(), &added_profile));
- EXPECT_EQ(static_cast<AutofillProfile*>(NULL), added_profile);
-
- // Add the profile for real this time.
- EXPECT_TRUE(db.EmptyAutofillProfilesTrash());
- EXPECT_TRUE(db.GetAutofillProfilesInTrash(&guids));
- EXPECT_TRUE(guids.empty());
- EXPECT_TRUE(db.AddAutofillProfile(profile));
- EXPECT_TRUE(db.GetAutofillProfile(profile.guid(), &added_profile));
- ASSERT_NE(static_cast<AutofillProfile*>(NULL), added_profile);
- delete added_profile;
-
- // Mark this profile as in the trash. This stops |UpdateAutofillProfileMulti|
- // from updating it. In normal operation a profile should not be both in the
- // trash and in the profiles table simultaneously.
- EXPECT_TRUE(db.AddAutofillGUIDToTrash(profile.guid()));
- profile.SetInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
- EXPECT_TRUE(db.UpdateAutofillProfileMulti(profile));
- AutofillProfile* updated_profile = NULL;
- EXPECT_TRUE(db.GetAutofillProfile(profile.guid(), &updated_profile));
- ASSERT_NE(static_cast<AutofillProfile*>(NULL), added_profile);
- EXPECT_EQ(ASCIIToUTF16("John"), updated_profile->GetInfo(NAME_FIRST));
- delete updated_profile;
-
- // Try to delete the trashed profile. This stops |RemoveAutofillProfile| from
- // deleting it. In normal operation deletion is done by migration step, and
- // removal from trash is done by |WebDataService|. |RemoveAutofillProfile|
- // does remove the item from the trash if it is found however, so that if
- // other clients remove it (via Sync say) then it is gone and doesn't need to
- // be processed further by |WebDataService|.
- EXPECT_TRUE(db.RemoveAutofillProfile(profile.guid()));
- AutofillProfile* removed_profile = NULL;
- EXPECT_TRUE(db.GetAutofillProfile(profile.guid(), &removed_profile));
- EXPECT_FALSE(db.IsAutofillGUIDInTrash(profile.guid()));
- ASSERT_NE(static_cast<AutofillProfile*>(NULL), removed_profile);
- delete removed_profile;
-
- // Check that emptying the trash now allows removal to occur.
- EXPECT_TRUE(db.EmptyAutofillProfilesTrash());
- EXPECT_TRUE(db.RemoveAutofillProfile(profile.guid()));
- removed_profile = NULL;
- EXPECT_FALSE(db.GetAutofillProfile(profile.guid(), &removed_profile));
- EXPECT_EQ(static_cast<AutofillProfile*>(NULL), removed_profile);
-}
-
-TEST_F(WebDatabaseTest, CreditCard) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- // Add a 'Work' credit card.
- CreditCard work_creditcard;
- work_creditcard.SetInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Jack Torrance"));
- work_creditcard.SetInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("1234567890123456"));
- work_creditcard.SetInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("04"));
- work_creditcard.SetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2013"));
-
- Time pre_creation_time = Time::Now();
- EXPECT_TRUE(db.AddCreditCard(work_creditcard));
- Time post_creation_time = Time::Now();
-
- // Get the 'Work' credit card.
- CreditCard* db_creditcard;
- ASSERT_TRUE(db.GetCreditCard(work_creditcard.guid(), &db_creditcard));
- EXPECT_EQ(work_creditcard, *db_creditcard);
- sql::Statement s_work(db.db_.GetUniqueStatement(
- "SELECT guid, name_on_card, expiration_month, expiration_year, "
- "card_number_encrypted, date_modified "
- "FROM credit_cards WHERE guid=?"));
- s_work.BindString(0, work_creditcard.guid());
- ASSERT_TRUE(s_work);
- ASSERT_TRUE(s_work.Step());
- EXPECT_GE(s_work.ColumnInt64(5), pre_creation_time.ToTimeT());
- EXPECT_LE(s_work.ColumnInt64(5), post_creation_time.ToTimeT());
- EXPECT_FALSE(s_work.Step());
- delete db_creditcard;
-
- // Add a 'Target' credit card.
- CreditCard target_creditcard;
- target_creditcard.SetInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Jack Torrance"));
- target_creditcard.SetInfo(CREDIT_CARD_NUMBER,
- ASCIIToUTF16("1111222233334444"));
- target_creditcard.SetInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("06"));
- target_creditcard.SetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2012"));
-
- pre_creation_time = Time::Now();
- EXPECT_TRUE(db.AddCreditCard(target_creditcard));
- post_creation_time = Time::Now();
- ASSERT_TRUE(db.GetCreditCard(target_creditcard.guid(), &db_creditcard));
- EXPECT_EQ(target_creditcard, *db_creditcard);
- sql::Statement s_target(db.db_.GetUniqueStatement(
- "SELECT guid, name_on_card, expiration_month, expiration_year, "
- "card_number_encrypted, date_modified "
- "FROM credit_cards WHERE guid=?"));
- s_target.BindString(0, target_creditcard.guid());
- ASSERT_TRUE(s_target);
- ASSERT_TRUE(s_target.Step());
- EXPECT_GE(s_target.ColumnInt64(5), pre_creation_time.ToTimeT());
- EXPECT_LE(s_target.ColumnInt64(5), post_creation_time.ToTimeT());
- EXPECT_FALSE(s_target.Step());
- delete db_creditcard;
-
- // Update the 'Target' credit card.
- target_creditcard.SetInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Charles Grady"));
- Time pre_modification_time = Time::Now();
- EXPECT_TRUE(db.UpdateCreditCard(target_creditcard));
- Time post_modification_time = Time::Now();
- ASSERT_TRUE(db.GetCreditCard(target_creditcard.guid(), &db_creditcard));
- EXPECT_EQ(target_creditcard, *db_creditcard);
- sql::Statement s_target_updated(db.db_.GetUniqueStatement(
- "SELECT guid, name_on_card, expiration_month, expiration_year, "
- "card_number_encrypted, date_modified "
- "FROM credit_cards WHERE guid=?"));
- s_target_updated.BindString(0, target_creditcard.guid());
- ASSERT_TRUE(s_target_updated);
- ASSERT_TRUE(s_target_updated.Step());
- EXPECT_GE(s_target_updated.ColumnInt64(5), pre_modification_time.ToTimeT());
- EXPECT_LE(s_target_updated.ColumnInt64(5), post_modification_time.ToTimeT());
- EXPECT_FALSE(s_target_updated.Step());
- delete db_creditcard;
-
- // Remove the 'Target' credit card.
- EXPECT_TRUE(db.RemoveCreditCard(target_creditcard.guid()));
- EXPECT_FALSE(db.GetCreditCard(target_creditcard.guid(), &db_creditcard));
-}
-
-TEST_F(WebDatabaseTest, UpdateAutofillProfile) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- // Add a profile to the db.
- AutofillProfile profile;
- profile.SetInfo(NAME_FIRST, ASCIIToUTF16("John"));
- profile.SetInfo(NAME_MIDDLE, ASCIIToUTF16("Q."));
- profile.SetInfo(NAME_LAST, ASCIIToUTF16("Smith"));
- profile.SetInfo(EMAIL_ADDRESS, ASCIIToUTF16("js@example.com"));
- profile.SetInfo(COMPANY_NAME, ASCIIToUTF16("Google"));
- profile.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Apple Way"));
- profile.SetInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("unit 5"));
- profile.SetInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Los Angeles"));
- profile.SetInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("CA"));
- profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("90025"));
- profile.SetInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
- profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("18181234567"));
- profile.SetInfo(PHONE_FAX_WHOLE_NUMBER, ASCIIToUTF16("1915243678"));
- db.AddAutofillProfile(profile);
-
- // Set a mocked value for the profile's creation time.
- const time_t mock_creation_date = Time::Now().ToTimeT() - 13;
- sql::Statement s_mock_creation_date(db.db_.GetUniqueStatement(
- "UPDATE autofill_profiles SET date_modified = ?"));
- ASSERT_TRUE(s_mock_creation_date);
- s_mock_creation_date.BindInt64(0, mock_creation_date);
- ASSERT_TRUE(s_mock_creation_date.Run());
-
- // Get the profile.
- AutofillProfile* tmp_profile;
- ASSERT_TRUE(db.GetAutofillProfile(profile.guid(), &tmp_profile));
- scoped_ptr<AutofillProfile> db_profile(tmp_profile);
- EXPECT_EQ(profile, *db_profile);
- sql::Statement s_original(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM autofill_profiles"));
- ASSERT_TRUE(s_original);
- ASSERT_TRUE(s_original.Step());
- EXPECT_EQ(mock_creation_date, s_original.ColumnInt64(0));
- EXPECT_FALSE(s_original.Step());
-
- // Now, update the profile and save the update to the database.
- // The modification date should change to reflect the update.
- profile.SetInfo(EMAIL_ADDRESS, ASCIIToUTF16("js@smith.xyz"));
- db.UpdateAutofillProfileMulti(profile);
-
- // Get the profile.
- ASSERT_TRUE(db.GetAutofillProfile(profile.guid(), &tmp_profile));
- db_profile.reset(tmp_profile);
- EXPECT_EQ(profile, *db_profile);
- sql::Statement s_updated(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM autofill_profiles"));
- ASSERT_TRUE(s_updated);
- ASSERT_TRUE(s_updated.Step());
- EXPECT_LT(mock_creation_date, s_updated.ColumnInt64(0));
- EXPECT_FALSE(s_updated.Step());
-
- // Set a mocked value for the profile's modification time.
- const time_t mock_modification_date = Time::Now().ToTimeT() - 7;
- sql::Statement s_mock_modification_date(db.db_.GetUniqueStatement(
- "UPDATE autofill_profiles SET date_modified = ?"));
- ASSERT_TRUE(s_mock_modification_date);
- s_mock_modification_date.BindInt64(0, mock_modification_date);
- ASSERT_TRUE(s_mock_modification_date.Run());
-
- // Finally, call into |UpdateAutofillProfileMulti()| without changing the
- // profile. The modification date should not change.
- db.UpdateAutofillProfileMulti(profile);
-
- // Get the profile.
- ASSERT_TRUE(db.GetAutofillProfile(profile.guid(), &tmp_profile));
- db_profile.reset(tmp_profile);
- EXPECT_EQ(profile, *db_profile);
- sql::Statement s_unchanged(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM autofill_profiles"));
- ASSERT_TRUE(s_unchanged);
- ASSERT_TRUE(s_unchanged.Step());
- EXPECT_EQ(mock_modification_date, s_unchanged.ColumnInt64(0));
- EXPECT_FALSE(s_unchanged.Step());
-}
-
-TEST_F(WebDatabaseTest, UpdateCreditCard) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- // Add a credit card to the db.
- CreditCard credit_card;
- credit_card.SetInfo(CREDIT_CARD_NAME, ASCIIToUTF16("Jack Torrance"));
- credit_card.SetInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("1234567890123456"));
- credit_card.SetInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("04"));
- credit_card.SetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2013"));
- db.AddCreditCard(credit_card);
-
- // Set a mocked value for the credit card's creation time.
- const time_t mock_creation_date = Time::Now().ToTimeT() - 13;
- sql::Statement s_mock_creation_date(db.db_.GetUniqueStatement(
- "UPDATE credit_cards SET date_modified = ?"));
- ASSERT_TRUE(s_mock_creation_date);
- s_mock_creation_date.BindInt64(0, mock_creation_date);
- ASSERT_TRUE(s_mock_creation_date.Run());
-
- // Get the credit card.
- CreditCard* tmp_credit_card;
- ASSERT_TRUE(db.GetCreditCard(credit_card.guid(), &tmp_credit_card));
- scoped_ptr<CreditCard> db_credit_card(tmp_credit_card);
- EXPECT_EQ(credit_card, *db_credit_card);
- sql::Statement s_original(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM credit_cards"));
- ASSERT_TRUE(s_original);
- ASSERT_TRUE(s_original.Step());
- EXPECT_EQ(mock_creation_date, s_original.ColumnInt64(0));
- EXPECT_FALSE(s_original.Step());
-
- // Now, update the credit card and save the update to the database.
- // The modification date should change to reflect the update.
- credit_card.SetInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("01"));
- db.UpdateCreditCard(credit_card);
-
- // Get the credit card.
- ASSERT_TRUE(db.GetCreditCard(credit_card.guid(), &tmp_credit_card));
- db_credit_card.reset(tmp_credit_card);
- EXPECT_EQ(credit_card, *db_credit_card);
- sql::Statement s_updated(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM credit_cards"));
- ASSERT_TRUE(s_updated);
- ASSERT_TRUE(s_updated.Step());
- EXPECT_LT(mock_creation_date, s_updated.ColumnInt64(0));
- EXPECT_FALSE(s_updated.Step());
-
- // Set a mocked value for the credit card's modification time.
- const time_t mock_modification_date = Time::Now().ToTimeT() - 7;
- sql::Statement s_mock_modification_date(db.db_.GetUniqueStatement(
- "UPDATE credit_cards SET date_modified = ?"));
- ASSERT_TRUE(s_mock_modification_date);
- s_mock_modification_date.BindInt64(0, mock_modification_date);
- ASSERT_TRUE(s_mock_modification_date.Run());
-
- // Finally, call into |UpdateCreditCard()| without changing the credit card.
- // The modification date should not change.
- db.UpdateCreditCard(credit_card);
-
- // Get the profile.
- ASSERT_TRUE(db.GetCreditCard(credit_card.guid(), &tmp_credit_card));
- db_credit_card.reset(tmp_credit_card);
- EXPECT_EQ(credit_card, *db_credit_card);
- sql::Statement s_unchanged(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM credit_cards"));
- ASSERT_TRUE(s_unchanged);
- ASSERT_TRUE(s_unchanged.Step());
- EXPECT_EQ(mock_modification_date, s_unchanged.ColumnInt64(0));
- EXPECT_FALSE(s_unchanged.Step());
-}
-
-TEST_F(WebDatabaseTest, RemoveAutofillProfilesAndCreditCardsModifiedBetween) {
- WebDatabase db;
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- // Populate the autofill_profiles and credit_cards tables.
- ASSERT_TRUE(db.db_.Execute(
- "INSERT INTO autofill_profiles (guid, date_modified) "
- "VALUES('00000000-0000-0000-0000-000000000000', 11);"
- "INSERT INTO autofill_profiles (guid, date_modified) "
- "VALUES('00000000-0000-0000-0000-000000000001', 21);"
- "INSERT INTO autofill_profiles (guid, date_modified) "
- "VALUES('00000000-0000-0000-0000-000000000002', 31);"
- "INSERT INTO autofill_profiles (guid, date_modified) "
- "VALUES('00000000-0000-0000-0000-000000000003', 41);"
- "INSERT INTO autofill_profiles (guid, date_modified) "
- "VALUES('00000000-0000-0000-0000-000000000004', 51);"
- "INSERT INTO autofill_profiles (guid, date_modified) "
- "VALUES('00000000-0000-0000-0000-000000000005', 61);"
- "INSERT INTO credit_cards (guid, date_modified) "
- "VALUES('00000000-0000-0000-0000-000000000006', 17);"
- "INSERT INTO credit_cards (guid, date_modified) "
- "VALUES('00000000-0000-0000-0000-000000000007', 27);"
- "INSERT INTO credit_cards (guid, date_modified) "
- "VALUES('00000000-0000-0000-0000-000000000008', 37);"
- "INSERT INTO credit_cards (guid, date_modified) "
- "VALUES('00000000-0000-0000-0000-000000000009', 47);"
- "INSERT INTO credit_cards (guid, date_modified) "
- "VALUES('00000000-0000-0000-0000-000000000010', 57);"
- "INSERT INTO credit_cards (guid, date_modified) "
- "VALUES('00000000-0000-0000-0000-000000000011', 67);"));
-
- // Remove all entries modified in the bounded time range [17,41).
- db.RemoveAutofillProfilesAndCreditCardsModifiedBetween(
- base::Time::FromTimeT(17), base::Time::FromTimeT(41));
- sql::Statement s_autofill_profiles_bounded(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM autofill_profiles"));
- ASSERT_TRUE(s_autofill_profiles_bounded);
- ASSERT_TRUE(s_autofill_profiles_bounded.Step());
- EXPECT_EQ(11, s_autofill_profiles_bounded.ColumnInt64(0));
- ASSERT_TRUE(s_autofill_profiles_bounded.Step());
- EXPECT_EQ(41, s_autofill_profiles_bounded.ColumnInt64(0));
- ASSERT_TRUE(s_autofill_profiles_bounded.Step());
- EXPECT_EQ(51, s_autofill_profiles_bounded.ColumnInt64(0));
- ASSERT_TRUE(s_autofill_profiles_bounded.Step());
- EXPECT_EQ(61, s_autofill_profiles_bounded.ColumnInt64(0));
- EXPECT_FALSE(s_autofill_profiles_bounded.Step());
- sql::Statement s_credit_cards_bounded(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM credit_cards"));
- ASSERT_TRUE(s_credit_cards_bounded);
- ASSERT_TRUE(s_credit_cards_bounded.Step());
- EXPECT_EQ(47, s_credit_cards_bounded.ColumnInt64(0));
- ASSERT_TRUE(s_credit_cards_bounded.Step());
- EXPECT_EQ(57, s_credit_cards_bounded.ColumnInt64(0));
- ASSERT_TRUE(s_credit_cards_bounded.Step());
- EXPECT_EQ(67, s_credit_cards_bounded.ColumnInt64(0));
- EXPECT_FALSE(s_credit_cards_bounded.Step());
-
- // Remove all entries modified on or after time 51 (unbounded range).
- db.RemoveAutofillProfilesAndCreditCardsModifiedBetween(
- base::Time::FromTimeT(51), base::Time());
- sql::Statement s_autofill_profiles_unbounded(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM autofill_profiles"));
- ASSERT_TRUE(s_autofill_profiles_unbounded);
- ASSERT_TRUE(s_autofill_profiles_unbounded.Step());
- EXPECT_EQ(11, s_autofill_profiles_unbounded.ColumnInt64(0));
- ASSERT_TRUE(s_autofill_profiles_unbounded.Step());
- EXPECT_EQ(41, s_autofill_profiles_unbounded.ColumnInt64(0));
- EXPECT_FALSE(s_autofill_profiles_unbounded.Step());
- sql::Statement s_credit_cards_unbounded(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM credit_cards"));
- ASSERT_TRUE(s_credit_cards_unbounded);
- ASSERT_TRUE(s_credit_cards_unbounded.Step());
- EXPECT_EQ(47, s_credit_cards_unbounded.ColumnInt64(0));
- EXPECT_FALSE(s_credit_cards_unbounded.Step());
-
- // Remove all remaining entries.
- db.RemoveAutofillProfilesAndCreditCardsModifiedBetween(base::Time(),
- base::Time());
- sql::Statement s_autofill_profiles_empty(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM autofill_profiles"));
- ASSERT_TRUE(s_autofill_profiles_empty);
- EXPECT_FALSE(s_autofill_profiles_empty.Step());
- sql::Statement s_credit_cards_empty(db.db_.GetUniqueStatement(
- "SELECT date_modified FROM credit_cards"));
- ASSERT_TRUE(s_credit_cards_empty);
- EXPECT_FALSE(s_credit_cards_empty.Step());
-}
-
-TEST_F(WebDatabaseTest, Autofill_GetAllAutofillEntries_NoResults) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- std::vector<AutofillEntry> entries;
- ASSERT_TRUE(db.GetAllAutofillEntries(&entries));
-
- EXPECT_EQ(0U, entries.size());
-}
-
-TEST_F(WebDatabaseTest, Autofill_GetAllAutofillEntries_OneResult) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillChangeList changes;
- std::map<std::string, std::vector<base::Time> > name_value_times_map;
-
- time_t start = 0;
- std::vector<base::Time> timestamps1;
- EXPECT_TRUE(db.AddFormFieldValueTime(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"),
- string16(),
- 0,
- false),
- &changes,
- Time::FromTimeT(start)));
- timestamps1.push_back(Time::FromTimeT(start));
- std::string key1("NameSuperman");
- name_value_times_map.insert(std::pair<std::string,
- std::vector<base::Time> > (key1, timestamps1));
-
- AutofillEntrySet expected_entries(CompareAutofillEntries);
- AutofillKey ak1(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"));
- AutofillEntry ae1(ak1, timestamps1);
-
- expected_entries.insert(ae1);
-
- std::vector<AutofillEntry> entries;
- ASSERT_TRUE(db.GetAllAutofillEntries(&entries));
- AutofillEntrySet entry_set(entries.begin(), entries.end(),
- CompareAutofillEntries);
-
- // make sure the lists of entries match
- ASSERT_EQ(expected_entries.size(), entry_set.size());
- AutofillEntrySetIterator it;
- for (it = entry_set.begin(); it != entry_set.end(); it++) {
- expected_entries.erase(*it);
- }
-
- EXPECT_EQ(0U, expected_entries.size());
-}
-
-TEST_F(WebDatabaseTest, Autofill_GetAllAutofillEntries_TwoDistinct) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillChangeList changes;
- std::map<std::string, std::vector<base::Time> > name_value_times_map;
- time_t start = 0;
-
- std::vector<base::Time> timestamps1;
- EXPECT_TRUE(db.AddFormFieldValueTime(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"),
- string16(),
- 0,
- false),
- &changes,
- Time::FromTimeT(start)));
- timestamps1.push_back(Time::FromTimeT(start));
- std::string key1("NameSuperman");
- name_value_times_map.insert(std::pair<std::string,
- std::vector<base::Time> > (key1, timestamps1));
-
- start++;
- std::vector<base::Time> timestamps2;
- EXPECT_TRUE(db.AddFormFieldValueTime(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Clark Kent"),
- string16(),
- 0,
- false),
- &changes,
- Time::FromTimeT(start)));
- timestamps2.push_back(Time::FromTimeT(start));
- std::string key2("NameClark Kent");
- name_value_times_map.insert(std::pair<std::string,
- std::vector<base::Time> > (key2, timestamps2));
-
- AutofillEntrySet expected_entries(CompareAutofillEntries);
- AutofillKey ak1(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"));
- AutofillKey ak2(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Kent"));
- AutofillEntry ae1(ak1, timestamps1);
- AutofillEntry ae2(ak2, timestamps2);
-
- expected_entries.insert(ae1);
- expected_entries.insert(ae2);
-
- std::vector<AutofillEntry> entries;
- ASSERT_TRUE(db.GetAllAutofillEntries(&entries));
- AutofillEntrySet entry_set(entries.begin(), entries.end(),
- CompareAutofillEntries);
-
- // make sure the lists of entries match
- ASSERT_EQ(expected_entries.size(), entry_set.size());
- AutofillEntrySetIterator it;
- for (it = entry_set.begin(); it != entry_set.end(); it++) {
- expected_entries.erase(*it);
- }
-
- EXPECT_EQ(0U, expected_entries.size());
-}
-
-TEST_F(WebDatabaseTest, Autofill_GetAllAutofillEntries_TwoSame) {
- WebDatabase db;
-
- ASSERT_EQ(sql::INIT_OK, db.Init(file_));
-
- AutofillChangeList changes;
- std::map<std::string, std::vector<base::Time> > name_value_times_map;
-
- time_t start = 0;
- std::vector<base::Time> timestamps;
- for (int i = 0; i < 2; i++) {
- EXPECT_TRUE(db.AddFormFieldValueTime(
- FormField(string16(),
- ASCIIToUTF16("Name"),
- ASCIIToUTF16("Superman"),
- string16(),
- 0,
- false),
- &changes,
- Time::FromTimeT(start)));
- timestamps.push_back(Time::FromTimeT(start));
- start++;
- }
-
- std::string key("NameSuperman");
- name_value_times_map.insert(std::pair<std::string,
- std::vector<base::Time> > (key, timestamps));
-
- AutofillEntrySet expected_entries(CompareAutofillEntries);
- AutofillKey ak1(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman"));
- AutofillEntry ae1(ak1, timestamps);
-
- expected_entries.insert(ae1);
-
- std::vector<AutofillEntry> entries;
- ASSERT_TRUE(db.GetAllAutofillEntries(&entries));
- AutofillEntrySet entry_set(entries.begin(), entries.end(),
- CompareAutofillEntries);
-
- // make sure the lists of entries match
- ASSERT_EQ(expected_entries.size(), entry_set.size());
- AutofillEntrySetIterator it;
- for (it = entry_set.begin(); it != entry_set.end(); it++) {
- expected_entries.erase(*it);
- }
-
- EXPECT_EQ(0U, expected_entries.size());
-}
-
// The WebDatabaseMigrationTest encapsulates testing of database migrations.
// Specifically, these tests are intended to exercise any schema changes in
// the WebDatabase and data migrations that occur in