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 3 // found in the LICENSE file. 4 5 #include "app/sql/connection.h" 6 7 #include <string.h> 8 9 #include "app/sql/statement.h" 10 #include "base/file_path.h" 11 #include "base/logging.h" 12 #include "base/string_util.h" 13 #include "base/utf_string_conversions.h" 14 #ifdef ANDROID 15 #include "sqlite3.h" 16 #else 17 #include "third_party/sqlite/sqlite3.h" 18 #endif 19 20 namespace { 21 22 // Spin for up to a second waiting for the lock to clear when setting 23 // up the database. 24 // TODO(shess): Better story on this. http://crbug.com/56559 25 const base::TimeDelta kBusyTimeout = base::TimeDelta::FromSeconds(1); 26 27 class ScopedBusyTimeout { 28 public: 29 explicit ScopedBusyTimeout(sqlite3* db) 30 : db_(db) { 31 } 32 ~ScopedBusyTimeout() { 33 sqlite3_busy_timeout(db_, 0); 34 } 35 36 int SetTimeout(base::TimeDelta timeout) { 37 DCHECK_LT(timeout.InMilliseconds(), INT_MAX); 38 return sqlite3_busy_timeout(db_, 39 static_cast<int>(timeout.InMilliseconds())); 40 } 41 42 private: 43 sqlite3* db_; 44 }; 45 46 } // namespace 47 48 namespace sql { 49 50 bool StatementID::operator<(const StatementID& other) const { 51 if (number_ != other.number_) 52 return number_ < other.number_; 53 return strcmp(str_, other.str_) < 0; 54 } 55 56 ErrorDelegate::ErrorDelegate() { 57 } 58 59 ErrorDelegate::~ErrorDelegate() { 60 } 61 62 Connection::StatementRef::StatementRef() 63 : connection_(NULL), 64 stmt_(NULL) { 65 } 66 67 Connection::StatementRef::StatementRef(Connection* connection, 68 sqlite3_stmt* stmt) 69 : connection_(connection), 70 stmt_(stmt) { 71 connection_->StatementRefCreated(this); 72 } 73 74 Connection::StatementRef::~StatementRef() { 75 if (connection_) 76 connection_->StatementRefDeleted(this); 77 Close(); 78 } 79 80 void Connection::StatementRef::Close() { 81 if (stmt_) { 82 sqlite3_finalize(stmt_); 83 stmt_ = NULL; 84 } 85 connection_ = NULL; // The connection may be getting deleted. 86 } 87 88 Connection::Connection() 89 : db_(NULL), 90 page_size_(0), 91 cache_size_(0), 92 exclusive_locking_(false), 93 transaction_nesting_(0), 94 needs_rollback_(false) { 95 } 96 97 Connection::~Connection() { 98 Close(); 99 } 100 101 bool Connection::Open(const FilePath& path) { 102 #if defined(OS_WIN) 103 return OpenInternal(WideToUTF8(path.value())); 104 #elif defined(OS_POSIX) 105 return OpenInternal(path.value()); 106 #endif 107 } 108 109 bool Connection::OpenInMemory() { 110 return OpenInternal(":memory:"); 111 } 112 113 void Connection::Close() { 114 statement_cache_.clear(); 115 DCHECK(open_statements_.empty()); 116 if (db_) { 117 sqlite3_close(db_); 118 db_ = NULL; 119 } 120 } 121 122 void Connection::Preload() { 123 if (!db_) { 124 NOTREACHED(); 125 return; 126 } 127 128 // A statement must be open for the preload command to work. If the meta 129 // table doesn't exist, it probably means this is a new database and there 130 // is nothing to preload (so it's OK we do nothing). 131 if (!DoesTableExist("meta")) 132 return; 133 Statement dummy(GetUniqueStatement("SELECT * FROM meta")); 134 if (!dummy || !dummy.Step()) 135 return; 136 137 #if !defined(USE_SYSTEM_SQLITE) 138 // This function is only defined in Chromium's version of sqlite. 139 // Do not call it when using system sqlite. 140 sqlite3_preload(db_); 141 #endif 142 } 143 144 bool Connection::BeginTransaction() { 145 if (needs_rollback_) { 146 DCHECK_GT(transaction_nesting_, 0); 147 148 // When we're going to rollback, fail on this begin and don't actually 149 // mark us as entering the nested transaction. 150 return false; 151 } 152 153 bool success = true; 154 if (!transaction_nesting_) { 155 needs_rollback_ = false; 156 157 Statement begin(GetCachedStatement(SQL_FROM_HERE, "BEGIN TRANSACTION")); 158 if (!begin || !begin.Run()) 159 return false; 160 } 161 transaction_nesting_++; 162 return success; 163 } 164 165 void Connection::RollbackTransaction() { 166 if (!transaction_nesting_) { 167 NOTREACHED() << "Rolling back a nonexistent transaction"; 168 return; 169 } 170 171 transaction_nesting_--; 172 173 if (transaction_nesting_ > 0) { 174 // Mark the outermost transaction as needing rollback. 175 needs_rollback_ = true; 176 return; 177 } 178 179 DoRollback(); 180 } 181 182 bool Connection::CommitTransaction() { 183 if (!transaction_nesting_) { 184 NOTREACHED() << "Rolling back a nonexistent transaction"; 185 return false; 186 } 187 transaction_nesting_--; 188 189 if (transaction_nesting_ > 0) { 190 // Mark any nested transactions as failing after we've already got one. 191 return !needs_rollback_; 192 } 193 194 if (needs_rollback_) { 195 DoRollback(); 196 return false; 197 } 198 199 Statement commit(GetCachedStatement(SQL_FROM_HERE, "COMMIT")); 200 if (!commit) 201 return false; 202 return commit.Run(); 203 } 204 205 bool Connection::Execute(const char* sql) { 206 if (!db_) 207 return false; 208 return sqlite3_exec(db_, sql, NULL, NULL, NULL) == SQLITE_OK; 209 } 210 211 bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) { 212 if (!db_) 213 return false; 214 215 ScopedBusyTimeout busy_timeout(db_); 216 busy_timeout.SetTimeout(timeout); 217 return sqlite3_exec(db_, sql, NULL, NULL, NULL) == SQLITE_OK; 218 } 219 220 bool Connection::HasCachedStatement(const StatementID& id) const { 221 return statement_cache_.find(id) != statement_cache_.end(); 222 } 223 224 scoped_refptr<Connection::StatementRef> Connection::GetCachedStatement( 225 const StatementID& id, 226 const char* sql) { 227 CachedStatementMap::iterator i = statement_cache_.find(id); 228 if (i != statement_cache_.end()) { 229 // Statement is in the cache. It should still be active (we're the only 230 // one invalidating cached statements, and we'll remove it from the cache 231 // if we do that. Make sure we reset it before giving out the cached one in 232 // case it still has some stuff bound. 233 DCHECK(i->second->is_valid()); 234 sqlite3_reset(i->second->stmt()); 235 return i->second; 236 } 237 238 scoped_refptr<StatementRef> statement = GetUniqueStatement(sql); 239 if (statement->is_valid()) 240 statement_cache_[id] = statement; // Only cache valid statements. 241 return statement; 242 } 243 244 scoped_refptr<Connection::StatementRef> Connection::GetUniqueStatement( 245 const char* sql) { 246 if (!db_) 247 return new StatementRef(this, NULL); // Return inactive statement. 248 249 sqlite3_stmt* stmt = NULL; 250 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) { 251 // Treat this as non-fatal, it can occur in a number of valid cases, and 252 // callers should be doing their own error handling. 253 DLOG(WARNING) << "SQL compile error " << GetErrorMessage(); 254 return new StatementRef(this, NULL); 255 } 256 return new StatementRef(this, stmt); 257 } 258 259 bool Connection::DoesTableExist(const char* table_name) const { 260 // GetUniqueStatement can't be const since statements may modify the 261 // database, but we know ours doesn't modify it, so the cast is safe. 262 Statement statement(const_cast<Connection*>(this)->GetUniqueStatement( 263 "SELECT name FROM sqlite_master " 264 "WHERE type='table' AND name=?")); 265 if (!statement) 266 return false; 267 statement.BindString(0, table_name); 268 return statement.Step(); // Table exists if any row was returned. 269 } 270 271 bool Connection::DoesColumnExist(const char* table_name, 272 const char* column_name) const { 273 std::string sql("PRAGMA TABLE_INFO("); 274 sql.append(table_name); 275 sql.append(")"); 276 277 // Our SQL is non-mutating, so this cast is OK. 278 Statement statement(const_cast<Connection*>(this)->GetUniqueStatement( 279 sql.c_str())); 280 if (!statement) 281 return false; 282 283 while (statement.Step()) { 284 if (!statement.ColumnString(1).compare(column_name)) 285 return true; 286 } 287 return false; 288 } 289 290 int64 Connection::GetLastInsertRowId() const { 291 if (!db_) { 292 NOTREACHED(); 293 return 0; 294 } 295 return sqlite3_last_insert_rowid(db_); 296 } 297 298 int Connection::GetLastChangeCount() const { 299 if (!db_) { 300 NOTREACHED(); 301 return 0; 302 } 303 return sqlite3_changes(db_); 304 } 305 306 int Connection::GetErrorCode() const { 307 if (!db_) 308 return SQLITE_ERROR; 309 return sqlite3_errcode(db_); 310 } 311 312 int Connection::GetLastErrno() const { 313 if (!db_) 314 return -1; 315 316 int err = 0; 317 if (SQLITE_OK != sqlite3_file_control(db_, NULL, SQLITE_LAST_ERRNO, &err)) 318 return -2; 319 320 return err; 321 } 322 323 const char* Connection::GetErrorMessage() const { 324 if (!db_) 325 return "sql::Connection has no connection."; 326 return sqlite3_errmsg(db_); 327 } 328 329 bool Connection::OpenInternal(const std::string& file_name) { 330 if (db_) { 331 NOTREACHED() << "sql::Connection is already open."; 332 return false; 333 } 334 335 int err = sqlite3_open(file_name.c_str(), &db_); 336 if (err != SQLITE_OK) { 337 OnSqliteError(err, NULL); 338 db_ = NULL; 339 return false; 340 } 341 342 // Enable extended result codes to provide more color on I/O errors. 343 // Not having extended result codes is not a fatal problem, as 344 // Chromium code does not attempt to handle I/O errors anyhow. The 345 // current implementation always returns SQLITE_OK, the DCHECK is to 346 // quickly notify someone if SQLite changes. 347 err = sqlite3_extended_result_codes(db_, 1); 348 DCHECK_EQ(err, SQLITE_OK) << "Could not enable extended result codes"; 349 350 // If indicated, lock up the database before doing anything else, so 351 // that the following code doesn't have to deal with locking. 352 // TODO(shess): This code is brittle. Find the cases where code 353 // doesn't request |exclusive_locking_| and audit that it does the 354 // right thing with SQLITE_BUSY, and that it doesn't make 355 // assumptions about who might change things in the database. 356 // http://crbug.com/56559 357 if (exclusive_locking_) { 358 // TODO(shess): This should probably be a full CHECK(). Code 359 // which requests exclusive locking but doesn't get it is almost 360 // certain to be ill-tested. 361 if (!Execute("PRAGMA locking_mode=EXCLUSIVE")) 362 NOTREACHED() << "Could not set locking mode: " << GetErrorMessage(); 363 } 364 365 if (page_size_ != 0) { 366 // Enforce SQLite restrictions on |page_size_|. 367 DCHECK(!(page_size_ & (page_size_ - 1))) 368 << " page_size_ " << page_size_ << " is not a power of two."; 369 static const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h 370 DCHECK_LE(page_size_, kSqliteMaxPageSize); 371 const std::string sql = StringPrintf("PRAGMA page_size=%d", page_size_); 372 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout)) 373 NOTREACHED() << "Could not set page size: " << GetErrorMessage(); 374 } 375 376 if (cache_size_ != 0) { 377 const std::string sql = StringPrintf("PRAGMA cache_size=%d", cache_size_); 378 if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout)) 379 NOTREACHED() << "Could not set cache size: " << GetErrorMessage(); 380 } 381 382 return true; 383 } 384 385 void Connection::DoRollback() { 386 Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK")); 387 if (rollback) 388 rollback.Run(); 389 } 390 391 void Connection::StatementRefCreated(StatementRef* ref) { 392 DCHECK(open_statements_.find(ref) == open_statements_.end()); 393 open_statements_.insert(ref); 394 } 395 396 void Connection::StatementRefDeleted(StatementRef* ref) { 397 StatementRefSet::iterator i = open_statements_.find(ref); 398 if (i == open_statements_.end()) 399 NOTREACHED(); 400 else 401 open_statements_.erase(i); 402 } 403 404 void Connection::ClearCache() { 405 statement_cache_.clear(); 406 407 // The cache clear will get most statements. There may be still be references 408 // to some statements that are held by others (including one-shot statements). 409 // This will deactivate them so they can't be used again. 410 for (StatementRefSet::iterator i = open_statements_.begin(); 411 i != open_statements_.end(); ++i) 412 (*i)->Close(); 413 } 414 415 int Connection::OnSqliteError(int err, sql::Statement *stmt) { 416 if (error_delegate_.get()) 417 return error_delegate_->OnError(err, this, stmt); 418 // The default handling is to assert on debug and to ignore on release. 419 NOTREACHED() << GetErrorMessage(); 420 return err; 421 } 422 423 } // namespace sql 424