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/file_path.h" | 9 #include "base/file_path.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 69 if (number_ != other.number_) | 69 if (number_ != other.number_) |
| 70 return number_ < other.number_; | 70 return number_ < other.number_; |
| 71 return strcmp(str_, other.str_) < 0; | 71 return strcmp(str_, other.str_) < 0; |
| 72 } | 72 } |
| 73 | 73 |
| 74 ErrorDelegate::~ErrorDelegate() { | 74 ErrorDelegate::~ErrorDelegate() { |
| 75 } | 75 } |
| 76 | 76 |
| 77 Connection::StatementRef::StatementRef() | 77 Connection::StatementRef::StatementRef() |
| 78 : connection_(NULL), | 78 : connection_(NULL), |
| 79 stmt_(NULL) { | 79 stmt_(NULL), |
| 80 was_valid_(false) { | |
| 80 } | 81 } |
| 81 | 82 |
| 82 Connection::StatementRef::StatementRef(sqlite3_stmt* stmt) | 83 Connection::StatementRef::StatementRef(sqlite3_stmt* stmt) |
| 83 : connection_(NULL), | 84 : connection_(NULL), |
| 84 stmt_(stmt) { | 85 stmt_(stmt), |
| 86 was_valid_(stmt != NULL) { | |
| 85 } | 87 } |
| 86 | 88 |
| 87 Connection::StatementRef::StatementRef(Connection* connection, | 89 Connection::StatementRef::StatementRef(Connection* connection, |
| 88 sqlite3_stmt* stmt) | 90 sqlite3_stmt* stmt) |
| 89 : connection_(connection), | 91 : connection_(connection), |
| 90 stmt_(stmt) { | 92 stmt_(stmt), |
| 93 was_valid_(stmt != NULL) { | |
| 91 connection_->StatementRefCreated(this); | 94 connection_->StatementRefCreated(this); |
| 92 } | 95 } |
| 93 | 96 |
| 94 Connection::StatementRef::~StatementRef() { | 97 Connection::StatementRef::~StatementRef() { |
| 95 if (connection_) | 98 if (connection_) |
| 96 connection_->StatementRefDeleted(this); | 99 connection_->StatementRefDeleted(this); |
| 97 Close(); | 100 Close(false); |
| 98 } | 101 } |
| 99 | 102 |
| 100 void Connection::StatementRef::Close() { | 103 void Connection::StatementRef::Close(bool forced) { |
| 101 if (stmt_) { | 104 if (stmt_) { |
| 102 // Call to AssertIOAllowed() cannot go at the beginning of the function | 105 // Call to AssertIOAllowed() cannot go at the beginning of the function |
| 103 // because Close() is called unconditionally from destructor to clean | 106 // because Close() is called unconditionally from destructor to clean |
| 104 // connection_. And if this is inactive statement this won't cause any | 107 // connection_. And if this is inactive statement this won't cause any |
| 105 // disk access and destructor most probably will be called on thread | 108 // disk access and destructor most probably will be called on thread |
| 106 // not allowing disk access. | 109 // not allowing disk access. |
| 107 // TODO(paivanof@gmail.com): This should move to the beginning | 110 // TODO(paivanof@gmail.com): This should move to the beginning |
| 108 // of the function. http://crbug.com/136655. | 111 // of the function. http://crbug.com/136655. |
| 109 AssertIOAllowed(); | 112 AssertIOAllowed(); |
| 110 sqlite3_finalize(stmt_); | 113 sqlite3_finalize(stmt_); |
| 111 stmt_ = NULL; | 114 stmt_ = NULL; |
| 112 } | 115 } |
| 113 connection_ = NULL; // The connection may be getting deleted. | 116 connection_ = NULL; // The connection may be getting deleted. |
| 117 | |
| 118 // Forced close is expected to happen from a statement error | |
| 119 // handler, in that case maintain the sense of |was_valid_| which | |
|
pkotwicz
2013/01/31 19:22:00
Nit: Use a ',' instead of a '.'
Scott Hess - ex-Googler
2013/02/05 01:20:25
I'll assume you meant it the other way around, or
| |
| 120 // previously held for this ref. | |
| 121 was_valid_ = was_valid_ && forced; | |
| 114 } | 122 } |
| 115 | 123 |
| 116 Connection::Connection() | 124 Connection::Connection() |
| 117 : db_(NULL), | 125 : db_(NULL), |
| 118 page_size_(0), | 126 page_size_(0), |
| 119 cache_size_(0), | 127 cache_size_(0), |
| 120 exclusive_locking_(false), | 128 exclusive_locking_(false), |
| 121 transaction_nesting_(0), | 129 transaction_nesting_(0), |
| 122 needs_rollback_(false), | 130 needs_rollback_(false), |
| 123 in_memory_(false), | 131 in_memory_(false), |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 134 #elif defined(OS_POSIX) | 142 #elif defined(OS_POSIX) |
| 135 return OpenInternal(path.value()); | 143 return OpenInternal(path.value()); |
| 136 #endif | 144 #endif |
| 137 } | 145 } |
| 138 | 146 |
| 139 bool Connection::OpenInMemory() { | 147 bool Connection::OpenInMemory() { |
| 140 in_memory_ = true; | 148 in_memory_ = true; |
| 141 return OpenInternal(":memory:"); | 149 return OpenInternal(":memory:"); |
| 142 } | 150 } |
| 143 | 151 |
| 144 void Connection::Close() { | 152 void Connection::CloseInternal(bool forced) { |
| 145 // TODO(shess): Calling "PRAGMA journal_mode = DELETE" at this point | 153 // TODO(shess): Calling "PRAGMA journal_mode = DELETE" at this point |
| 146 // will delete the -journal file. For ChromiumOS or other more | 154 // will delete the -journal file. For ChromiumOS or other more |
| 147 // embedded systems, this is probably not appropriate, whereas on | 155 // embedded systems, this is probably not appropriate, whereas on |
| 148 // desktop it might make some sense. | 156 // desktop it might make some sense. |
| 149 | 157 |
| 150 // sqlite3_close() needs all prepared statements to be finalized. | 158 // sqlite3_close() needs all prepared statements to be finalized. |
| 151 // Release all cached statements, then assert that the client has | 159 |
| 152 // released all statements. | 160 // Release cached statements. |
| 153 statement_cache_.clear(); | 161 statement_cache_.clear(); |
| 154 DCHECK(open_statements_.empty()); | |
| 155 | 162 |
| 156 // Additionally clear the prepared statements, because they contain | 163 // With cached statements released, in-use statements will remain. |
| 157 // weak references to this connection. This case has come up when | 164 // Closing the database while statements are in use is an API |
| 158 // error-handling code is hit in production. | 165 // violation, except for forced close (which happens from within a |
| 159 ClearCache(); | 166 // statement's error handler). |
| 167 DCHECK(forced || open_statements_.empty()); | |
| 168 | |
| 169 // Deactivate any outstanding statements so sqlite3_close() works. | |
| 170 for (StatementRefSet::iterator i = open_statements_.begin(); | |
| 171 i != open_statements_.end(); ++i) | |
| 172 (*i)->Close(forced); | |
| 173 open_statements_.clear(); | |
| 160 | 174 |
| 161 if (db_) { | 175 if (db_) { |
| 162 // Call to AssertIOAllowed() cannot go at the beginning of the function | 176 // Call to AssertIOAllowed() cannot go at the beginning of the function |
| 163 // because Close() must be called from destructor to clean | 177 // because Close() must be called from destructor to clean |
| 164 // statement_cache_, it won't cause any disk access and it most probably | 178 // statement_cache_, it won't cause any disk access and it most probably |
| 165 // will happen on thread not allowing disk access. | 179 // will happen on thread not allowing disk access. |
| 166 // TODO(paivanof@gmail.com): This should move to the beginning | 180 // TODO(paivanof@gmail.com): This should move to the beginning |
| 167 // of the function. http://crbug.com/136655. | 181 // of the function. http://crbug.com/136655. |
| 168 AssertIOAllowed(); | 182 AssertIOAllowed(); |
| 169 // TODO(shess): Histogram for failure. | 183 // TODO(shess): Histogram for failure. |
| 170 sqlite3_close(db_); | 184 sqlite3_close(db_); |
| 171 db_ = NULL; | 185 db_ = NULL; |
| 172 } | 186 } |
| 173 } | 187 } |
| 174 | 188 |
| 189 void Connection::Close() { | |
| 190 // Database was already closed via RazeAndClose(), ignore. | |
| 191 if (poisoned_) | |
| 192 return; | |
| 193 | |
| 194 CloseInternal(false); | |
| 195 } | |
| 196 | |
| 175 void Connection::Preload() { | 197 void Connection::Preload() { |
| 176 AssertIOAllowed(); | 198 AssertIOAllowed(); |
| 177 | 199 |
| 178 if (!db_) { | 200 if (!db_) { |
| 179 DLOG(FATAL) << "Cannot preload null db"; | 201 DLOG_IF(FATAL, !poisoned_) << "Cannot preload null db"; |
| 180 return; | 202 return; |
| 181 } | 203 } |
| 182 | 204 |
| 183 // A statement must be open for the preload command to work. If the meta | 205 // A statement must be open for the preload command to work. If the meta |
| 184 // table doesn't exist, it probably means this is a new database and there | 206 // table doesn't exist, it probably means this is a new database and there |
| 185 // is nothing to preload (so it's OK we do nothing). | 207 // is nothing to preload (so it's OK we do nothing). |
| 186 if (!DoesTableExist("meta")) | 208 if (!DoesTableExist("meta")) |
| 187 return; | 209 return; |
| 188 Statement dummy(GetUniqueStatement("SELECT * FROM meta")); | 210 Statement dummy(GetUniqueStatement("SELECT * FROM meta")); |
| 189 if (!dummy.Step()) | 211 if (!dummy.Step()) |
| 190 return; | 212 return; |
| 191 | 213 |
| 192 #if !defined(USE_SYSTEM_SQLITE) | 214 #if !defined(USE_SYSTEM_SQLITE) |
| 193 // This function is only defined in Chromium's version of sqlite. | 215 // This function is only defined in Chromium's version of sqlite. |
| 194 // Do not call it when using system sqlite. | 216 // Do not call it when using system sqlite. |
| 195 sqlite3_preload(db_); | 217 sqlite3_preload(db_); |
| 196 #endif | 218 #endif |
| 197 } | 219 } |
| 198 | 220 |
| 199 // Create an in-memory database with the existing database's page | 221 // Create an in-memory database with the existing database's page |
| 200 // size, then backup that database over the existing database. | 222 // size, then backup that database over the existing database. |
| 201 bool Connection::Raze() { | 223 bool Connection::Raze() { |
| 202 AssertIOAllowed(); | 224 AssertIOAllowed(); |
| 203 | 225 |
| 204 if (!db_) { | 226 if (!db_) { |
| 205 DLOG(FATAL) << "Cannot raze null db"; | 227 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; |
| 206 return false; | 228 return false; |
| 207 } | 229 } |
| 208 | 230 |
| 209 if (transaction_nesting_ > 0) { | 231 if (transaction_nesting_ > 0) { |
| 210 DLOG(FATAL) << "Cannot raze within a transaction"; | 232 DLOG(FATAL) << "Cannot raze within a transaction"; |
| 211 return false; | 233 return false; |
| 212 } | 234 } |
| 213 | 235 |
| 214 sql::Connection null_db; | 236 sql::Connection null_db; |
| 215 if (!null_db.OpenInMemory()) { | 237 if (!null_db.OpenInMemory()) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 285 | 307 |
| 286 // Exactly one page should have been backed up. If this breaks, | 308 // Exactly one page should have been backed up. If this breaks, |
| 287 // check this function to make sure assumptions aren't being broken. | 309 // check this function to make sure assumptions aren't being broken. |
| 288 DCHECK_EQ(pages, 1); | 310 DCHECK_EQ(pages, 1); |
| 289 | 311 |
| 290 return true; | 312 return true; |
| 291 } | 313 } |
| 292 | 314 |
| 293 bool Connection::RazeWithTimout(base::TimeDelta timeout) { | 315 bool Connection::RazeWithTimout(base::TimeDelta timeout) { |
| 294 if (!db_) { | 316 if (!db_) { |
| 295 DLOG(FATAL) << "Cannot raze null db"; | 317 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; |
| 296 return false; | 318 return false; |
| 297 } | 319 } |
| 298 | 320 |
| 299 ScopedBusyTimeout busy_timeout(db_); | 321 ScopedBusyTimeout busy_timeout(db_); |
| 300 busy_timeout.SetTimeout(timeout); | 322 busy_timeout.SetTimeout(timeout); |
| 301 return Raze(); | 323 return Raze(); |
| 302 } | 324 } |
| 303 | 325 |
| 326 bool Connection::RazeAndClose() { | |
| 327 if (!db_) { | |
| 328 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; | |
| 329 return false; | |
| 330 } | |
| 331 | |
| 332 // Raze() cannot run in a transaction. | |
| 333 while (transaction_nesting_) { | |
|
pkotwicz
2013/01/31 19:22:00
Nit: The braces are not necessary
Scott Hess - ex-Googler
2013/02/05 01:20:25
I'll plead the personal-preference exemption in th
| |
| 334 RollbackTransaction(); | |
| 335 } | |
| 336 | |
| 337 bool result = Raze(); | |
| 338 | |
| 339 CloseInternal(true); | |
| 340 | |
| 341 // Mark the database so that future API calls fail appropriately, | |
| 342 // but don't DCHECK (because after calling this function they are | |
| 343 // expected to fail). | |
| 344 poisoned_ = true; | |
| 345 | |
| 346 return result; | |
| 347 } | |
| 348 | |
| 304 bool Connection::BeginTransaction() { | 349 bool Connection::BeginTransaction() { |
| 305 if (needs_rollback_) { | 350 if (needs_rollback_) { |
| 306 DCHECK_GT(transaction_nesting_, 0); | 351 DCHECK_GT(transaction_nesting_, 0); |
| 307 | 352 |
| 308 // When we're going to rollback, fail on this begin and don't actually | 353 // When we're going to rollback, fail on this begin and don't actually |
| 309 // mark us as entering the nested transaction. | 354 // mark us as entering the nested transaction. |
| 310 return false; | 355 return false; |
| 311 } | 356 } |
| 312 | 357 |
| 313 bool success = true; | 358 bool success = true; |
| 314 if (!transaction_nesting_) { | 359 if (!transaction_nesting_) { |
| 315 needs_rollback_ = false; | 360 needs_rollback_ = false; |
| 316 | 361 |
| 317 Statement begin(GetCachedStatement(SQL_FROM_HERE, "BEGIN TRANSACTION")); | 362 Statement begin(GetCachedStatement(SQL_FROM_HERE, "BEGIN TRANSACTION")); |
| 318 if (!begin.Run()) | 363 if (!begin.Run()) |
| 319 return false; | 364 return false; |
| 320 } | 365 } |
| 321 transaction_nesting_++; | 366 transaction_nesting_++; |
| 322 return success; | 367 return success; |
| 323 } | 368 } |
| 324 | 369 |
| 325 void Connection::RollbackTransaction() { | 370 void Connection::RollbackTransaction() { |
| 326 if (!transaction_nesting_) { | 371 if (!transaction_nesting_) { |
| 327 DLOG(FATAL) << "Rolling back a nonexistent transaction"; | 372 DLOG_IF(FATAL, !poisoned_) << "Rolling back a nonexistent transaction"; |
| 328 return; | 373 return; |
| 329 } | 374 } |
| 330 | 375 |
| 331 transaction_nesting_--; | 376 transaction_nesting_--; |
| 332 | 377 |
| 333 if (transaction_nesting_ > 0) { | 378 if (transaction_nesting_ > 0) { |
| 334 // Mark the outermost transaction as needing rollback. | 379 // Mark the outermost transaction as needing rollback. |
| 335 needs_rollback_ = true; | 380 needs_rollback_ = true; |
| 336 return; | 381 return; |
| 337 } | 382 } |
| 338 | 383 |
| 339 DoRollback(); | 384 DoRollback(); |
| 340 } | 385 } |
| 341 | 386 |
| 342 bool Connection::CommitTransaction() { | 387 bool Connection::CommitTransaction() { |
| 343 if (!transaction_nesting_) { | 388 if (!transaction_nesting_) { |
| 344 DLOG(FATAL) << "Rolling back a nonexistent transaction"; | 389 DLOG_IF(FATAL, !poisoned_) << "Rolling back a nonexistent transaction"; |
| 345 return false; | 390 return false; |
| 346 } | 391 } |
| 347 transaction_nesting_--; | 392 transaction_nesting_--; |
| 348 | 393 |
| 349 if (transaction_nesting_ > 0) { | 394 if (transaction_nesting_ > 0) { |
| 350 // Mark any nested transactions as failing after we've already got one. | 395 // Mark any nested transactions as failing after we've already got one. |
| 351 return !needs_rollback_; | 396 return !needs_rollback_; |
| 352 } | 397 } |
| 353 | 398 |
| 354 if (needs_rollback_) { | 399 if (needs_rollback_) { |
| 355 DoRollback(); | 400 DoRollback(); |
| 356 return false; | 401 return false; |
| 357 } | 402 } |
| 358 | 403 |
| 359 Statement commit(GetCachedStatement(SQL_FROM_HERE, "COMMIT")); | 404 Statement commit(GetCachedStatement(SQL_FROM_HERE, "COMMIT")); |
| 360 return commit.Run(); | 405 return commit.Run(); |
| 361 } | 406 } |
| 362 | 407 |
| 363 int Connection::ExecuteAndReturnErrorCode(const char* sql) { | 408 int Connection::ExecuteAndReturnErrorCode(const char* sql) { |
| 364 AssertIOAllowed(); | 409 AssertIOAllowed(); |
| 365 if (!db_) | 410 if (!db_) |
| 366 return false; | 411 return false; |
|
pkotwicz
2013/01/31 19:22:00
false == SQLITE_OK ?
Scott Hess - ex-Googler
2013/02/05 01:20:25
GOOD CATCH! I hope that nobody is currently hitti
| |
| 367 return sqlite3_exec(db_, sql, NULL, NULL, NULL); | 412 return sqlite3_exec(db_, sql, NULL, NULL, NULL); |
| 368 } | 413 } |
| 369 | 414 |
| 370 bool Connection::Execute(const char* sql) { | 415 bool Connection::Execute(const char* sql) { |
| 371 int error = ExecuteAndReturnErrorCode(sql); | 416 int error = ExecuteAndReturnErrorCode(sql); |
| 372 if (error != SQLITE_OK) | 417 if (error != SQLITE_OK) |
| 373 error = OnSqliteError(error, NULL); | 418 error = OnSqliteError(error, NULL); |
| 374 | 419 |
| 375 // This needs to be a FATAL log because the error case of arriving here is | 420 // This needs to be a FATAL log because the error case of arriving here is |
| 376 // that there's a malformed SQL statement. This can arise in development if | 421 // that there's a malformed SQL statement. This can arise in development if |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 443 if (rc != SQLITE_OK) { | 488 if (rc != SQLITE_OK) { |
| 444 // This is evidence of a syntax error in the incoming SQL. | 489 // This is evidence of a syntax error in the incoming SQL. |
| 445 DLOG(FATAL) << "SQL compile error " << GetErrorMessage(); | 490 DLOG(FATAL) << "SQL compile error " << GetErrorMessage(); |
| 446 return new StatementRef(); | 491 return new StatementRef(); |
| 447 } | 492 } |
| 448 return new StatementRef(stmt); | 493 return new StatementRef(stmt); |
| 449 } | 494 } |
| 450 | 495 |
| 451 bool Connection::IsSQLValid(const char* sql) { | 496 bool Connection::IsSQLValid(const char* sql) { |
| 452 AssertIOAllowed(); | 497 AssertIOAllowed(); |
| 498 if (!db_) { | |
| 499 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; | |
| 500 return false; | |
| 501 } | |
| 502 | |
| 453 sqlite3_stmt* stmt = NULL; | 503 sqlite3_stmt* stmt = NULL; |
| 454 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) | 504 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) |
| 455 return false; | 505 return false; |
| 456 | 506 |
| 457 sqlite3_finalize(stmt); | 507 sqlite3_finalize(stmt); |
| 458 return true; | 508 return true; |
| 459 } | 509 } |
| 460 | 510 |
| 461 bool Connection::DoesTableExist(const char* table_name) const { | 511 bool Connection::DoesTableExist(const char* table_name) const { |
| 462 return DoesTableOrIndexExist(table_name, "table"); | 512 return DoesTableOrIndexExist(table_name, "table"); |
| 463 } | 513 } |
| 464 | 514 |
| 465 bool Connection::DoesIndexExist(const char* index_name) const { | 515 bool Connection::DoesIndexExist(const char* index_name) const { |
| 466 return DoesTableOrIndexExist(index_name, "index"); | 516 return DoesTableOrIndexExist(index_name, "index"); |
| 467 } | 517 } |
| 468 | 518 |
| 469 bool Connection::DoesTableOrIndexExist( | 519 bool Connection::DoesTableOrIndexExist( |
|
pkotwicz
2013/01/31 19:22:00
Comment: Calling this method after the connection
Scott Hess - ex-Googler
2013/02/05 01:20:25
I don't think so - it should fail comprehensively
| |
| 470 const char* name, const char* type) const { | 520 const char* name, const char* type) const { |
| 471 const char* kSql = "SELECT name FROM sqlite_master WHERE type=? AND name=?"; | 521 const char* kSql = "SELECT name FROM sqlite_master WHERE type=? AND name=?"; |
| 472 Statement statement(GetUntrackedStatement(kSql)); | 522 Statement statement(GetUntrackedStatement(kSql)); |
| 473 statement.BindString(0, type); | 523 statement.BindString(0, type); |
| 474 statement.BindString(1, name); | 524 statement.BindString(1, name); |
| 475 | 525 |
| 476 return statement.Step(); // Table exists if any row was returned. | 526 return statement.Step(); // Table exists if any row was returned. |
| 477 } | 527 } |
| 478 | 528 |
| 479 bool Connection::DoesColumnExist(const char* table_name, | 529 bool Connection::DoesColumnExist(const char* table_name, |
| 480 const char* column_name) const { | 530 const char* column_name) const { |
| 481 std::string sql("PRAGMA TABLE_INFO("); | 531 std::string sql("PRAGMA TABLE_INFO("); |
| 482 sql.append(table_name); | 532 sql.append(table_name); |
| 483 sql.append(")"); | 533 sql.append(")"); |
| 484 | 534 |
| 485 Statement statement(GetUntrackedStatement(sql.c_str())); | 535 Statement statement(GetUntrackedStatement(sql.c_str())); |
| 486 while (statement.Step()) { | 536 while (statement.Step()) { |
| 487 if (!statement.ColumnString(1).compare(column_name)) | 537 if (!statement.ColumnString(1).compare(column_name)) |
| 488 return true; | 538 return true; |
| 489 } | 539 } |
| 490 return false; | 540 return false; |
| 491 } | 541 } |
| 492 | 542 |
| 493 int64 Connection::GetLastInsertRowId() const { | 543 int64 Connection::GetLastInsertRowId() const { |
| 494 if (!db_) { | 544 if (!db_) { |
| 495 DLOG(FATAL) << "Illegal use of connection without a db"; | 545 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
| 496 return 0; | 546 return 0; |
| 497 } | 547 } |
| 498 return sqlite3_last_insert_rowid(db_); | 548 return sqlite3_last_insert_rowid(db_); |
| 499 } | 549 } |
| 500 | 550 |
| 501 int Connection::GetLastChangeCount() const { | 551 int Connection::GetLastChangeCount() const { |
| 502 if (!db_) { | 552 if (!db_) { |
| 503 DLOG(FATAL) << "Illegal use of connection without a db"; | 553 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
| 504 return 0; | 554 return 0; |
| 505 } | 555 } |
| 506 return sqlite3_changes(db_); | 556 return sqlite3_changes(db_); |
| 507 } | 557 } |
| 508 | 558 |
| 509 int Connection::GetErrorCode() const { | 559 int Connection::GetErrorCode() const { |
| 510 if (!db_) | 560 if (!db_) |
| 511 return SQLITE_ERROR; | 561 return SQLITE_ERROR; |
| 512 return sqlite3_errcode(db_); | 562 return sqlite3_errcode(db_); |
| 513 } | 563 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 525 | 575 |
| 526 const char* Connection::GetErrorMessage() const { | 576 const char* Connection::GetErrorMessage() const { |
| 527 if (!db_) | 577 if (!db_) |
| 528 return "sql::Connection has no connection."; | 578 return "sql::Connection has no connection."; |
| 529 return sqlite3_errmsg(db_); | 579 return sqlite3_errmsg(db_); |
| 530 } | 580 } |
| 531 | 581 |
| 532 bool Connection::OpenInternal(const std::string& file_name) { | 582 bool Connection::OpenInternal(const std::string& file_name) { |
| 533 AssertIOAllowed(); | 583 AssertIOAllowed(); |
| 534 | 584 |
| 585 // Reset, in case connection is re-used. This usage may not be an | |
| 586 // intentional API contract, but tests do it. | |
| 587 poisoned_ = false; | |
| 588 | |
| 535 if (db_) { | 589 if (db_) { |
| 536 DLOG(FATAL) << "sql::Connection is already open."; | 590 DLOG(FATAL) << "sql::Connection is already open."; |
| 537 return false; | 591 return false; |
| 538 } | 592 } |
| 539 | 593 |
| 540 int err = sqlite3_open(file_name.c_str(), &db_); | 594 int err = sqlite3_open(file_name.c_str(), &db_); |
| 541 if (err != SQLITE_OK) { | 595 if (err != SQLITE_OK) { |
| 542 // Histogram failures specific to initial open for debugging | 596 // Histogram failures specific to initial open for debugging |
| 543 // purposes. | 597 // purposes. |
| 544 UMA_HISTOGRAM_ENUMERATION("Sqlite.OpenFailure", err & 0xff, 50); | 598 UMA_HISTOGRAM_ENUMERATION("Sqlite.OpenFailure", err & 0xff, 50); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 634 } | 688 } |
| 635 | 689 |
| 636 void Connection::StatementRefDeleted(StatementRef* ref) { | 690 void Connection::StatementRefDeleted(StatementRef* ref) { |
| 637 StatementRefSet::iterator i = open_statements_.find(ref); | 691 StatementRefSet::iterator i = open_statements_.find(ref); |
| 638 if (i == open_statements_.end()) | 692 if (i == open_statements_.end()) |
| 639 DLOG(FATAL) << "Could not find statement"; | 693 DLOG(FATAL) << "Could not find statement"; |
| 640 else | 694 else |
| 641 open_statements_.erase(i); | 695 open_statements_.erase(i); |
| 642 } | 696 } |
| 643 | 697 |
| 644 void Connection::ClearCache() { | |
| 645 statement_cache_.clear(); | |
| 646 | |
| 647 // The cache clear will get most statements. There may be still be references | |
| 648 // to some statements that are held by others (including one-shot statements). | |
| 649 // This will deactivate them so they can't be used again. | |
| 650 for (StatementRefSet::iterator i = open_statements_.begin(); | |
| 651 i != open_statements_.end(); ++i) | |
| 652 (*i)->Close(); | |
| 653 } | |
| 654 | |
| 655 int Connection::OnSqliteError(int err, sql::Statement *stmt) { | 698 int Connection::OnSqliteError(int err, sql::Statement *stmt) { |
| 656 // Strip extended error codes. | 699 // Strip extended error codes. |
| 657 int base_err = err&0xff; | 700 int base_err = err&0xff; |
| 658 | 701 |
| 659 static size_t kSqliteErrorMax = 50; | 702 static size_t kSqliteErrorMax = 50; |
| 660 UMA_HISTOGRAM_ENUMERATION("Sqlite.Error", base_err, kSqliteErrorMax); | 703 UMA_HISTOGRAM_ENUMERATION("Sqlite.Error", base_err, kSqliteErrorMax); |
| 661 if (!error_histogram_name_.empty()) { | 704 if (!error_histogram_name_.empty()) { |
| 662 // TODO(shess): The histogram macros create a bit of static | 705 // TODO(shess): The histogram macros create a bit of static |
| 663 // storage for caching the histogram object. Since SQLite is | 706 // storage for caching the histogram object. Since SQLite is |
| 664 // being used for I/O, generally without error, this code | 707 // being used for I/O, generally without error, this code |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 680 | 723 |
| 681 if (error_delegate_.get()) | 724 if (error_delegate_.get()) |
| 682 return error_delegate_->OnError(err, this, stmt); | 725 return error_delegate_->OnError(err, this, stmt); |
| 683 | 726 |
| 684 // The default handling is to assert on debug and to ignore on release. | 727 // The default handling is to assert on debug and to ignore on release. |
| 685 DLOG(FATAL) << GetErrorMessage(); | 728 DLOG(FATAL) << GetErrorMessage(); |
| 686 return err; | 729 return err; |
| 687 } | 730 } |
| 688 | 731 |
| 689 } // namespace sql | 732 } // namespace sql |
| OLD | NEW |