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