Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: components/password_manager/core/browser/affiliation_database.cc

Issue 2949573002: Move the files related to Android<->Web credentials to a separate folder. (Closed)
Patch Set: Remove includes Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "components/password_manager/core/browser/affiliation_database.h"
6
7 #include <stdint.h>
8
9 #include "base/bind.h"
10 #include "base/files/file_path.h"
11 #include "sql/connection.h"
12 #include "sql/error_delegate_util.h"
13 #include "sql/meta_table.h"
14 #include "sql/statement.h"
15 #include "sql/transaction.h"
16
17 namespace password_manager {
18
19 namespace {
20 const int kVersion = 1;
21 const int kCompatibleVersion = 1;
22 } // namespace
23
24 AffiliationDatabase::AffiliationDatabase() {
25 }
26
27 AffiliationDatabase::~AffiliationDatabase() {
28 }
29
30 bool AffiliationDatabase::Init(const base::FilePath& path) {
31 sql_connection_.reset(new sql::Connection);
32 sql_connection_->set_histogram_tag("Affiliation");
33 sql_connection_->set_error_callback(base::Bind(
34 &AffiliationDatabase::SQLErrorCallback, base::Unretained(this)));
35
36 if (!sql_connection_->Open(path))
37 return false;
38
39 if (!sql_connection_->Execute("PRAGMA foreign_keys=1")) {
40 sql_connection_->Poison();
41 return false;
42 }
43
44 sql::MetaTable metatable;
45 if (!metatable.Init(sql_connection_.get(), kVersion, kCompatibleVersion)) {
46 sql_connection_->Poison();
47 return false;
48 }
49
50 if (metatable.GetCompatibleVersionNumber() > kVersion) {
51 LOG(WARNING) << "AffiliationDatabase is too new.";
52 sql_connection_->Poison();
53 return false;
54 }
55
56 if (!CreateTablesAndIndicesIfNeeded()) {
57 sql_connection_->Poison();
58 return false;
59 }
60
61 return true;
62 }
63
64 bool AffiliationDatabase::GetAffiliationsForFacet(
65 const FacetURI& facet_uri,
66 AffiliatedFacetsWithUpdateTime* result) const {
67 DCHECK(result);
68 result->facets.clear();
69
70 sql::Statement statement(sql_connection_->GetCachedStatement(
71 SQL_FROM_HERE,
72 "SELECT m2.facet_uri, c.last_update_time "
73 "FROM eq_class_members m1, eq_class_members m2, eq_classes c "
74 "WHERE m1.facet_uri = ? AND m1.set_id = m2.set_id AND m1.set_id = c.id"));
75 statement.BindString(0, facet_uri.canonical_spec());
76
77 while (statement.Step()) {
78 result->facets.push_back(
79 FacetURI::FromCanonicalSpec(statement.ColumnString(0)));
80 result->last_update_time =
81 base::Time::FromInternalValue(statement.ColumnInt64(1));
82 }
83
84 return !result->facets.empty();
85 }
86
87 void AffiliationDatabase::GetAllAffiliations(
88 std::vector<AffiliatedFacetsWithUpdateTime>* results) const {
89 DCHECK(results);
90 results->clear();
91
92 sql::Statement statement(sql_connection_->GetCachedStatement(
93 SQL_FROM_HERE,
94 "SELECT m.facet_uri, c.last_update_time, c.id "
95 "FROM eq_class_members m, eq_classes c "
96 "WHERE m.set_id = c.id "
97 "ORDER BY c.id"));
98
99 int64_t last_eq_class_id = 0;
100 while (statement.Step()) {
101 int64_t eq_class_id = statement.ColumnInt64(2);
102 if (results->empty() || eq_class_id != last_eq_class_id) {
103 results->push_back(AffiliatedFacetsWithUpdateTime());
104 last_eq_class_id = eq_class_id;
105 }
106 results->back().facets.push_back(
107 FacetURI::FromCanonicalSpec(statement.ColumnString(0)));
108 results->back().last_update_time =
109 base::Time::FromInternalValue(statement.ColumnInt64(1));
110 }
111 }
112
113 void AffiliationDatabase::DeleteAffiliationsForFacet(
114 const FacetURI& facet_uri) {
115 sql::Transaction transaction(sql_connection_.get());
116 if (!transaction.Begin())
117 return;
118
119 sql::Statement statement_lookup(sql_connection_->GetCachedStatement(
120 SQL_FROM_HERE,
121 "SELECT m.set_id FROM eq_class_members m "
122 "WHERE m.facet_uri = ?"));
123 statement_lookup.BindString(0, facet_uri.canonical_spec());
124
125 // No such |facet_uri|, nothing to do.
126 if (!statement_lookup.Step())
127 return;
128
129 int64_t eq_class_id = statement_lookup.ColumnInt64(0);
130
131 // Children will get deleted due to 'ON DELETE CASCADE'.
132 sql::Statement statement_parent(sql_connection_->GetCachedStatement(
133 SQL_FROM_HERE, "DELETE FROM eq_classes WHERE eq_classes.id = ?"));
134 statement_parent.BindInt64(0, eq_class_id);
135 if (!statement_parent.Run())
136 return;
137
138 transaction.Commit();
139 }
140
141 void AffiliationDatabase::DeleteAffiliationsOlderThan(
142 const base::Time& cutoff_threshold) {
143 // Children will get deleted due to 'ON DELETE CASCADE'.
144 sql::Statement statement_parent(sql_connection_->GetCachedStatement(
145 SQL_FROM_HERE,
146 "DELETE FROM eq_classes "
147 "WHERE eq_classes.last_update_time < ?"));
148 statement_parent.BindInt64(0, cutoff_threshold.ToInternalValue());
149 statement_parent.Run();
150 }
151
152 void AffiliationDatabase::DeleteAllAffiliations() {
153 // Children will get deleted due to 'ON DELETE CASCADE'.
154 sql::Statement statement_parent(
155 sql_connection_->GetUniqueStatement("DELETE FROM eq_classes"));
156 statement_parent.Run();
157 }
158
159 bool AffiliationDatabase::Store(
160 const AffiliatedFacetsWithUpdateTime& affiliated_facets) {
161 DCHECK(!affiliated_facets.facets.empty());
162
163 sql::Statement statement_parent(sql_connection_->GetCachedStatement(
164 SQL_FROM_HERE, "INSERT INTO eq_classes(last_update_time) VALUES (?)"));
165
166 sql::Statement statement_child(sql_connection_->GetCachedStatement(
167 SQL_FROM_HERE,
168 "INSERT INTO eq_class_members(facet_uri, set_id) VALUES (?, ?)"));
169
170 sql::Transaction transaction(sql_connection_.get());
171 if (!transaction.Begin())
172 return false;
173
174 statement_parent.BindInt64(
175 0, affiliated_facets.last_update_time.ToInternalValue());
176 if (!statement_parent.Run())
177 return false;
178
179 int64_t eq_class_id = sql_connection_->GetLastInsertRowId();
180 for (const FacetURI& uri : affiliated_facets.facets) {
181 statement_child.Reset(true);
182 statement_child.BindString(0, uri.canonical_spec());
183 statement_child.BindInt64(1, eq_class_id);
184 if (!statement_child.Run())
185 return false;
186 }
187
188 return transaction.Commit();
189 }
190
191 void AffiliationDatabase::StoreAndRemoveConflicting(
192 const AffiliatedFacetsWithUpdateTime& affiliation,
193 std::vector<AffiliatedFacetsWithUpdateTime>* removed_affiliations) {
194 DCHECK(!affiliation.facets.empty());
195 DCHECK(removed_affiliations);
196 removed_affiliations->clear();
197
198 sql::Transaction transaction(sql_connection_.get());
199 if (!transaction.Begin())
200 return;
201
202 for (const FacetURI& uri : affiliation.facets) {
203 AffiliatedFacetsWithUpdateTime old_affiliation;
204 if (GetAffiliationsForFacet(uri, &old_affiliation)) {
205 if (!AreEquivalenceClassesEqual(old_affiliation.facets,
206 affiliation.facets)) {
207 removed_affiliations->push_back(old_affiliation);
208 }
209 DeleteAffiliationsForFacet(uri);
210 }
211 }
212
213 if (!Store(affiliation))
214 NOTREACHED();
215
216 transaction.Commit();
217 }
218
219 // static
220 void AffiliationDatabase::Delete(const base::FilePath& path) {
221 bool success = sql::Connection::Delete(path);
222 DCHECK(success);
223 }
224
225 bool AffiliationDatabase::CreateTablesAndIndicesIfNeeded() {
226 if (!sql_connection_->Execute(
227 "CREATE TABLE IF NOT EXISTS eq_classes("
228 "id INTEGER PRIMARY KEY,"
229 "last_update_time INTEGER)")) {
230 return false;
231 }
232
233 if (!sql_connection_->Execute(
234 "CREATE TABLE IF NOT EXISTS eq_class_members("
235 "id INTEGER PRIMARY KEY,"
236 "facet_uri LONGVARCHAR UNIQUE NOT NULL,"
237 "set_id INTEGER NOT NULL"
238 " REFERENCES eq_classes(id) ON DELETE CASCADE)")) {
239 return false;
240 }
241
242 // An index on eq_class_members.facet_uri is automatically created due to the
243 // UNIQUE constraint, however, we must create one on eq_class_members.set_id
244 // manually (to prevent linear scan when joining).
245 return sql_connection_->Execute(
246 "CREATE INDEX IF NOT EXISTS index_on_eq_class_members_set_id ON "
247 "eq_class_members (set_id)");
248 }
249
250 void AffiliationDatabase::SQLErrorCallback(int error,
251 sql::Statement* statement) {
252 if (sql::IsErrorCatastrophic(error)) {
253 // Normally this will poison the database, causing any subsequent operations
254 // to silently fail without any side effects. However, if RazeAndClose() is
255 // called from the error callback in response to an error raised from within
256 // sql::Connection::Open, opening the now-razed database will be retried.
257 sql_connection_->RazeAndClose();
258 return;
259 }
260
261 // The default handling is to assert on debug and to ignore on release.
262 if (!sql::Connection::IsExpectedSqliteError(error))
263 DLOG(FATAL) << sql_connection_->GetErrorMessage();
264 }
265
266 } // namespace password_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698