Give names to all utility processes.
[chromium-blink-merge.git] / components / password_manager / core / browser / affiliation_database.cc
blob065ee8431096bd54809282d2a0ff94096dc49d96
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/password_manager/core/browser/affiliation_database.h"
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "sql/connection.h"
10 #include "sql/error_delegate_util.h"
11 #include "sql/meta_table.h"
12 #include "sql/statement.h"
13 #include "sql/transaction.h"
15 namespace password_manager {
17 namespace {
18 const int kVersion = 1;
19 const int kCompatibleVersion = 1;
20 } // namespace
22 AffiliationDatabase::AffiliationDatabase() {
25 AffiliationDatabase::~AffiliationDatabase() {
28 bool AffiliationDatabase::Init(const base::FilePath& path) {
29 sql_connection_.reset(new sql::Connection);
30 sql_connection_->set_histogram_tag("Affiliation");
31 sql_connection_->set_error_callback(base::Bind(
32 &AffiliationDatabase::SQLErrorCallback, base::Unretained(this)));
34 if (!sql_connection_->Open(path))
35 return false;
37 if (!sql_connection_->Execute("PRAGMA foreign_keys=1"))
38 return false;
40 sql::MetaTable metatable;
41 if (!metatable.Init(sql_connection_.get(), kVersion, kCompatibleVersion))
42 return false;
44 if (metatable.GetCompatibleVersionNumber() > kVersion) {
45 LOG(WARNING) << "AffiliationDatabase is too new.";
46 return false;
49 return CreateTablesAndIndicesIfNeeded();
52 bool AffiliationDatabase::GetAffiliationsForFacet(
53 const FacetURI& facet_uri,
54 AffiliatedFacetsWithUpdateTime* result) const {
55 DCHECK(result);
56 result->facets.clear();
58 sql::Statement statement(sql_connection_->GetCachedStatement(
59 SQL_FROM_HERE,
60 "SELECT m2.facet_uri, c.last_update_time "
61 "FROM eq_class_members m1, eq_class_members m2, eq_classes c "
62 "WHERE m1.facet_uri = ? AND m1.set_id = m2.set_id AND m1.set_id = c.id"));
63 statement.BindString(0, facet_uri.canonical_spec());
65 while (statement.Step()) {
66 result->facets.push_back(
67 FacetURI::FromCanonicalSpec(statement.ColumnString(0)));
68 result->last_update_time =
69 base::Time::FromInternalValue(statement.ColumnInt64(1));
72 return !result->facets.empty();
75 void AffiliationDatabase::GetAllAffiliations(
76 std::vector<AffiliatedFacetsWithUpdateTime>* results) const {
77 DCHECK(results);
78 results->clear();
80 sql::Statement statement(sql_connection_->GetCachedStatement(
81 SQL_FROM_HERE,
82 "SELECT m.facet_uri, c.last_update_time, c.id "
83 "FROM eq_class_members m, eq_classes c "
84 "WHERE m.set_id = c.id "
85 "ORDER BY c.id"));
87 int64 last_eq_class_id = 0;
88 while (statement.Step()) {
89 int64 eq_class_id = statement.ColumnInt64(2);
90 if (results->empty() || eq_class_id != last_eq_class_id) {
91 results->push_back(AffiliatedFacetsWithUpdateTime());
92 last_eq_class_id = eq_class_id;
94 results->back().facets.push_back(
95 FacetURI::FromCanonicalSpec(statement.ColumnString(0)));
96 results->back().last_update_time =
97 base::Time::FromInternalValue(statement.ColumnInt64(1));
101 void AffiliationDatabase::DeleteAffiliationsForFacet(
102 const FacetURI& facet_uri) {
103 sql::Transaction transaction(sql_connection_.get());
104 if (!transaction.Begin())
105 return;
107 sql::Statement statement_lookup(sql_connection_->GetCachedStatement(
108 SQL_FROM_HERE,
109 "SELECT m.set_id FROM eq_class_members m "
110 "WHERE m.facet_uri = ?"));
111 statement_lookup.BindString(0, facet_uri.canonical_spec());
113 // No such |facet_uri|, nothing to do.
114 if (!statement_lookup.Step())
115 return;
117 int64 eq_class_id = statement_lookup.ColumnInt64(0);
119 // Children will get deleted due to 'ON DELETE CASCADE'.
120 sql::Statement statement_parent(sql_connection_->GetCachedStatement(
121 SQL_FROM_HERE, "DELETE FROM eq_classes WHERE eq_classes.id = ?"));
122 statement_parent.BindInt64(0, eq_class_id);
123 if (!statement_parent.Run())
124 return;
126 transaction.Commit();
129 void AffiliationDatabase::DeleteAffiliationsOlderThan(
130 const base::Time& cutoff_threshold) {
131 // Children will get deleted due to 'ON DELETE CASCADE'.
132 sql::Statement statement_parent(sql_connection_->GetCachedStatement(
133 SQL_FROM_HERE,
134 "DELETE FROM eq_classes "
135 "WHERE eq_classes.last_update_time < ?"));
136 statement_parent.BindInt64(0, cutoff_threshold.ToInternalValue());
137 statement_parent.Run();
140 void AffiliationDatabase::DeleteAllAffiliations() {
141 // Children will get deleted due to 'ON DELETE CASCADE'.
142 sql::Statement statement_parent(
143 sql_connection_->GetUniqueStatement("DELETE FROM eq_classes"));
144 statement_parent.Run();
147 bool AffiliationDatabase::Store(
148 const AffiliatedFacetsWithUpdateTime& affiliated_facets) {
149 DCHECK(!affiliated_facets.facets.empty());
151 sql::Statement statement_parent(sql_connection_->GetCachedStatement(
152 SQL_FROM_HERE, "INSERT INTO eq_classes(last_update_time) VALUES (?)"));
154 sql::Statement statement_child(sql_connection_->GetCachedStatement(
155 SQL_FROM_HERE,
156 "INSERT INTO eq_class_members(facet_uri, set_id) VALUES (?, ?)"));
158 sql::Transaction transaction(sql_connection_.get());
159 if (!transaction.Begin())
160 return false;
162 statement_parent.BindInt64(
163 0, affiliated_facets.last_update_time.ToInternalValue());
164 if (!statement_parent.Run())
165 return false;
167 int64 eq_class_id = sql_connection_->GetLastInsertRowId();
168 for (const FacetURI& uri : affiliated_facets.facets) {
169 statement_child.Reset(true);
170 statement_child.BindString(0, uri.canonical_spec());
171 statement_child.BindInt64(1, eq_class_id);
172 if (!statement_child.Run())
173 return false;
176 return transaction.Commit();
179 void AffiliationDatabase::StoreAndRemoveConflicting(
180 const AffiliatedFacetsWithUpdateTime& affiliation,
181 std::vector<AffiliatedFacetsWithUpdateTime>* removed_affiliations) {
182 DCHECK(!affiliation.facets.empty());
183 DCHECK(removed_affiliations);
184 removed_affiliations->clear();
186 sql::Transaction transaction(sql_connection_.get());
187 if (!transaction.Begin())
188 return;
190 for (const FacetURI& uri : affiliation.facets) {
191 AffiliatedFacetsWithUpdateTime old_affiliation;
192 if (GetAffiliationsForFacet(uri, &old_affiliation)) {
193 if (!AreEquivalenceClassesEqual(old_affiliation.facets,
194 affiliation.facets)) {
195 removed_affiliations->push_back(old_affiliation);
197 DeleteAffiliationsForFacet(uri);
201 if (!Store(affiliation))
202 NOTREACHED();
204 transaction.Commit();
207 bool AffiliationDatabase::CreateTablesAndIndicesIfNeeded() {
208 if (!sql_connection_->Execute(
209 "CREATE TABLE IF NOT EXISTS eq_classes("
210 "id INTEGER PRIMARY KEY,"
211 "last_update_time INTEGER)")) {
212 return false;
215 if (!sql_connection_->Execute(
216 "CREATE TABLE IF NOT EXISTS eq_class_members("
217 "id INTEGER PRIMARY KEY,"
218 "facet_uri LONGVARCHAR UNIQUE NOT NULL,"
219 "set_id INTEGER NOT NULL"
220 " REFERENCES eq_classes(id) ON DELETE CASCADE)")) {
221 return false;
224 // An index on eq_class_members.facet_uri is automatically created due to the
225 // UNIQUE constraint, however, we must create one on eq_class_members.set_id
226 // manually (to prevent linear scan when joining).
227 return sql_connection_->Execute(
228 "CREATE INDEX IF NOT EXISTS index_on_eq_class_members_set_id ON "
229 "eq_class_members (set_id)");
232 void AffiliationDatabase::SQLErrorCallback(int error,
233 sql::Statement* statement) {
234 if (sql::IsErrorCatastrophic(error)) {
235 // Normally this will poison the database, causing any subsequent operations
236 // to silently fail without any side effects. However, if RazeAndClose() is
237 // called from the error callback in response to an error raised from within
238 // sql::Connection::Open, opening the now-razed database will be retried.
239 sql_connection_->RazeAndClose();
240 return;
243 // The default handling is to assert on debug and to ignore on release.
244 if (!sql::Connection::ShouldIgnoreSqliteError(error))
245 DLOG(FATAL) << sql_connection_->GetErrorMessage();
248 } // namespace password_manager