Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(444)

Side by Side Diff: sql/connection.cc

Issue 8899012: Put debugging assertions into sql::Statement. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Oops, Execute() should stay loose. Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sql/connection.h ('k') | sql/connection_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 // prevent optimization. 125 // prevent optimization.
126 CHECK_LT(nTouched, 1000*1000*1000U); 126 CHECK_LT(nTouched, 1000*1000*1000U);
127 #endif 127 #endif
128 sqlite3_close(db_); 128 sqlite3_close(db_);
129 db_ = NULL; 129 db_ = NULL;
130 } 130 }
131 } 131 }
132 132
133 void Connection::Preload() { 133 void Connection::Preload() {
134 if (!db_) { 134 if (!db_) {
135 NOTREACHED(); 135 DLOG(FATAL) << "Cannot preload null db";
136 return; 136 return;
137 } 137 }
138 138
139 // A statement must be open for the preload command to work. If the meta 139 // A statement must be open for the preload command to work. If the meta
140 // table doesn't exist, it probably means this is a new database and there 140 // table doesn't exist, it probably means this is a new database and there
141 // is nothing to preload (so it's OK we do nothing). 141 // is nothing to preload (so it's OK we do nothing).
142 if (!DoesTableExist("meta")) 142 if (!DoesTableExist("meta"))
143 return; 143 return;
144 Statement dummy(GetUniqueStatement("SELECT * FROM meta")); 144 Statement dummy(GetUniqueStatement("SELECT * FROM meta"));
145 if (!dummy || !dummy.Step()) 145 if (!dummy.Step())
146 return; 146 return;
147 147
148 #if !defined(USE_SYSTEM_SQLITE) 148 #if !defined(USE_SYSTEM_SQLITE)
149 // This function is only defined in Chromium's version of sqlite. 149 // This function is only defined in Chromium's version of sqlite.
150 // Do not call it when using system sqlite. 150 // Do not call it when using system sqlite.
151 sqlite3_preload(db_); 151 sqlite3_preload(db_);
152 #endif 152 #endif
153 } 153 }
154 154
155 bool Connection::BeginTransaction() { 155 bool Connection::BeginTransaction() {
156 if (needs_rollback_) { 156 if (needs_rollback_) {
157 DCHECK_GT(transaction_nesting_, 0); 157 DCHECK_GT(transaction_nesting_, 0);
158 158
159 // When we're going to rollback, fail on this begin and don't actually 159 // When we're going to rollback, fail on this begin and don't actually
160 // mark us as entering the nested transaction. 160 // mark us as entering the nested transaction.
161 return false; 161 return false;
162 } 162 }
163 163
164 bool success = true; 164 bool success = true;
165 if (!transaction_nesting_) { 165 if (!transaction_nesting_) {
166 needs_rollback_ = false; 166 needs_rollback_ = false;
167 167
168 Statement begin(GetCachedStatement(SQL_FROM_HERE, "BEGIN TRANSACTION")); 168 Statement begin(GetCachedStatement(SQL_FROM_HERE, "BEGIN TRANSACTION"));
169 if (!begin || !begin.Run()) 169 if (!begin.Run())
170 return false; 170 return false;
171 } 171 }
172 transaction_nesting_++; 172 transaction_nesting_++;
173 return success; 173 return success;
174 } 174 }
175 175
176 void Connection::RollbackTransaction() { 176 void Connection::RollbackTransaction() {
177 if (!transaction_nesting_) { 177 if (!transaction_nesting_) {
178 NOTREACHED() << "Rolling back a nonexistent transaction"; 178 DLOG(FATAL) << "Rolling back a nonexistent transaction";
179 return; 179 return;
180 } 180 }
181 181
182 transaction_nesting_--; 182 transaction_nesting_--;
183 183
184 if (transaction_nesting_ > 0) { 184 if (transaction_nesting_ > 0) {
185 // Mark the outermost transaction as needing rollback. 185 // Mark the outermost transaction as needing rollback.
186 needs_rollback_ = true; 186 needs_rollback_ = true;
187 return; 187 return;
188 } 188 }
189 189
190 DoRollback(); 190 DoRollback();
191 } 191 }
192 192
193 bool Connection::CommitTransaction() { 193 bool Connection::CommitTransaction() {
194 if (!transaction_nesting_) { 194 if (!transaction_nesting_) {
195 NOTREACHED() << "Rolling back a nonexistent transaction"; 195 DLOG(FATAL) << "Rolling back a nonexistent transaction";
196 return false; 196 return false;
197 } 197 }
198 transaction_nesting_--; 198 transaction_nesting_--;
199 199
200 if (transaction_nesting_ > 0) { 200 if (transaction_nesting_ > 0) {
201 // Mark any nested transactions as failing after we've already got one. 201 // Mark any nested transactions as failing after we've already got one.
202 return !needs_rollback_; 202 return !needs_rollback_;
203 } 203 }
204 204
205 if (needs_rollback_) { 205 if (needs_rollback_) {
206 DoRollback(); 206 DoRollback();
207 return false; 207 return false;
208 } 208 }
209 209
210 Statement commit(GetCachedStatement(SQL_FROM_HERE, "COMMIT")); 210 Statement commit(GetCachedStatement(SQL_FROM_HERE, "COMMIT"));
211 if (!commit)
212 return false;
213 return commit.Run(); 211 return commit.Run();
214 } 212 }
215 213
216 bool Connection::Execute(const char* sql) { 214 int Connection::ExecuteAndReturnErrorCode(const char* sql) {
217 if (!db_) 215 if (!db_)
218 return false; 216 return false;
219 return sqlite3_exec(db_, sql, NULL, NULL, NULL) == SQLITE_OK; 217 return sqlite3_exec(db_, sql, NULL, NULL, NULL);
218 }
219
220 bool Connection::Execute(const char* sql) {
221 int error = ExecuteAndReturnErrorCode(sql);
222 // TODO(shess,gbillock): DLOG(FATAL) once Execute() clients are
223 // converted.
224 if (error == SQLITE_ERROR)
225 DLOG(ERROR) << "SQL Error in " << sql << ", " << GetErrorMessage();
226 return error == SQLITE_OK;
220 } 227 }
221 228
222 bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) { 229 bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) {
223 if (!db_) 230 if (!db_)
224 return false; 231 return false;
225 232
226 ScopedBusyTimeout busy_timeout(db_); 233 ScopedBusyTimeout busy_timeout(db_);
227 busy_timeout.SetTimeout(timeout); 234 busy_timeout.SetTimeout(timeout);
228 return sqlite3_exec(db_, sql, NULL, NULL, NULL) == SQLITE_OK; 235 return Execute(sql);
229 } 236 }
230 237
231 bool Connection::HasCachedStatement(const StatementID& id) const { 238 bool Connection::HasCachedStatement(const StatementID& id) const {
232 return statement_cache_.find(id) != statement_cache_.end(); 239 return statement_cache_.find(id) != statement_cache_.end();
233 } 240 }
234 241
235 scoped_refptr<Connection::StatementRef> Connection::GetCachedStatement( 242 scoped_refptr<Connection::StatementRef> Connection::GetCachedStatement(
236 const StatementID& id, 243 const StatementID& id,
237 const char* sql) { 244 const char* sql) {
238 CachedStatementMap::iterator i = statement_cache_.find(id); 245 CachedStatementMap::iterator i = statement_cache_.find(id);
(...skipping 13 matching lines...) Expand all
252 return statement; 259 return statement;
253 } 260 }
254 261
255 scoped_refptr<Connection::StatementRef> Connection::GetUniqueStatement( 262 scoped_refptr<Connection::StatementRef> Connection::GetUniqueStatement(
256 const char* sql) { 263 const char* sql) {
257 if (!db_) 264 if (!db_)
258 return new StatementRef(this, NULL); // Return inactive statement. 265 return new StatementRef(this, NULL); // Return inactive statement.
259 266
260 sqlite3_stmt* stmt = NULL; 267 sqlite3_stmt* stmt = NULL;
261 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) { 268 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) {
262 // Treat this as non-fatal, it can occur in a number of valid cases, and 269 // This is evidence of a syntax error in the incoming SQL.
263 // callers should be doing their own error handling. 270 DLOG(FATAL) << "SQL compile error " << GetErrorMessage();
264 DLOG(WARNING) << "SQL compile error " << GetErrorMessage();
265 return new StatementRef(this, NULL); 271 return new StatementRef(this, NULL);
266 } 272 }
267 return new StatementRef(this, stmt); 273 return new StatementRef(this, stmt);
268 } 274 }
269 275
276 bool Connection::IsSQLValid(const char* sql) {
277 sqlite3_stmt* stmt = NULL;
278 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK)
279 return false;
280
281 sqlite3_finalize(stmt);
282 return true;
283 }
284
270 bool Connection::DoesTableExist(const char* table_name) const { 285 bool Connection::DoesTableExist(const char* table_name) const {
271 // GetUniqueStatement can't be const since statements may modify the 286 // GetUniqueStatement can't be const since statements may modify the
272 // database, but we know ours doesn't modify it, so the cast is safe. 287 // database, but we know ours doesn't modify it, so the cast is safe.
273 Statement statement(const_cast<Connection*>(this)->GetUniqueStatement( 288 Statement statement(const_cast<Connection*>(this)->GetUniqueStatement(
274 "SELECT name FROM sqlite_master " 289 "SELECT name FROM sqlite_master "
275 "WHERE type='table' AND name=?")); 290 "WHERE type='table' AND name=?"));
276 if (!statement)
277 return false;
278 statement.BindString(0, table_name); 291 statement.BindString(0, table_name);
279 return statement.Step(); // Table exists if any row was returned. 292 return statement.Step(); // Table exists if any row was returned.
280 } 293 }
281 294
282 bool Connection::DoesColumnExist(const char* table_name, 295 bool Connection::DoesColumnExist(const char* table_name,
283 const char* column_name) const { 296 const char* column_name) const {
284 std::string sql("PRAGMA TABLE_INFO("); 297 std::string sql("PRAGMA TABLE_INFO(");
285 sql.append(table_name); 298 sql.append(table_name);
286 sql.append(")"); 299 sql.append(")");
287 300
288 // Our SQL is non-mutating, so this cast is OK. 301 // Our SQL is non-mutating, so this cast is OK.
289 Statement statement(const_cast<Connection*>(this)->GetUniqueStatement( 302 Statement statement(const_cast<Connection*>(this)->GetUniqueStatement(
290 sql.c_str())); 303 sql.c_str()));
291 if (!statement)
292 return false;
293 304
294 while (statement.Step()) { 305 while (statement.Step()) {
295 if (!statement.ColumnString(1).compare(column_name)) 306 if (!statement.ColumnString(1).compare(column_name))
296 return true; 307 return true;
297 } 308 }
298 return false; 309 return false;
299 } 310 }
300 311
301 int64 Connection::GetLastInsertRowId() const { 312 int64 Connection::GetLastInsertRowId() const {
302 if (!db_) { 313 if (!db_) {
303 NOTREACHED(); 314 DLOG(FATAL) << "Illegal use of connection without a db";
304 return 0; 315 return 0;
305 } 316 }
306 return sqlite3_last_insert_rowid(db_); 317 return sqlite3_last_insert_rowid(db_);
307 } 318 }
308 319
309 int Connection::GetLastChangeCount() const { 320 int Connection::GetLastChangeCount() const {
310 if (!db_) { 321 if (!db_) {
311 NOTREACHED(); 322 DLOG(FATAL) << "Illegal use of connection without a db";
312 return 0; 323 return 0;
313 } 324 }
314 return sqlite3_changes(db_); 325 return sqlite3_changes(db_);
315 } 326 }
316 327
317 int Connection::GetErrorCode() const { 328 int Connection::GetErrorCode() const {
318 if (!db_) 329 if (!db_)
319 return SQLITE_ERROR; 330 return SQLITE_ERROR;
320 return sqlite3_errcode(db_); 331 return sqlite3_errcode(db_);
321 } 332 }
(...skipping 10 matching lines...) Expand all
332 } 343 }
333 344
334 const char* Connection::GetErrorMessage() const { 345 const char* Connection::GetErrorMessage() const {
335 if (!db_) 346 if (!db_)
336 return "sql::Connection has no connection."; 347 return "sql::Connection has no connection.";
337 return sqlite3_errmsg(db_); 348 return sqlite3_errmsg(db_);
338 } 349 }
339 350
340 bool Connection::OpenInternal(const std::string& file_name) { 351 bool Connection::OpenInternal(const std::string& file_name) {
341 if (db_) { 352 if (db_) {
342 NOTREACHED() << "sql::Connection is already open."; 353 DLOG(FATAL) << "sql::Connection is already open.";
343 return false; 354 return false;
344 } 355 }
345 356
346 int err = sqlite3_open(file_name.c_str(), &db_); 357 int err = sqlite3_open(file_name.c_str(), &db_);
347 if (err != SQLITE_OK) { 358 if (err != SQLITE_OK) {
348 OnSqliteError(err, NULL); 359 OnSqliteError(err, NULL);
349 db_ = NULL; 360 db_ = NULL;
350 return false; 361 return false;
351 } 362 }
352 363
(...skipping 10 matching lines...) Expand all
363 // TODO(shess): This code is brittle. Find the cases where code 374 // TODO(shess): This code is brittle. Find the cases where code
364 // doesn't request |exclusive_locking_| and audit that it does the 375 // doesn't request |exclusive_locking_| and audit that it does the
365 // right thing with SQLITE_BUSY, and that it doesn't make 376 // right thing with SQLITE_BUSY, and that it doesn't make
366 // assumptions about who might change things in the database. 377 // assumptions about who might change things in the database.
367 // http://crbug.com/56559 378 // http://crbug.com/56559
368 if (exclusive_locking_) { 379 if (exclusive_locking_) {
369 // TODO(shess): This should probably be a full CHECK(). Code 380 // TODO(shess): This should probably be a full CHECK(). Code
370 // which requests exclusive locking but doesn't get it is almost 381 // which requests exclusive locking but doesn't get it is almost
371 // certain to be ill-tested. 382 // certain to be ill-tested.
372 if (!Execute("PRAGMA locking_mode=EXCLUSIVE")) 383 if (!Execute("PRAGMA locking_mode=EXCLUSIVE"))
373 NOTREACHED() << "Could not set locking mode: " << GetErrorMessage(); 384 DLOG(FATAL) << "Could not set locking mode: " << GetErrorMessage();
374 } 385 }
375 386
376 const base::TimeDelta kBusyTimeout = 387 const base::TimeDelta kBusyTimeout =
377 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds); 388 base::TimeDelta::FromSeconds(kBusyTimeoutSeconds);
378 389
379 if (page_size_ != 0) { 390 if (page_size_ != 0) {
380 // Enforce SQLite restrictions on |page_size_|. 391 // Enforce SQLite restrictions on |page_size_|.
381 DCHECK(!(page_size_ & (page_size_ - 1))) 392 DCHECK(!(page_size_ & (page_size_ - 1)))
382 << " page_size_ " << page_size_ << " is not a power of two."; 393 << " page_size_ " << page_size_ << " is not a power of two.";
383 static const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h 394 static const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h
384 DCHECK_LE(page_size_, kSqliteMaxPageSize); 395 DCHECK_LE(page_size_, kSqliteMaxPageSize);
385 const std::string sql = StringPrintf("PRAGMA page_size=%d", page_size_); 396 const std::string sql = StringPrintf("PRAGMA page_size=%d", page_size_);
386 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout)) 397 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout))
387 NOTREACHED() << "Could not set page size: " << GetErrorMessage(); 398 DLOG(FATAL) << "Could not set page size: " << GetErrorMessage();
388 } 399 }
389 400
390 if (cache_size_ != 0) { 401 if (cache_size_ != 0) {
391 const std::string sql = StringPrintf("PRAGMA cache_size=%d", cache_size_); 402 const std::string sql = StringPrintf("PRAGMA cache_size=%d", cache_size_);
392 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout)) 403 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout))
393 NOTREACHED() << "Could not set cache size: " << GetErrorMessage(); 404 DLOG(FATAL) << "Could not set cache size: " << GetErrorMessage();
394 } 405 }
395 406
396 if (!ExecuteWithTimeout("PRAGMA secure_delete=ON", kBusyTimeout)) { 407 if (!ExecuteWithTimeout("PRAGMA secure_delete=ON", kBusyTimeout)) {
397 NOTREACHED() << "Could not enable secure_delete: " << GetErrorMessage(); 408 DLOG(FATAL) << "Could not enable secure_delete: " << GetErrorMessage();
398 Close(); 409 Close();
399 return false; 410 return false;
400 } 411 }
401 412
402 return true; 413 return true;
403 } 414 }
404 415
405 void Connection::DoRollback() { 416 void Connection::DoRollback() {
406 Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK")); 417 Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK"));
407 if (rollback) 418 rollback.Run();
408 rollback.Run();
409 } 419 }
410 420
411 void Connection::StatementRefCreated(StatementRef* ref) { 421 void Connection::StatementRefCreated(StatementRef* ref) {
412 DCHECK(open_statements_.find(ref) == open_statements_.end()); 422 DCHECK(open_statements_.find(ref) == open_statements_.end());
413 open_statements_.insert(ref); 423 open_statements_.insert(ref);
414 } 424 }
415 425
416 void Connection::StatementRefDeleted(StatementRef* ref) { 426 void Connection::StatementRefDeleted(StatementRef* ref) {
417 StatementRefSet::iterator i = open_statements_.find(ref); 427 StatementRefSet::iterator i = open_statements_.find(ref);
418 if (i == open_statements_.end()) 428 if (i == open_statements_.end())
419 NOTREACHED(); 429 DLOG(FATAL) << "Could not find statement";
420 else 430 else
421 open_statements_.erase(i); 431 open_statements_.erase(i);
422 } 432 }
423 433
424 void Connection::ClearCache() { 434 void Connection::ClearCache() {
425 statement_cache_.clear(); 435 statement_cache_.clear();
426 436
427 // The cache clear will get most statements. There may be still be references 437 // The cache clear will get most statements. There may be still be references
428 // to some statements that are held by others (including one-shot statements). 438 // to some statements that are held by others (including one-shot statements).
429 // This will deactivate them so they can't be used again. 439 // This will deactivate them so they can't be used again.
430 for (StatementRefSet::iterator i = open_statements_.begin(); 440 for (StatementRefSet::iterator i = open_statements_.begin();
431 i != open_statements_.end(); ++i) 441 i != open_statements_.end(); ++i)
432 (*i)->Close(); 442 (*i)->Close();
433 } 443 }
434 444
435 int Connection::OnSqliteError(int err, sql::Statement *stmt) { 445 int Connection::OnSqliteError(int err, sql::Statement *stmt) {
436 if (error_delegate_.get()) 446 if (error_delegate_.get())
437 return error_delegate_->OnError(err, this, stmt); 447 return error_delegate_->OnError(err, this, stmt);
438 // The default handling is to assert on debug and to ignore on release. 448 // The default handling is to assert on debug and to ignore on release.
439 NOTREACHED() << GetErrorMessage(); 449 DLOG(FATAL) << GetErrorMessage();
440 return err; 450 return err;
441 } 451 }
442 452
443 } // namespace sql 453 } // namespace sql
OLDNEW
« no previous file with comments | « sql/connection.h ('k') | sql/connection_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698