diff options
author | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-09 01:18:10 +0000 |
---|---|---|
committer | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-09 01:18:10 +0000 |
commit | 0e7f8d0b2aaf1eea1671c1ea4a1352b827566f94 (patch) | |
tree | 97c118c3c91d01fe8a931987a0346ea66d183d53 /chrome/browser/sync/util | |
parent | d6b94838c9c7cfe13933e819bebb99b08f13d08b (diff) | |
download | chromium_src-0e7f8d0b2aaf1eea1671c1ea4a1352b827566f94.zip chromium_src-0e7f8d0b2aaf1eea1671c1ea4a1352b827566f94.tar.gz chromium_src-0e7f8d0b2aaf1eea1671c1ea4a1352b827566f94.tar.bz2 |
Move sqlite_utils.* to sync/util/ directory.
BUG=77634
TEST=None
R=akalin@chromium.org
Review URL: http://codereview.chromium.org/7550059
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@95927 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/sync/util')
-rw-r--r-- | chrome/browser/sync/util/sqlite_utils.cc | 510 | ||||
-rw-r--r-- | chrome/browser/sync/util/sqlite_utils.h | 400 | ||||
-rw-r--r-- | chrome/browser/sync/util/user_settings.cc | 2 | ||||
-rw-r--r-- | chrome/browser/sync/util/user_settings_posix.cc | 4 | ||||
-rw-r--r-- | chrome/browser/sync/util/user_settings_win.cc | 2 |
5 files changed, 914 insertions, 4 deletions
diff --git a/chrome/browser/sync/util/sqlite_utils.cc b/chrome/browser/sync/util/sqlite_utils.cc new file mode 100644 index 0000000..7b6f250 --- /dev/null +++ b/chrome/browser/sync/util/sqlite_utils.cc @@ -0,0 +1,510 @@ +// Copyright (c) 2011 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/browser/sync/util/sqlite_utils.h" + +#include <list> + +#include "base/file_path.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/stl_util.h" +#include "base/string16.h" +#include "base/synchronization/lock.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) { + base::AutoLock lock(lock_); + errors_.push_back(handler); + } + + typedef std::list<SQLErrorHandler*> ErrorList; + ErrorList errors_; + base::Lock lock_; +}; + +static base::LazyInstance<DefaultSQLErrorHandlerFactory> + g_default_sql_error_handler_factory(base::LINKER_INITIALIZED); + +SQLErrorHandlerFactory* GetErrorHandlerFactory() { + // TODO(cpu): Testing needs to override the error handler. + // Destruction of DefaultSQLErrorHandlerFactory handled by at_exit manager. + return g_default_sql_error_handler_factory.Pointer(); +} + +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; +} diff --git a/chrome/browser/sync/util/sqlite_utils.h b/chrome/browser/sync/util/sqlite_utils.h new file mode 100644 index 0000000..42c0418 --- /dev/null +++ b/chrome/browser/sync/util/sqlite_utils.h @@ -0,0 +1,400 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_SYNC_UTIL_SQLITE_UTILS_H_ +#define CHROME_BROWSER_SYNC_UTIL_SQLITE_UTILS_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/string16.h" +#include "base/utf_string_conversions.h" +#include "third_party/sqlite/sqlite3.h" + +// forward declarations of classes defined here +class FilePath; +class SQLTransaction; +class SQLNestedTransaction; +class SQLNestedTransactionSite; +class scoped_sqlite3_stmt_ptr; +class SQLStatement; + +//------------------------------------------------------------------------------ +// Interface to be implemented by objects that can handle exceptional sqlite +// conditions. This way client code can focus on handling normal condtions. +//------------------------------------------------------------------------------ +class SQLErrorHandler { + public: + virtual ~SQLErrorHandler() {} + // Handle a sqlite error. |error| is the return code an of sqlite operation + // which is considered an error. This handler is free to try repair, notify + // someone or even break into the debugger depending on the situation. + virtual int HandleError(int error, sqlite3* db) = 0; + // Returns the last value of |error| passed to HandleError. + virtual int GetLastError() const = 0; +}; + +//------------------------------------------------------------------------------ +// The factory interface is used to create the different error handling +// strategies for debug, release and for diagnostic mode. +//------------------------------------------------------------------------------ +class SQLErrorHandlerFactory { + public: + virtual ~SQLErrorHandlerFactory() {} + virtual SQLErrorHandler* Make() = 0; +}; + +//------------------------------------------------------------------------------ +// A wrapper for sqlite transactions that rollsback when the wrapper +// goes out of scope if the caller has not already called Commit or Rollback. +// Note: the constructor does NOT Begin a transaction. +//------------------------------------------------------------------------------ +class SQLTransaction { + public: + explicit SQLTransaction(sqlite3* db); + virtual ~SQLTransaction(); + + int Begin() { + // By default, we BEGIN IMMEDIATE to establish file locks at the + // onset of a transaction. This avoids SQLITE_BUSY errors, without + // waiting for the busy timeout period, which can occur when BEGIN + // DEFERRED is used. + return BeginImmediate(); + } + + int BeginExclusive() { + return BeginCommand("BEGIN EXCLUSIVE"); + } + + int BeginImmediate() { + return BeginCommand("BEGIN IMMEDIATE"); + } + + int BeginDeferred() { + return BeginCommand("BEGIN DEFERRED"); + } + + int Commit() { + return EndCommand("COMMIT"); + } + + int Rollback() { + return EndCommand("ROLLBACK"); + } + + bool HasBegun() { + return began_; + } + + protected: + virtual int BeginCommand(const char* command); + virtual int EndCommand(const char* command); + + sqlite3* db_; + bool began_; + DISALLOW_COPY_AND_ASSIGN(SQLTransaction); +}; + + +//------------------------------------------------------------------------------ +// A class for use with SQLNestedTransaction. +//------------------------------------------------------------------------------ +class SQLNestedTransactionSite { + protected: + SQLNestedTransactionSite() : db_(NULL), top_transaction_(NULL) {} + virtual ~SQLNestedTransactionSite(); + + // The following virtual methods provide notification of true transaction + // boundaries as they are crossed by a top nested transaction. + // Intended to be overriden (See WebCacheDB) + // SQLNestedTransaction calls these after the underlying database + // operation has been performed. + + virtual void OnBegin() {} + virtual void OnCommit() {} + virtual void OnRollback() {} + + // Returns the sqlite3 database connection associated with this site + // Used by SQLNestedTransaction + sqlite3* GetSqlite3DB() { return db_; } + + // Returns the current top nested transaction associated with this site + // Used by SQLNestedTransaction + SQLNestedTransaction* GetTopTransaction() { + return top_transaction_; + } + + // Sets or clears the top nested transaction associated with this site + // Used by SQLNestedTransaction + void SetTopTransaction(SQLNestedTransaction* top); + + sqlite3* db_; + SQLNestedTransaction* top_transaction_; + friend class SQLNestedTransaction; +}; + +//------------------------------------------------------------------------------ +// SQLite does not support nested transactions. This class provides a gross +// approximation of nested transactions. +// +// Really there is only one transaction, the top transaction. +// +// A nested transaction commits with respect to the top transaction. +// That is, even though the nested transaction commits, the permanence of its +// effects depends on the top transaction committing. If the top +// transaction rollsback, the results of the nested transaction are backed out. +// If any nested transaction aborts, the top transaction ultimately rollsback +// as well. +// +// Note: If a nested transaction is open for a particular db connection, an +// attempt to open a non-nested transaction (class SQLTransaction) will fail. +// And vice versa. +// +// TODO(michaeln): demonstrate usage here +// TODO(michaeln): safegaurds to prevent mis-use +//------------------------------------------------------------------------------ +class SQLNestedTransaction : public SQLTransaction { + public: + explicit SQLNestedTransaction(SQLNestedTransactionSite* site); + virtual ~SQLNestedTransaction(); + + protected: + virtual int BeginCommand(const char* command); + virtual int EndCommand(const char* command); + + private: + bool needs_rollback_; + SQLNestedTransactionSite* site_; + DISALLOW_COPY_AND_ASSIGN(SQLNestedTransaction); +}; + +//------------------------------------------------------------------------------ +// A scoped sqlite statement that finalizes when it goes out of scope. +//------------------------------------------------------------------------------ +class scoped_sqlite3_stmt_ptr { + public: + ~scoped_sqlite3_stmt_ptr() { + finalize(); + } + + scoped_sqlite3_stmt_ptr() : stmt_(NULL) { + } + + explicit scoped_sqlite3_stmt_ptr(sqlite3_stmt* stmt) + : stmt_(stmt) { + } + + sqlite3_stmt* get() const { + return stmt_; + } + + void set(sqlite3_stmt* stmt) { + finalize(); + stmt_ = stmt; + } + + sqlite3_stmt* release() { + sqlite3_stmt* tmp = stmt_; + stmt_ = NULL; + return tmp; + } + + // It is not safe to call sqlite3_finalize twice on the same stmt. + // Sqlite3's sqlite3_finalize() function should not be called directly + // without calling the release method. If sqlite3_finalize() must be + // called directly, the following usage is advised: + // scoped_sqlite3_stmt_ptr stmt; + // ... do something with stmt ... + // sqlite3_finalize(stmt.release()); + int finalize() { + int err = sqlite3_finalize(stmt_); + stmt_ = NULL; + return err; + } + + protected: + sqlite3_stmt* stmt_; + + private: + DISALLOW_COPY_AND_ASSIGN(scoped_sqlite3_stmt_ptr); +}; + +//------------------------------------------------------------------------------ +// A scoped sqlite statement with convenient C++ wrappers for sqlite3 APIs. +//------------------------------------------------------------------------------ +class SQLStatement : public scoped_sqlite3_stmt_ptr { + public: + SQLStatement() {} + + int prepare(sqlite3* db, const char* sql) { + return prepare(db, sql, -1); + } + + int prepare(sqlite3* db, const char* sql, int sql_len); + + int step(); + int reset(); + sqlite_int64 last_insert_rowid(); + int changes(); + sqlite3* db_handle(); + + // + // Parameter binding helpers (NOTE: index is 0-based) + // + + int bind_parameter_count(); + + typedef void (*Function)(void*); + + int bind_blob(int index, std::vector<unsigned char>* blob); + int bind_blob(int index, const void* value, int value_len); + int bind_blob(int index, const void* value, int value_len, Function dtor); + int bind_double(int index, double value); + int bind_bool(int index, bool value); + int bind_int(int index, int value); + int bind_int64(int index, sqlite_int64 value); + int bind_null(int index); + + int bind_string(int index, const std::string& value) { + // don't use c_str so it doesn't have to fix up the null terminator + // (sqlite just uses the length) + return bind_text(index, value.data(), + static_cast<int>(value.length()), SQLITE_TRANSIENT); + } + + int bind_string16(int index, const string16& value) { + // don't use c_str so it doesn't have to fix up the null terminator + // (sqlite just uses the length) + std::string value_utf8(UTF16ToUTF8(value)); + return bind_text(index, value_utf8.data(), + static_cast<int>(value_utf8.length()), SQLITE_TRANSIENT); + } + + int bind_wstring(int index, const std::wstring& value) { + // don't use c_str so it doesn't have to fix up the null terminator + // (sqlite just uses the length) + std::string value_utf8(WideToUTF8(value)); + return bind_text(index, value_utf8.data(), + static_cast<int>(value_utf8.length()), SQLITE_TRANSIENT); + } + + int bind_text(int index, const char* value) { + return bind_text(index, value, -1, SQLITE_TRANSIENT); + } + + // value_len is number of characters or may be negative + // a for null-terminated value string + int bind_text(int index, const char* value, int value_len) { + return bind_text(index, value, value_len, SQLITE_TRANSIENT); + } + + // value_len is number of characters or may be negative + // a for null-terminated value string + int bind_text(int index, const char* value, int value_len, + Function dtor); + + int bind_text16(int index, const char16* value) { + return bind_text16(index, value, -1, SQLITE_TRANSIENT); + } + + // value_len is number of characters or may be negative + // a for null-terminated value string + int bind_text16(int index, const char16* value, int value_len) { + return bind_text16(index, value, value_len, SQLITE_TRANSIENT); + } + + // value_len is number of characters or may be negative + // a for null-terminated value string + int bind_text16(int index, const char16* value, int value_len, + Function dtor); + + int bind_value(int index, const sqlite3_value* value); + + // + // Column helpers (NOTE: index is 0-based) + // + + int column_count(); + int column_type(int index); + const void* column_blob(int index); + bool column_blob_as_vector(int index, std::vector<unsigned char>* blob); + bool column_blob_as_string(int index, std::string* blob); + int column_bytes(int index); + int column_bytes16(int index); + double column_double(int index); + bool column_bool(int index); + int column_int(int index); + sqlite_int64 column_int64(int index); + const char* column_text(int index); + bool column_string(int index, std::string* str); + std::string column_string(int index); + const char16* column_text16(int index); + bool column_string16(int index, string16* str); + string16 column_string16(int index); + bool column_wstring(int index, std::wstring* str); + std::wstring column_wstring(int index); + + private: + DISALLOW_COPY_AND_ASSIGN(SQLStatement); +}; + +namespace sqlite_utils { + +//------------------------------------------------------------------------------ +// A scoped sqlite database that closes when it goes out of scope. +//------------------------------------------------------------------------------ +class DBClose { + public: + inline void operator()(sqlite3* x) const { + sqlite3_close(x); + } +}; + +typedef scoped_ptr_malloc<sqlite3, DBClose> scoped_sqlite_db_ptr; + +// Opens the DB in the file pointed to by |filepath|. This method forces the +// database to be in UTF-8 mode on all platforms. See +// http://www.sqlite.org/capi3ref.html#sqlite3_open for an explanation of the +// return value. +int OpenSqliteDb(const FilePath& filepath, sqlite3** database); + +// Returns true if there is a table with the given name in the database. +// For the version where a database name is specified, it may be NULL or the +// empty string if no database name is necessary. +bool DoesSqliteTableExist(sqlite3* db, + const char* db_name, + const char* table_name); +inline bool DoesSqliteTableExist(sqlite3* db, const char* table_name) { + return DoesSqliteTableExist(db, NULL, table_name); +} + +// Test whether a table has a column matching the provided name and type. +// Returns true if the column exist and false otherwise. There are two +// versions, one that takes a database name, the other that doesn't. The +// database name can be NULL or empty if no name is desired. +// +// Column type is optional, it can be NULL or empty. If specified, we the +// function will check that the column is of the correct type (case-sensetive). +bool DoesSqliteColumnExist(sqlite3* db, + const char* datbase_name, + const char* table_name, + const char* column_name, + const char* column_type); +inline bool DoesSqliteColumnExist(sqlite3* db, + const char* table_name, + const char* column_name, + const char* column_type) { + return DoesSqliteColumnExist(db, NULL, table_name, column_name, column_type); +} + +// Test whether a table has one or more rows. Returns true if the table +// has one or more rows and false if the table is empty or doesn't exist. +bool DoesSqliteTableHaveRow(sqlite3* db, const char* table_name); + +} // namespace sqlite_utils + +#endif // CHROME_BROWSER_SYNC_UTIL_SQLITE_UTILS_H_ diff --git a/chrome/browser/sync/util/user_settings.cc b/chrome/browser/sync/util/user_settings.cc index 6ce150e..414b599 100644 --- a/chrome/browser/sync/util/user_settings.cc +++ b/chrome/browser/sync/util/user_settings.cc @@ -23,8 +23,8 @@ #include "base/string_util.h" #include "chrome/browser/sync/syncable/directory_manager.h" // For migration. #include "chrome/browser/sync/util/data_encryption.h" +#include "chrome/browser/sync/util/sqlite_utils.h" #include "chrome/common/random.h" -#include "chrome/common/sqlite_utils.h" using std::numeric_limits; using std::string; diff --git a/chrome/browser/sync/util/user_settings_posix.cc b/chrome/browser/sync/util/user_settings_posix.cc index 6f480fe..48baf78 100644 --- a/chrome/browser/sync/util/user_settings_posix.cc +++ b/chrome/browser/sync/util/user_settings_posix.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. // @@ -8,7 +8,7 @@ #include "base/logging.h" #include "chrome/browser/password_manager/encryptor.h" -#include "chrome/common/sqlite_utils.h" +#include "chrome/browser/sync/util/sqlite_utils.h" namespace browser_sync { diff --git a/chrome/browser/sync/util/user_settings_win.cc b/chrome/browser/sync/util/user_settings_win.cc index d2b0447..d55e459 100644 --- a/chrome/browser/sync/util/user_settings_win.cc +++ b/chrome/browser/sync/util/user_settings_win.cc @@ -8,7 +8,7 @@ #include "base/logging.h" #include "chrome/browser/sync/util/data_encryption.h" -#include "chrome/common/sqlite_utils.h" +#include "chrome/browser/sync/util/sqlite_utils.h" using std::string; |