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 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 base::HistogramBase* histogram = | 187 base::HistogramBase* histogram = |
188 base::Histogram::FactoryGet( | 188 base::Histogram::FactoryGet( |
189 full_histogram_name, 1, 1000000, 50, | 189 full_histogram_name, 1, 1000000, 50, |
190 base::HistogramBase::kUmaTargetedHistogramFlag); | 190 base::HistogramBase::kUmaTargetedHistogramFlag); |
191 if (histogram) | 191 if (histogram) |
192 histogram->Add(sample); | 192 histogram->Add(sample); |
193 } | 193 } |
194 } | 194 } |
195 | 195 |
196 #if defined(OS_WIN) | 196 #if defined(OS_WIN) |
197 return OpenInternal(WideToUTF8(path.value())); | 197 return OpenInternal(WideToUTF8(path.value()), RETRY_ON_POISON); |
198 #elif defined(OS_POSIX) | 198 #elif defined(OS_POSIX) |
199 return OpenInternal(path.value()); | 199 return OpenInternal(path.value(), RETRY_ON_POISON); |
200 #endif | 200 #endif |
201 } | 201 } |
202 | 202 |
203 bool Connection::OpenInMemory() { | 203 bool Connection::OpenInMemory() { |
204 in_memory_ = true; | 204 in_memory_ = true; |
205 return OpenInternal(":memory:"); | 205 return OpenInternal(":memory:", NO_RETRY); |
206 } | 206 } |
207 | 207 |
208 void Connection::CloseInternal(bool forced) { | 208 void Connection::CloseInternal(bool forced) { |
209 // TODO(shess): Calling "PRAGMA journal_mode = DELETE" at this point | 209 // TODO(shess): Calling "PRAGMA journal_mode = DELETE" at this point |
210 // will delete the -journal file. For ChromiumOS or other more | 210 // will delete the -journal file. For ChromiumOS or other more |
211 // embedded systems, this is probably not appropriate, whereas on | 211 // embedded systems, this is probably not appropriate, whereas on |
212 // desktop it might make some sense. | 212 // desktop it might make some sense. |
213 | 213 |
214 // sqlite3_close() needs all prepared statements to be finalized. | 214 // sqlite3_close() needs all prepared statements to be finalized. |
215 | 215 |
(...skipping 15 matching lines...) Expand all Loading... |
231 if (db_) { | 231 if (db_) { |
232 // Call to AssertIOAllowed() cannot go at the beginning of the function | 232 // Call to AssertIOAllowed() cannot go at the beginning of the function |
233 // because Close() must be called from destructor to clean | 233 // because Close() must be called from destructor to clean |
234 // statement_cache_, it won't cause any disk access and it most probably | 234 // statement_cache_, it won't cause any disk access and it most probably |
235 // will happen on thread not allowing disk access. | 235 // will happen on thread not allowing disk access. |
236 // TODO(paivanof@gmail.com): This should move to the beginning | 236 // TODO(paivanof@gmail.com): This should move to the beginning |
237 // of the function. http://crbug.com/136655. | 237 // of the function. http://crbug.com/136655. |
238 AssertIOAllowed(); | 238 AssertIOAllowed(); |
239 // TODO(shess): Histogram for failure. | 239 // TODO(shess): Histogram for failure. |
240 sqlite3_close(db_); | 240 sqlite3_close(db_); |
241 db_ = NULL; | |
242 } | 241 } |
| 242 db_ = NULL; |
243 } | 243 } |
244 | 244 |
245 void Connection::Close() { | 245 void Connection::Close() { |
246 // If the database was already closed by RazeAndClose(), then no | 246 // If the database was already closed by RazeAndClose(), then no |
247 // need to close again. Clear the |poisoned_| bit so that incorrect | 247 // need to close again. Clear the |poisoned_| bit so that incorrect |
248 // API calls are caught. | 248 // API calls are caught. |
249 if (poisoned_) { | 249 if (poisoned_) { |
250 poisoned_ = false; | 250 poisoned_ = false; |
251 return; | 251 return; |
252 } | 252 } |
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
692 | 692 |
693 return err; | 693 return err; |
694 } | 694 } |
695 | 695 |
696 const char* Connection::GetErrorMessage() const { | 696 const char* Connection::GetErrorMessage() const { |
697 if (!db_) | 697 if (!db_) |
698 return "sql::Connection has no connection."; | 698 return "sql::Connection has no connection."; |
699 return sqlite3_errmsg(db_); | 699 return sqlite3_errmsg(db_); |
700 } | 700 } |
701 | 701 |
702 bool Connection::OpenInternal(const std::string& file_name) { | 702 bool Connection::OpenInternal(const std::string& file_name, |
| 703 Connection::Retry retry_flag) { |
703 AssertIOAllowed(); | 704 AssertIOAllowed(); |
704 | 705 |
705 if (db_) { | 706 if (db_) { |
706 DLOG(FATAL) << "sql::Connection is already open."; | 707 DLOG(FATAL) << "sql::Connection is already open."; |
707 return false; | 708 return false; |
708 } | 709 } |
709 | 710 |
710 // If |poisoned_| is set, it means an error handler called | 711 // If |poisoned_| is set, it means an error handler called |
711 // RazeAndClose(). Until regular Close() is called, the caller | 712 // RazeAndClose(). Until regular Close() is called, the caller |
712 // should be treating the database as open, but is_open() currently | 713 // should be treating the database as open, but is_open() currently |
713 // only considers the sqlite3 handle's state. | 714 // only considers the sqlite3 handle's state. |
714 // TODO(shess): Revise is_open() to consider poisoned_, and review | 715 // TODO(shess): Revise is_open() to consider poisoned_, and review |
715 // to see if any non-testing code even depends on it. | 716 // to see if any non-testing code even depends on it. |
716 DLOG_IF(FATAL, poisoned_) << "sql::Connection is already open."; | 717 DLOG_IF(FATAL, poisoned_) << "sql::Connection is already open."; |
717 poisoned_ = false; | 718 poisoned_ = false; |
718 | 719 |
719 int err = sqlite3_open(file_name.c_str(), &db_); | 720 int err = sqlite3_open(file_name.c_str(), &db_); |
720 if (err != SQLITE_OK) { | 721 if (err != SQLITE_OK) { |
721 // Histogram failures specific to initial open for debugging | 722 // Histogram failures specific to initial open for debugging |
722 // purposes. | 723 // purposes. |
723 UMA_HISTOGRAM_ENUMERATION("Sqlite.OpenFailure", err & 0xff, 50); | 724 UMA_HISTOGRAM_ENUMERATION("Sqlite.OpenFailure", err & 0xff, 50); |
724 | 725 |
725 OnSqliteError(err, NULL); | 726 OnSqliteError(err, NULL); |
| 727 bool was_poisoned = poisoned_; |
726 Close(); | 728 Close(); |
727 db_ = NULL; | 729 |
| 730 if (was_poisoned && retry_flag == RETRY_ON_POISON) |
| 731 return OpenInternal(file_name, NO_RETRY); |
728 return false; | 732 return false; |
729 } | 733 } |
730 | 734 |
731 // SQLite uses a lookaside buffer to improve performance of small mallocs. | 735 // SQLite uses a lookaside buffer to improve performance of small mallocs. |
732 // Chromium already depends on small mallocs being efficient, so we disable | 736 // Chromium already depends on small mallocs being efficient, so we disable |
733 // this to avoid the extra memory overhead. | 737 // this to avoid the extra memory overhead. |
734 // This must be called immediatly after opening the database before any SQL | 738 // This must be called immediatly after opening the database before any SQL |
735 // statements are run. | 739 // statements are run. |
736 sqlite3_db_config(db_, SQLITE_DBCONFIG_LOOKASIDE, NULL, 0, 0); | 740 sqlite3_db_config(db_, SQLITE_DBCONFIG_LOOKASIDE, NULL, 0, 0); |
737 | 741 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
799 ignore_result(ExecuteWithTimeout(sql.c_str(), kBusyTimeout)); | 803 ignore_result(ExecuteWithTimeout(sql.c_str(), kBusyTimeout)); |
800 } | 804 } |
801 | 805 |
802 if (cache_size_ != 0) { | 806 if (cache_size_ != 0) { |
803 const std::string sql = | 807 const std::string sql = |
804 base::StringPrintf("PRAGMA cache_size=%d", cache_size_); | 808 base::StringPrintf("PRAGMA cache_size=%d", cache_size_); |
805 ignore_result(ExecuteWithTimeout(sql.c_str(), kBusyTimeout)); | 809 ignore_result(ExecuteWithTimeout(sql.c_str(), kBusyTimeout)); |
806 } | 810 } |
807 | 811 |
808 if (!ExecuteWithTimeout("PRAGMA secure_delete=ON", kBusyTimeout)) { | 812 if (!ExecuteWithTimeout("PRAGMA secure_delete=ON", kBusyTimeout)) { |
| 813 bool was_poisoned = poisoned_; |
809 Close(); | 814 Close(); |
| 815 if (was_poisoned && retry_flag == RETRY_ON_POISON) |
| 816 return OpenInternal(file_name, NO_RETRY); |
810 return false; | 817 return false; |
811 } | 818 } |
812 | 819 |
813 return true; | 820 return true; |
814 } | 821 } |
815 | 822 |
816 void Connection::DoRollback() { | 823 void Connection::DoRollback() { |
817 Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK")); | 824 Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK")); |
818 rollback.Run(); | 825 rollback.Run(); |
819 needs_rollback_ = false; | 826 needs_rollback_ = false; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
902 } | 909 } |
903 | 910 |
904 // Best effort to put things back as they were before. | 911 // Best effort to put things back as they were before. |
905 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF"; | 912 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF"; |
906 ignore_result(Execute(kNoWritableSchema)); | 913 ignore_result(Execute(kNoWritableSchema)); |
907 | 914 |
908 return ret; | 915 return ret; |
909 } | 916 } |
910 | 917 |
911 } // namespace sql | 918 } // namespace sql |
OLD | NEW |