| 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 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 | 87 |
| 88 // If successful, exactly one page should have been backed up. If | 88 // If successful, exactly one page should have been backed up. If |
| 89 // this breaks, check this function to make sure assumptions aren't | 89 // this breaks, check this function to make sure assumptions aren't |
| 90 // being broken. | 90 // being broken. |
| 91 if (rc == SQLITE_DONE) | 91 if (rc == SQLITE_DONE) |
| 92 DCHECK_EQ(pages, 1); | 92 DCHECK_EQ(pages, 1); |
| 93 | 93 |
| 94 return rc; | 94 return rc; |
| 95 } | 95 } |
| 96 | 96 |
| 97 // Be very strict on attachment point. SQLite can handle a much wider |
| 98 // character set with appropriate quoting, but Chromium code should |
| 99 // just use clean names to start with. |
| 100 bool ValidAttachmentPoint(const char* attachment_point) { |
| 101 for (size_t i = 0; attachment_point[i]; ++i) { |
| 102 if (!((attachment_point[i] >= '0' && attachment_point[i] <= '9') || |
| 103 (attachment_point[i] >= 'a' && attachment_point[i] <= 'z') || |
| 104 (attachment_point[i] >= 'A' && attachment_point[i] <= 'Z') || |
| 105 attachment_point[i] == '_')) { |
| 106 return false; |
| 107 } |
| 108 } |
| 109 return true; |
| 110 } |
| 111 |
| 97 } // namespace | 112 } // namespace |
| 98 | 113 |
| 99 namespace sql { | 114 namespace sql { |
| 100 | 115 |
| 101 // static | 116 // static |
| 102 Connection::ErrorIgnorerCallback* Connection::current_ignorer_cb_ = NULL; | 117 Connection::ErrorIgnorerCallback* Connection::current_ignorer_cb_ = NULL; |
| 103 | 118 |
| 104 // static | 119 // static |
| 105 bool Connection::ShouldIgnore(int error) { | 120 bool Connection::ShouldIgnore(int error) { |
| 106 if (!current_ignorer_cb_) | 121 if (!current_ignorer_cb_) |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 #elif defined(OS_POSIX) | 213 #elif defined(OS_POSIX) |
| 199 return OpenInternal(path.value(), RETRY_ON_POISON); | 214 return OpenInternal(path.value(), RETRY_ON_POISON); |
| 200 #endif | 215 #endif |
| 201 } | 216 } |
| 202 | 217 |
| 203 bool Connection::OpenInMemory() { | 218 bool Connection::OpenInMemory() { |
| 204 in_memory_ = true; | 219 in_memory_ = true; |
| 205 return OpenInternal(":memory:", NO_RETRY); | 220 return OpenInternal(":memory:", NO_RETRY); |
| 206 } | 221 } |
| 207 | 222 |
| 223 bool Connection::OpenTemporary() { |
| 224 return OpenInternal("", NO_RETRY); |
| 225 } |
| 226 |
| 208 void Connection::CloseInternal(bool forced) { | 227 void Connection::CloseInternal(bool forced) { |
| 209 // TODO(shess): Calling "PRAGMA journal_mode = DELETE" at this point | 228 // TODO(shess): Calling "PRAGMA journal_mode = DELETE" at this point |
| 210 // will delete the -journal file. For ChromiumOS or other more | 229 // will delete the -journal file. For ChromiumOS or other more |
| 211 // embedded systems, this is probably not appropriate, whereas on | 230 // embedded systems, this is probably not appropriate, whereas on |
| 212 // desktop it might make some sense. | 231 // desktop it might make some sense. |
| 213 | 232 |
| 214 // sqlite3_close() needs all prepared statements to be finalized. | 233 // sqlite3_close() needs all prepared statements to be finalized. |
| 215 | 234 |
| 216 // Release cached statements. | 235 // Release cached statements. |
| 217 statement_cache_.clear(); | 236 statement_cache_.clear(); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 return Raze(); | 424 return Raze(); |
| 406 } | 425 } |
| 407 | 426 |
| 408 bool Connection::RazeAndClose() { | 427 bool Connection::RazeAndClose() { |
| 409 if (!db_) { | 428 if (!db_) { |
| 410 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; | 429 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; |
| 411 return false; | 430 return false; |
| 412 } | 431 } |
| 413 | 432 |
| 414 // Raze() cannot run in a transaction. | 433 // Raze() cannot run in a transaction. |
| 415 while (transaction_nesting_) { | 434 RollbackAllTransactions(); |
| 416 RollbackTransaction(); | |
| 417 } | |
| 418 | 435 |
| 419 bool result = Raze(); | 436 bool result = Raze(); |
| 420 | 437 |
| 421 CloseInternal(true); | 438 CloseInternal(true); |
| 422 | 439 |
| 423 // Mark the database so that future API calls fail appropriately, | 440 // Mark the database so that future API calls fail appropriately, |
| 424 // but don't DCHECK (because after calling this function they are | 441 // but don't DCHECK (because after calling this function they are |
| 425 // expected to fail). | 442 // expected to fail). |
| 426 poisoned_ = true; | 443 poisoned_ = true; |
| 427 | 444 |
| 428 return result; | 445 return result; |
| 429 } | 446 } |
| 430 | 447 |
| 448 void Connection::Poison() { |
| 449 if (!db_) { |
| 450 DLOG_IF(FATAL, !poisoned_) << "Cannot poison null db"; |
| 451 return; |
| 452 } |
| 453 |
| 454 RollbackAllTransactions(); |
| 455 CloseInternal(true); |
| 456 |
| 457 // Mark the database so that future API calls fail appropriately, |
| 458 // but don't DCHECK (because after calling this function they are |
| 459 // expected to fail). |
| 460 poisoned_ = true; |
| 461 } |
| 462 |
| 431 // TODO(shess): To the extent possible, figure out the optimal | 463 // TODO(shess): To the extent possible, figure out the optimal |
| 432 // ordering for these deletes which will prevent other connections | 464 // ordering for these deletes which will prevent other connections |
| 433 // from seeing odd behavior. For instance, it may be necessary to | 465 // from seeing odd behavior. For instance, it may be necessary to |
| 434 // manually lock the main database file in a SQLite-compatible fashion | 466 // manually lock the main database file in a SQLite-compatible fashion |
| 435 // (to prevent other processes from opening it), then delete the | 467 // (to prevent other processes from opening it), then delete the |
| 436 // journal files, then delete the main database file. Another option | 468 // journal files, then delete the main database file. Another option |
| 437 // might be to lock the main database file and poison the header with | 469 // might be to lock the main database file and poison the header with |
| 438 // junk to prevent other processes from opening it successfully (like | 470 // junk to prevent other processes from opening it successfully (like |
| 439 // Gears "SQLite poison 3" trick). | 471 // Gears "SQLite poison 3" trick). |
| 440 // | 472 // |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 | 538 |
| 507 if (needs_rollback_) { | 539 if (needs_rollback_) { |
| 508 DoRollback(); | 540 DoRollback(); |
| 509 return false; | 541 return false; |
| 510 } | 542 } |
| 511 | 543 |
| 512 Statement commit(GetCachedStatement(SQL_FROM_HERE, "COMMIT")); | 544 Statement commit(GetCachedStatement(SQL_FROM_HERE, "COMMIT")); |
| 513 return commit.Run(); | 545 return commit.Run(); |
| 514 } | 546 } |
| 515 | 547 |
| 548 void Connection::RollbackAllTransactions() { |
| 549 if (transaction_nesting_ > 0) { |
| 550 transaction_nesting_ = 0; |
| 551 DoRollback(); |
| 552 } |
| 553 } |
| 554 |
| 555 bool Connection::AttachDatabase(const base::FilePath& other_db_path, |
| 556 const char* attachment_point) { |
| 557 DCHECK(ValidAttachmentPoint(attachment_point)); |
| 558 |
| 559 Statement s(GetUniqueStatement("ATTACH DATABASE ? AS ?")); |
| 560 #if OS_WIN |
| 561 s.BindString16(0, other_db_path.value()); |
| 562 #else |
| 563 s.BindString(0, other_db_path.value()); |
| 564 #endif |
| 565 s.BindString(1, attachment_point); |
| 566 return s.Run(); |
| 567 } |
| 568 |
| 569 bool Connection::DetachDatabase(const char* attachment_point) { |
| 570 DCHECK(ValidAttachmentPoint(attachment_point)); |
| 571 |
| 572 Statement s(GetUniqueStatement("DETACH DATABASE ?")); |
| 573 s.BindString(0, attachment_point); |
| 574 return s.Run(); |
| 575 } |
| 576 |
| 516 int Connection::ExecuteAndReturnErrorCode(const char* sql) { | 577 int Connection::ExecuteAndReturnErrorCode(const char* sql) { |
| 517 AssertIOAllowed(); | 578 AssertIOAllowed(); |
| 518 if (!db_) { | 579 if (!db_) { |
| 519 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; | 580 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
| 520 return SQLITE_ERROR; | 581 return SQLITE_ERROR; |
| 521 } | 582 } |
| 522 return sqlite3_exec(db_, sql, NULL, NULL, NULL); | 583 return sqlite3_exec(db_, sql, NULL, NULL, NULL); |
| 523 } | 584 } |
| 524 | 585 |
| 525 bool Connection::Execute(const char* sql) { | 586 bool Connection::Execute(const char* sql) { |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 909 } | 970 } |
| 910 | 971 |
| 911 // Best effort to put things back as they were before. | 972 // Best effort to put things back as they were before. |
| 912 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF"; | 973 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF"; |
| 913 ignore_result(Execute(kNoWritableSchema)); | 974 ignore_result(Execute(kNoWritableSchema)); |
| 914 | 975 |
| 915 return ret; | 976 return ret; |
| 916 } | 977 } |
| 917 | 978 |
| 918 } // namespace sql | 979 } // namespace sql |
| OLD | NEW |