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 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 | 67 |
68 bool StatementID::operator<(const StatementID& other) const { | 68 bool StatementID::operator<(const StatementID& other) const { |
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() | |
78 : connection_(NULL), | |
79 stmt_(NULL) { | |
80 } | |
81 | |
82 Connection::StatementRef::StatementRef(sqlite3_stmt* stmt) | |
83 : connection_(NULL), | |
84 stmt_(stmt) { | |
85 } | |
86 | |
87 Connection::StatementRef::StatementRef(Connection* connection, | 77 Connection::StatementRef::StatementRef(Connection* connection, |
88 sqlite3_stmt* stmt) | 78 sqlite3_stmt* stmt, |
| 79 bool was_valid) |
89 : connection_(connection), | 80 : connection_(connection), |
90 stmt_(stmt) { | 81 stmt_(stmt), |
91 connection_->StatementRefCreated(this); | 82 was_valid_(was_valid) { |
| 83 if (connection) |
| 84 connection_->StatementRefCreated(this); |
92 } | 85 } |
93 | 86 |
94 Connection::StatementRef::~StatementRef() { | 87 Connection::StatementRef::~StatementRef() { |
95 if (connection_) | 88 if (connection_) |
96 connection_->StatementRefDeleted(this); | 89 connection_->StatementRefDeleted(this); |
97 Close(); | 90 Close(false); |
98 } | 91 } |
99 | 92 |
100 void Connection::StatementRef::Close() { | 93 void Connection::StatementRef::Close(bool forced) { |
101 if (stmt_) { | 94 if (stmt_) { |
102 // Call to AssertIOAllowed() cannot go at the beginning of the function | 95 // Call to AssertIOAllowed() cannot go at the beginning of the function |
103 // because Close() is called unconditionally from destructor to clean | 96 // because Close() is called unconditionally from destructor to clean |
104 // connection_. And if this is inactive statement this won't cause any | 97 // connection_. And if this is inactive statement this won't cause any |
105 // disk access and destructor most probably will be called on thread | 98 // disk access and destructor most probably will be called on thread |
106 // not allowing disk access. | 99 // not allowing disk access. |
107 // TODO(paivanof@gmail.com): This should move to the beginning | 100 // TODO(paivanof@gmail.com): This should move to the beginning |
108 // of the function. http://crbug.com/136655. | 101 // of the function. http://crbug.com/136655. |
109 AssertIOAllowed(); | 102 AssertIOAllowed(); |
110 sqlite3_finalize(stmt_); | 103 sqlite3_finalize(stmt_); |
111 stmt_ = NULL; | 104 stmt_ = NULL; |
112 } | 105 } |
113 connection_ = NULL; // The connection may be getting deleted. | 106 connection_ = NULL; // The connection may be getting deleted. |
| 107 |
| 108 // Forced close is expected to happen from a statement error |
| 109 // handler. In that case maintain the sense of |was_valid_| which |
| 110 // previously held for this ref. |
| 111 was_valid_ = was_valid_ && forced; |
114 } | 112 } |
115 | 113 |
116 Connection::Connection() | 114 Connection::Connection() |
117 : db_(NULL), | 115 : db_(NULL), |
118 page_size_(0), | 116 page_size_(0), |
119 cache_size_(0), | 117 cache_size_(0), |
120 exclusive_locking_(false), | 118 exclusive_locking_(false), |
121 transaction_nesting_(0), | 119 transaction_nesting_(0), |
122 needs_rollback_(false), | 120 needs_rollback_(false), |
123 in_memory_(false), | 121 in_memory_(false), |
| 122 poisoned_(false), |
124 error_delegate_(NULL) { | 123 error_delegate_(NULL) { |
125 } | 124 } |
126 | 125 |
127 Connection::~Connection() { | 126 Connection::~Connection() { |
128 Close(); | 127 Close(); |
129 } | 128 } |
130 | 129 |
131 bool Connection::Open(const base::FilePath& path) { | 130 bool Connection::Open(const base::FilePath& path) { |
132 #if defined(OS_WIN) | 131 #if defined(OS_WIN) |
133 return OpenInternal(WideToUTF8(path.value())); | 132 return OpenInternal(WideToUTF8(path.value())); |
134 #elif defined(OS_POSIX) | 133 #elif defined(OS_POSIX) |
135 return OpenInternal(path.value()); | 134 return OpenInternal(path.value()); |
136 #endif | 135 #endif |
137 } | 136 } |
138 | 137 |
139 bool Connection::OpenInMemory() { | 138 bool Connection::OpenInMemory() { |
140 in_memory_ = true; | 139 in_memory_ = true; |
141 return OpenInternal(":memory:"); | 140 return OpenInternal(":memory:"); |
142 } | 141 } |
143 | 142 |
144 void Connection::Close() { | 143 void Connection::CloseInternal(bool forced) { |
145 // TODO(shess): Calling "PRAGMA journal_mode = DELETE" at this point | 144 // TODO(shess): Calling "PRAGMA journal_mode = DELETE" at this point |
146 // will delete the -journal file. For ChromiumOS or other more | 145 // will delete the -journal file. For ChromiumOS or other more |
147 // embedded systems, this is probably not appropriate, whereas on | 146 // embedded systems, this is probably not appropriate, whereas on |
148 // desktop it might make some sense. | 147 // desktop it might make some sense. |
149 | 148 |
150 // sqlite3_close() needs all prepared statements to be finalized. | 149 // sqlite3_close() needs all prepared statements to be finalized. |
151 // Release all cached statements, then assert that the client has | 150 |
152 // released all statements. | 151 // Release cached statements. |
153 statement_cache_.clear(); | 152 statement_cache_.clear(); |
154 DCHECK(open_statements_.empty()); | |
155 | 153 |
156 // Additionally clear the prepared statements, because they contain | 154 // With cached statements released, in-use statements will remain. |
157 // weak references to this connection. This case has come up when | 155 // Closing the database while statements are in use is an API |
158 // error-handling code is hit in production. | 156 // violation, except for forced close (which happens from within a |
159 ClearCache(); | 157 // statement's error handler). |
| 158 DCHECK(forced || open_statements_.empty()); |
| 159 |
| 160 // Deactivate any outstanding statements so sqlite3_close() works. |
| 161 for (StatementRefSet::iterator i = open_statements_.begin(); |
| 162 i != open_statements_.end(); ++i) |
| 163 (*i)->Close(forced); |
| 164 open_statements_.clear(); |
160 | 165 |
161 if (db_) { | 166 if (db_) { |
162 // Call to AssertIOAllowed() cannot go at the beginning of the function | 167 // Call to AssertIOAllowed() cannot go at the beginning of the function |
163 // because Close() must be called from destructor to clean | 168 // because Close() must be called from destructor to clean |
164 // statement_cache_, it won't cause any disk access and it most probably | 169 // statement_cache_, it won't cause any disk access and it most probably |
165 // will happen on thread not allowing disk access. | 170 // will happen on thread not allowing disk access. |
166 // TODO(paivanof@gmail.com): This should move to the beginning | 171 // TODO(paivanof@gmail.com): This should move to the beginning |
167 // of the function. http://crbug.com/136655. | 172 // of the function. http://crbug.com/136655. |
168 AssertIOAllowed(); | 173 AssertIOAllowed(); |
169 // TODO(shess): Histogram for failure. | 174 // TODO(shess): Histogram for failure. |
170 sqlite3_close(db_); | 175 sqlite3_close(db_); |
171 db_ = NULL; | 176 db_ = NULL; |
172 } | 177 } |
173 } | 178 } |
174 | 179 |
| 180 void Connection::Close() { |
| 181 // If the database was already closed by RazeAndClose(), then no |
| 182 // need to close again. Clear the |poisoned_| bit so that incorrect |
| 183 // API calls are caught. |
| 184 if (poisoned_) { |
| 185 poisoned_ = false; |
| 186 return; |
| 187 } |
| 188 |
| 189 CloseInternal(false); |
| 190 } |
| 191 |
175 void Connection::Preload() { | 192 void Connection::Preload() { |
176 AssertIOAllowed(); | 193 AssertIOAllowed(); |
177 | 194 |
178 if (!db_) { | 195 if (!db_) { |
179 DLOG(FATAL) << "Cannot preload null db"; | 196 DLOG_IF(FATAL, !poisoned_) << "Cannot preload null db"; |
180 return; | 197 return; |
181 } | 198 } |
182 | 199 |
183 // A statement must be open for the preload command to work. If the meta | 200 // 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 | 201 // 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). | 202 // is nothing to preload (so it's OK we do nothing). |
186 if (!DoesTableExist("meta")) | 203 if (!DoesTableExist("meta")) |
187 return; | 204 return; |
188 Statement dummy(GetUniqueStatement("SELECT * FROM meta")); | 205 Statement dummy(GetUniqueStatement("SELECT * FROM meta")); |
189 if (!dummy.Step()) | 206 if (!dummy.Step()) |
190 return; | 207 return; |
191 | 208 |
192 #if !defined(USE_SYSTEM_SQLITE) | 209 #if !defined(USE_SYSTEM_SQLITE) |
193 // This function is only defined in Chromium's version of sqlite. | 210 // This function is only defined in Chromium's version of sqlite. |
194 // Do not call it when using system sqlite. | 211 // Do not call it when using system sqlite. |
195 sqlite3_preload(db_); | 212 sqlite3_preload(db_); |
196 #endif | 213 #endif |
197 } | 214 } |
198 | 215 |
199 // Create an in-memory database with the existing database's page | 216 // Create an in-memory database with the existing database's page |
200 // size, then backup that database over the existing database. | 217 // size, then backup that database over the existing database. |
201 bool Connection::Raze() { | 218 bool Connection::Raze() { |
202 AssertIOAllowed(); | 219 AssertIOAllowed(); |
203 | 220 |
204 if (!db_) { | 221 if (!db_) { |
205 DLOG(FATAL) << "Cannot raze null db"; | 222 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; |
206 return false; | 223 return false; |
207 } | 224 } |
208 | 225 |
209 if (transaction_nesting_ > 0) { | 226 if (transaction_nesting_ > 0) { |
210 DLOG(FATAL) << "Cannot raze within a transaction"; | 227 DLOG(FATAL) << "Cannot raze within a transaction"; |
211 return false; | 228 return false; |
212 } | 229 } |
213 | 230 |
214 sql::Connection null_db; | 231 sql::Connection null_db; |
215 if (!null_db.OpenInMemory()) { | 232 if (!null_db.OpenInMemory()) { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 | 302 |
286 // Exactly one page should have been backed up. If this breaks, | 303 // Exactly one page should have been backed up. If this breaks, |
287 // check this function to make sure assumptions aren't being broken. | 304 // check this function to make sure assumptions aren't being broken. |
288 DCHECK_EQ(pages, 1); | 305 DCHECK_EQ(pages, 1); |
289 | 306 |
290 return true; | 307 return true; |
291 } | 308 } |
292 | 309 |
293 bool Connection::RazeWithTimout(base::TimeDelta timeout) { | 310 bool Connection::RazeWithTimout(base::TimeDelta timeout) { |
294 if (!db_) { | 311 if (!db_) { |
295 DLOG(FATAL) << "Cannot raze null db"; | 312 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; |
296 return false; | 313 return false; |
297 } | 314 } |
298 | 315 |
299 ScopedBusyTimeout busy_timeout(db_); | 316 ScopedBusyTimeout busy_timeout(db_); |
300 busy_timeout.SetTimeout(timeout); | 317 busy_timeout.SetTimeout(timeout); |
301 return Raze(); | 318 return Raze(); |
302 } | 319 } |
303 | 320 |
| 321 bool Connection::RazeAndClose() { |
| 322 if (!db_) { |
| 323 DLOG_IF(FATAL, !poisoned_) << "Cannot raze null db"; |
| 324 return false; |
| 325 } |
| 326 |
| 327 // Raze() cannot run in a transaction. |
| 328 while (transaction_nesting_) { |
| 329 RollbackTransaction(); |
| 330 } |
| 331 |
| 332 bool result = Raze(); |
| 333 |
| 334 CloseInternal(true); |
| 335 |
| 336 // Mark the database so that future API calls fail appropriately, |
| 337 // but don't DCHECK (because after calling this function they are |
| 338 // expected to fail). |
| 339 poisoned_ = true; |
| 340 |
| 341 return result; |
| 342 } |
| 343 |
304 bool Connection::BeginTransaction() { | 344 bool Connection::BeginTransaction() { |
305 if (needs_rollback_) { | 345 if (needs_rollback_) { |
306 DCHECK_GT(transaction_nesting_, 0); | 346 DCHECK_GT(transaction_nesting_, 0); |
307 | 347 |
308 // When we're going to rollback, fail on this begin and don't actually | 348 // When we're going to rollback, fail on this begin and don't actually |
309 // mark us as entering the nested transaction. | 349 // mark us as entering the nested transaction. |
310 return false; | 350 return false; |
311 } | 351 } |
312 | 352 |
313 bool success = true; | 353 bool success = true; |
314 if (!transaction_nesting_) { | 354 if (!transaction_nesting_) { |
315 needs_rollback_ = false; | 355 needs_rollback_ = false; |
316 | 356 |
317 Statement begin(GetCachedStatement(SQL_FROM_HERE, "BEGIN TRANSACTION")); | 357 Statement begin(GetCachedStatement(SQL_FROM_HERE, "BEGIN TRANSACTION")); |
318 if (!begin.Run()) | 358 if (!begin.Run()) |
319 return false; | 359 return false; |
320 } | 360 } |
321 transaction_nesting_++; | 361 transaction_nesting_++; |
322 return success; | 362 return success; |
323 } | 363 } |
324 | 364 |
325 void Connection::RollbackTransaction() { | 365 void Connection::RollbackTransaction() { |
326 if (!transaction_nesting_) { | 366 if (!transaction_nesting_) { |
327 DLOG(FATAL) << "Rolling back a nonexistent transaction"; | 367 DLOG_IF(FATAL, !poisoned_) << "Rolling back a nonexistent transaction"; |
328 return; | 368 return; |
329 } | 369 } |
330 | 370 |
331 transaction_nesting_--; | 371 transaction_nesting_--; |
332 | 372 |
333 if (transaction_nesting_ > 0) { | 373 if (transaction_nesting_ > 0) { |
334 // Mark the outermost transaction as needing rollback. | 374 // Mark the outermost transaction as needing rollback. |
335 needs_rollback_ = true; | 375 needs_rollback_ = true; |
336 return; | 376 return; |
337 } | 377 } |
338 | 378 |
339 DoRollback(); | 379 DoRollback(); |
340 } | 380 } |
341 | 381 |
342 bool Connection::CommitTransaction() { | 382 bool Connection::CommitTransaction() { |
343 if (!transaction_nesting_) { | 383 if (!transaction_nesting_) { |
344 DLOG(FATAL) << "Rolling back a nonexistent transaction"; | 384 DLOG_IF(FATAL, !poisoned_) << "Rolling back a nonexistent transaction"; |
345 return false; | 385 return false; |
346 } | 386 } |
347 transaction_nesting_--; | 387 transaction_nesting_--; |
348 | 388 |
349 if (transaction_nesting_ > 0) { | 389 if (transaction_nesting_ > 0) { |
350 // Mark any nested transactions as failing after we've already got one. | 390 // Mark any nested transactions as failing after we've already got one. |
351 return !needs_rollback_; | 391 return !needs_rollback_; |
352 } | 392 } |
353 | 393 |
354 if (needs_rollback_) { | 394 if (needs_rollback_) { |
355 DoRollback(); | 395 DoRollback(); |
356 return false; | 396 return false; |
357 } | 397 } |
358 | 398 |
359 Statement commit(GetCachedStatement(SQL_FROM_HERE, "COMMIT")); | 399 Statement commit(GetCachedStatement(SQL_FROM_HERE, "COMMIT")); |
360 return commit.Run(); | 400 return commit.Run(); |
361 } | 401 } |
362 | 402 |
363 int Connection::ExecuteAndReturnErrorCode(const char* sql) { | 403 int Connection::ExecuteAndReturnErrorCode(const char* sql) { |
364 AssertIOAllowed(); | 404 AssertIOAllowed(); |
365 if (!db_) | 405 if (!db_) { |
366 return false; | 406 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
| 407 return SQLITE_ERROR; |
| 408 } |
367 return sqlite3_exec(db_, sql, NULL, NULL, NULL); | 409 return sqlite3_exec(db_, sql, NULL, NULL, NULL); |
368 } | 410 } |
369 | 411 |
370 bool Connection::Execute(const char* sql) { | 412 bool Connection::Execute(const char* sql) { |
| 413 if (!db_) { |
| 414 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
| 415 return false; |
| 416 } |
| 417 |
371 int error = ExecuteAndReturnErrorCode(sql); | 418 int error = ExecuteAndReturnErrorCode(sql); |
372 if (error != SQLITE_OK) | 419 if (error != SQLITE_OK) |
373 error = OnSqliteError(error, NULL); | 420 error = OnSqliteError(error, NULL); |
374 | 421 |
375 // This needs to be a FATAL log because the error case of arriving here is | 422 // 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 | 423 // that there's a malformed SQL statement. This can arise in development if |
377 // a change alters the schema but not all queries adjust. | 424 // a change alters the schema but not all queries adjust. |
378 if (error == SQLITE_ERROR) | 425 if (error == SQLITE_ERROR) |
379 DLOG(FATAL) << "SQL Error in " << sql << ", " << GetErrorMessage(); | 426 DLOG(FATAL) << "SQL Error in " << sql << ", " << GetErrorMessage(); |
380 return error == SQLITE_OK; | 427 return error == SQLITE_OK; |
381 } | 428 } |
382 | 429 |
383 bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) { | 430 bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) { |
384 if (!db_) | 431 if (!db_) { |
| 432 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
385 return false; | 433 return false; |
| 434 } |
386 | 435 |
387 ScopedBusyTimeout busy_timeout(db_); | 436 ScopedBusyTimeout busy_timeout(db_); |
388 busy_timeout.SetTimeout(timeout); | 437 busy_timeout.SetTimeout(timeout); |
389 return Execute(sql); | 438 return Execute(sql); |
390 } | 439 } |
391 | 440 |
392 bool Connection::HasCachedStatement(const StatementID& id) const { | 441 bool Connection::HasCachedStatement(const StatementID& id) const { |
393 return statement_cache_.find(id) != statement_cache_.end(); | 442 return statement_cache_.find(id) != statement_cache_.end(); |
394 } | 443 } |
395 | 444 |
(...skipping 14 matching lines...) Expand all Loading... |
410 scoped_refptr<StatementRef> statement = GetUniqueStatement(sql); | 459 scoped_refptr<StatementRef> statement = GetUniqueStatement(sql); |
411 if (statement->is_valid()) | 460 if (statement->is_valid()) |
412 statement_cache_[id] = statement; // Only cache valid statements. | 461 statement_cache_[id] = statement; // Only cache valid statements. |
413 return statement; | 462 return statement; |
414 } | 463 } |
415 | 464 |
416 scoped_refptr<Connection::StatementRef> Connection::GetUniqueStatement( | 465 scoped_refptr<Connection::StatementRef> Connection::GetUniqueStatement( |
417 const char* sql) { | 466 const char* sql) { |
418 AssertIOAllowed(); | 467 AssertIOAllowed(); |
419 | 468 |
| 469 // Return inactive statement. |
420 if (!db_) | 470 if (!db_) |
421 return new StatementRef(); // Return inactive statement. | 471 return new StatementRef(NULL, NULL, poisoned_); |
422 | 472 |
423 sqlite3_stmt* stmt = NULL; | 473 sqlite3_stmt* stmt = NULL; |
424 int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL); | 474 int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL); |
425 if (rc != SQLITE_OK) { | 475 if (rc != SQLITE_OK) { |
426 // This is evidence of a syntax error in the incoming SQL. | 476 // This is evidence of a syntax error in the incoming SQL. |
427 DLOG(FATAL) << "SQL compile error " << GetErrorMessage(); | 477 DLOG(FATAL) << "SQL compile error " << GetErrorMessage(); |
428 | 478 |
429 // It could also be database corruption. | 479 // It could also be database corruption. |
430 OnSqliteError(rc, NULL); | 480 OnSqliteError(rc, NULL); |
431 return new StatementRef(); | 481 return new StatementRef(NULL, NULL, false); |
432 } | 482 } |
433 return new StatementRef(this, stmt); | 483 return new StatementRef(this, stmt, true); |
434 } | 484 } |
435 | 485 |
436 scoped_refptr<Connection::StatementRef> Connection::GetUntrackedStatement( | 486 scoped_refptr<Connection::StatementRef> Connection::GetUntrackedStatement( |
437 const char* sql) const { | 487 const char* sql) const { |
| 488 // Return inactive statement. |
438 if (!db_) | 489 if (!db_) |
439 return new StatementRef(); // Return inactive statement. | 490 return new StatementRef(NULL, NULL, poisoned_); |
440 | 491 |
441 sqlite3_stmt* stmt = NULL; | 492 sqlite3_stmt* stmt = NULL; |
442 int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL); | 493 int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL); |
443 if (rc != SQLITE_OK) { | 494 if (rc != SQLITE_OK) { |
444 // This is evidence of a syntax error in the incoming SQL. | 495 // This is evidence of a syntax error in the incoming SQL. |
445 DLOG(FATAL) << "SQL compile error " << GetErrorMessage(); | 496 DLOG(FATAL) << "SQL compile error " << GetErrorMessage(); |
446 return new StatementRef(); | 497 return new StatementRef(NULL, NULL, false); |
447 } | 498 } |
448 return new StatementRef(stmt); | 499 return new StatementRef(NULL, stmt, true); |
449 } | 500 } |
450 | 501 |
451 bool Connection::IsSQLValid(const char* sql) { | 502 bool Connection::IsSQLValid(const char* sql) { |
452 AssertIOAllowed(); | 503 AssertIOAllowed(); |
| 504 if (!db_) { |
| 505 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
| 506 return false; |
| 507 } |
| 508 |
453 sqlite3_stmt* stmt = NULL; | 509 sqlite3_stmt* stmt = NULL; |
454 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) | 510 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) |
455 return false; | 511 return false; |
456 | 512 |
457 sqlite3_finalize(stmt); | 513 sqlite3_finalize(stmt); |
458 return true; | 514 return true; |
459 } | 515 } |
460 | 516 |
461 bool Connection::DoesTableExist(const char* table_name) const { | 517 bool Connection::DoesTableExist(const char* table_name) const { |
462 return DoesTableOrIndexExist(table_name, "table"); | 518 return DoesTableOrIndexExist(table_name, "table"); |
(...skipping 22 matching lines...) Expand all Loading... |
485 Statement statement(GetUntrackedStatement(sql.c_str())); | 541 Statement statement(GetUntrackedStatement(sql.c_str())); |
486 while (statement.Step()) { | 542 while (statement.Step()) { |
487 if (!statement.ColumnString(1).compare(column_name)) | 543 if (!statement.ColumnString(1).compare(column_name)) |
488 return true; | 544 return true; |
489 } | 545 } |
490 return false; | 546 return false; |
491 } | 547 } |
492 | 548 |
493 int64 Connection::GetLastInsertRowId() const { | 549 int64 Connection::GetLastInsertRowId() const { |
494 if (!db_) { | 550 if (!db_) { |
495 DLOG(FATAL) << "Illegal use of connection without a db"; | 551 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
496 return 0; | 552 return 0; |
497 } | 553 } |
498 return sqlite3_last_insert_rowid(db_); | 554 return sqlite3_last_insert_rowid(db_); |
499 } | 555 } |
500 | 556 |
501 int Connection::GetLastChangeCount() const { | 557 int Connection::GetLastChangeCount() const { |
502 if (!db_) { | 558 if (!db_) { |
503 DLOG(FATAL) << "Illegal use of connection without a db"; | 559 DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db"; |
504 return 0; | 560 return 0; |
505 } | 561 } |
506 return sqlite3_changes(db_); | 562 return sqlite3_changes(db_); |
507 } | 563 } |
508 | 564 |
509 int Connection::GetErrorCode() const { | 565 int Connection::GetErrorCode() const { |
510 if (!db_) | 566 if (!db_) |
511 return SQLITE_ERROR; | 567 return SQLITE_ERROR; |
512 return sqlite3_errcode(db_); | 568 return sqlite3_errcode(db_); |
513 } | 569 } |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
634 } | 690 } |
635 | 691 |
636 void Connection::StatementRefDeleted(StatementRef* ref) { | 692 void Connection::StatementRefDeleted(StatementRef* ref) { |
637 StatementRefSet::iterator i = open_statements_.find(ref); | 693 StatementRefSet::iterator i = open_statements_.find(ref); |
638 if (i == open_statements_.end()) | 694 if (i == open_statements_.end()) |
639 DLOG(FATAL) << "Could not find statement"; | 695 DLOG(FATAL) << "Could not find statement"; |
640 else | 696 else |
641 open_statements_.erase(i); | 697 open_statements_.erase(i); |
642 } | 698 } |
643 | 699 |
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) { | 700 int Connection::OnSqliteError(int err, sql::Statement *stmt) { |
656 // Strip extended error codes. | 701 // Strip extended error codes. |
657 int base_err = err&0xff; | 702 int base_err = err&0xff; |
658 | 703 |
659 static size_t kSqliteErrorMax = 50; | 704 static size_t kSqliteErrorMax = 50; |
660 UMA_HISTOGRAM_ENUMERATION("Sqlite.Error", base_err, kSqliteErrorMax); | 705 UMA_HISTOGRAM_ENUMERATION("Sqlite.Error", base_err, kSqliteErrorMax); |
661 if (!error_histogram_name_.empty()) { | 706 if (!error_histogram_name_.empty()) { |
662 // TODO(shess): The histogram macros create a bit of static | 707 // TODO(shess): The histogram macros create a bit of static |
663 // storage for caching the histogram object. Since SQLite is | 708 // storage for caching the histogram object. Since SQLite is |
664 // being used for I/O, generally without error, this code | 709 // being used for I/O, generally without error, this code |
(...skipping 15 matching lines...) Expand all Loading... |
680 | 725 |
681 if (error_delegate_.get()) | 726 if (error_delegate_.get()) |
682 return error_delegate_->OnError(err, this, stmt); | 727 return error_delegate_->OnError(err, this, stmt); |
683 | 728 |
684 // The default handling is to assert on debug and to ignore on release. | 729 // The default handling is to assert on debug and to ignore on release. |
685 DLOG(FATAL) << GetErrorMessage(); | 730 DLOG(FATAL) << GetErrorMessage(); |
686 return err; | 731 return err; |
687 } | 732 } |
688 | 733 |
689 } // namespace sql | 734 } // namespace sql |
OLD | NEW |