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