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 DCHECK_NE(src, dst); |
| 71 sqlite3_backup* backup = sqlite3_backup_init(dst, db_name, src, db_name); |
| 72 if (!backup) { |
| 73 // Since this call only sets things up, this indicates a gross |
| 74 // error in SQLite. |
| 75 DLOG(FATAL) << "Unable to start sqlite3_backup(): " << sqlite3_errmsg(dst); |
| 76 return sqlite3_errcode(dst); |
| 77 } |
| 78 |
| 79 // -1 backs up the entire database. |
| 80 int rc = sqlite3_backup_step(backup, -1); |
| 81 int pages = sqlite3_backup_pagecount(backup); |
| 82 sqlite3_backup_finish(backup); |
| 83 |
| 84 // If successful, exactly one page should have been backed up. If |
| 85 // this breaks, check this function to make sure assumptions aren't |
| 86 // being broken. |
| 87 if (rc == SQLITE_DONE) |
| 88 DCHECK_EQ(pages, 1); |
| 89 |
| 90 return rc; |
| 91 } |
| 92 |
67 } // namespace | 93 } // namespace |
68 | 94 |
69 namespace sql { | 95 namespace sql { |
70 | 96 |
71 // static | 97 // static |
72 Connection::ErrorIgnorerCallback* Connection::current_ignorer_cb_ = NULL; | 98 Connection::ErrorIgnorerCallback* Connection::current_ignorer_cb_ = NULL; |
73 | 99 |
74 // static | 100 // static |
75 bool Connection::ShouldIgnore(int error) { | 101 bool Connection::ShouldIgnore(int error) { |
76 if (!current_ignorer_cb_) | 102 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 | 332 // page, and if it does not match the total retrieved from a |
307 // filesystem call, treats the database as corrupt. This situation | 333 // filesystem call, treats the database as corrupt. This situation |
308 // breaks almost all SQLite calls. "PRAGMA writable_schema" can be | 334 // breaks almost all SQLite calls. "PRAGMA writable_schema" can be |
309 // used to hint to SQLite to soldier on in that case, specifically | 335 // used to hint to SQLite to soldier on in that case, specifically |
310 // for purposes of recovery. [See SQLITE_CORRUPT_BKPT case in | 336 // for purposes of recovery. [See SQLITE_CORRUPT_BKPT case in |
311 // sqlite3.c lockBtree().] | 337 // sqlite3.c lockBtree().] |
312 // TODO(shess): With this, "PRAGMA auto_vacuum" and "PRAGMA | 338 // TODO(shess): With this, "PRAGMA auto_vacuum" and "PRAGMA |
313 // page_size" can be used to query such a database. | 339 // page_size" can be used to query such a database. |
314 ScopedWritableSchema writable_schema(db_); | 340 ScopedWritableSchema writable_schema(db_); |
315 | 341 |
316 sqlite3_backup* backup = sqlite3_backup_init(db_, "main", | 342 const char* kMain = "main"; |
317 null_db.db_, "main"); | 343 int rc = BackupDatabase(null_db.db_, db_, kMain); |
318 if (!backup) { | 344 UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.RazeDatabase",rc); |
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 | 345 |
328 // The destination database was locked. | 346 // The destination database was locked. |
329 if (rc == SQLITE_BUSY) { | 347 if (rc == SQLITE_BUSY) { |
330 return false; | 348 return false; |
331 } | 349 } |
332 | 350 |
| 351 // SQLITE_NOTADB can happen if page 1 of db_ exists, but is not |
| 352 // formatted correctly. SQLITE_IOERR_SHORT_READ can happen if db_ |
| 353 // isn't even big enough for one page. Either way, reach in and |
| 354 // truncate it before trying again. |
| 355 // TODO(shess): Maybe it would be worthwhile to just truncate from |
| 356 // the get-go? |
| 357 if (rc == SQLITE_NOTADB || rc == SQLITE_IOERR_SHORT_READ) { |
| 358 sqlite3_file* file = NULL; |
| 359 rc = sqlite3_file_control(db_, "main", SQLITE_FCNTL_FILE_POINTER, &file); |
| 360 if (rc != SQLITE_OK) { |
| 361 DLOG(FATAL) << "Failure getting file handle."; |
| 362 return false; |
| 363 } else if (!file) { |
| 364 DLOG(FATAL) << "File handle is empty."; |
| 365 return false; |
| 366 } |
| 367 |
| 368 rc = file->pMethods->xTruncate(file, 0); |
| 369 if (rc != SQLITE_OK) { |
| 370 UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.RazeDatabaseTruncate",rc); |
| 371 DLOG(FATAL) << "Failed to truncate file."; |
| 372 return false; |
| 373 } |
| 374 |
| 375 rc = BackupDatabase(null_db.db_, db_, kMain); |
| 376 UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.RazeDatabase2",rc); |
| 377 |
| 378 if (rc != SQLITE_DONE) { |
| 379 DLOG(FATAL) << "Failed retrying Raze()."; |
| 380 } |
| 381 } |
| 382 |
333 // The entire database should have been backed up. | 383 // The entire database should have been backed up. |
334 if (rc != SQLITE_DONE) { | 384 if (rc != SQLITE_DONE) { |
| 385 // TODO(shess): Figure out which other cases can happen. |
335 DLOG(FATAL) << "Unable to copy entire null database."; | 386 DLOG(FATAL) << "Unable to copy entire null database."; |
336 return false; | 387 return false; |
337 } | 388 } |
338 | 389 |
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; | 390 return true; |
344 } | 391 } |
345 | 392 |
346 bool Connection::RazeWithTimout(base::TimeDelta timeout) { | 393 bool Connection::RazeWithTimout(base::TimeDelta timeout) { |
347 if (!db_) { | 394 if (!db_) { |
348 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; | 395 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; |
349 return false; | 396 return false; |
350 } | 397 } |
351 | 398 |
352 ScopedBusyTimeout busy_timeout(db_); | 399 ScopedBusyTimeout busy_timeout(db_); |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
656 return false; | 703 return false; |
657 } | 704 } |
658 | 705 |
659 // If |poisoned_| is set, it means an error handler called | 706 // If |poisoned_| is set, it means an error handler called |
660 // RazeAndClose(). Until regular Close() is called, the caller | 707 // RazeAndClose(). Until regular Close() is called, the caller |
661 // should be treating the database as open, but is_open() currently | 708 // should be treating the database as open, but is_open() currently |
662 // only considers the sqlite3 handle's state. | 709 // only considers the sqlite3 handle's state. |
663 // TODO(shess): Revise is_open() to consider poisoned_, and review | 710 // TODO(shess): Revise is_open() to consider poisoned_, and review |
664 // to see if any non-testing code even depends on it. | 711 // to see if any non-testing code even depends on it. |
665 DLOG_IF(FATAL, poisoned_) << "sql::Connection is already open."; | 712 DLOG_IF(FATAL, poisoned_) << "sql::Connection is already open."; |
| 713 poisoned_ = false; |
666 | 714 |
667 int err = sqlite3_open(file_name.c_str(), &db_); | 715 int err = sqlite3_open(file_name.c_str(), &db_); |
668 if (err != SQLITE_OK) { | 716 if (err != SQLITE_OK) { |
669 // Histogram failures specific to initial open for debugging | 717 // Histogram failures specific to initial open for debugging |
670 // purposes. | 718 // purposes. |
671 UMA_HISTOGRAM_ENUMERATION("Sqlite.OpenFailure", err & 0xff, 50); | 719 UMA_HISTOGRAM_ENUMERATION("Sqlite.OpenFailure", err & 0xff, 50); |
672 | 720 |
673 OnSqliteError(err, NULL); | 721 OnSqliteError(err, NULL); |
674 Close(); | 722 Close(); |
675 db_ = NULL; | 723 db_ = NULL; |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
840 } | 888 } |
841 | 889 |
842 // Best effort to put things back as they were before. | 890 // Best effort to put things back as they were before. |
843 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF"; | 891 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF"; |
844 ignore_result(Execute(kNoWritableSchema)); | 892 ignore_result(Execute(kNoWritableSchema)); |
845 | 893 |
846 return ret; | 894 return ret; |
847 } | 895 } |
848 | 896 |
849 } // namespace sql | 897 } // namespace sql |
OLD | NEW |