OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |