Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |