summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync/util
diff options
context:
space:
mode:
authortfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-09 01:18:10 +0000
committertfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-09 01:18:10 +0000
commit0e7f8d0b2aaf1eea1671c1ea4a1352b827566f94 (patch)
tree97c118c3c91d01fe8a931987a0346ea66d183d53 /chrome/browser/sync/util
parentd6b94838c9c7cfe13933e819bebb99b08f13d08b (diff)
downloadchromium_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.cc510
-rw-r--r--chrome/browser/sync/util/sqlite_utils.h400
-rw-r--r--chrome/browser/sync/util/user_settings.cc2
-rw-r--r--chrome/browser/sync/util/user_settings_posix.cc4
-rw-r--r--chrome/browser/sync/util/user_settings_win.cc2
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;