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

Side by Side Diff: sql/connection.cc

Issue 17752002: [sql] Additional Raze() unit tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | 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) 2012 The Chromium Authors. All rights reserved. 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 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/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 sqlite3_exec(db_, "PRAGMA writable_schema=1", NULL, NULL, NULL); 57 sqlite3_exec(db_, "PRAGMA writable_schema=1", NULL, NULL, NULL);
58 } 58 }
59 ~ScopedWritableSchema() { 59 ~ScopedWritableSchema() {
60 sqlite3_exec(db_, "PRAGMA writable_schema=0", NULL, NULL, NULL); 60 sqlite3_exec(db_, "PRAGMA writable_schema=0", NULL, NULL, NULL);
61 } 61 }
62 62
63 private: 63 private:
64 sqlite3* db_; 64 sqlite3* db_;
65 }; 65 };
66 66
67 // Helper to wrap the sqlite3_backup_*() step of Raze(). Return
68 // SQLite error code from running the backup step.
69 int BackupDatabase(sqlite3* src, sqlite3* dst, const char* db_name) {
Greg Billock 2013/06/27 21:01:47 Docs say src and dst must be different. Want to DC
Scott Hess - ex-Googler 2013/06/27 22:41:47 Done.
70 sqlite3_backup* backup = sqlite3_backup_init(dst, db_name, src, db_name);
71 if (!backup) {
72 // Since this call only sets things up, this indicates a gross
73 // error in SQLite.
74 DLOG(FATAL) << "Unable to start sqlite3_backup().";
Greg Billock 2013/06/27 21:01:47 Print out dst->errmsg/errcode as well here?
Scott Hess - ex-Googler 2013/06/27 22:41:47 OK. Not entirely convinced it will be useful due
75 return SQLITE_ABORT;
76 }
77
78 // -1 backs up the entire database.
79 int rc = sqlite3_backup_step(backup, -1);
80 int pages = sqlite3_backup_pagecount(backup);
Greg Billock 2013/06/27 21:01:47 Useful if rc != SQLITE_DONE? Also, need to deal wi
Scott Hess - ex-Googler 2013/06/27 22:41:47 Honestly, I am not sure what to do in those cases.
81 sqlite3_backup_finish(backup);
82
83 // If successful, exactly one page should have been backed up. If
84 // this breaks, check this function to make sure assumptions aren't
85 // being broken.
86 if (rc == SQLITE_DONE)
87 DCHECK_EQ(pages, 1);
88
89 return rc;
90 }
91
67 } // namespace 92 } // namespace
68 93
69 namespace sql { 94 namespace sql {
70 95
71 // static 96 // static
72 Connection::ErrorIgnorerCallback* Connection::current_ignorer_cb_ = NULL; 97 Connection::ErrorIgnorerCallback* Connection::current_ignorer_cb_ = NULL;
73 98
74 // static 99 // static
75 bool Connection::ShouldIgnore(int error) { 100 bool Connection::ShouldIgnore(int error) {
76 if (!current_ignorer_cb_) 101 if (!current_ignorer_cb_)
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 // page, and if it does not match the total retrieved from a 331 // page, and if it does not match the total retrieved from a
307 // filesystem call, treats the database as corrupt. This situation 332 // filesystem call, treats the database as corrupt. This situation
308 // breaks almost all SQLite calls. "PRAGMA writable_schema" can be 333 // breaks almost all SQLite calls. "PRAGMA writable_schema" can be
309 // used to hint to SQLite to soldier on in that case, specifically 334 // used to hint to SQLite to soldier on in that case, specifically
310 // for purposes of recovery. [See SQLITE_CORRUPT_BKPT case in 335 // for purposes of recovery. [See SQLITE_CORRUPT_BKPT case in
311 // sqlite3.c lockBtree().] 336 // sqlite3.c lockBtree().]
312 // TODO(shess): With this, "PRAGMA auto_vacuum" and "PRAGMA 337 // TODO(shess): With this, "PRAGMA auto_vacuum" and "PRAGMA
313 // page_size" can be used to query such a database. 338 // page_size" can be used to query such a database.
314 ScopedWritableSchema writable_schema(db_); 339 ScopedWritableSchema writable_schema(db_);
315 340
316 sqlite3_backup* backup = sqlite3_backup_init(db_, "main", 341 const char* kMain = "main";
317 null_db.db_, "main"); 342 int rc = BackupDatabase(null_db.db_, db_, kMain);
318 if (!backup) {
319 DLOG(FATAL) << "Unable to start sqlite3_backup().";
320 return false;
321 }
322
323 // -1 backs up the entire database.
324 int rc = sqlite3_backup_step(backup, -1);
325 int pages = sqlite3_backup_pagecount(backup);
326 sqlite3_backup_finish(backup);
327 343
328 // The destination database was locked. 344 // The destination database was locked.
329 if (rc == SQLITE_BUSY) { 345 if (rc == SQLITE_BUSY) {
330 return false; 346 return false;
331 } 347 }
332 348
349 // SQLITE_NOTADB can happen if page 1 exists but is not formatted
Greg Billock 2013/06/27 21:01:47 So this is page 1 of the destination?
Scott Hess - ex-Googler 2013/06/27 22:41:47 Comment amended.
350 // correctly. SQLITE_IOERR_SHORT_READ can happen if the database
351 // isn't even big enough for one page. Either way, reach in and
352 // truncate it before trying again.
Greg Billock 2013/06/27 21:01:47 Above it sounds like PRAGMA writeable_schema will
Scott Hess - ex-Googler 2013/06/27 22:41:47 That case covers when the database in the filesyst
Greg Billock 2013/06/28 14:29:09 So we see both these on corruption? On 2013/06/27
353 // TODO(shess): Maybe it would be worthwhile to just truncate from
354 // the get-go?
355 if (rc == SQLITE_NOTADB || rc == SQLITE_IOERR_SHORT_READ) {
Greg Billock 2013/06/27 21:01:47 Should this stanza go in the backup method?
Scott Hess - ex-Googler 2013/06/27 22:41:47 That's what the TODO is about. First it tries to
Greg Billock 2013/06/28 14:29:09 I see. The histogram ought to provide good guidanc
356 sqlite3_file* file = NULL;
357 rc = sqlite3_file_control(db_, "main", SQLITE_FCNTL_FILE_POINTER, &file);
358 if (rc != SQLITE_OK) {
359 DLOG(FATAL) << "Failure getting file handle.";
360 return false;
361 } else if (!file) {
362 DLOG(FATAL) << "File handle is empty.";
363 return false;
364 }
365
366 rc = file->pMethods->xTruncate(file, 0);
367 if (rc != SQLITE_OK) {
368 DLOG(FATAL) << "Failed to truncate file.";
369 return false;
370 }
371
372 rc = BackupDatabase(null_db.db_, db_, kMain);
373
374 if (rc != SQLITE_DONE) {
375 DLOG(FATAL) << "Failed retrying Raze().";
376 }
377 }
378
333 // The entire database should have been backed up. 379 // The entire database should have been backed up.
334 if (rc != SQLITE_DONE) { 380 if (rc != SQLITE_DONE) {
381 // TODO(shess): Figure out which other cases can happen.
335 DLOG(FATAL) << "Unable to copy entire null database."; 382 DLOG(FATAL) << "Unable to copy entire null database.";
336 return false; 383 return false;
337 } 384 }
338 385
339 // Exactly one page should have been backed up. If this breaks,
340 // check this function to make sure assumptions aren't being broken.
341 DCHECK_EQ(pages, 1);
342
343 return true; 386 return true;
344 } 387 }
345 388
346 bool Connection::RazeWithTimout(base::TimeDelta timeout) { 389 bool Connection::RazeWithTimout(base::TimeDelta timeout) {
347 if (!db_) { 390 if (!db_) {
348 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; 391 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db";
349 return false; 392 return false;
350 } 393 }
351 394
352 ScopedBusyTimeout busy_timeout(db_); 395 ScopedBusyTimeout busy_timeout(db_);
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
656 return false; 699 return false;
657 } 700 }
658 701
659 // If |poisoned_| is set, it means an error handler called 702 // If |poisoned_| is set, it means an error handler called
660 // RazeAndClose(). Until regular Close() is called, the caller 703 // RazeAndClose(). Until regular Close() is called, the caller
661 // should be treating the database as open, but is_open() currently 704 // should be treating the database as open, but is_open() currently
662 // only considers the sqlite3 handle's state. 705 // only considers the sqlite3 handle's state.
663 // TODO(shess): Revise is_open() to consider poisoned_, and review 706 // TODO(shess): Revise is_open() to consider poisoned_, and review
664 // to see if any non-testing code even depends on it. 707 // to see if any non-testing code even depends on it.
665 DLOG_IF(FATAL, poisoned_) << "sql::Connection is already open."; 708 DLOG_IF(FATAL, poisoned_) << "sql::Connection is already open.";
709 poisoned_ = false;
666 710
667 int err = sqlite3_open(file_name.c_str(), &db_); 711 int err = sqlite3_open(file_name.c_str(), &db_);
668 if (err != SQLITE_OK) { 712 if (err != SQLITE_OK) {
669 // Histogram failures specific to initial open for debugging 713 // Histogram failures specific to initial open for debugging
670 // purposes. 714 // purposes.
671 UMA_HISTOGRAM_ENUMERATION("Sqlite.OpenFailure", err & 0xff, 50); 715 UMA_HISTOGRAM_ENUMERATION("Sqlite.OpenFailure", err & 0xff, 50);
672 716
673 OnSqliteError(err, NULL); 717 OnSqliteError(err, NULL);
674 Close(); 718 Close();
675 db_ = NULL; 719 db_ = NULL;
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
840 } 884 }
841 885
842 // Best effort to put things back as they were before. 886 // Best effort to put things back as they were before.
843 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF"; 887 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF";
844 ignore_result(Execute(kNoWritableSchema)); 888 ignore_result(Execute(kNoWritableSchema));
845 889
846 return ret; 890 return ret;
847 } 891 }
848 892
849 } // namespace sql 893 } // namespace sql
OLDNEW
« no previous file with comments | « no previous file | sql/connection_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698