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) { | |
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()."; | |
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); | |
81 sqlite3_backup_finish(backup); | |
82 | |
83 // Exactly one page should have been backed up. If this breaks, | |
84 // check this function to make sure assumptions aren't being broken. | |
85 if (rc == SQLITE_DONE) | |
86 DCHECK_EQ(pages, 1); | |
87 | |
88 return rc; | |
89 } | |
90 | |
91 // Hooks for ScopedErrorIgnorer. | |
92 sql::ScopedErrorIgnorer* g_current_ignorer = NULL; | |
93 bool ShouldIgnoreError(int error) { | |
94 if (g_current_ignorer) | |
95 return g_current_ignorer->ShouldIgnoreError(error); | |
96 return false; | |
97 } | |
98 | |
67 } // namespace | 99 } // namespace |
68 | 100 |
69 namespace sql { | 101 namespace sql { |
70 | 102 |
71 bool StatementID::operator<(const StatementID& other) const { | 103 bool StatementID::operator<(const StatementID& other) const { |
72 if (number_ != other.number_) | 104 if (number_ != other.number_) |
73 return number_ < other.number_; | 105 return number_ < other.number_; |
74 return strcmp(str_, other.str_) < 0; | 106 return strcmp(str_, other.str_) < 0; |
75 } | 107 } |
76 | 108 |
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
288 // page, and if it does not match the total retrieved from a | 320 // page, and if it does not match the total retrieved from a |
289 // filesystem call, treats the database as corrupt. This situation | 321 // filesystem call, treats the database as corrupt. This situation |
290 // breaks almost all SQLite calls. "PRAGMA writable_schema" can be | 322 // breaks almost all SQLite calls. "PRAGMA writable_schema" can be |
291 // used to hint to SQLite to soldier on in that case, specifically | 323 // used to hint to SQLite to soldier on in that case, specifically |
292 // for purposes of recovery. [See SQLITE_CORRUPT_BKPT case in | 324 // for purposes of recovery. [See SQLITE_CORRUPT_BKPT case in |
293 // sqlite3.c lockBtree().] | 325 // sqlite3.c lockBtree().] |
294 // TODO(shess): With this, "PRAGMA auto_vacuum" and "PRAGMA | 326 // TODO(shess): With this, "PRAGMA auto_vacuum" and "PRAGMA |
295 // page_size" can be used to query such a database. | 327 // page_size" can be used to query such a database. |
296 ScopedWritableSchema writable_schema(db_); | 328 ScopedWritableSchema writable_schema(db_); |
297 | 329 |
298 sqlite3_backup* backup = sqlite3_backup_init(db_, "main", | 330 const char* kMain = "main"; |
299 null_db.db_, "main"); | 331 int rc = BackupDatabase(null_db.db_, db_, kMain); |
300 if (!backup) { | |
301 DLOG(FATAL) << "Unable to start sqlite3_backup()."; | |
302 return false; | |
303 } | |
304 | |
305 // -1 backs up the entire database. | |
306 int rc = sqlite3_backup_step(backup, -1); | |
307 int pages = sqlite3_backup_pagecount(backup); | |
308 sqlite3_backup_finish(backup); | |
309 | 332 |
310 // The destination database was locked. | 333 // The destination database was locked. |
311 if (rc == SQLITE_BUSY) { | 334 if (rc == SQLITE_BUSY) { |
312 return false; | 335 return false; |
313 } | 336 } |
314 | 337 |
338 // SQLITE_NOTADB can happen if page 1 exists but is not formatted | |
erikwright (departed)
2013/06/11 18:54:19
Can/should this block be a separate CL?
Scott Hess - ex-Googler
2013/06/12 22:42:46
It's in here so that the example tests can pass.
| |
339 // correctly. SQLITE_IOERR_SHORT_READ can happen if the database | |
340 // isn't even big enough for one page. Either way, reach in and | |
341 // truncate it before trying again. | |
342 // TODO(shess): Maybe it would be worthwhile to just truncate from | |
343 // the get-go? | |
344 if (rc == SQLITE_NOTADB || rc == SQLITE_IOERR_SHORT_READ) { | |
345 sqlite3_file* file = NULL; | |
346 rc = sqlite3_file_control(db_, "main", SQLITE_FCNTL_FILE_POINTER, &file); | |
347 if (rc != SQLITE_OK) { | |
348 DLOG(FATAL) << "Failure getting file handle."; | |
349 return false; | |
350 } else if (!file) { | |
351 DLOG(FATAL) << "File handle is empty."; | |
352 return false; | |
353 } | |
354 | |
355 rc = file->pMethods->xTruncate(file, 0); | |
356 if (rc != SQLITE_OK) { | |
357 DLOG(FATAL) << "Failed to truncate file."; | |
358 return false; | |
359 } | |
360 | |
361 rc = BackupDatabase(null_db.db_, db_, kMain); | |
362 | |
363 if (rc != SQLITE_DONE) { | |
364 DLOG(FATAL) << "Failed retrying Raze()."; | |
365 } | |
366 } | |
367 | |
315 // The entire database should have been backed up. | 368 // The entire database should have been backed up. |
316 if (rc != SQLITE_DONE) { | 369 if (rc != SQLITE_DONE) { |
370 // TODO(shess): Figure out which other cases can happen. | |
317 DLOG(FATAL) << "Unable to copy entire null database."; | 371 DLOG(FATAL) << "Unable to copy entire null database."; |
318 return false; | 372 return false; |
319 } | 373 } |
320 | 374 |
321 // Exactly one page should have been backed up. If this breaks, | |
322 // check this function to make sure assumptions aren't being broken. | |
323 DCHECK_EQ(pages, 1); | |
324 | |
325 return true; | 375 return true; |
326 } | 376 } |
327 | 377 |
328 bool Connection::RazeWithTimout(base::TimeDelta timeout) { | 378 bool Connection::RazeWithTimout(base::TimeDelta timeout) { |
329 if (!db_) { | 379 if (!db_) { |
330 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; | 380 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; |
331 return false; | 381 return false; |
332 } | 382 } |
333 | 383 |
334 ScopedBusyTimeout busy_timeout(db_); | 384 ScopedBusyTimeout busy_timeout(db_); |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
432 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; | 482 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
433 return false; | 483 return false; |
434 } | 484 } |
435 | 485 |
436 int error = ExecuteAndReturnErrorCode(sql); | 486 int error = ExecuteAndReturnErrorCode(sql); |
437 if (error != SQLITE_OK) | 487 if (error != SQLITE_OK) |
438 error = OnSqliteError(error, NULL); | 488 error = OnSqliteError(error, NULL); |
439 | 489 |
440 // This needs to be a FATAL log because the error case of arriving here is | 490 // This needs to be a FATAL log because the error case of arriving here is |
441 // that there's a malformed SQL statement. This can arise in development if | 491 // that there's a malformed SQL statement. This can arise in development if |
442 // a change alters the schema but not all queries adjust. | 492 // a change alters the schema but not all queries adjust. This can happen |
493 // in production if the schema is corrupted. | |
443 if (error == SQLITE_ERROR) | 494 if (error == SQLITE_ERROR) |
444 DLOG(FATAL) << "SQL Error in " << sql << ", " << GetErrorMessage(); | 495 DLOG(FATAL) << "SQL Error in " << sql << ", " << GetErrorMessage(); |
445 return error == SQLITE_OK; | 496 return error == SQLITE_OK; |
446 } | 497 } |
447 | 498 |
448 bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) { | 499 bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) { |
449 if (!db_) { | 500 if (!db_) { |
450 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; | 501 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
451 return false; | 502 return false; |
452 } | 503 } |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
650 DCHECK_EQ(err, SQLITE_OK) << "Could not enable extended result codes"; | 701 DCHECK_EQ(err, SQLITE_OK) << "Could not enable extended result codes"; |
651 | 702 |
652 // If indicated, lock up the database before doing anything else, so | 703 // If indicated, lock up the database before doing anything else, so |
653 // that the following code doesn't have to deal with locking. | 704 // that the following code doesn't have to deal with locking. |
654 // TODO(shess): This code is brittle. Find the cases where code | 705 // TODO(shess): This code is brittle. Find the cases where code |
655 // doesn't request |exclusive_locking_| and audit that it does the | 706 // doesn't request |exclusive_locking_| and audit that it does the |
656 // right thing with SQLITE_BUSY, and that it doesn't make | 707 // right thing with SQLITE_BUSY, and that it doesn't make |
657 // assumptions about who might change things in the database. | 708 // assumptions about who might change things in the database. |
658 // http://crbug.com/56559 | 709 // http://crbug.com/56559 |
659 if (exclusive_locking_) { | 710 if (exclusive_locking_) { |
660 // TODO(shess): This should probably be a full CHECK(). Code | 711 // TODO(shess): This should probably be a failure. Code which |
661 // which requests exclusive locking but doesn't get it is almost | 712 // requests exclusive locking but doesn't get it is almost certain |
662 // certain to be ill-tested. | 713 // to be ill-tested. |
663 if (!Execute("PRAGMA locking_mode=EXCLUSIVE")) | 714 ignore_result(Execute("PRAGMA locking_mode=EXCLUSIVE")); |
664 DLOG(FATAL) << "Could not set locking mode: " << GetErrorMessage(); | |
665 } | 715 } |
666 | 716 |
667 // http://www.sqlite.org/pragma.html#pragma_journal_mode | 717 // http://www.sqlite.org/pragma.html#pragma_journal_mode |
668 // DELETE (default) - delete -journal file to commit. | 718 // DELETE (default) - delete -journal file to commit. |
669 // TRUNCATE - truncate -journal file to commit. | 719 // TRUNCATE - truncate -journal file to commit. |
670 // PERSIST - zero out header of -journal file to commit. | 720 // PERSIST - zero out header of -journal file to commit. |
671 // journal_size_limit provides size to trim to in PERSIST. | 721 // journal_size_limit provides size to trim to in PERSIST. |
672 // TODO(shess): Figure out if PERSIST and journal_size_limit really | 722 // TODO(shess): Figure out if PERSIST and journal_size_limit really |
673 // matter. In theory, it keeps pages pre-allocated, so if | 723 // matter. In theory, it keeps pages pre-allocated, so if |
674 // transactions usually fit, it should be faster. | 724 // transactions usually fit, it should be faster. |
675 ignore_result(Execute("PRAGMA journal_mode = PERSIST")); | 725 ignore_result(Execute("PRAGMA journal_mode = PERSIST")); |
676 ignore_result(Execute("PRAGMA journal_size_limit = 16384")); | 726 ignore_result(Execute("PRAGMA journal_size_limit = 16384")); |
677 | 727 |
678 const base::TimeDelta kBusyTimeout = | 728 const base::TimeDelta kBusyTimeout = |
679 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds); | 729 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds); |
680 | 730 |
681 if (page_size_ != 0) { | 731 if (page_size_ != 0) { |
682 // Enforce SQLite restrictions on |page_size_|. | 732 // Enforce SQLite restrictions on |page_size_|. |
683 DCHECK(!(page_size_ & (page_size_ - 1))) | 733 DCHECK(!(page_size_ & (page_size_ - 1))) |
684 << " page_size_ " << page_size_ << " is not a power of two."; | 734 << " page_size_ " << page_size_ << " is not a power of two."; |
685 const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h | 735 const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h |
686 DCHECK_LE(page_size_, kSqliteMaxPageSize); | 736 DCHECK_LE(page_size_, kSqliteMaxPageSize); |
687 const std::string sql = | 737 const std::string sql = |
688 base::StringPrintf("PRAGMA page_size=%d", page_size_); | 738 base::StringPrintf("PRAGMA page_size=%d", page_size_); |
689 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout)) | 739 ignore_result(ExecuteWithTimeout(sql.c_str(), kBusyTimeout)); |
690 DLOG(FATAL) << "Could not set page size: " << GetErrorMessage(); | |
691 } | 740 } |
692 | 741 |
693 if (cache_size_ != 0) { | 742 if (cache_size_ != 0) { |
694 const std::string sql = | 743 const std::string sql = |
695 base::StringPrintf("PRAGMA cache_size=%d", cache_size_); | 744 base::StringPrintf("PRAGMA cache_size=%d", cache_size_); |
696 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout)) | 745 ignore_result(ExecuteWithTimeout(sql.c_str(), kBusyTimeout)); |
697 DLOG(FATAL) << "Could not set cache size: " << GetErrorMessage(); | |
698 } | 746 } |
699 | 747 |
700 if (!ExecuteWithTimeout("PRAGMA secure_delete=ON", kBusyTimeout)) { | 748 if (!ExecuteWithTimeout("PRAGMA secure_delete=ON", kBusyTimeout)) { |
701 DLOG(FATAL) << "Could not enable secure_delete: " << GetErrorMessage(); | |
702 Close(); | 749 Close(); |
703 return false; | 750 return false; |
704 } | 751 } |
705 | 752 |
706 return true; | 753 return true; |
707 } | 754 } |
708 | 755 |
709 void Connection::DoRollback() { | 756 void Connection::DoRollback() { |
710 Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK")); | 757 Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK")); |
711 rollback.Run(); | 758 rollback.Run(); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
756 error_callback_.Run(err, stmt); | 803 error_callback_.Run(err, stmt); |
757 return err; | 804 return err; |
758 } | 805 } |
759 | 806 |
760 // TODO(shess): Remove |error_delegate_| once everything is | 807 // TODO(shess): Remove |error_delegate_| once everything is |
761 // converted to |error_callback_|. | 808 // converted to |error_callback_|. |
762 if (error_delegate_.get()) | 809 if (error_delegate_.get()) |
763 return error_delegate_->OnError(err, this, stmt); | 810 return error_delegate_->OnError(err, this, stmt); |
764 | 811 |
765 // The default handling is to assert on debug and to ignore on release. | 812 // The default handling is to assert on debug and to ignore on release. |
766 DLOG(FATAL) << GetErrorMessage(); | 813 if (!ShouldIgnoreError(err)) |
814 DLOG(FATAL) << GetErrorMessage(); | |
767 return err; | 815 return err; |
768 } | 816 } |
769 | 817 |
770 // TODO(shess): Allow specifying integrity_check versus quick_check. | 818 // TODO(shess): Allow specifying integrity_check versus quick_check. |
771 // TODO(shess): Allow specifying maximum results (default 100 lines). | 819 // TODO(shess): Allow specifying maximum results (default 100 lines). |
772 bool Connection::IntegrityCheck(std::vector<std::string>* messages) { | 820 bool Connection::IntegrityCheck(std::vector<std::string>* messages) { |
773 const char kSql[] = "PRAGMA integrity_check"; | 821 const char kSql[] = "PRAGMA integrity_check"; |
774 sql::Statement stmt(GetUniqueStatement(kSql)); | 822 sql::Statement stmt(GetUniqueStatement(kSql)); |
775 | 823 |
776 messages->clear(); | 824 messages->clear(); |
777 | 825 |
778 // The pragma appears to return all results (up to 100 by default) | 826 // The pragma appears to return all results (up to 100 by default) |
779 // as a single string. This doesn't appear to be an API contract, | 827 // as a single string. This doesn't appear to be an API contract, |
780 // it could return separate lines, so loop _and_ split. | 828 // it could return separate lines, so loop _and_ split. |
781 while (stmt.Step()) { | 829 while (stmt.Step()) { |
782 std::string result(stmt.ColumnString(0)); | 830 std::string result(stmt.ColumnString(0)); |
783 base::SplitString(result, '\n', messages); | 831 base::SplitString(result, '\n', messages); |
784 } | 832 } |
785 return stmt.Succeeded(); | 833 return stmt.Succeeded(); |
786 } | 834 } |
787 | 835 |
836 ScopedErrorIgnorer::ScopedErrorIgnorer() | |
837 : checked_(false), | |
838 next_(g_current_ignorer) { | |
839 g_current_ignorer = this; | |
840 } | |
841 | |
842 ScopedErrorIgnorer::~ScopedErrorIgnorer() { | |
843 CHECK(checked_); | |
erikwright (departed)
2013/06/11 18:54:19
This should probably be ADD_FAILURE instead of CHE
Scott Hess - ex-Googler
2013/06/12 22:42:46
Basically I hate all this :-).
OK, so would it ma
| |
844 DCHECK_EQ(g_current_ignorer, this); | |
845 g_current_ignorer = next_; | |
846 } | |
847 | |
848 void ScopedErrorIgnorer::IgnoreError(int err) { | |
849 DCHECK_EQ(0u, ignore_errors_.count(err)); | |
850 ignore_errors_.insert(err); | |
851 } | |
852 | |
853 bool ScopedErrorIgnorer::CheckIgnoredErrors() { | |
854 checked_ = true; | |
855 return errors_ignored_ == ignore_errors_; | |
856 } | |
857 | |
858 // static | |
859 bool ScopedErrorIgnorer::ShouldIgnoreError(int err) { | |
860 // Do not ignore if no scoped ignorer. | |
861 if (!g_current_ignorer) | |
862 return false; | |
863 | |
864 // Check extended code. | |
865 if (g_current_ignorer->ignore_errors_.count(err) > 0) { | |
866 // Record that the error was seen and ignore it. | |
867 g_current_ignorer->errors_ignored_.insert(err); | |
868 return true; | |
869 } | |
870 | |
871 // Trim extended codes. | |
872 err &= 0xff; | |
873 | |
874 // Check extended code. | |
erikwright (departed)
2013/06/11 18:54:19
It seems like either line 874 or 864 is wrong?
Scott Hess - ex-Googler
2013/06/12 22:42:46
Doh, this one is checking the non-extended code.
| |
875 if (g_current_ignorer->ignore_errors_.count(err) > 0) { | |
876 // Record that the error was seen and ignore it. | |
877 g_current_ignorer->errors_ignored_.insert(err); | |
878 return true; | |
879 } | |
880 | |
881 // Unexpected error, do not ignore. | |
882 return false; | |
883 } | |
884 | |
788 } // namespace sql | 885 } // namespace sql |
OLD | NEW |