• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ScopedBusyTimeout(sqlite3 * db)29   explicit ScopedBusyTimeout(sqlite3* db)
30       : db_(db) {
31   }
~ScopedBusyTimeout()32   ~ScopedBusyTimeout() {
33     sqlite3_busy_timeout(db_, 0);
34   }
35 
SetTimeout(base::TimeDelta timeout)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 
operator <(const StatementID & other) const50 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 
ErrorDelegate()56 ErrorDelegate::ErrorDelegate() {
57 }
58 
~ErrorDelegate()59 ErrorDelegate::~ErrorDelegate() {
60 }
61 
StatementRef()62 Connection::StatementRef::StatementRef()
63     : connection_(NULL),
64       stmt_(NULL) {
65 }
66 
StatementRef(Connection * connection,sqlite3_stmt * stmt)67 Connection::StatementRef::StatementRef(Connection* connection,
68                                        sqlite3_stmt* stmt)
69     : connection_(connection),
70       stmt_(stmt) {
71   connection_->StatementRefCreated(this);
72 }
73 
~StatementRef()74 Connection::StatementRef::~StatementRef() {
75   if (connection_)
76     connection_->StatementRefDeleted(this);
77   Close();
78 }
79 
Close()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 
Connection()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 
~Connection()97 Connection::~Connection() {
98   Close();
99 }
100 
Open(const FilePath & path)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 
OpenInMemory()109 bool Connection::OpenInMemory() {
110   return OpenInternal(":memory:");
111 }
112 
Close()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 
Preload()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 
BeginTransaction()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 
RollbackTransaction()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 
CommitTransaction()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 
Execute(const char * sql)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 
ExecuteWithTimeout(const char * sql,base::TimeDelta timeout)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 
HasCachedStatement(const StatementID & id) const220 bool Connection::HasCachedStatement(const StatementID& id) const {
221   return statement_cache_.find(id) != statement_cache_.end();
222 }
223 
GetCachedStatement(const StatementID & id,const char * sql)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 
GetUniqueStatement(const char * sql)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 
DoesTableExist(const char * table_name) const259 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 
DoesColumnExist(const char * table_name,const char * column_name) const271 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 
GetLastInsertRowId() const290 int64 Connection::GetLastInsertRowId() const {
291   if (!db_) {
292     NOTREACHED();
293     return 0;
294   }
295   return sqlite3_last_insert_rowid(db_);
296 }
297 
GetLastChangeCount() const298 int Connection::GetLastChangeCount() const {
299   if (!db_) {
300     NOTREACHED();
301     return 0;
302   }
303   return sqlite3_changes(db_);
304 }
305 
GetErrorCode() const306 int Connection::GetErrorCode() const {
307   if (!db_)
308     return SQLITE_ERROR;
309   return sqlite3_errcode(db_);
310 }
311 
GetLastErrno() const312 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 
GetErrorMessage() const323 const char* Connection::GetErrorMessage() const {
324   if (!db_)
325     return "sql::Connection has no connection.";
326   return sqlite3_errmsg(db_);
327 }
328 
OpenInternal(const std::string & file_name)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 
DoRollback()385 void Connection::DoRollback() {
386   Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK"));
387   if (rollback)
388     rollback.Run();
389 }
390 
StatementRefCreated(StatementRef * ref)391 void Connection::StatementRefCreated(StatementRef* ref) {
392   DCHECK(open_statements_.find(ref) == open_statements_.end());
393   open_statements_.insert(ref);
394 }
395 
StatementRefDeleted(StatementRef * ref)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 
ClearCache()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 
OnSqliteError(int err,sql::Statement * stmt)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