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

Side by Side Diff: sql/connection.cc

Issue 8899012: Put debugging assertions into sql::Statement. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years 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 | Annotate | Revision Log
« no previous file with comments | « sql/connection.h ('k') | sql/connection_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sql/connection.h" 5 #include "sql/connection.h"
6 6
7 #include <string.h> 7 #include <string.h>
8 8
9 #include "base/file_path.h" 9 #include "base/file_path.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 // prevent optimization. 125 // prevent optimization.
126 CHECK_LT(nTouched, 1000*1000*1000U); 126 CHECK_LT(nTouched, 1000*1000*1000U);
127 #endif 127 #endif
128 sqlite3_close(db_); 128 sqlite3_close(db_);
129 db_ = NULL; 129 db_ = NULL;
130 } 130 }
131 } 131 }
132 132
133 void Connection::Preload() { 133 void Connection::Preload() {
134 if (!db_) { 134 if (!db_) {
135 NOTREACHED(); 135 DLOG(FATAL) << "Cannot preload null db";
136 return; 136 return;
137 } 137 }
138 138
139 // A statement must be open for the preload command to work. If the meta 139 // A statement must be open for the preload command to work. If the meta
140 // table doesn't exist, it probably means this is a new database and there 140 // table doesn't exist, it probably means this is a new database and there
141 // is nothing to preload (so it's OK we do nothing). 141 // is nothing to preload (so it's OK we do nothing).
142 if (!DoesTableExist("meta")) 142 if (!DoesTableExist("meta"))
143 return; 143 return;
144 Statement dummy(GetUniqueStatement("SELECT * FROM meta")); 144 Statement dummy(GetUniqueStatement("SELECT * FROM meta"));
145 if (!dummy || !dummy.Step()) 145 if (!dummy.Step())
146 return; 146 return;
147 147
148 #if !defined(USE_SYSTEM_SQLITE) 148 #if !defined(USE_SYSTEM_SQLITE)
149 // This function is only defined in Chromium's version of sqlite. 149 // This function is only defined in Chromium's version of sqlite.
150 // Do not call it when using system sqlite. 150 // Do not call it when using system sqlite.
151 sqlite3_preload(db_); 151 sqlite3_preload(db_);
152 #endif 152 #endif
153 } 153 }
154 154
155 bool Connection::BeginTransaction() { 155 bool Connection::BeginTransaction() {
156 if (needs_rollback_) { 156 if (needs_rollback_) {
157 DCHECK_GT(transaction_nesting_, 0); 157 DCHECK_GT(transaction_nesting_, 0);
158 158
159 // When we're going to rollback, fail on this begin and don't actually 159 // When we're going to rollback, fail on this begin and don't actually
160 // mark us as entering the nested transaction. 160 // mark us as entering the nested transaction.
161 return false; 161 return false;
162 } 162 }
163 163
164 bool success = true; 164 bool success = true;
165 if (!transaction_nesting_) { 165 if (!transaction_nesting_) {
166 needs_rollback_ = false; 166 needs_rollback_ = false;
167 167
168 Statement begin(GetCachedStatement(SQL_FROM_HERE, "BEGIN TRANSACTION")); 168 Statement begin(GetCachedStatement(SQL_FROM_HERE, "BEGIN TRANSACTION"));
169 if (!begin || !begin.Run()) 169 if (!begin.Run())
170 return false; 170 return false;
171 } 171 }
172 transaction_nesting_++; 172 transaction_nesting_++;
173 return success; 173 return success;
174 } 174 }
175 175
176 void Connection::RollbackTransaction() { 176 void Connection::RollbackTransaction() {
177 if (!transaction_nesting_) { 177 if (!transaction_nesting_) {
178 NOTREACHED() << "Rolling back a nonexistent transaction"; 178 DLOG(FATAL) << "Rolling back a nonexistent transaction";
179 return; 179 return;
180 } 180 }
181 181
182 transaction_nesting_--; 182 transaction_nesting_--;
183 183
184 if (transaction_nesting_ > 0) { 184 if (transaction_nesting_ > 0) {
185 // Mark the outermost transaction as needing rollback. 185 // Mark the outermost transaction as needing rollback.
186 needs_rollback_ = true; 186 needs_rollback_ = true;
187 return; 187 return;
188 } 188 }
189 189
190 DoRollback(); 190 DoRollback();
191 } 191 }
192 192
193 bool Connection::CommitTransaction() { 193 bool Connection::CommitTransaction() {
194 if (!transaction_nesting_) { 194 if (!transaction_nesting_) {
195 NOTREACHED() << "Rolling back a nonexistent transaction"; 195 DLOG(FATAL) << "Rolling back a nonexistent transaction";
196 return false; 196 return false;
197 } 197 }
198 transaction_nesting_--; 198 transaction_nesting_--;
199 199
200 if (transaction_nesting_ > 0) { 200 if (transaction_nesting_ > 0) {
201 // Mark any nested transactions as failing after we've already got one. 201 // Mark any nested transactions as failing after we've already got one.
202 return !needs_rollback_; 202 return !needs_rollback_;
203 } 203 }
204 204
205 if (needs_rollback_) { 205 if (needs_rollback_) {
206 DoRollback(); 206 DoRollback();
207 return false; 207 return false;
208 } 208 }
209 209
210 Statement commit(GetCachedStatement(SQL_FROM_HERE, "COMMIT")); 210 Statement commit(GetCachedStatement(SQL_FROM_HERE, "COMMIT"));
211 if (!commit)
212 return false;
213 return commit.Run(); 211 return commit.Run();
214 } 212 }
215 213
216 bool Connection::Execute(const char* sql) { 214 int Connection::ExecuteAndReturnErrorCode(const char* sql) {
217 if (!db_) 215 if (!db_)
218 return false; 216 return false;
219 return sqlite3_exec(db_, sql, NULL, NULL, NULL) == SQLITE_OK; 217 return sqlite3_exec(db_, sql, NULL, NULL, NULL);
218 }
219
220 bool Connection::Execute(const char* sql) {
221 int error = ExecuteAndReturnErrorCode(sql);
222 if (error == SQLITE_ERROR)
223 DLOG(FATAL) << "SQL Error in " << sql;
Scott Hess - ex-Googler 2011/12/09 22:54:40 In my final review, I went over the OnSqliteError(
224 return error == SQLITE_OK;
220 } 225 }
221 226
222 bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) { 227 bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) {
223 if (!db_) 228 if (!db_)
224 return false; 229 return false;
225 230
226 ScopedBusyTimeout busy_timeout(db_); 231 ScopedBusyTimeout busy_timeout(db_);
227 busy_timeout.SetTimeout(timeout); 232 busy_timeout.SetTimeout(timeout);
228 return sqlite3_exec(db_, sql, NULL, NULL, NULL) == SQLITE_OK; 233 return Execute(sql);
229 } 234 }
230 235
231 bool Connection::HasCachedStatement(const StatementID& id) const { 236 bool Connection::HasCachedStatement(const StatementID& id) const {
232 return statement_cache_.find(id) != statement_cache_.end(); 237 return statement_cache_.find(id) != statement_cache_.end();
233 } 238 }
234 239
235 scoped_refptr<Connection::StatementRef> Connection::GetCachedStatement( 240 scoped_refptr<Connection::StatementRef> Connection::GetCachedStatement(
236 const StatementID& id, 241 const StatementID& id,
237 const char* sql) { 242 const char* sql) {
238 CachedStatementMap::iterator i = statement_cache_.find(id); 243 CachedStatementMap::iterator i = statement_cache_.find(id);
(...skipping 13 matching lines...) Expand all
252 return statement; 257 return statement;
253 } 258 }
254 259
255 scoped_refptr<Connection::StatementRef> Connection::GetUniqueStatement( 260 scoped_refptr<Connection::StatementRef> Connection::GetUniqueStatement(
256 const char* sql) { 261 const char* sql) {
257 if (!db_) 262 if (!db_)
258 return new StatementRef(this, NULL); // Return inactive statement. 263 return new StatementRef(this, NULL); // Return inactive statement.
259 264
260 sqlite3_stmt* stmt = NULL; 265 sqlite3_stmt* stmt = NULL;
261 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) { 266 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) {
262 // Treat this as non-fatal, it can occur in a number of valid cases, and 267 // This is evidence of a syntax error in the incoming SQL.
263 // callers should be doing their own error handling. 268 DLOG(FATAL) << "SQL compile error " << GetErrorMessage();
264 DLOG(WARNING) << "SQL compile error " << GetErrorMessage();
265 return new StatementRef(this, NULL); 269 return new StatementRef(this, NULL);
266 } 270 }
267 return new StatementRef(this, stmt); 271 return new StatementRef(this, stmt);
268 } 272 }
269 273
274 bool Connection::IsSQLValid(const char* sql) {
275 sqlite3_stmt* stmt = NULL;
276 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK)
277 return false;
278
279 sqlite3_finalize(stmt);
280 return true;
281 }
282
270 bool Connection::DoesTableExist(const char* table_name) const { 283 bool Connection::DoesTableExist(const char* table_name) const {
271 // GetUniqueStatement can't be const since statements may modify the 284 // GetUniqueStatement can't be const since statements may modify the
272 // database, but we know ours doesn't modify it, so the cast is safe. 285 // database, but we know ours doesn't modify it, so the cast is safe.
273 Statement statement(const_cast<Connection*>(this)->GetUniqueStatement( 286 Statement statement(const_cast<Connection*>(this)->GetUniqueStatement(
274 "SELECT name FROM sqlite_master " 287 "SELECT name FROM sqlite_master "
275 "WHERE type='table' AND name=?")); 288 "WHERE type='table' AND name=?"));
276 if (!statement)
277 return false;
278 statement.BindString(0, table_name); 289 statement.BindString(0, table_name);
279 return statement.Step(); // Table exists if any row was returned. 290 return statement.Step(); // Table exists if any row was returned.
280 } 291 }
281 292
282 bool Connection::DoesColumnExist(const char* table_name, 293 bool Connection::DoesColumnExist(const char* table_name,
283 const char* column_name) const { 294 const char* column_name) const {
284 std::string sql("PRAGMA TABLE_INFO("); 295 std::string sql("PRAGMA TABLE_INFO(");
285 sql.append(table_name); 296 sql.append(table_name);
286 sql.append(")"); 297 sql.append(")");
287 298
288 // Our SQL is non-mutating, so this cast is OK. 299 // Our SQL is non-mutating, so this cast is OK.
289 Statement statement(const_cast<Connection*>(this)->GetUniqueStatement( 300 Statement statement(const_cast<Connection*>(this)->GetUniqueStatement(
290 sql.c_str())); 301 sql.c_str()));
291 if (!statement)
292 return false;
293 302
294 while (statement.Step()) { 303 while (statement.Step()) {
295 if (!statement.ColumnString(1).compare(column_name)) 304 if (!statement.ColumnString(1).compare(column_name))
296 return true; 305 return true;
297 } 306 }
298 return false; 307 return false;
299 } 308 }
300 309
301 int64 Connection::GetLastInsertRowId() const { 310 int64 Connection::GetLastInsertRowId() const {
302 if (!db_) { 311 if (!db_) {
303 NOTREACHED(); 312 DLOG(FATAL) << "Illegal use of connection without a db";
304 return 0; 313 return 0;
305 } 314 }
306 return sqlite3_last_insert_rowid(db_); 315 return sqlite3_last_insert_rowid(db_);
307 } 316 }
308 317
309 int Connection::GetLastChangeCount() const { 318 int Connection::GetLastChangeCount() const {
310 if (!db_) { 319 if (!db_) {
311 NOTREACHED(); 320 DLOG(FATAL) << "Illegal use of connection without a db";
312 return 0; 321 return 0;
313 } 322 }
314 return sqlite3_changes(db_); 323 return sqlite3_changes(db_);
315 } 324 }
316 325
317 int Connection::GetErrorCode() const { 326 int Connection::GetErrorCode() const {
318 if (!db_) 327 if (!db_)
319 return SQLITE_ERROR; 328 return SQLITE_ERROR;
320 return sqlite3_errcode(db_); 329 return sqlite3_errcode(db_);
321 } 330 }
(...skipping 10 matching lines...) Expand all
332 } 341 }
333 342
334 const char* Connection::GetErrorMessage() const { 343 const char* Connection::GetErrorMessage() const {
335 if (!db_) 344 if (!db_)
336 return "sql::Connection has no connection."; 345 return "sql::Connection has no connection.";
337 return sqlite3_errmsg(db_); 346 return sqlite3_errmsg(db_);
338 } 347 }
339 348
340 bool Connection::OpenInternal(const std::string& file_name) { 349 bool Connection::OpenInternal(const std::string& file_name) {
341 if (db_) { 350 if (db_) {
342 NOTREACHED() << "sql::Connection is already open."; 351 DLOG(FATAL) << "sql::Connection is already open.";
343 return false; 352 return false;
344 } 353 }
345 354
346 int err = sqlite3_open(file_name.c_str(), &db_); 355 int err = sqlite3_open(file_name.c_str(), &db_);
347 if (err != SQLITE_OK) { 356 if (err != SQLITE_OK) {
348 OnSqliteError(err, NULL); 357 OnSqliteError(err, NULL);
349 db_ = NULL; 358 db_ = NULL;
350 return false; 359 return false;
351 } 360 }
352 361
(...skipping 10 matching lines...) Expand all
363 // TODO(shess): This code is brittle. Find the cases where code 372 // TODO(shess): This code is brittle. Find the cases where code
364 // doesn't request |exclusive_locking_| and audit that it does the 373 // doesn't request |exclusive_locking_| and audit that it does the
365 // right thing with SQLITE_BUSY, and that it doesn't make 374 // right thing with SQLITE_BUSY, and that it doesn't make
366 // assumptions about who might change things in the database. 375 // assumptions about who might change things in the database.
367 // http://crbug.com/56559 376 // http://crbug.com/56559
368 if (exclusive_locking_) { 377 if (exclusive_locking_) {
369 // TODO(shess): This should probably be a full CHECK(). Code 378 // TODO(shess): This should probably be a full CHECK(). Code
370 // which requests exclusive locking but doesn't get it is almost 379 // which requests exclusive locking but doesn't get it is almost
371 // certain to be ill-tested. 380 // certain to be ill-tested.
372 if (!Execute("PRAGMA locking_mode=EXCLUSIVE")) 381 if (!Execute("PRAGMA locking_mode=EXCLUSIVE"))
373 NOTREACHED() << "Could not set locking mode: " << GetErrorMessage(); 382 DLOG(FATAL) << "Could not set locking mode: " << GetErrorMessage();
374 } 383 }
375 384
376 const base::TimeDelta kBusyTimeout = 385 const base::TimeDelta kBusyTimeout =
377 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds); 386 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds);
378 387
379 if (page_size_ != 0) { 388 if (page_size_ != 0) {
380 // Enforce SQLite restrictions on |page_size_|. 389 // Enforce SQLite restrictions on |page_size_|.
381 DCHECK(!(page_size_ & (page_size_ - 1))) 390 DCHECK(!(page_size_ & (page_size_ - 1)))
382 << " page_size_ " << page_size_ << " is not a power of two."; 391 << " page_size_ " << page_size_ << " is not a power of two.";
383 static const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h 392 static const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h
384 DCHECK_LE(page_size_, kSqliteMaxPageSize); 393 DCHECK_LE(page_size_, kSqliteMaxPageSize);
385 const std::string sql = StringPrintf("PRAGMA page_size=%d", page_size_); 394 const std::string sql = StringPrintf("PRAGMA page_size=%d", page_size_);
386 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout)) 395 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout))
387 NOTREACHED() << "Could not set page size: " << GetErrorMessage(); 396 DLOG(FATAL) << "Could not set page size: " << GetErrorMessage();
388 } 397 }
389 398
390 if (cache_size_ != 0) { 399 if (cache_size_ != 0) {
391 const std::string sql = StringPrintf("PRAGMA cache_size=%d", cache_size_); 400 const std::string sql = StringPrintf("PRAGMA cache_size=%d", cache_size_);
392 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout)) 401 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout))
393 NOTREACHED() << "Could not set cache size: " << GetErrorMessage(); 402 DLOG(FATAL) << "Could not set cache size: " << GetErrorMessage();
394 } 403 }
395 404
396 if (!ExecuteWithTimeout("PRAGMA secure_delete=ON", kBusyTimeout)) { 405 if (!ExecuteWithTimeout("PRAGMA secure_delete=ON", kBusyTimeout)) {
397 NOTREACHED() << "Could not enable secure_delete: " << GetErrorMessage(); 406 DLOG(FATAL) << "Could not enable secure_delete: " << GetErrorMessage();
398 Close(); 407 Close();
399 return false; 408 return false;
400 } 409 }
401 410
402 return true; 411 return true;
403 } 412 }
404 413
405 void Connection::DoRollback() { 414 void Connection::DoRollback() {
406 Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK")); 415 Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK"));
407 if (rollback) 416 rollback.Run();
408 rollback.Run();
409 } 417 }
410 418
411 void Connection::StatementRefCreated(StatementRef* ref) { 419 void Connection::StatementRefCreated(StatementRef* ref) {
412 DCHECK(open_statements_.find(ref) == open_statements_.end()); 420 DCHECK(open_statements_.find(ref) == open_statements_.end());
413 open_statements_.insert(ref); 421 open_statements_.insert(ref);
414 } 422 }
415 423
416 void Connection::StatementRefDeleted(StatementRef* ref) { 424 void Connection::StatementRefDeleted(StatementRef* ref) {
417 StatementRefSet::iterator i = open_statements_.find(ref); 425 StatementRefSet::iterator i = open_statements_.find(ref);
418 if (i == open_statements_.end()) 426 if (i == open_statements_.end())
419 NOTREACHED(); 427 DLOG(FATAL) << "Could not find statement";
420 else 428 else
421 open_statements_.erase(i); 429 open_statements_.erase(i);
422 } 430 }
423 431
424 void Connection::ClearCache() { 432 void Connection::ClearCache() {
425 statement_cache_.clear(); 433 statement_cache_.clear();
426 434
427 // The cache clear will get most statements. There may be still be references 435 // The cache clear will get most statements. There may be still be references
428 // to some statements that are held by others (including one-shot statements). 436 // to some statements that are held by others (including one-shot statements).
429 // This will deactivate them so they can't be used again. 437 // This will deactivate them so they can't be used again.
430 for (StatementRefSet::iterator i = open_statements_.begin(); 438 for (StatementRefSet::iterator i = open_statements_.begin();
431 i != open_statements_.end(); ++i) 439 i != open_statements_.end(); ++i)
432 (*i)->Close(); 440 (*i)->Close();
433 } 441 }
434 442
435 int Connection::OnSqliteError(int err, sql::Statement *stmt) { 443 int Connection::OnSqliteError(int err, sql::Statement *stmt) {
436 if (error_delegate_.get()) 444 if (error_delegate_.get())
437 return error_delegate_->OnError(err, this, stmt); 445 return error_delegate_->OnError(err, this, stmt);
438 // The default handling is to assert on debug and to ignore on release. 446 // The default handling is to assert on debug and to ignore on release.
439 NOTREACHED() << GetErrorMessage(); 447 DLOG(FATAL) << GetErrorMessage();
440 return err; 448 return err;
441 } 449 }
442 450
443 } // namespace sql 451 } // namespace sql
OLDNEW
« no previous file with comments | « sql/connection.h ('k') | sql/connection_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698