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 |