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 |