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

Side by Side Diff: webkit/dom_storage/dom_storage_database.cc

Issue 9159020: Create a class to represent a DOM Storage Database. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Disable test that uses the webcore localstorage file pending the test data getting checked in. Created 8 years, 10 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 (c) 2012 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 "webkit/dom_storage/dom_storage_database.h"
6
7 #include "base/file_util.h"
8 #include "base/logging.h"
9 #include "sql/diagnostic_error_delegate.h"
10 #include "sql/statement.h"
11 #include "sql/transaction.h"
12
13 namespace {
14
15 class HistogramUniquifier {
16 public:
17 static const char* name() { return "Sqlite.DomStorageDatabase.Error"; }
18 };
19
20 sql::ErrorDelegate* GetErrorHandlerForDomStorageDatabase() {
21 return new sql::DiagnosticErrorDelegate<HistogramUniquifier>();
22 }
23
24 } // anon namespace
25
26 namespace dom_storage {
27
28 DomStorageDatabase::DomStorageDatabase(const FilePath& file_path)
29 : file_path_(file_path),
30 db_(NULL) {
31 DCHECK(!file_path_.empty());
32 }
33
34 DomStorageDatabase::~DomStorageDatabase() {
35 }
36
37 void DomStorageDatabase::ReadAllValues(
38 DomStorageDatabase::ValuesMap* result) {
39 if (!LazyOpen(false))
40 return;
41
42 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE,
43 "SELECT * from ItemTable"));
44 DCHECK(statement.is_valid());
45
46 while (statement.Step()) {
47 string16 key = statement.ColumnString16(0);
48 string16 value;
49 statement.ColumnBlobAsString16(1, &value);
50 (*result)[key] = NullableString16(value, false);
51 }
52 }
53
54 bool DomStorageDatabase::CommitChanges(bool clear_all_first,
55 const ValuesMap& changes) {
56 if (!LazyOpen(!changes.empty()))
57 return false;
58
59 sql::Transaction transaction(db_.get());
60 if (!transaction.Begin())
61 return false;
62
63 if (clear_all_first) {
64 if (!db_->Execute("DELETE FROM ItemTable"))
65 return false;
66 }
67
68 ValuesMap::const_iterator it = changes.begin();
69 for(; it != changes.end(); ++it) {
70 sql::Statement statement;
71 string16 key = it->first;
72 NullableString16 value = it->second;
73 if (value.is_null()) {
74 statement.Assign(db_->GetCachedStatement(SQL_FROM_HERE,
75 "DELETE FROM ItemTable WHERE key=?"));
76 statement.BindString16(0, key);
77 } else {
78 statement.Assign(db_->GetCachedStatement(SQL_FROM_HERE,
79 "INSERT INTO ItemTable VALUES (?,?)"));
michaeln 2012/02/03 04:45:15 style nit: indent two more spaces
benm (inactive) 2012/02/03 11:46:40 Done.
80 statement.BindString16(0, key);
81 statement.BindBlob(1, value.string().data(),
82 value.string().length() * sizeof(char16));
83 }
84 DCHECK(statement.is_valid());
85 statement.Run();
86 }
87 return transaction.Commit();
88 }
89
90 bool DomStorageDatabase::LazyOpen(bool create_if_needed) {
91 if (IsOpen())
92 return true;
93
94 bool database_exists = file_util::PathExists(file_path_);
95
96 if (!database_exists && !create_if_needed) {
97 // If the file doesn't exist already and we haven't been asked to create
98 // a file on disk, then we don't bother opening the database. This means
99 // we wait until we absolutely need to put something onto disk before we
100 // do so.
101 return false;
102 }
103
104 db_.reset(new sql::Connection());
105 db_->set_error_delegate(GetErrorHandlerForDomStorageDatabase());
106 if (!db_->Open(file_path_)) {
michaeln 2012/02/03 04:45:15 please put a todo here about dealing with this sor
benm (inactive) 2012/02/03 11:46:40 Done.
107 LOG(WARNING) << "Unable to open DOM storage database at "
108 << file_path_.value();
109 return false;
110 }
111
112 // sql::Connection uses UTF-8 encoding, but WebCore style databases use
113 // UTF-16, so ensure we match.
114 ignore_result(db_->Execute("PRAGMA encoding=\"UTF-16\""));
115
116 // If the table doesn't exist, try to create it at the current version.
117 if (!db_->DoesTableExist("ItemTable")) {
118 if (CreateTable())
119 return true;
120 // Couldn't create the table.
121 Close();
122 return false;
123 }
124
125 // Table exists, so ensure we're at the right version, upgrading if
126 // necessary.
127 if (UpgradeVersion1To2IfNeeded())
128 return true;
129
130 // Upgrade failed, drop table and start fresh.
131 if (db_->Execute("DROP TABLE ItemTable")) {
michaeln 2012/02/03 04:45:15 The DROP TABLE statement and the following CREATE
benm (inactive) 2012/02/03 11:46:40 Done.
132 if (CreateTable())
133 return true;
134 }
135
136 Close();
137 return false;
138 }
139
140 bool DomStorageDatabase::CreateTable() {
141 DCHECK(IsOpen());
142 // Current version is 2.
143 return CreateTableV2();
144 }
145
146 bool DomStorageDatabase::CreateTableV2() {
147 DCHECK(IsOpen());
148
149 return db_->Execute(
150 "CREATE TABLE IF NOT EXISTS ItemTable ("
151 "key TEXT UNIQUE ON CONFLICT REPLACE, "
152 "value BLOB NOT NULL ON CONFLICT FAIL)");
153 }
154
155 bool DomStorageDatabase::UpgradeVersion1To2IfNeeded() {
156 DCHECK(IsOpen());
157 sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE,
158 "SELECT * FROM ItemTable"));
159 DCHECK(statement.is_valid());
160
161 // Quick check to see if we need to upgrade or not. The single
162 // effect of V1 -> V2 is to change the value column from type
163 // TEXT to type BLOB.
164 sql::ColType value_column_type = statement.DeclaredColumnType(1);
165 if (value_column_type == sql::COLUMN_TYPE_BLOB)
166 return true;
167
168 if (value_column_type != sql::COLUMN_TYPE_TEXT) {
169 // Something is messed up. This is not a V1 database.
170 return false;
171 }
172
173 // Need to migrate from TEXT value column to BLOB.
174 // Store the current database content so we can re-insert
175 // the data into the new V2 table.
176 ValuesMap values;
177 while (statement.Step()) {
178 string16 key = statement.ColumnString16(0);
179 NullableString16 value(statement.ColumnString16(1), false);
180 values[key] = value;
181 }
182
183 sql::Transaction migration(db_.get());
184 if (!migration.Begin())
185 return false;
186
187 if (db_->Execute("DROP TABLE ItemTable")) {
188 CreateTableV2();
189 if (CommitChanges(false, values))
190 return migration.Commit();
191 }
192 return false;
193 }
194
195 void DomStorageDatabase::Close() {
196 if (!IsOpen())
197 return;
198
199 db_->Close();
200 db_.reset(NULL);
michaeln 2012/02/03 04:45:15 could this be simplified to just db_.reset(NULL) a
benm (inactive) 2012/02/03 11:46:40 lgtm! :)
201 }
202
203 } // namespace dom_storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698