summaryrefslogtreecommitdiffstats
path: root/chrome/common/sqlite_utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/common/sqlite_utils.cc')
-rw-r--r--chrome/common/sqlite_utils.cc508
1 files changed, 508 insertions, 0 deletions
diff --git a/chrome/common/sqlite_utils.cc b/chrome/common/sqlite_utils.cc
new file mode 100644
index 0000000..ed383be
--- /dev/null
+++ b/chrome/common/sqlite_utils.cc
@@ -0,0 +1,508 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/sqlite_utils.h"
+
+#include <list>
+
+#include "base/at_exit.h"
+#include "base/file_path.h"
+#include "base/lock.h"
+#include "base/logging.h"
+#include "base/singleton.h"
+#include "base/stl_util-inl.h"
+#include "base/string16.h"
+
+// The vanilla error handler implements the common fucntionality for all the
+// error handlers. Specialized error handlers are expected to only override
+// the Handler() function.
+class VanillaSQLErrorHandler : public SQLErrorHandler {
+ public:
+ VanillaSQLErrorHandler() : error_(SQLITE_OK) {
+ }
+ virtual int GetLastError() const {
+ return error_;
+ }
+ protected:
+ int error_;
+};
+
+class DebugSQLErrorHandler: public VanillaSQLErrorHandler {
+ public:
+ virtual int HandleError(int error, sqlite3* db) {
+ error_ = error;
+ NOTREACHED() << "sqlite error " << error
+ << " db " << static_cast<void*>(db);
+ return error;
+ }
+};
+
+class ReleaseSQLErrorHandler : public VanillaSQLErrorHandler {
+ public:
+ virtual int HandleError(int error, sqlite3* db) {
+ error_ = error;
+ // Used to have a CHECK here. Got lots of crashes.
+ return error;
+ }
+};
+
+// The default error handler factory is also in charge of managing the
+// lifetime of the error objects. This object is multi-thread safe.
+class DefaultSQLErrorHandlerFactory : public SQLErrorHandlerFactory {
+ public:
+ ~DefaultSQLErrorHandlerFactory() {
+ STLDeleteContainerPointers(errors_.begin(), errors_.end());
+ }
+
+ virtual SQLErrorHandler* Make() {
+ SQLErrorHandler* handler;
+#ifndef NDEBUG
+ handler = new DebugSQLErrorHandler;
+#else
+ handler = new ReleaseSQLErrorHandler;
+#endif // NDEBUG
+ AddHandler(handler);
+ return handler;
+ }
+
+ private:
+ void AddHandler(SQLErrorHandler* handler) {
+ AutoLock lock(lock_);
+ errors_.push_back(handler);
+ }
+
+ typedef std::list<SQLErrorHandler*> ErrorList;
+ ErrorList errors_;
+ Lock lock_;
+};
+
+SQLErrorHandlerFactory* GetErrorHandlerFactory() {
+ // TODO(cpu): Testing needs to override the error handler.
+ // Destruction of DefaultSQLErrorHandlerFactory handled by at_exit manager.
+ return Singleton<DefaultSQLErrorHandlerFactory>::get();
+}
+
+namespace sqlite_utils {
+
+int OpenSqliteDb(const FilePath& filepath, sqlite3** database) {
+#if defined(OS_WIN)
+ // We want the default encoding to always be UTF-8, so we use the
+ // 8-bit version of open().
+ return sqlite3_open(WideToUTF8(filepath.value()).c_str(), database);
+#elif defined(OS_POSIX)
+ return sqlite3_open(filepath.value().c_str(), database);
+#endif
+}
+
+bool DoesSqliteTableExist(sqlite3* db,
+ const char* db_name,
+ const char* table_name) {
+ // sqlite doesn't allow binding parameters as table names, so we have to
+ // manually construct the sql
+ std::string sql("SELECT name FROM ");
+ if (db_name && db_name[0]) {
+ sql.append(db_name);
+ sql.push_back('.');
+ }
+ sql.append("sqlite_master WHERE type='table' AND name=?");
+
+ SQLStatement statement;
+ if (statement.prepare(db, sql.c_str()) != SQLITE_OK)
+ return false;
+
+ if (statement.bind_text(0, table_name) != SQLITE_OK)
+ return false;
+
+ // we only care about if this matched a row, not the actual data
+ return sqlite3_step(statement.get()) == SQLITE_ROW;
+}
+
+bool DoesSqliteColumnExist(sqlite3* db,
+ const char* database_name,
+ const char* table_name,
+ const char* column_name,
+ const char* column_type) {
+ SQLStatement s;
+ std::string sql;
+ sql.append("PRAGMA ");
+ if (database_name && database_name[0]) {
+ // optional database name specified
+ sql.append(database_name);
+ sql.push_back('.');
+ }
+ sql.append("TABLE_INFO(");
+ sql.append(table_name);
+ sql.append(")");
+
+ if (s.prepare(db, sql.c_str()) != SQLITE_OK)
+ return false;
+
+ while (s.step() == SQLITE_ROW) {
+ if (!s.column_string(1).compare(column_name)) {
+ if (column_type && column_type[0])
+ return !s.column_string(2).compare(column_type);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool DoesSqliteTableHaveRow(sqlite3* db, const char* table_name) {
+ SQLStatement s;
+ std::string b;
+ b.append("SELECT * FROM ");
+ b.append(table_name);
+
+ if (s.prepare(db, b.c_str()) != SQLITE_OK)
+ return false;
+
+ return s.step() == SQLITE_ROW;
+}
+
+} // namespace sqlite_utils
+
+SQLTransaction::SQLTransaction(sqlite3* db) : db_(db), began_(false) {
+}
+
+SQLTransaction::~SQLTransaction() {
+ if (began_) {
+ Rollback();
+ }
+}
+
+int SQLTransaction::BeginCommand(const char* command) {
+ int rv = SQLITE_ERROR;
+ if (!began_ && db_) {
+ rv = sqlite3_exec(db_, command, NULL, NULL, NULL);
+ began_ = (rv == SQLITE_OK);
+ }
+ return rv;
+}
+
+int SQLTransaction::EndCommand(const char* command) {
+ int rv = SQLITE_ERROR;
+ if (began_ && db_) {
+ rv = sqlite3_exec(db_, command, NULL, NULL, NULL);
+ began_ = (rv != SQLITE_OK);
+ }
+ return rv;
+}
+
+SQLNestedTransactionSite::~SQLNestedTransactionSite() {
+ DCHECK(!top_transaction_);
+}
+
+void SQLNestedTransactionSite::SetTopTransaction(SQLNestedTransaction* top) {
+ DCHECK(!top || !top_transaction_);
+ top_transaction_ = top;
+}
+
+SQLNestedTransaction::SQLNestedTransaction(SQLNestedTransactionSite* site)
+ : SQLTransaction(site->GetSqlite3DB()),
+ needs_rollback_(false),
+ site_(site) {
+ DCHECK(site);
+ if (site->GetTopTransaction() == NULL) {
+ site->SetTopTransaction(this);
+ }
+}
+
+SQLNestedTransaction::~SQLNestedTransaction() {
+ if (began_) {
+ Rollback();
+ }
+ if (site_->GetTopTransaction() == this) {
+ site_->SetTopTransaction(NULL);
+ }
+}
+
+int SQLNestedTransaction::BeginCommand(const char* command) {
+ DCHECK(db_);
+ DCHECK(site_ && site_->GetTopTransaction());
+ if (!db_ || began_) {
+ return SQLITE_ERROR;
+ }
+ if (site_->GetTopTransaction() == this) {
+ int rv = sqlite3_exec(db_, command, NULL, NULL, NULL);
+ began_ = (rv == SQLITE_OK);
+ if (began_) {
+ site_->OnBegin();
+ }
+ return rv;
+ } else {
+ if (site_->GetTopTransaction()->needs_rollback_) {
+ return SQLITE_ERROR;
+ }
+ began_ = true;
+ return SQLITE_OK;
+ }
+}
+
+int SQLNestedTransaction::EndCommand(const char* command) {
+ DCHECK(db_);
+ DCHECK(site_ && site_->GetTopTransaction());
+ if (!db_ || !began_) {
+ return SQLITE_ERROR;
+ }
+ if (site_->GetTopTransaction() == this) {
+ if (needs_rollback_) {
+ sqlite3_exec(db_, "ROLLBACK", NULL, NULL, NULL);
+ began_ = false; // reset so we don't try to rollback or call
+ // OnRollback() again
+ site_->OnRollback();
+ return SQLITE_ERROR;
+ } else {
+ int rv = sqlite3_exec(db_, command, NULL, NULL, NULL);
+ began_ = (rv != SQLITE_OK);
+ if (strcmp(command, "ROLLBACK") == 0) {
+ began_ = false; // reset so we don't try to rollbck or call
+ // OnRollback() again
+ site_->OnRollback();
+ } else {
+ DCHECK(strcmp(command, "COMMIT") == 0);
+ if (rv == SQLITE_OK) {
+ site_->OnCommit();
+ }
+ }
+ return rv;
+ }
+ } else {
+ if (strcmp(command, "ROLLBACK") == 0) {
+ site_->GetTopTransaction()->needs_rollback_ = true;
+ }
+ began_ = false;
+ return SQLITE_OK;
+ }
+}
+
+int SQLStatement::prepare(sqlite3* db, const char* sql, int sql_len) {
+ DCHECK(!stmt_);
+ int rv = sqlite3_prepare_v2(db, sql, sql_len, &stmt_, NULL);
+ if (rv != SQLITE_OK) {
+ SQLErrorHandler* error_handler = GetErrorHandlerFactory()->Make();
+ return error_handler->HandleError(rv, db);
+ }
+ return rv;
+}
+
+int SQLStatement::step() {
+ DCHECK(stmt_);
+ int status = sqlite3_step(stmt_);
+ if ((status == SQLITE_ROW) || (status == SQLITE_DONE))
+ return status;
+ // We got a problem.
+ SQLErrorHandler* error_handler = GetErrorHandlerFactory()->Make();
+ return error_handler->HandleError(status, db_handle());
+}
+
+int SQLStatement::reset() {
+ DCHECK(stmt_);
+ return sqlite3_reset(stmt_);
+}
+
+sqlite_int64 SQLStatement::last_insert_rowid() {
+ DCHECK(stmt_);
+ return sqlite3_last_insert_rowid(db_handle());
+}
+
+int SQLStatement::changes() {
+ DCHECK(stmt_);
+ return sqlite3_changes(db_handle());
+}
+
+sqlite3* SQLStatement::db_handle() {
+ DCHECK(stmt_);
+ return sqlite3_db_handle(stmt_);
+}
+
+int SQLStatement::bind_parameter_count() {
+ DCHECK(stmt_);
+ return sqlite3_bind_parameter_count(stmt_);
+}
+
+int SQLStatement::bind_blob(int index, std::vector<unsigned char>* blob) {
+ if (blob) {
+ const void* value = blob->empty() ? NULL : &(*blob)[0];
+ int len = static_cast<int>(blob->size());
+ return bind_blob(index, value, len);
+ } else {
+ return bind_null(index);
+ }
+}
+
+int SQLStatement::bind_blob(int index, const void* value, int value_len) {
+ return bind_blob(index, value, value_len, SQLITE_TRANSIENT);
+}
+
+int SQLStatement::bind_blob(int index, const void* value, int value_len,
+ Function dtor) {
+ DCHECK(stmt_);
+ return sqlite3_bind_blob(stmt_, index + 1, value, value_len, dtor);
+}
+
+int SQLStatement::bind_double(int index, double value) {
+ DCHECK(stmt_);
+ return sqlite3_bind_double(stmt_, index + 1, value);
+}
+
+int SQLStatement::bind_bool(int index, bool value) {
+ DCHECK(stmt_);
+ return sqlite3_bind_int(stmt_, index + 1, value);
+}
+
+int SQLStatement::bind_int(int index, int value) {
+ DCHECK(stmt_);
+ return sqlite3_bind_int(stmt_, index + 1, value);
+}
+
+int SQLStatement::bind_int64(int index, sqlite_int64 value) {
+ DCHECK(stmt_);
+ return sqlite3_bind_int64(stmt_, index + 1, value);
+}
+
+int SQLStatement::bind_null(int index) {
+ DCHECK(stmt_);
+ return sqlite3_bind_null(stmt_, index + 1);
+}
+
+int SQLStatement::bind_text(int index, const char* value, int value_len,
+ Function dtor) {
+ DCHECK(stmt_);
+ return sqlite3_bind_text(stmt_, index + 1, value, value_len, dtor);
+}
+
+int SQLStatement::bind_text16(int index, const char16* value, int value_len,
+ Function dtor) {
+ DCHECK(stmt_);
+ value_len *= sizeof(char16);
+ return sqlite3_bind_text16(stmt_, index + 1, value, value_len, dtor);
+}
+
+int SQLStatement::bind_value(int index, const sqlite3_value* value) {
+ DCHECK(stmt_);
+ return sqlite3_bind_value(stmt_, index + 1, value);
+}
+
+int SQLStatement::column_count() {
+ DCHECK(stmt_);
+ return sqlite3_column_count(stmt_);
+}
+
+int SQLStatement::column_type(int index) {
+ DCHECK(stmt_);
+ return sqlite3_column_type(stmt_, index);
+}
+
+const void* SQLStatement::column_blob(int index) {
+ DCHECK(stmt_);
+ return sqlite3_column_blob(stmt_, index);
+}
+
+bool SQLStatement::column_blob_as_vector(int index,
+ std::vector<unsigned char>* blob) {
+ DCHECK(stmt_);
+ const void* p = column_blob(index);
+ size_t len = column_bytes(index);
+ blob->resize(len);
+ if (blob->size() != len) {
+ return false;
+ }
+ if (len > 0)
+ memcpy(&(blob->front()), p, len);
+ return true;
+}
+
+bool SQLStatement::column_blob_as_string(int index, std::string* blob) {
+ DCHECK(stmt_);
+ const void* p = column_blob(index);
+ size_t len = column_bytes(index);
+ blob->resize(len);
+ if (blob->size() != len) {
+ return false;
+ }
+ blob->assign(reinterpret_cast<const char*>(p), len);
+ return true;
+}
+
+int SQLStatement::column_bytes(int index) {
+ DCHECK(stmt_);
+ return sqlite3_column_bytes(stmt_, index);
+}
+
+int SQLStatement::column_bytes16(int index) {
+ DCHECK(stmt_);
+ return sqlite3_column_bytes16(stmt_, index);
+}
+
+double SQLStatement::column_double(int index) {
+ DCHECK(stmt_);
+ return sqlite3_column_double(stmt_, index);
+}
+
+bool SQLStatement::column_bool(int index) {
+ DCHECK(stmt_);
+ return sqlite3_column_int(stmt_, index) ? true : false;
+}
+
+int SQLStatement::column_int(int index) {
+ DCHECK(stmt_);
+ return sqlite3_column_int(stmt_, index);
+}
+
+sqlite_int64 SQLStatement::column_int64(int index) {
+ DCHECK(stmt_);
+ return sqlite3_column_int64(stmt_, index);
+}
+
+const char* SQLStatement::column_text(int index) {
+ DCHECK(stmt_);
+ return reinterpret_cast<const char*>(sqlite3_column_text(stmt_, index));
+}
+
+bool SQLStatement::column_string(int index, std::string* str) {
+ DCHECK(stmt_);
+ DCHECK(str);
+ const char* s = column_text(index);
+ str->assign(s ? s : std::string());
+ return s != NULL;
+}
+
+std::string SQLStatement::column_string(int index) {
+ std::string str;
+ column_string(index, &str);
+ return str;
+}
+
+const char16* SQLStatement::column_text16(int index) {
+ DCHECK(stmt_);
+ return static_cast<const char16*>(sqlite3_column_text16(stmt_, index));
+}
+
+bool SQLStatement::column_string16(int index, string16* str) {
+ DCHECK(stmt_);
+ DCHECK(str);
+ const char* s = column_text(index);
+ str->assign(s ? UTF8ToUTF16(s) : string16());
+ return (s != NULL);
+}
+
+string16 SQLStatement::column_string16(int index) {
+ string16 str;
+ column_string16(index, &str);
+ return str;
+}
+
+bool SQLStatement::column_wstring(int index, std::wstring* str) {
+ DCHECK(stmt_);
+ DCHECK(str);
+ const char* s = column_text(index);
+ str->assign(s ? UTF8ToWide(s) : std::wstring());
+ return (s != NULL);
+}
+
+std::wstring SQLStatement::column_wstring(int index) {
+ std::wstring wstr;
+ column_wstring(index, &wstr);
+ return wstr;
+}