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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 } | 61 } |
62 | 62 |
63 private: | 63 private: |
64 sqlite3* db_; | 64 sqlite3* db_; |
65 }; | 65 }; |
66 | 66 |
67 } // namespace | 67 } // namespace |
68 | 68 |
69 namespace sql { | 69 namespace sql { |
70 | 70 |
| 71 // static |
| 72 Connection::ErrorIgnorerCallback* Connection::current_ignorer_cb_ = NULL; |
| 73 |
| 74 // static |
| 75 bool Connection::ShouldIgnore(int error) { |
| 76 if (!current_ignorer_cb_) |
| 77 return false; |
| 78 return current_ignorer_cb_->Run(error); |
| 79 } |
| 80 |
| 81 // static |
| 82 void Connection::SetErrorIgnorer(Connection::ErrorIgnorerCallback* cb) { |
| 83 CHECK(current_ignorer_cb_ == NULL); |
| 84 current_ignorer_cb_ = cb; |
| 85 } |
| 86 |
| 87 // static |
| 88 void Connection::ResetErrorIgnorer() { |
| 89 CHECK(current_ignorer_cb_); |
| 90 current_ignorer_cb_ = NULL; |
| 91 } |
| 92 |
71 bool StatementID::operator<(const StatementID& other) const { | 93 bool StatementID::operator<(const StatementID& other) const { |
72 if (number_ != other.number_) | 94 if (number_ != other.number_) |
73 return number_ < other.number_; | 95 return number_ < other.number_; |
74 return strcmp(str_, other.str_) < 0; | 96 return strcmp(str_, other.str_) < 0; |
75 } | 97 } |
76 | 98 |
77 ErrorDelegate::~ErrorDelegate() { | 99 ErrorDelegate::~ErrorDelegate() { |
78 } | 100 } |
79 | 101 |
80 Connection::StatementRef::StatementRef(Connection* connection, | 102 Connection::StatementRef::StatementRef(Connection* connection, |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; | 454 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
433 return false; | 455 return false; |
434 } | 456 } |
435 | 457 |
436 int error = ExecuteAndReturnErrorCode(sql); | 458 int error = ExecuteAndReturnErrorCode(sql); |
437 if (error != SQLITE_OK) | 459 if (error != SQLITE_OK) |
438 error = OnSqliteError(error, NULL); | 460 error = OnSqliteError(error, NULL); |
439 | 461 |
440 // This needs to be a FATAL log because the error case of arriving here is | 462 // 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 | 463 // that there's a malformed SQL statement. This can arise in development if |
442 // a change alters the schema but not all queries adjust. | 464 // a change alters the schema but not all queries adjust. This can happen |
| 465 // in production if the schema is corrupted. |
443 if (error == SQLITE_ERROR) | 466 if (error == SQLITE_ERROR) |
444 DLOG(FATAL) << "SQL Error in " << sql << ", " << GetErrorMessage(); | 467 DLOG(FATAL) << "SQL Error in " << sql << ", " << GetErrorMessage(); |
445 return error == SQLITE_OK; | 468 return error == SQLITE_OK; |
446 } | 469 } |
447 | 470 |
448 bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) { | 471 bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) { |
449 if (!db_) { | 472 if (!db_) { |
450 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; | 473 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
451 return false; | 474 return false; |
452 } | 475 } |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 DCHECK_EQ(err, SQLITE_OK) << "Could not enable extended result codes"; | 680 DCHECK_EQ(err, SQLITE_OK) << "Could not enable extended result codes"; |
658 | 681 |
659 // If indicated, lock up the database before doing anything else, so | 682 // If indicated, lock up the database before doing anything else, so |
660 // that the following code doesn't have to deal with locking. | 683 // that the following code doesn't have to deal with locking. |
661 // TODO(shess): This code is brittle. Find the cases where code | 684 // TODO(shess): This code is brittle. Find the cases where code |
662 // doesn't request |exclusive_locking_| and audit that it does the | 685 // doesn't request |exclusive_locking_| and audit that it does the |
663 // right thing with SQLITE_BUSY, and that it doesn't make | 686 // right thing with SQLITE_BUSY, and that it doesn't make |
664 // assumptions about who might change things in the database. | 687 // assumptions about who might change things in the database. |
665 // http://crbug.com/56559 | 688 // http://crbug.com/56559 |
666 if (exclusive_locking_) { | 689 if (exclusive_locking_) { |
667 // TODO(shess): This should probably be a full CHECK(). Code | 690 // TODO(shess): This should probably be a failure. Code which |
668 // which requests exclusive locking but doesn't get it is almost | 691 // requests exclusive locking but doesn't get it is almost certain |
669 // certain to be ill-tested. | 692 // to be ill-tested. |
670 if (!Execute("PRAGMA locking_mode=EXCLUSIVE")) | 693 ignore_result(Execute("PRAGMA locking_mode=EXCLUSIVE")); |
671 DLOG(FATAL) << "Could not set locking mode: " << GetErrorMessage(); | |
672 } | 694 } |
673 | 695 |
674 // http://www.sqlite.org/pragma.html#pragma_journal_mode | 696 // http://www.sqlite.org/pragma.html#pragma_journal_mode |
675 // DELETE (default) - delete -journal file to commit. | 697 // DELETE (default) - delete -journal file to commit. |
676 // TRUNCATE - truncate -journal file to commit. | 698 // TRUNCATE - truncate -journal file to commit. |
677 // PERSIST - zero out header of -journal file to commit. | 699 // PERSIST - zero out header of -journal file to commit. |
678 // journal_size_limit provides size to trim to in PERSIST. | 700 // journal_size_limit provides size to trim to in PERSIST. |
679 // TODO(shess): Figure out if PERSIST and journal_size_limit really | 701 // TODO(shess): Figure out if PERSIST and journal_size_limit really |
680 // matter. In theory, it keeps pages pre-allocated, so if | 702 // matter. In theory, it keeps pages pre-allocated, so if |
681 // transactions usually fit, it should be faster. | 703 // transactions usually fit, it should be faster. |
682 ignore_result(Execute("PRAGMA journal_mode = PERSIST")); | 704 ignore_result(Execute("PRAGMA journal_mode = PERSIST")); |
683 ignore_result(Execute("PRAGMA journal_size_limit = 16384")); | 705 ignore_result(Execute("PRAGMA journal_size_limit = 16384")); |
684 | 706 |
685 const base::TimeDelta kBusyTimeout = | 707 const base::TimeDelta kBusyTimeout = |
686 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds); | 708 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds); |
687 | 709 |
688 if (page_size_ != 0) { | 710 if (page_size_ != 0) { |
689 // Enforce SQLite restrictions on |page_size_|. | 711 // Enforce SQLite restrictions on |page_size_|. |
690 DCHECK(!(page_size_ & (page_size_ - 1))) | 712 DCHECK(!(page_size_ & (page_size_ - 1))) |
691 << " page_size_ " << page_size_ << " is not a power of two."; | 713 << " page_size_ " << page_size_ << " is not a power of two."; |
692 const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h | 714 const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h |
693 DCHECK_LE(page_size_, kSqliteMaxPageSize); | 715 DCHECK_LE(page_size_, kSqliteMaxPageSize); |
694 const std::string sql = | 716 const std::string sql = |
695 base::StringPrintf("PRAGMA page_size=%d", page_size_); | 717 base::StringPrintf("PRAGMA page_size=%d", page_size_); |
696 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout)) | 718 ignore_result(ExecuteWithTimeout(sql.c_str(), kBusyTimeout)); |
697 DLOG(FATAL) << "Could not set page size: " << GetErrorMessage(); | |
698 } | 719 } |
699 | 720 |
700 if (cache_size_ != 0) { | 721 if (cache_size_ != 0) { |
701 const std::string sql = | 722 const std::string sql = |
702 base::StringPrintf("PRAGMA cache_size=%d", cache_size_); | 723 base::StringPrintf("PRAGMA cache_size=%d", cache_size_); |
703 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout)) | 724 ignore_result(ExecuteWithTimeout(sql.c_str(), kBusyTimeout)); |
704 DLOG(FATAL) << "Could not set cache size: " << GetErrorMessage(); | |
705 } | 725 } |
706 | 726 |
707 if (!ExecuteWithTimeout("PRAGMA secure_delete=ON", kBusyTimeout)) { | 727 if (!ExecuteWithTimeout("PRAGMA secure_delete=ON", kBusyTimeout)) { |
708 DLOG(FATAL) << "Could not enable secure_delete: " << GetErrorMessage(); | |
709 Close(); | 728 Close(); |
710 return false; | 729 return false; |
711 } | 730 } |
712 | 731 |
713 return true; | 732 return true; |
714 } | 733 } |
715 | 734 |
716 void Connection::DoRollback() { | 735 void Connection::DoRollback() { |
717 Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK")); | 736 Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK")); |
718 rollback.Run(); | 737 rollback.Run(); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
763 error_callback_.Run(err, stmt); | 782 error_callback_.Run(err, stmt); |
764 return err; | 783 return err; |
765 } | 784 } |
766 | 785 |
767 // TODO(shess): Remove |error_delegate_| once everything is | 786 // TODO(shess): Remove |error_delegate_| once everything is |
768 // converted to |error_callback_|. | 787 // converted to |error_callback_|. |
769 if (error_delegate_.get()) | 788 if (error_delegate_.get()) |
770 return error_delegate_->OnError(err, this, stmt); | 789 return error_delegate_->OnError(err, this, stmt); |
771 | 790 |
772 // The default handling is to assert on debug and to ignore on release. | 791 // The default handling is to assert on debug and to ignore on release. |
773 DLOG(FATAL) << GetErrorMessage(); | 792 if (!ShouldIgnore(err)) |
| 793 DLOG(FATAL) << GetErrorMessage(); |
774 return err; | 794 return err; |
775 } | 795 } |
776 | 796 |
777 // TODO(shess): Allow specifying integrity_check versus quick_check. | 797 // TODO(shess): Allow specifying integrity_check versus quick_check. |
778 // TODO(shess): Allow specifying maximum results (default 100 lines). | 798 // TODO(shess): Allow specifying maximum results (default 100 lines). |
779 bool Connection::IntegrityCheck(std::vector<std::string>* messages) { | 799 bool Connection::IntegrityCheck(std::vector<std::string>* messages) { |
780 messages->clear(); | 800 messages->clear(); |
781 | 801 |
782 // This has the side effect of setting SQLITE_RecoveryMode, which | 802 // This has the side effect of setting SQLITE_RecoveryMode, which |
783 // allows SQLite to process through certain cases of corruption. | 803 // allows SQLite to process through certain cases of corruption. |
(...skipping 19 matching lines...) Expand all Loading... |
803 } | 823 } |
804 | 824 |
805 // Best effort to put things back as they were before. | 825 // Best effort to put things back as they were before. |
806 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF"; | 826 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF"; |
807 ignore_result(Execute(kNoWritableSchema)); | 827 ignore_result(Execute(kNoWritableSchema)); |
808 | 828 |
809 return ret; | 829 return ret; |
810 } | 830 } |
811 | 831 |
812 } // namespace sql | 832 } // namespace sql |
OLD | NEW |