Convert history to use new sql wrappers. Enhance wrappers in several ways to
support the needs of history.

BUG=none
TEST=covered by unit tests
Review URL: http://codereview.chromium.org/246053

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27832 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/app/sql/connection.cc b/app/sql/connection.cc
index 886f781..ac1c545 100644
--- a/app/sql/connection.cc
+++ b/app/sql/connection.cc
@@ -59,36 +59,16 @@
   Close();
 }
 
-bool Connection::Init(const FilePath& path) {
+bool Connection::Open(const FilePath& path) {
 #if defined(OS_WIN)
-  // We want the default encoding to always be UTF-8, so we use the
-  // 8-bit version of open().
-  int err = sqlite3_open(WideToUTF8(path.value()).c_str(), &db_);
+  return OpenInternal(WideToUTF8(path.value()));
 #elif defined(OS_POSIX)
-  int err = sqlite3_open(path.value().c_str(), &db_);
+  return OpenInternal(path.value());
 #endif
+}
 
-  if (err != SQLITE_OK) {
-    db_ = NULL;
-    return false;
-  }
-
-  if (page_size_ != 0) {
-    if (!Execute(StringPrintf("PRAGMA page_size=%d", page_size_).c_str()))
-      NOTREACHED() << "Could not set page size";
-  }
-
-  if (cache_size_ != 0) {
-    if (!Execute(StringPrintf("PRAGMA cache_size=%d", cache_size_).c_str()))
-      NOTREACHED() << "Could not set page size";
-  }
-
-  if (exclusive_locking_) {
-    if (!Execute("PRAGMA locking_mode=EXCLUSIVE"))
-      NOTREACHED() << "Could not set locking mode.";
-  }
-
-  return true;
+bool Connection::OpenInMemory() {
+  return OpenInternal(":memory:");
 }
 
 void Connection::Close() {
@@ -283,6 +263,32 @@
   return sqlite3_errmsg(db_);
 }
 
+bool Connection::OpenInternal(const std::string& file_name) {
+  int err = sqlite3_open(file_name.c_str(), &db_);
+  if (err != SQLITE_OK) {
+    OnSqliteError(err, NULL);
+    db_ = NULL;
+    return false;
+  }
+
+  if (page_size_ != 0) {
+    if (!Execute(StringPrintf("PRAGMA page_size=%d", page_size_).c_str()))
+      NOTREACHED() << "Could not set page size";
+  }
+
+  if (cache_size_ != 0) {
+    if (!Execute(StringPrintf("PRAGMA cache_size=%d", cache_size_).c_str()))
+      NOTREACHED() << "Could not set page size";
+  }
+
+  if (exclusive_locking_) {
+    if (!Execute("PRAGMA locking_mode=EXCLUSIVE"))
+      NOTREACHED() << "Could not set locking mode.";
+  }
+
+  return true;
+}
+
 void Connection::DoRollback() {
   Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK"));
   if (rollback)
diff --git a/app/sql/connection.h b/app/sql/connection.h
index 904d614c..e87baa8 100644
--- a/app/sql/connection.h
+++ b/app/sql/connection.h
@@ -79,8 +79,12 @@
   virtual ~ErrorDelegate() {}
   // |error| is an sqlite result code as seen in sqlite\preprocessed\sqlite3.h
   // |connection| is db connection where the error happened and |stmt| is
-  // our best guess at the statement that triggered the error. Do not store
+  // our best guess at the statement that triggered the error.  Do not store
   // these pointers.
+  //
+  // |stmt| MAY BE NULL if there is no statement causing the problem (i.e. on
+  // initialization).
+  //
   // If the error condition has been fixed an the original statement succesfuly
   // re-tried then returning SQLITE_OK is appropiate; otherwise is recomended
   // that you return the original |error| or the appropiae error code.
@@ -92,14 +96,14 @@
   class StatementRef;  // Forward declaration, see real one below.
 
  public:
-  // The database is opened by calling Init(). Any uncommitted transactions
-  // will be rolled back when this object is deleted.
+  // The database is opened by calling Open[InMemory](). Any uncommitted
+  // transactions will be rolled back when this object is deleted.
   Connection();
   ~Connection();
 
   // Pre-init configuration ----------------------------------------------------
 
-  // Sets the page size that will be used when creating a new adtabase. This
+  // Sets the page size that will be used when creating a new database. This
   // must be called before Init(), and will only have an effect on new
   // databases.
   //
@@ -110,7 +114,7 @@
 
   // Sets the number of pages that will be cached in memory by sqlite. The
   // total cache size in bytes will be page_size * cache_size. This must be
-  // called before Init() to have an effect.
+  // called before Open() to have an effect.
   void set_cache_size(int cache_size) { cache_size_ = cache_size; }
 
   // Call to put the database in exclusive locking mode. There is no "back to
@@ -122,11 +126,11 @@
   // transaction, which means there may be less time spent initializing the
   // next transaction because it doesn't have to re-aquire locks.
   //
-  // This must be called before Init() to have an effect.
+  // This must be called before Open() to have an effect.
   void set_exclusive_locking() { exclusive_locking_ = true; }
 
   // Sets the object that will handle errors. Recomended that it should be set
-  // before calling Init(). If not set, the default is to ignore errors on
+  // before calling Open(). If not set, the default is to ignore errors on
   // release and assert on debug builds.
   void set_error_delegate(ErrorDelegate* delegate) {
     error_delegate_ = delegate;
@@ -135,8 +139,16 @@
   // Initialization ------------------------------------------------------------
 
   // Initializes the SQL connection for the given file, returning true if the
-  // file could be opened.
-  bool Init(const FilePath& path);
+  // file could be opened. You can call this or InitInMemory to initialize.
+  bool Open(const FilePath& path);
+
+  // Initializes the SQL connection for a temporary in-memory database. There
+  // will be no associated file on disk, and the initial database will be
+  // empty. You must call this or Init to open the database.
+  bool OpenInMemory();
+
+  // Returns trie if the database has been successfully opened.
+  bool is_open() const { return !!db_; }
 
   // Closes the database. This is automatically performed on destruction for
   // you, but this allows you to close the database early. You must not call
@@ -225,7 +237,7 @@
   // Info querying -------------------------------------------------------------
 
   // Returns true if the given table exists.
-  bool DoesTableExist( const char* table_name) const;
+  bool DoesTableExist(const char* table_name) const;
 
   // Returns true if a column with the given name exists in the given table.
   bool DoesColumnExist(const char* table_name, const char* column_name) const;
@@ -253,6 +265,11 @@
   // (they should go through Statement).
   friend class Statement;
 
+  // Internal initialize function used by both Init and InitInMemory. The file
+  // name is always 8 bits since we want to use the 8-bit version of
+  // sqlite3_open. The string can also be sqlite's special ":memory:" string.
+  bool OpenInternal(const std::string& file_name);
+
   // A StatementRef is a refcounted wrapper around a sqlite statement pointer.
   // Refcounting allows us to give these statements out to sql::Statement
   // objects while also optionally maintaining a cache of compiled statements
diff --git a/app/sql/connection_unittest.cc b/app/sql/connection_unittest.cc
index 70c9ffc8..a36fca7 100644
--- a/app/sql/connection_unittest.cc
+++ b/app/sql/connection_unittest.cc
@@ -18,7 +18,7 @@
     ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &path_));
     path_ = path_.AppendASCII("SQLConnectionTest.db");
     file_util::Delete(path_, false);
-    ASSERT_TRUE(db_.Init(path_));
+    ASSERT_TRUE(db_.Open(path_));
   }
 
   void TearDown() {
diff --git a/app/sql/statement.cc b/app/sql/statement.cc
index 3cadb6e..7abc225 100644
--- a/app/sql/statement.cc
+++ b/app/sql/statement.cc
@@ -70,6 +70,10 @@
   return false;
 }
 
+bool Statement::BindBool(int col, bool val) {
+  return BindInt(col, val ? 1 : 0);
+}
+
 bool Statement::BindInt(int col, int val) {
   if (is_valid()) {
     int err = CheckError(sqlite3_bind_int(ref_->stmt(), col + 1, val));
@@ -129,6 +133,21 @@
   return sqlite3_column_count(ref_->stmt());
 }
 
+ColType Statement::ColumnType(int col) const {
+  // Verify that our enum matches sqlite's values.
+  COMPILE_ASSERT(COLUMN_TYPE_INTEGER == SQLITE_INTEGER, integer_no_match);
+  COMPILE_ASSERT(COLUMN_TYPE_FLOAT == SQLITE_FLOAT, float_no_match);
+  COMPILE_ASSERT(COLUMN_TYPE_TEXT == SQLITE_TEXT, integer_no_match);
+  COMPILE_ASSERT(COLUMN_TYPE_BLOB == SQLITE_BLOB, blob_no_match);
+  COMPILE_ASSERT(COLUMN_TYPE_NULL == SQLITE_NULL, null_no_match);
+
+  return static_cast<ColType>(sqlite3_column_type(ref_->stmt(), col));
+}
+
+bool Statement::ColumnBool(int col) const {
+  return !!ColumnInt(col);
+}
+
 int Statement::ColumnInt(int col) const {
   if (!is_valid()) {
     NOTREACHED();
diff --git a/app/sql/statement.h b/app/sql/statement.h
index 6211d348..8ee6ef5 100644
--- a/app/sql/statement.h
+++ b/app/sql/statement.h
@@ -14,6 +14,16 @@
 
 namespace sql {
 
+// Possible return values from ColumnType in a statement. These should match
+// the values in sqlite3.h.
+enum ColType {
+  COLUMN_TYPE_INTEGER = 1,
+  COLUMN_TYPE_FLOAT = 2,
+  COLUMN_TYPE_TEXT = 3,
+  COLUMN_TYPE_BLOB = 4,
+  COLUMN_TYPE_NULL = 5,
+};
+
 // Normal usage:
 //   sql::Statement s = connection_.GetUniqueStatement(...);
 //   if (!s)  // You should check for errors before using the statement.
@@ -88,6 +98,7 @@
   // The main thing you may want to check is when binding large blobs or
   // strings there may be out of memory.
   bool BindNull(int col);
+  bool BindBool(int col, bool val);
   bool BindInt(int col, int val);
   bool BindInt64(int col, int64 val);
   bool BindDouble(int col, double val);
@@ -100,7 +111,16 @@
   // Returns the number of output columns in the result.
   int ColumnCount() const;
 
+  // Returns the type associated with the given column.
+  //
+  // Watch out: the type may be undefined if you've done something to cause a
+  // "type conversion." This means requesting the value of a column of a type
+  // where that type is not the native type. For safety, call ColumnType only
+  // on a column before getting the value out in any way.
+  ColType ColumnType(int col) const;
+
   // These all take a 0-based argument index.
+  bool ColumnBool(int col) const;
   int ColumnInt(int col) const;
   int64 ColumnInt64(int col) const;
   double ColumnDouble(int col) const;
diff --git a/app/sql/statement_unittest.cc b/app/sql/statement_unittest.cc
index 5f04880..90f421c 100644
--- a/app/sql/statement_unittest.cc
+++ b/app/sql/statement_unittest.cc
@@ -19,7 +19,7 @@
   virtual int OnError(int error, sql::Connection* connection,
                       sql::Statement* stmt) {
     error_ = error;
-    const char* sql_txt = stmt->GetSQLStatement();
+    const char* sql_txt = stmt ? stmt->GetSQLStatement() : NULL;
     sql_text_ = sql_txt ? sql_txt : "no statement available";
     return error;
   }
@@ -46,7 +46,7 @@
     ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &path_));
     path_ = path_.AppendASCII("SQLStatementTest.db");
     file_util::Delete(path_, false);
-    ASSERT_TRUE(db_.Init(path_));
+    ASSERT_TRUE(db_.Open(path_));
     // The |error_handler_| will be called if any sqlite statement operation
     // returns an error code.
     db_.set_error_delegate(error_handler_);
diff --git a/app/sql/transaction_unittest.cc b/app/sql/transaction_unittest.cc
index 0da79e3..55b77b93 100644
--- a/app/sql/transaction_unittest.cc
+++ b/app/sql/transaction_unittest.cc
@@ -19,7 +19,7 @@
     ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &path_));
     path_ = path_.AppendASCII("SQLStatementTest.db");
     file_util::Delete(path_, false);
-    ASSERT_TRUE(db_.Init(path_));
+    ASSERT_TRUE(db_.Open(path_));
 
     ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
   }
diff --git a/chrome/browser/history/archived_database.cc b/chrome/browser/history/archived_database.cc
index 20b9cd88..b7cd8bd 100644
--- a/chrome/browser/history/archived_database.cc
+++ b/chrome/browser/history/archived_database.cc
@@ -1,13 +1,14 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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 <algorithm>
 #include <string>
 
+#include "app/sql/statement.h"
+#include "app/sql/transaction.h"
 #include "base/string_util.h"
 #include "chrome/browser/history/archived_database.h"
-#include "chrome/common/sqlite_utils.h"
 
 namespace history {
 
@@ -18,88 +19,71 @@
 
 }  // namespace
 
-ArchivedDatabase::ArchivedDatabase()
-    : db_(NULL),
-      statement_cache_(NULL),
-      transaction_nesting_(0) {
+ArchivedDatabase::ArchivedDatabase() {
 }
 
 ArchivedDatabase::~ArchivedDatabase() {
 }
 
 bool ArchivedDatabase::Init(const FilePath& file_name) {
-  // OpenSqliteDb uses the narrow version of open, indicating to sqlite that we
-  // want the database to be in UTF-8 if it doesn't already exist.
-  DCHECK(!db_) << "Already initialized!";
-  if (OpenSqliteDb(file_name, &db_) != SQLITE_OK)
-    return false;
-  statement_cache_ = new SqliteStatementCache(db_);
-  DBCloseScoper scoper(&db_, &statement_cache_);
-
   // Set the database page size to something a little larger to give us
   // better performance (we're typically seek rather than bandwidth limited).
   // This only has an effect before any tables have been created, otherwise
   // this is a NOP. Must be a power of 2 and a max of 8192.
-  sqlite3_exec(db_, "PRAGMA page_size=4096", NULL, NULL, NULL);
+  db_.set_page_size(4096);
 
   // Don't use very much memory caching this database. We seldom use it for
   // anything important.
-  sqlite3_exec(db_, "PRAGMA cache_size=64", NULL, NULL, NULL);
+  db_.set_cache_size(64);
 
   // Run the database in exclusive mode. Nobody else should be accessing the
   // database while we're running, and this will give somewhat improved perf.
-  sqlite3_exec(db_, "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, NULL);
+  db_.set_exclusive_locking();
 
-  BeginTransaction();
+  if (!db_.Open(file_name))
+    return false;
+
+  sql::Transaction transaction(&db_);
+  if (!transaction.Begin()) {
+    db_.Close();
+    return false;
+  }
 
   // Version check.
-  if (!meta_table_.Init(std::string(), kCurrentVersionNumber,
-                        kCompatibleVersionNumber, db_))
+  if (!meta_table_.Init(&db_, kCurrentVersionNumber,
+                        kCompatibleVersionNumber)) {
+    db_.Close();
     return false;
+  }
 
   // Create the tables.
   if (!CreateURLTable(false) || !InitVisitTable() ||
-      !InitKeywordSearchTermsTable())
+      !InitKeywordSearchTermsTable()) {
+    db_.Close();
     return false;
+  }
   CreateMainURLIndex();
 
-  if (EnsureCurrentVersion() != INIT_OK)
+  if (EnsureCurrentVersion() != INIT_OK) {
+    db_.Close();
     return false;
+  }
 
-  // Succeeded: keep the DB open by detaching the auto-closer.
-  scoper.Detach();
-  db_closer_.Attach(&db_, &statement_cache_);
-  CommitTransaction();
-  return true;
+  return transaction.Commit();
 }
 
 void ArchivedDatabase::BeginTransaction() {
-  DCHECK(db_);
-  if (transaction_nesting_ == 0) {
-    int rv = sqlite3_exec(db_, "BEGIN TRANSACTION", NULL, NULL, NULL);
-    DCHECK(rv == SQLITE_OK) << "Failed to begin transaction";
-  }
-  transaction_nesting_++;
+  db_.BeginTransaction();
 }
 
 void ArchivedDatabase::CommitTransaction() {
-  DCHECK(db_);
-  DCHECK_GT(transaction_nesting_, 0) << "Committing too many transactions";
-  transaction_nesting_--;
-  if (transaction_nesting_ == 0) {
-    int rv = sqlite3_exec(db_, "COMMIT", NULL, NULL, NULL);
-    DCHECK(rv == SQLITE_OK) << "Failed to commit transaction";
-  }
+  db_.CommitTransaction();
 }
 
-sqlite3* ArchivedDatabase::GetDB() {
+sql::Connection& ArchivedDatabase::GetDB() {
   return db_;
 }
 
-SqliteStatementCache& ArchivedDatabase::GetStatementCache() {
-  return *statement_cache_;
-}
-
 // Migration -------------------------------------------------------------------
 
 InitStatus ArchivedDatabase::EnsureCurrentVersion() {
diff --git a/chrome/browser/history/archived_database.h b/chrome/browser/history/archived_database.h
index f444477..13bc5625 100644
--- a/chrome/browser/history/archived_database.h
+++ b/chrome/browser/history/archived_database.h
@@ -1,16 +1,15 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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_HISTORY_ARCHIVED_DATABASE_H_
 #define CHROME_BROWSER_HISTORY_ARCHIVED_DATABASE_H_
 
+#include "app/sql/connection.h"
+#include "app/sql/meta_table.h"
 #include "base/basictypes.h"
 #include "chrome/browser/history/url_database.h"
 #include "chrome/browser/history/visit_database.h"
-#include "chrome/browser/meta_table_helper.h"
-
-struct sqlite3;
 
 class FilePath;
 
@@ -40,8 +39,7 @@
 
  private:
   // Implemented for the specialized databases.
-  virtual sqlite3* GetDB();
-  virtual SqliteStatementCache& GetStatementCache();
+  virtual sql::Connection& GetDB();
 
   // Makes sure the version is up-to-date, updating if necessary. If the
   // database is too old to migrate, the user will be notified. In this case, or
@@ -53,17 +51,8 @@
   InitStatus EnsureCurrentVersion();
 
   // The database.
-  //
-  // The close scoper will free the database and delete the statement cache in
-  // the correct order automatically when we are destroyed.
-  DBCloseScoper db_closer_;
-  sqlite3* db_;
-  SqliteStatementCache* statement_cache_;
-
-  // The number of nested transactions currently in progress.
-  int transaction_nesting_;
-
-  MetaTableHelper meta_table_;
+  sql::Connection db_;
+  sql::MetaTable meta_table_;
 
   DISALLOW_COPY_AND_ASSIGN(ArchivedDatabase);
 };
diff --git a/chrome/browser/history/download_database.cc b/chrome/browser/history/download_database.cc
index 996e1199..4fcf386 100644
--- a/chrome/browser/history/download_database.cc
+++ b/chrome/browser/history/download_database.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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.
 
@@ -7,12 +7,12 @@
 #include <limits>
 #include <vector>
 
+#include "app/sql/connection.h"
+#include "app/sql/statement.h"
+#include "base/string_util.h"
+#include "build/build_config.h"
 #include "chrome/browser/download/download_manager.h"
 #include "chrome/browser/history/download_types.h"
-#include "chrome/common/sqlite_utils.h"
-#include "chrome/common/sqlite_compiled_statement.h"
-
-using base::Time;
 
 // Download schema:
 //
@@ -28,6 +28,32 @@
 
 namespace history {
 
+namespace {
+
+#if defined(OS_POSIX)
+
+// Binds/reads the given file path to the given column of the given statement.
+void BindFilePath(sql::Statement& statement, const FilePath& path, int col) {
+  statement.BindString(col, path.value());
+}
+FilePath ColumnFilePath(sql::Statement& statement, int col) {
+  return FilePath(statement.ColumnString(col));
+}
+
+#else
+
+// See above.
+void BindFilePath(sql::Statement& statement, const FilePath& path, int col) {
+  statement.BindString(col, UTF16ToUTF8(path.value()));
+}
+FilePath ColumnFilePath(sql::Statement& statement, int col) {
+  return FilePath(UTF8ToUTF16(statement.ColumnString(col)));
+}
+
+#endif
+
+}  // namespace
+
 DownloadDatabase::DownloadDatabase() {
 }
 
@@ -35,51 +61,47 @@
 }
 
 bool DownloadDatabase::InitDownloadTable() {
-  if (!DoesSqliteTableExist(GetDB(), "downloads")) {
-    if (sqlite3_exec(GetDB(),
-                     "CREATE TABLE downloads ("
-                     "id INTEGER PRIMARY KEY,"
-                     "full_path LONGVARCHAR NOT NULL,"
-                     "url LONGVARCHAR NOT NULL,"
-                     "start_time INTEGER NOT NULL,"
-                     "received_bytes INTEGER NOT NULL,"
-                     "total_bytes INTEGER NOT NULL,"
-                     "state INTEGER NOT NULL)", NULL, NULL, NULL) != SQLITE_OK)
+  if (!GetDB().DoesTableExist("downloads")) {
+    if (!GetDB().Execute(
+        "CREATE TABLE downloads ("
+        "id INTEGER PRIMARY KEY,"
+        "full_path LONGVARCHAR NOT NULL,"
+        "url LONGVARCHAR NOT NULL,"
+        "start_time INTEGER NOT NULL,"
+        "received_bytes INTEGER NOT NULL,"
+        "total_bytes INTEGER NOT NULL,"
+        "state INTEGER NOT NULL)"))
       return false;
   }
   return true;
 }
 
 bool DownloadDatabase::DropDownloadTable() {
-  return sqlite3_exec(GetDB(), "DROP TABLE downloads", NULL, NULL, NULL) ==
-      SQLITE_OK;
+  return GetDB().Execute("DROP TABLE downloads");
 }
 
 void DownloadDatabase::QueryDownloads(
     std::vector<DownloadCreateInfo>* results) {
   results->clear();
 
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT id, full_path, url, start_time, received_bytes, "
         "total_bytes, state "
       "FROM downloads "
-      "ORDER BY start_time");
-  if (!statement.is_valid())
+      "ORDER BY start_time"));
+  if (!statement)
     return;
 
-  while (statement->step() == SQLITE_ROW) {
+  while (statement.Step()) {
     DownloadCreateInfo info;
-    info.db_handle = statement->column_int64(0);
-    std::wstring path_str;
-    statement->column_wstring(1, &path_str);
-    info.path = FilePath::FromWStringHack(path_str);
-    std::wstring url_str;
-    statement->column_wstring(2, &url_str);
-    info.url = GURL(WideToUTF8(url_str));
-    info.start_time = Time::FromTimeT(statement->column_int64(3));
-    info.received_bytes = statement->column_int64(4);
-    info.total_bytes = statement->column_int64(5);
-    info.state = statement->column_int(6);
+    info.db_handle = statement.ColumnInt64(0);
+
+    info.path = ColumnFilePath(statement, 1);
+    info.url = GURL(statement.ColumnString(2));
+    info.start_time = base::Time::FromTimeT(statement.ColumnInt64(3));
+    info.received_bytes = statement.ColumnInt64(4);
+    info.total_bytes = statement.ColumnInt64(5);
+    info.state = statement.ColumnInt(6);
     results->push_back(info);
   }
 }
@@ -88,99 +110,98 @@
                                       int32 state,
                                       DownloadID db_handle) {
   DCHECK(db_handle > 0);
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "UPDATE downloads "
-      "SET received_bytes=?, state=? WHERE id=?");
-  if (!statement.is_valid())
+      "SET received_bytes=?, state=? WHERE id=?"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, received_bytes);
-  statement->bind_int(1, state);
-  statement->bind_int64(2, db_handle);
-  return statement->step() == SQLITE_DONE;
+  statement.BindInt64(0, received_bytes);
+  statement.BindInt(1, state);
+  statement.BindInt64(2, db_handle);
+  return statement.Run();
 }
 
 bool DownloadDatabase::UpdateDownloadPath(const std::wstring& path,
                                           DownloadID db_handle) {
   DCHECK(db_handle > 0);
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "UPDATE downloads "
-      "SET full_path=? WHERE id=?");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "UPDATE downloads SET full_path=? WHERE id=?"));
+  if (!statement)
     return false;
 
-  statement->bind_wstring(0, path);
-  statement->bind_int64(1, db_handle);
-  return statement->step() == SQLITE_DONE;
+  statement.BindString(0, WideToUTF8(path));
+  statement.BindInt64(1, db_handle);
+  return statement.Run();
 }
 
 int64 DownloadDatabase::CreateDownload(const DownloadCreateInfo& info) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "INSERT INTO downloads "
       "(full_path, url, start_time, received_bytes, total_bytes, state) "
-      "VALUES (?, ?, ?, ?, ?, ?)");
-  if (!statement.is_valid())
+      "VALUES (?, ?, ?, ?, ?, ?)"));
+  if (!statement)
     return 0;
 
-  statement->bind_wstring(0, info.path.ToWStringHack());
-  statement->bind_wstring(1, UTF8ToWide(info.url.spec()));
-  statement->bind_int64(2, info.start_time.ToTimeT());
-  statement->bind_int64(3, info.received_bytes);
-  statement->bind_int64(4, info.total_bytes);
-  statement->bind_int(5, info.state);
-  if (statement->step() == SQLITE_DONE)
-    return sqlite3_last_insert_rowid(GetDB());
+  BindFilePath(statement, info.path, 0);
+  statement.BindString(1, info.url.spec());
+  statement.BindInt64(2, info.start_time.ToTimeT());
+  statement.BindInt64(3, info.received_bytes);
+  statement.BindInt64(4, info.total_bytes);
+  statement.BindInt(5, info.state);
 
+  if (statement.Run())
+    return GetDB().GetLastInsertRowId();
   return 0;
 }
 
 void DownloadDatabase::RemoveDownload(DownloadID db_handle) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "DELETE FROM downloads WHERE id=?");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "DELETE FROM downloads WHERE id=?"));
+  if (!statement)
     return;
 
-  statement->bind_int64(0, db_handle);
-  statement->step();
+  statement.BindInt64(0, db_handle);
+  statement.Run();
 }
 
-void DownloadDatabase::RemoveDownloadsBetween(Time delete_begin,
-                                              Time delete_end) {
+void DownloadDatabase::RemoveDownloadsBetween(base::Time delete_begin,
+                                              base::Time delete_end) {
   // This does not use an index. We currently aren't likely to have enough
   // downloads where an index by time will give us a lot of benefit.
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "DELETE FROM downloads WHERE start_time >= ? AND start_time < ? "
-      "AND (State = ? OR State = ?)");
-  if (!statement.is_valid())
+      "AND (State = ? OR State = ?)"));
+  if (!statement)
     return;
 
   time_t start_time = delete_begin.ToTimeT();
   time_t end_time = delete_end.ToTimeT();
-  statement->bind_int64(0, start_time);
-  statement->bind_int64(
+  statement.BindInt64(0, start_time);
+  statement.BindInt64(
       1,
       end_time ? end_time : std::numeric_limits<int64>::max());
-  statement->bind_int(2, DownloadItem::COMPLETE);
-  statement->bind_int(3, DownloadItem::CANCELLED);
-  statement->step();
+  statement.BindInt(2, DownloadItem::COMPLETE);
+  statement.BindInt(3, DownloadItem::CANCELLED);
+  statement.Run();
 }
 
 void DownloadDatabase::SearchDownloads(std::vector<int64>* results,
                                        const std::wstring& search_text) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT id FROM downloads WHERE url LIKE ? "
-      "OR full_path LIKE ? ORDER BY id");
-  if (!statement.is_valid())
+      "OR full_path LIKE ? ORDER BY id"));
+  if (!statement)
     return;
 
-  std::wstring text(L"%");
-  text.append(search_text);
-  text.append(L"%");
-  statement->bind_wstring(0, text);
-  statement->bind_wstring(1, text);
+  std::string text("%");
+  text.append(WideToUTF8(search_text));
+  text.push_back('%');
+  statement.BindString(0, text);
+  statement.BindString(1, text);
 
-  while (statement->step() == SQLITE_ROW)
-    results->push_back(statement->column_int64(0));
+  while (statement.Step())
+    results->push_back(statement.ColumnInt64(0));
 }
 
 }  // namespace history
diff --git a/chrome/browser/history/download_database.h b/chrome/browser/history/download_database.h
index e005de6..1efb6d4 100644
--- a/chrome/browser/history/download_database.h
+++ b/chrome/browser/history/download_database.h
@@ -1,17 +1,18 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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_HISTORY_DOWNLOAD_DATABASE_H__
-#define CHROME_BROWSER_HISTORY_DOWNLOAD_DATABASE_H__
+#ifndef CHROME_BROWSER_HISTORY_DOWNLOAD_DATABASE_H_
+#define CHROME_BROWSER_HISTORY_DOWNLOAD_DATABASE_H_
 
 #include "chrome/browser/history/history_types.h"
 
-struct sqlite3;
-class SqliteStatementCache;
-class SQLStatement;
 struct DownloadCreateInfo;
 
+namespace sql {
+class Connection;
+}
+
 namespace history {
 
 // Maintains a table of downloads.
@@ -47,11 +48,8 @@
                        const std::wstring& search_text);
 
  protected:
-  // Returns the database and statement cache for the functions in this
-  // interface. The descendant of this class implements these functions to
-  // return its objects.
-  virtual sqlite3* GetDB() = 0;
-  virtual SqliteStatementCache& GetStatementCache() = 0;
+  // Returns the database for the functions in this interface.
+  virtual sql::Connection& GetDB() = 0;
 
   // Creates the downloads table if needed.
   bool InitDownloadTable();
@@ -61,9 +59,9 @@
   bool DropDownloadTable();
 
  private:
-  DISALLOW_EVIL_CONSTRUCTORS(DownloadDatabase);
+  DISALLOW_COPY_AND_ASSIGN(DownloadDatabase);
 };
 
 }  // namespace history
 
-#endif  // CHROME_BROWSER_HISTORY_DOWNLOAD_DATABASE_H__
+#endif  // CHROME_BROWSER_HISTORY_DOWNLOAD_DATABASE_H_
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index 339d584a..f9855f4 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -515,7 +515,7 @@
   // Fill the in-memory database and send it back to the history service on the
   // main thread.
   InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend;
-  if (mem_backend->Init(history_name.ToWStringHack()))
+  if (mem_backend->Init(history_name))
     delegate_->SetInMemoryBackend(mem_backend);  // Takes ownership of pointer.
   else
     delete mem_backend;  // Error case, run without the in-memory DB.
diff --git a/chrome/browser/history/history_database.cc b/chrome/browser/history/history_database.cc
index 23939fc..ee0b179 100644
--- a/chrome/browser/history/history_database.cc
+++ b/chrome/browser/history/history_database.cc
@@ -8,13 +8,11 @@
 #include <set>
 #include <string>
 
+#include "app/sql/transaction.h"
 #include "base/file_util.h"
 #include "base/histogram.h"
 #include "base/rand_util.h"
 #include "base/string_util.h"
-#include "chrome/common/sqlite_utils.h"
-
-using base::Time;
 
 namespace history {
 
@@ -27,7 +25,8 @@
 static const int kCompatibleVersionNumber = 16;
 static const char kEarlyExpirationThresholdKey[] = "early_expiration_threshold";
 
-void ComputeDatabaseMetrics(const FilePath& history_name, sqlite3* db) {
+void ComputeDatabaseMetrics(const FilePath& history_name,
+                            sql::Connection& db) {
   if (base::RandInt(1, 100) != 50)
     return;  // Only do this computation sometimes since it can be expensive.
 
@@ -37,26 +36,22 @@
   int file_mb = static_cast<int>(file_size / (1024 * 1024));
   UMA_HISTOGRAM_MEMORY_MB("History.DatabaseFileMB", file_mb);
 
-  SQLStatement url_count;
-  if (url_count.prepare(db, "SELECT count(*) FROM urls") != SQLITE_OK ||
-      url_count.step() != SQLITE_ROW)
+  sql::Statement url_count(db.GetUniqueStatement("SELECT count(*) FROM urls"));
+  if (!url_count || !url_count.Step())
     return;
-  UMA_HISTOGRAM_COUNTS("History.URLTableCount", url_count.column_int(0));
+  UMA_HISTOGRAM_COUNTS("History.URLTableCount", url_count.ColumnInt(0));
 
-  SQLStatement visit_count;
-  if (visit_count.prepare(db, "SELECT count(*) FROM visits") != SQLITE_OK ||
-      visit_count.step() != SQLITE_ROW)
+  sql::Statement visit_count(db.GetUniqueStatement(
+      "SELECT count(*) FROM visits"));
+  if (!visit_count || !visit_count.Step())
     return;
-  UMA_HISTOGRAM_COUNTS("History.VisitTableCount", visit_count.column_int(0));
+  UMA_HISTOGRAM_COUNTS("History.VisitTableCount", visit_count.ColumnInt(0));
 }
 
 }  // namespace
 
 HistoryDatabase::HistoryDatabase()
-    : transaction_nesting_(0),
-      db_(NULL),
-      statement_cache_(NULL),
-      needs_version_17_migration_(false) {
+    : needs_version_17_migration_(false) {
 }
 
 HistoryDatabase::~HistoryDatabase() {
@@ -64,41 +59,38 @@
 
 InitStatus HistoryDatabase::Init(const FilePath& history_name,
                                  const FilePath& bookmarks_path) {
-  // OpenSqliteDb uses the narrow version of open, indicating to sqlite that we
-  // want the database to be in UTF-8 if it doesn't already exist.
-  DCHECK(!db_) << "Already initialized!";
-  if (OpenSqliteDb(history_name, &db_) != SQLITE_OK)
-    return INIT_FAILURE;
-  statement_cache_ = new SqliteStatementCache;
-  DBCloseScoper scoper(&db_, &statement_cache_);
-
   // Set the database page size to something a little larger to give us
   // better performance (we're typically seek rather than bandwidth limited).
   // This only has an effect before any tables have been created, otherwise
   // this is a NOP. Must be a power of 2 and a max of 8192.
-  sqlite3_exec(db_, "PRAGMA page_size=4096", NULL, NULL, NULL);
+  db_.set_page_size(4096);
 
   // Increase the cache size. The page size, plus a little extra, times this
   // value, tells us how much memory the cache will use maximum.
   // 6000 * 4MB = 24MB
   // TODO(brettw) scale this value to the amount of available memory.
-  sqlite3_exec(db_, "PRAGMA cache_size=6000", NULL, NULL, NULL);
+  db_.set_cache_size(6000);
+
+  // Note that we don't set exclusive locking here. That's done by
+  // BeginExclusiveMode below which is called later (we have to be in shared
+  // mode to start out for the in-memory backend to read the data).
+
+  if (!db_.Open(history_name))
+    return INIT_FAILURE;
 
   // Wrap the rest of init in a tranaction. This will prevent the database from
   // getting corrupted if we crash in the middle of initialization or migration.
-  TransactionScoper transaction(this);
-
-  // Make sure the statement cache is properly initialized.
-  statement_cache_->set_db(db_);
+  sql::Transaction committer(&db_);
+  if (!committer.Begin())
+    return INIT_FAILURE;
 
   // Prime the cache.
-  MetaTableHelper::PrimeCache(std::string(), db_);
+  db_.Preload();
 
   // Create the tables and indices.
   // NOTE: If you add something here, also add it to
   //       RecreateAllButStarAndURLTables.
-  if (!meta_table_.Init(std::string(), kCurrentVersionNumber,
-                        kCompatibleVersionNumber, db_))
+  if (!meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber))
     return INIT_FAILURE;
   if (!CreateURLTable(false) || !InitVisitTable() ||
       !InitKeywordSearchTermsTable() || !InitDownloadTable() ||
@@ -112,15 +104,14 @@
   if (version_status != INIT_OK)
     return version_status;
 
-  // Succeeded: keep the DB open by detaching the auto-closer.
-  scoper.Detach();
-  db_closer_.Attach(&db_, &statement_cache_);
   ComputeDatabaseMetrics(history_name, db_);
-  return INIT_OK;
+  return committer.Commit() ? INIT_OK : INIT_FAILURE;
 }
 
 void HistoryDatabase::BeginExclusiveMode() {
-  sqlite3_exec(db_, "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, NULL);
+  // We can't use set_exclusive_locking() since that only has an effect before
+  // the DB is opened.
+  db_.Execute("PRAGMA locking_mode=EXCLUSIVE");
 }
 
 // static
@@ -129,22 +120,11 @@
 }
 
 void HistoryDatabase::BeginTransaction() {
-  DCHECK(db_);
-  if (transaction_nesting_ == 0) {
-    int rv = sqlite3_exec(db_, "BEGIN TRANSACTION", NULL, NULL, NULL);
-    DCHECK(rv == SQLITE_OK) << "Failed to begin transaction";
-  }
-  transaction_nesting_++;
+  db_.BeginTransaction();
 }
 
 void HistoryDatabase::CommitTransaction() {
-  DCHECK(db_);
-  DCHECK_GT(transaction_nesting_, 0) << "Committing too many transactions";
-  transaction_nesting_--;
-  if (transaction_nesting_ == 0) {
-    int rv = sqlite3_exec(db_, "COMMIT", NULL, NULL, NULL);
-    DCHECK(rv == SQLITE_OK) << "Failed to commit transaction";
-  }
+  db_.CommitTransaction();
 }
 
 bool HistoryDatabase::RecreateAllTablesButURL() {
@@ -171,42 +151,43 @@
 }
 
 void HistoryDatabase::Vacuum() {
-  DCHECK_EQ(0, transaction_nesting_) <<
+  DCHECK_EQ(0, db_.transaction_nesting()) <<
       "Can not have a transaction when vacuuming.";
-  sqlite3_exec(db_, "VACUUM", NULL, NULL, NULL);
+  db_.Execute("VACUUM");
 }
 
 bool HistoryDatabase::SetSegmentID(VisitID visit_id, SegmentID segment_id) {
-  SQLStatement s;
-  if (s.prepare(db_, "UPDATE visits SET segment_id = ? WHERE id = ?") !=
-      SQLITE_OK) {
-    NOTREACHED();
+  sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
+      "UPDATE visits SET segment_id = ? WHERE id = ?"));
+  if (!s) {
+    NOTREACHED() << db_.GetErrorMessage();
     return false;
   }
-  s.bind_int64(0, segment_id);
-  s.bind_int64(1, visit_id);
-  return s.step() == SQLITE_DONE;
+  s.BindInt64(0, segment_id);
+  s.BindInt64(1, visit_id);
+  DCHECK(db_.GetLastChangeCount() == 1);
+  return s.Run();
 }
 
 SegmentID HistoryDatabase::GetSegmentID(VisitID visit_id) {
-  SQLStatement s;
-  if (s.prepare(db_, "SELECT segment_id FROM visits WHERE id = ?")
-      != SQLITE_OK) {
-    NOTREACHED();
+  sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
+      "SELECT segment_id FROM visits WHERE id = ?"));
+  if (!s) {
+    NOTREACHED() << db_.GetErrorMessage();
     return 0;
   }
 
-  s.bind_int64(0, visit_id);
-  if (s.step() == SQLITE_ROW) {
-    if (s.column_type(0) == SQLITE_NULL)
+  s.BindInt64(0, visit_id);
+  if (s.Step()) {
+    if (s.ColumnType(0) == sql::COLUMN_TYPE_NULL)
       return 0;
     else
-      return s.column_int64(0);
+      return s.ColumnInt64(0);
   }
   return 0;
 }
 
-Time HistoryDatabase::GetEarlyExpirationThreshold() {
+base::Time HistoryDatabase::GetEarlyExpirationThreshold() {
   if (!cached_early_expiration_threshold_.is_null())
     return cached_early_expiration_threshold_;
 
@@ -217,24 +198,20 @@
     threshold = 1L;
   }
 
-  cached_early_expiration_threshold_ = Time::FromInternalValue(threshold);
+  cached_early_expiration_threshold_ = base::Time::FromInternalValue(threshold);
   return cached_early_expiration_threshold_;
 }
 
-void HistoryDatabase::UpdateEarlyExpirationThreshold(Time threshold) {
+void HistoryDatabase::UpdateEarlyExpirationThreshold(base::Time threshold) {
   meta_table_.SetValue(kEarlyExpirationThresholdKey,
                        threshold.ToInternalValue());
   cached_early_expiration_threshold_ = threshold;
 }
 
-sqlite3* HistoryDatabase::GetDB() {
+sql::Connection& HistoryDatabase::GetDB() {
   return db_;
 }
 
-SqliteStatementCache& HistoryDatabase::GetStatementCache() {
-  return *statement_cache_;
-}
-
 // Migration -------------------------------------------------------------------
 
 InitStatus HistoryDatabase::EnsureCurrentVersion(
@@ -294,21 +271,18 @@
   // Update all the times in the URLs and visits table in the main database.
   // For visits, clear the indexed flag since we'll delete the FTS databases in
   // the next step.
-  sqlite3_exec(GetDB(),
+  db_.Execute(
       "UPDATE urls "
       "SET last_visit_time = last_visit_time + 11644473600000000 "
-      "WHERE id IN (SELECT id FROM urls WHERE last_visit_time > 0);",
-      NULL, NULL, NULL);
-  sqlite3_exec(GetDB(),
+      "WHERE id IN (SELECT id FROM urls WHERE last_visit_time > 0);");
+  db_.Execute(
       "UPDATE visits "
       "SET visit_time = visit_time + 11644473600000000, is_indexed = 0 "
-      "WHERE id IN (SELECT id FROM visits WHERE visit_time > 0);",
-      NULL, NULL, NULL);
-  sqlite3_exec(GetDB(),
+      "WHERE id IN (SELECT id FROM visits WHERE visit_time > 0);");
+  db_.Execute(
       "UPDATE segment_usage "
       "SET time_slot = time_slot + 11644473600000000 "
-      "WHERE id IN (SELECT id FROM segment_usage WHERE time_slot > 0);",
-      NULL, NULL, NULL);
+      "WHERE id IN (SELECT id FROM segment_usage WHERE time_slot > 0);");
 
   // Erase all the full text index files. These will take a while to update and
   // are less important, so we just blow them away. Same with the archived
diff --git a/chrome/browser/history/history_database.h b/chrome/browser/history/history_database.h
index 9351c26..560b699 100644
--- a/chrome/browser/history/history_database.h
+++ b/chrome/browser/history/history_database.h
@@ -1,10 +1,12 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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_HISTORY_HISTORY_DATABASE_H_
 #define CHROME_BROWSER_HISTORY_HISTORY_DATABASE_H_
 
+#include "app/sql/connection.h"
+#include "app/sql/meta_table.h"
 #include "build/build_config.h"
 #include "chrome/browser/history/download_database.h"
 #include "chrome/browser/history/history_types.h"
@@ -12,9 +14,6 @@
 #include "chrome/browser/history/url_database.h"
 #include "chrome/browser/history/visit_database.h"
 #include "chrome/browser/history/visitsegment_database.h"
-#include "chrome/browser/meta_table_helper.h"
-
-struct sqlite3;
 
 class FilePath;
 
@@ -85,7 +84,7 @@
   void BeginTransaction();
   void CommitTransaction();
   int transaction_nesting() const {  // for debugging and assertion purposes
-    return transaction_nesting_;
+    return db_.transaction_nesting();
   }
 
   // Drops all tables except the URL, and download tables, and recreates them
@@ -142,8 +141,7 @@
 
  private:
   // Implemented for URLDatabase.
-  virtual sqlite3* GetDB();
-  virtual SqliteStatementCache& GetStatementCache();
+  virtual sql::Connection& GetDB();
 
   // Migration -----------------------------------------------------------------
 
@@ -164,20 +162,9 @@
 
   // ---------------------------------------------------------------------------
 
-  // How many nested transactions are pending? When this gets to 0, we commit.
-  int transaction_nesting_;
+  sql::Connection db_;
+  sql::MetaTable meta_table_;
 
-  // The database. The closer automatically closes the deletes the db and the
-  // statement cache. These must be done in a specific order, so we don't want
-  // to rely on C++'s implicit destructors for the individual objects.
-  //
-  // The close scoper will free the database and delete the statement cache in
-  // the correct order automatically when we are destroyed.
-  DBCloseScoper db_closer_;
-  sqlite3* db_;
-  SqliteStatementCache* statement_cache_;
-
-  MetaTableHelper meta_table_;
   base::Time cached_early_expiration_threshold_;
 
   // See the getter above.
diff --git a/chrome/browser/history/history_unittest.cc b/chrome/browser/history/history_unittest.cc
index 55bac89..be84f014 100644
--- a/chrome/browser/history/history_unittest.cc
+++ b/chrome/browser/history/history_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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.
 
@@ -20,6 +20,8 @@
 #include <time.h>
 #include <algorithm>
 
+#include "app/sql/connection.h"
+#include "app/sql/statement.h"
 #include "base/basictypes.h"
 #include "base/file_path.h"
 #include "base/file_util.h"
@@ -39,7 +41,6 @@
 #include "chrome/browser/history/page_usage_data.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/notification_service.h"
-#include "chrome/common/sqlite_utils.h"
 #include "chrome/common/thumbnail_score.h"
 #include "chrome/tools/profiles/thumbnail-inl.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -738,19 +739,16 @@
 
   int cur_version = HistoryDatabase::GetCurrentVersion();
 
-  sqlite3* db;
-  ASSERT_EQ(SQLITE_OK, OpenSqliteDb(file, &db));
+  sql::Connection db;
+  ASSERT_TRUE(db.Open(file));
 
   {
-    SQLStatement s;
-    ASSERT_EQ(SQLITE_OK, s.prepare(db,
+    sql::Statement s(db.GetUniqueStatement(
         "SELECT value FROM meta WHERE key = 'version'"));
-    EXPECT_EQ(SQLITE_ROW, s.step());
-    int file_version = s.column_int(0);
+    EXPECT_TRUE(s.Step());
+    int file_version = s.ColumnInt(0);
     EXPECT_EQ(cur_version, file_version);
   }
-
-  ASSERT_EQ(SQLITE_OK, sqlite3_close(db));
 }
 
 namespace {
diff --git a/chrome/browser/history/in_memory_database.cc b/chrome/browser/history/in_memory_database.cc
index 245b75d..f5bff01 100644
--- a/chrome/browser/history/in_memory_database.cc
+++ b/chrome/browser/history/in_memory_database.cc
@@ -1,50 +1,46 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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/history/in_memory_database.h"
 
+#include "base/file_path.h"
 #include "base/histogram.h"
 #include "base/logging.h"
 #include "base/string_util.h"
 #include "base/time.h"
+#include "build/build_config.h"
 
 namespace history {
 
-InMemoryDatabase::InMemoryDatabase()
-    : URLDatabase(),
-      db_(NULL),
-      statement_cache_(NULL) {
+InMemoryDatabase::InMemoryDatabase() : URLDatabase() {
 }
 
 InMemoryDatabase::~InMemoryDatabase() {
 }
 
 bool InMemoryDatabase::InitDB() {
-  DCHECK(!db_) << "Already initialized!";
-  if (sqlite3_open(":memory:", &db_) != SQLITE_OK) {
-    NOTREACHED() << "Cannot open memory database";
+  // Set the database page size to 4K for better performance.
+  db_.set_page_size(4096);
+
+  if (!db_.OpenInMemory()) {
+    NOTREACHED() << "Cannot open databse " << GetDB().GetErrorMessage();
     return false;
   }
-  statement_cache_ = new SqliteStatementCache(db_);
-  DBCloseScoper scoper(&db_, &statement_cache_);  // closes the DB on error
 
   // No reason to leave data behind in memory when rows are removed.
-  sqlite3_exec(db_, "PRAGMA auto_vacuum=1", NULL, NULL, NULL);
-  // Set the database page size to 4K for better performance.
-  sqlite3_exec(db_, "PRAGMA page_size=4096", NULL, NULL, NULL);
+  db_.Execute("PRAGMA auto_vacuum=1");
+
   // Ensure this is really an in-memory-only cache.
-  sqlite3_exec(db_, "PRAGMA temp_store=MEMORY", NULL, NULL, NULL);
+  db_.Execute("PRAGMA temp_store=MEMORY");
 
   // Create the URL table, but leave it empty for now.
   if (!CreateURLTable(false)) {
     NOTREACHED() << "Unable to create table";
+    db_.Close();
     return false;
   }
 
-  // Succeeded, keep the DB open.
-  scoper.Detach();
-  db_closer_.Attach(&db_, &statement_cache_);
   return true;
 }
 
@@ -58,38 +54,41 @@
   return true;
 }
 
-bool InMemoryDatabase::InitFromDisk(const std::wstring& history_name) {
+bool InMemoryDatabase::InitFromDisk(const FilePath& history_name) {
   if (!InitDB())
     return false;
 
   // Attach to the history database on disk.  (We can't ATTACH in the middle of
   // a transaction.)
-  SQLStatement attach;
-  if (attach.prepare(db_, "ATTACH ? AS history") != SQLITE_OK) {
+  sql::Statement attach(GetDB().GetUniqueStatement("ATTACH ? AS history"));
+  if (!attach) {
     NOTREACHED() << "Unable to attach to history database.";
     return false;
   }
-  attach.bind_string(0, WideToUTF8(history_name));
-  if (attach.step() != SQLITE_DONE) {
-    NOTREACHED() << "Unable to bind";
+#if defined(OS_POSIX)
+  attach.BindString(0, history_name.value());
+#else
+  attach.BindString(0, WideToUTF8(history_name.value()));
+#endif
+  if (!attach.Run()) {
+    NOTREACHED() << GetDB().GetErrorMessage();
     return false;
   }
 
   // Copy URL data to memory.
   base::TimeTicks begin_load = base::TimeTicks::Now();
-  if (sqlite3_exec(db_,
-      "INSERT INTO urls SELECT * FROM history.urls WHERE typed_count > 0",
-      NULL, NULL, NULL) != SQLITE_OK) {
+  if (!db_.Execute(
+      "INSERT INTO urls SELECT * FROM history.urls WHERE typed_count > 0")) {
     // Unable to get data from the history database. This is OK, the file may
     // just not exist yet.
   }
   base::TimeTicks end_load = base::TimeTicks::Now();
   UMA_HISTOGRAM_MEDIUM_TIMES("History.InMemoryDBPopulate",
                              end_load - begin_load);
-  UMA_HISTOGRAM_COUNTS("History.InMemoryDBItemCount", sqlite3_changes(db_));
+  UMA_HISTOGRAM_COUNTS("History.InMemoryDBItemCount", db_.GetLastChangeCount());
 
   // Detach from the history database on disk.
-  if (sqlite3_exec(db_, "DETACH history", NULL, NULL, NULL) != SQLITE_OK) {
+  if (!db_.Execute("DETACH history")) {
     NOTREACHED() << "Unable to detach from history database.";
     return false;
   }
@@ -101,12 +100,8 @@
   return true;
 }
 
-sqlite3* InMemoryDatabase::GetDB() {
+sql::Connection& InMemoryDatabase::GetDB() {
   return db_;
 }
 
-SqliteStatementCache& InMemoryDatabase::GetStatementCache() {
-  return *statement_cache_;
-}
-
 }  // namespace history
diff --git a/chrome/browser/history/in_memory_database.h b/chrome/browser/history/in_memory_database.h
index 3d526fe..9f28cf29 100644
--- a/chrome/browser/history/in_memory_database.h
+++ b/chrome/browser/history/in_memory_database.h
@@ -1,18 +1,17 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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_HISTORY_HISTORY_MEMORY_DB_H__
-#define CHROME_BROWSER_HISTORY_HISTORY_MEMORY_DB_H__
+#ifndef CHROME_BROWSER_HISTORY_HISTORY_MEMORY_DB_H_
+#define CHROME_BROWSER_HISTORY_HISTORY_MEMORY_DB_H_
 
 #include <string>
 
+#include "app/sql/connection.h"
 #include "base/basictypes.h"
 #include "chrome/browser/history/url_database.h"
 
-struct sqlite3;
-
-class SqliteStatementCache;
+class FilePath;
 
 namespace history {
 
@@ -31,27 +30,22 @@
   // file. Conceptually, the InMemoryHistoryBackend should do the populating
   // after this object does some common initialization, but that would be
   // much slower.
-  bool InitFromDisk(const std::wstring& history_name);
+  bool InitFromDisk(const FilePath& history_name);
 
  protected:
   // Implemented for URLDatabase.
-  virtual sqlite3* GetDB();
-  virtual SqliteStatementCache& GetStatementCache();
+  virtual sql::Connection& GetDB();
 
  private:
   // Initializes the database connection, this is the shared code between
   // InitFromScratch() and InitFromDisk() above. Returns true on success.
   bool InitDB();
 
-  // The close scoper will free the database and delete the statement cache in
-  // the correct order automatically when we are destroyed.
-  DBCloseScoper db_closer_;
-  sqlite3* db_;
-  SqliteStatementCache* statement_cache_;
+  sql::Connection db_;
 
-  DISALLOW_EVIL_CONSTRUCTORS(InMemoryDatabase);
+  DISALLOW_COPY_AND_ASSIGN(InMemoryDatabase);
 };
 
 }  // namespace history
 
-#endif  // CHROME_BROWSER_HISTORY_HISTORY_MEMORY_DB_H__
+#endif  // CHROME_BROWSER_HISTORY_HISTORY_MEMORY_DB_H_
diff --git a/chrome/browser/history/in_memory_history_backend.cc b/chrome/browser/history/in_memory_history_backend.cc
index ab9b34c..d40c581 100644
--- a/chrome/browser/history/in_memory_history_backend.cc
+++ b/chrome/browser/history/in_memory_history_backend.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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.
 
@@ -23,7 +23,7 @@
 InMemoryHistoryBackend::~InMemoryHistoryBackend() {
 }
 
-bool InMemoryHistoryBackend::Init(const std::wstring& history_filename) {
+bool InMemoryHistoryBackend::Init(const FilePath& history_filename) {
   db_.reset(new InMemoryDatabase);
   return db_->InitFromDisk(history_filename);
 }
diff --git a/chrome/browser/history/in_memory_history_backend.h b/chrome/browser/history/in_memory_history_backend.h
index 131a444..b421c5f 100644
--- a/chrome/browser/history/in_memory_history_backend.h
+++ b/chrome/browser/history/in_memory_history_backend.h
@@ -20,6 +20,7 @@
 #include "chrome/common/notification_registrar.h"
 #include "testing/gtest/include/gtest/gtest_prod.h"
 
+class FilePath;
 class HistoryDatabase;
 class Profile;
 
@@ -35,7 +36,7 @@
   ~InMemoryHistoryBackend();
 
   // Initializes with data from the given history database.
-  bool Init(const std::wstring& history_filename);
+  bool Init(const FilePath& history_filename);
 
   // Does initialization work when this object is attached to the history
   // system on the main thread. The argument is the profile with which the
diff --git a/chrome/browser/history/starred_url_database.cc b/chrome/browser/history/starred_url_database.cc
index b56bcd9..7c775744 100644
--- a/chrome/browser/history/starred_url_database.cc
+++ b/chrome/browser/history/starred_url_database.cc
@@ -1,9 +1,11 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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/history/starred_url_database.h"
 
+#include "app/sql/connection.h"
+#include "app/sql/statement.h"
 #include "base/file_util.h"
 #include "base/logging.h"
 #include "base/json_writer.h"
@@ -16,10 +18,6 @@
 #include "chrome/browser/history/history.h"
 #include "chrome/browser/history/query_parser.h"
 #include "chrome/browser/meta_table_helper.h"
-#include "chrome/common/sqlite_compiled_statement.h"
-#include "chrome/common/sqlite_utils.h"
-
-using base::Time;
 
 // The following table is used to store star (aka bookmark) information. This
 // class derives from URLDatabase, which has its own schema.
@@ -53,13 +51,13 @@
     "starred.group_id, starred.date_modified "
 const char kHistoryStarFields[] = STAR_FIELDS;
 
-void FillInStarredEntry(SQLStatement* s, StarredEntry* entry) {
+void FillInStarredEntry(const sql::Statement& s, StarredEntry* entry) {
   DCHECK(entry);
-  entry->id = s->column_int64(0);
-  switch (s->column_int(1)) {
+  entry->id = s.ColumnInt64(0);
+  switch (s.ColumnInt(1)) {
     case 0:
       entry->type = history::StarredEntry::URL;
-      entry->url = GURL(WideToUTF8(s->column_wstring(6)));
+      entry->url = GURL(s.ColumnString(6));
       break;
     case 1:
       entry->type = history::StarredEntry::BOOKMARK_BAR;
@@ -74,13 +72,13 @@
       NOTREACHED();
       break;
   }
-  entry->title = s->column_wstring(2);
-  entry->date_added = Time::FromInternalValue(s->column_int64(3));
-  entry->visual_order = s->column_int(4);
-  entry->parent_group_id = s->column_int64(5);
-  entry->url_id = s->column_int64(7);
-  entry->group_id = s->column_int64(8);
-  entry->date_group_modified = Time::FromInternalValue(s->column_int64(9));
+  entry->title = UTF8ToWide(s.ColumnString(2));
+  entry->date_added = base::Time::FromInternalValue(s.ColumnInt64(3));
+  entry->visual_order = s.ColumnInt(4);
+  entry->parent_group_id = s.ColumnInt64(5);
+  entry->url_id = s.ColumnInt64(7);
+  entry->group_id = s.ColumnInt64(8);
+  entry->date_group_modified = base::Time::FromInternalValue(s.ColumnInt64(9));
 }
 
 }  // namespace
@@ -92,7 +90,7 @@
 }
 
 bool StarredURLDatabase::MigrateBookmarksToFile(const FilePath& path) {
-  if (!DoesSqliteTableExist(GetDB(), "starred"))
+  if (!GetDB().DoesTableExist("starred"))
     return true;
 
   if (EnsureStarredIntegrity() && !MigrateBookmarksToFileImpl(path)) {
@@ -100,8 +98,7 @@
     return false;
   }
 
-  if (sqlite3_exec(GetDB(), "DROP TABLE starred", NULL, NULL,
-                   NULL) != SQLITE_OK) {
+  if (!GetDB().Execute("DROP TABLE starred")) {
     NOTREACHED() << "Unable to drop starred table";
     return false;
   }
@@ -116,15 +113,15 @@
   sql.append("FROM starred LEFT JOIN urls ON starred.url_id = urls.id ");
   sql += "ORDER BY parent_id, visual_order";
 
-  SQLStatement s;
-  if (s.prepare(GetDB(), sql.c_str()) != SQLITE_OK) {
+  sql::Statement s(GetDB().GetUniqueStatement(sql.c_str()));
+  if (!s) {
     NOTREACHED() << "Statement prepare failed";
     return false;
   }
 
   history::StarredEntry entry;
-  while (s.step() == SQLITE_ROW) {
-    FillInStarredEntry(&s, &entry);
+  while (s.Step()) {
+    FillInStarredEntry(s, &entry);
     // Reset the url for non-url types. This is needed as we're reusing the
     // same entry for the loop.
     if (entry.type != history::StarredEntry::URL)
@@ -157,104 +154,104 @@
                                                const std::wstring& title,
                                                UIStarID parent_group_id,
                                                int visual_order,
-                                               Time date_modified) {
+                                               base::Time date_modified) {
   DCHECK(star_id && visual_order >= 0);
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "UPDATE starred SET title=?, parent_id=?, visual_order=?, "
-      "date_modified=? WHERE id=?");
-  if (!statement.is_valid())
+      "date_modified=? WHERE id=?"));
+  if (!statement)
     return 0;
 
-  statement->bind_wstring(0, title);
-  statement->bind_int64(1, parent_group_id);
-  statement->bind_int(2, visual_order);
-  statement->bind_int64(3, date_modified.ToInternalValue());
-  statement->bind_int64(4, star_id);
-  return statement->step() == SQLITE_DONE;
+  statement.BindString(0, WideToUTF8(title));
+  statement.BindInt64(1, parent_group_id);
+  statement.BindInt(2, visual_order);
+  statement.BindInt64(3, date_modified.ToInternalValue());
+  statement.BindInt64(4, star_id);
+  return statement.Run();
 }
 
 bool StarredURLDatabase::AdjustStarredVisualOrder(UIStarID parent_group_id,
                                                   int start_visual_order,
                                                   int delta) {
   DCHECK(parent_group_id && start_visual_order >= 0);
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "UPDATE starred SET visual_order=visual_order+? "
-      "WHERE parent_id=? AND visual_order >= ?");
-  if (!statement.is_valid())
+      "WHERE parent_id=? AND visual_order >= ?"));
+  if (!statement)
     return false;
 
-  statement->bind_int(0, delta);
-  statement->bind_int64(1, parent_group_id);
-  statement->bind_int(2, start_visual_order);
-  return statement->step() == SQLITE_DONE;
+  statement.BindInt(0, delta);
+  statement.BindInt64(1, parent_group_id);
+  statement.BindInt(2, start_visual_order);
+  return statement.Run();
 }
 
 StarID StarredURLDatabase::CreateStarredEntryRow(URLID url_id,
                                                  UIStarID group_id,
                                                  UIStarID parent_group_id,
                                                  const std::wstring& title,
-                                                 const Time& date_added,
+                                                 const base::Time& date_added,
                                                  int visual_order,
                                                  StarredEntry::Type type) {
   DCHECK(visual_order >= 0 &&
          (type != history::StarredEntry::URL || url_id));
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "INSERT INTO starred "
       "(type, url_id, group_id, title, date_added, visual_order, parent_id, "
-      "date_modified) VALUES (?,?,?,?,?,?,?,?)");
-  if (!statement.is_valid())
+      "date_modified) VALUES (?,?,?,?,?,?,?,?)"));
+  if (!statement)
     return 0;
 
   switch (type) {
     case history::StarredEntry::URL:
-      statement->bind_int(0, 0);
+      statement.BindInt(0, 0);
       break;
     case history::StarredEntry::BOOKMARK_BAR:
-      statement->bind_int(0, 1);
+      statement.BindInt(0, 1);
       break;
     case history::StarredEntry::USER_GROUP:
-      statement->bind_int(0, 2);
+      statement.BindInt(0, 2);
       break;
     case history::StarredEntry::OTHER:
-      statement->bind_int(0, 3);
+      statement.BindInt(0, 3);
       break;
     default:
       NOTREACHED();
   }
-  statement->bind_int64(1, url_id);
-  statement->bind_int64(2, group_id);
-  statement->bind_wstring(3, title);
-  statement->bind_int64(4, date_added.ToInternalValue());
-  statement->bind_int(5, visual_order);
-  statement->bind_int64(6, parent_group_id);
-  statement->bind_int64(7, Time().ToInternalValue());
-  if (statement->step() == SQLITE_DONE)
-    return sqlite3_last_insert_rowid(GetDB());
+  statement.BindInt64(1, url_id);
+  statement.BindInt64(2, group_id);
+  statement.BindString(3, WideToUTF8(title));
+  statement.BindInt64(4, date_added.ToInternalValue());
+  statement.BindInt(5, visual_order);
+  statement.BindInt64(6, parent_group_id);
+  statement.BindInt64(7, base::Time().ToInternalValue());
+  if (statement.Run())
+    return GetDB().GetLastInsertRowId();
   return 0;
 }
 
 bool StarredURLDatabase::DeleteStarredEntryRow(StarID star_id) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-                          "DELETE FROM starred WHERE id=?");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "DELETE FROM starred WHERE id=?"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, star_id);
-  return statement->step() == SQLITE_DONE;
+  statement.BindInt64(0, star_id);
+  return statement.Run();
 }
 
 bool StarredURLDatabase::GetStarredEntry(StarID star_id, StarredEntry* entry) {
   DCHECK(entry && star_id);
-  SQLITE_UNIQUE_STATEMENT(s, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT" STAR_FIELDS "FROM starred LEFT JOIN urls ON "
-      "starred.url_id = urls.id WHERE starred.id=?");
-  if (!s.is_valid())
+      "starred.url_id = urls.id WHERE starred.id=?"));
+  if (!statement)
     return false;
 
-  s->bind_int64(0, star_id);
+  statement.BindInt64(0, star_id);
 
-  if (s->step() == SQLITE_ROW) {
-    FillInStarredEntry(s.statement(), entry);
+  if (statement.Step()) {
+    FillInStarredEntry(statement, entry);
     return true;
   }
   return false;
@@ -306,17 +303,17 @@
 }
 
 UIStarID StarredURLDatabase::GetMaxGroupID() {
-  SQLStatement max_group_id_statement;
-  if (max_group_id_statement.prepare(GetDB(),
-      "SELECT MAX(group_id) FROM starred") != SQLITE_OK) {
-    NOTREACHED();
+  sql::Statement max_group_id_statement(GetDB().GetUniqueStatement(
+      "SELECT MAX(group_id) FROM starred"));
+  if (!max_group_id_statement) {
+    NOTREACHED() << GetDB().GetErrorMessage();
     return 0;
   }
-  if (max_group_id_statement.step() != SQLITE_ROW) {
-    NOTREACHED();
+  if (!max_group_id_statement.Step()) {
+    NOTREACHED() << GetDB().GetErrorMessage();
     return 0;
   }
-  return max_group_id_statement.column_int64(0);
+  return max_group_id_statement.ColumnInt64(0);
 }
 
 bool StarredURLDatabase::BuildStarNodes(
@@ -451,7 +448,7 @@
       return false;
     }
     entry.id = CreateStarredEntryRow(
-        0, entry.group_id, 0, L"other", Time::Now(), 0,
+        0, entry.group_id, 0, L"other", base::Time::Now(), 0,
         history::StarredEntry::OTHER);
     if (!entry.id) {
       NOTREACHED() << "Unable to create other bookmarks folder";
diff --git a/chrome/browser/history/starred_url_database.h b/chrome/browser/history/starred_url_database.h
index fd11ac2..1dd3337 100644
--- a/chrome/browser/history/starred_url_database.h
+++ b/chrome/browser/history/starred_url_database.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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.
 
@@ -13,9 +13,11 @@
 #include "chrome/browser/history/url_database.h"
 #include "testing/gtest/include/gtest/gtest_prod.h"
 
-struct sqlite3;
 class FilePath;
-class SqliteStatementCache;
+
+namespace sql {
+class Connection;
+}
 
 namespace history {
 
@@ -38,11 +40,8 @@
   // Writes bookmarks to the specified file.
   bool MigrateBookmarksToFile(const FilePath& path);
 
-  // Returns the database and statement cache for the functions in this
-  // interface. The decendent of this class implements these functions to
-  // return its objects.
-  virtual sqlite3* GetDB() = 0;
-  virtual SqliteStatementCache& GetStatementCache() = 0;
+  // Returns the database for the functions in this interface.
+  virtual sql::Connection& GetDB() = 0;
 
  private:
   // Makes sure the starred table is in a sane state. This does the following:
diff --git a/chrome/browser/history/starred_url_database_unittest.cc b/chrome/browser/history/starred_url_database_unittest.cc
index 1c97927..961b240a 100644
--- a/chrome/browser/history/starred_url_database_unittest.cc
+++ b/chrome/browser/history/starred_url_database_unittest.cc
@@ -18,7 +18,7 @@
 class StarredURLDatabaseTest : public testing::Test,
                                public StarredURLDatabase {
  public:
-  StarredURLDatabaseTest() : db_(NULL), statement_cache_(NULL) {
+  StarredURLDatabaseTest() {
   }
 
   void AddPage(const GURL& url) {
@@ -44,7 +44,7 @@
   }
 
   int GetStarredEntryCount() {
-    DCHECK(db_);
+    DCHECK(db_.is_open());
     std::vector<StarredEntry> entries;
     GetAllStarredEntries(&entries);
     return static_cast<int>(entries.size());
@@ -77,8 +77,7 @@
         FILE_PATH_LITERAL("History_with_empty_starred"));
     file_util::CopyFile(old_history_path, db_file_);
 
-    EXPECT_EQ(SQLITE_OK, OpenSqliteDb(db_file_, &db_));
-    statement_cache_ = new SqliteStatementCache(db_);
+    EXPECT_TRUE(db_.Open(db_file_));
 
     // Initialize the tables for this test.
     CreateURLTable(false);
@@ -86,22 +85,17 @@
     EnsureStarredIntegrity();
   }
   void TearDown() {
-    delete statement_cache_;
-    sqlite3_close(db_);
+    db_.Close();
     file_util::Delete(db_file_, false);
   }
 
   // Provided for URL/StarredURLDatabase.
-  virtual sqlite3* GetDB() {
+  virtual sql::Connection& GetDB() {
     return db_;
   }
-  virtual SqliteStatementCache& GetStatementCache() {
-    return *statement_cache_;
-  }
 
   FilePath db_file_;
-  sqlite3* db_;
-  SqliteStatementCache* statement_cache_;
+  sql::Connection db_;
 };
 
 //-----------------------------------------------------------------------------
diff --git a/chrome/browser/history/text_database.cc b/chrome/browser/history/text_database.cc
index e9b37eb..fa46853 100644
--- a/chrome/browser/history/text_database.cc
+++ b/chrome/browser/history/text_database.cc
@@ -35,8 +35,6 @@
 // an FTS table that is indexed like a normal table, and the index over it is
 // free since sqlite always indexes the internal rowid.
 
-using base::Time;
-
 namespace history {
 
 namespace {
@@ -158,7 +156,7 @@
   db_.set_exclusive_locking();
 
   // Attach the database to our index file.
-  if (!db_.Init(file_name_))
+  if (!db_.Open(file_name_))
     return false;
 
   // Meta table tracking version information.
@@ -215,7 +213,7 @@
   return true;
 }
 
-bool TextDatabase::AddPageData(Time time,
+bool TextDatabase::AddPageData(base::Time time,
                                const std::string& url,
                                const std::string& title,
                                const std::string& contents) {
@@ -257,7 +255,7 @@
   return committer.Commit();
 }
 
-void TextDatabase::DeletePageData(Time time, const std::string& url) {
+void TextDatabase::DeletePageData(base::Time time, const std::string& url) {
   // First get all rows that match. Selecing on time (which has an index) allows
   // us to avoid brute-force searches on the full-text-index table (there will
   // generally be only one match per time).
@@ -316,7 +314,7 @@
                                   const QueryOptions& options,
                                   std::vector<Match>* results,
                                   URLSet* found_urls,
-                                  Time* first_time_searched) {
+                                  base::Time* first_time_searched) {
   *first_time_searched = options.begin_time;
 
   sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
@@ -360,7 +358,7 @@
     match.url.Swap(&url);
 
     match.title = UTF8ToWide(statement.ColumnString(1));
-    match.time = Time::FromInternalValue(statement.ColumnInt64(2));
+    match.time = base::Time::FromInternalValue(statement.ColumnInt64(2));
 
     // Extract any matches in the title.
     std::string offsets_str = statement.ColumnString(3);
diff --git a/chrome/browser/history/text_database_manager.cc b/chrome/browser/history/text_database_manager.cc
index 03e992f..868a5d8 100644
--- a/chrome/browser/history/text_database_manager.cc
+++ b/chrome/browser/history/text_database_manager.cc
@@ -72,7 +72,6 @@
                                          URLDatabase* url_database,
                                          VisitDatabase* visit_database)
     : dir_(dir),
-      db_(NULL),
       url_database_(url_database),
       visit_database_(visit_database),
       recent_changes_(RecentChangeList::NO_AUTO_EVICT),
diff --git a/chrome/browser/history/text_database_manager.h b/chrome/browser/history/text_database_manager.h
index 85b9992..b27b9db8 100644
--- a/chrome/browser/history/text_database_manager.h
+++ b/chrome/browser/history/text_database_manager.h
@@ -244,10 +244,6 @@
   // Directory holding our index files.
   const FilePath dir_;
 
-  // The database connection.
-  sqlite3* db_;
-  DBCloseScoper db_close_scoper_;
-
   // Non-owning pointers to the recent history databases for URLs and visits.
   URLDatabase* url_database_;
   VisitDatabase* visit_database_;
diff --git a/chrome/browser/history/text_database_manager_unittest.cc b/chrome/browser/history/text_database_manager_unittest.cc
index 9762ec1f..ea23e96 100644
--- a/chrome/browser/history/text_database_manager_unittest.cc
+++ b/chrome/browser/history/text_database_manager_unittest.cc
@@ -1,7 +1,8 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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 "app/sql/connection.h"
 #include "base/file_path.h"
 #include "base/file_util.h"
 #include "base/message_loop.h"
@@ -43,26 +44,19 @@
 class InMemDB : public URLDatabase, public VisitDatabase {
  public:
   InMemDB() {
-    sqlite3_open(":memory:", &db_);
-    statement_cache_ = new SqliteStatementCache(db_);
+    EXPECT_TRUE(db_.OpenInMemory());
     CreateURLTable(false);
     InitVisitTable();
   }
   ~InMemDB() {
-    delete statement_cache_;
-    sqlite3_close(db_);
   }
 
  private:
-  virtual sqlite3* GetDB() { return db_; }
-  virtual SqliteStatementCache& GetStatementCache() {
-    return *statement_cache_;
-  }
+  virtual sql::Connection& GetDB() { return db_; }
 
-  sqlite3* db_;
-  SqliteStatementCache* statement_cache_;
+  sql::Connection db_;
 
-  DISALLOW_EVIL_CONSTRUCTORS(InMemDB);
+  DISALLOW_COPY_AND_ASSIGN(InMemDB);
 };
 
 // Adds all the pages once, and the first page once more in the next month.
diff --git a/chrome/browser/history/thumbnail_database.cc b/chrome/browser/history/thumbnail_database.cc
index f3bdeca..735440f6 100644
--- a/chrome/browser/history/thumbnail_database.cc
+++ b/chrome/browser/history/thumbnail_database.cc
@@ -1,32 +1,27 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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/history/thumbnail_database.h"
 
+#include "app/sql/statement.h"
+#include "app/sql/transaction.h"
 #include "base/file_util.h"
 #include "base/gfx/jpeg_codec.h"
 #include "base/time.h"
 #include "base/string_util.h"
 #include "chrome/browser/history/history_publisher.h"
 #include "chrome/browser/history/url_database.h"
-#include "chrome/common/sqlite_utils.h"
 #include "chrome/common/thumbnail_score.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
-using base::Time;
-
 namespace history {
 
 // Version number of the database.
 static const int kCurrentVersionNumber = 3;
 static const int kCompatibleVersionNumber = 3;
 
-ThumbnailDatabase::ThumbnailDatabase()
-    : db_(NULL),
-      statement_cache_(NULL),
-      transaction_nesting_(0),
-      history_publisher_(NULL) {
+ThumbnailDatabase::ThumbnailDatabase() : history_publisher_(NULL) {
 }
 
 ThumbnailDatabase::~ThumbnailDatabase() {
@@ -37,18 +32,13 @@
                                    const HistoryPublisher* history_publisher) {
   history_publisher_ = history_publisher;
 
-  // OpenSqliteDb uses the narrow version of open, so the resulting DB is in
-  // UTF-8.
-  if (OpenSqliteDb(db_name, &db_) != SQLITE_OK)
-    return INIT_FAILURE;
-
   // Set the database page size to something  larger to give us
   // better performance (we're typically seek rather than bandwidth limited).
   // This only has an effect before any tables have been created, otherwise
   // this is a NOP. Must be a power of 2 and a max of 8192. We use a bigger
   // one because we're storing larger data (4-16K) in it, so we want a few
   // blocks per element.
-  sqlite3_exec(db_, "PRAGMA page_size=4096", NULL, NULL, NULL);
+  db_.set_page_size(4096);
 
   // The UI is generally designed to work well when the thumbnail database is
   // slow, so we can tolerate much less caching. The file is also very large
@@ -56,25 +46,27 @@
   // reducing the benefit of caching in the first place. With the default cache
   // size of 2000 pages, it will take >8MB of memory, so reducing it can be a
   // big savings.
-  sqlite3_exec(db_, "PRAGMA cache_size=64", NULL, NULL, NULL);
+  db_.set_cache_size(64);
 
   // Run the database in exclusive mode. Nobody else should be accessing the
   // database while we're running, and this will give somewhat improved perf.
-  sqlite3_exec(db_, "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, NULL);
+  db_.set_exclusive_locking();
 
-  statement_cache_ = new SqliteStatementCache;
-  DBCloseScoper scoper(&db_, &statement_cache_);
+  if (!db_.Open(db_name))
+    return INIT_FAILURE;
 
   // Scope initialization in a transaction so we can't be partially initialized.
-  SQLTransaction transaction(db_);
+  sql::Transaction transaction(&db_);
   transaction.Begin();
 
   // Create the tables.
-  if (!meta_table_.Init(std::string(), kCurrentVersionNumber,
-                        kCompatibleVersionNumber, db_) ||
+  if (!meta_table_.Init(&db_, kCurrentVersionNumber,
+                        kCompatibleVersionNumber) ||
       !InitThumbnailTable() ||
-      !InitFavIconsTable(false))
+      !InitFavIconsTable(false)) {
+    db_.Close();
     return INIT_FAILURE;
+  }
   InitFavIconsIndex();
 
   // Version check. We should not encounter a database too old for us to handle
@@ -88,6 +80,7 @@
   if (cur_version == 2) {
     if (!UpgradeToVersion3()) {
       LOG(WARNING) << "Unable to update to thumbnail database to version 3.";
+      db_.Close();
       return INIT_FAILURE;
     }
     ++cur_version;
@@ -97,13 +90,10 @@
       "Thumbnail database version " << cur_version << " is too old to handle.";
 
   // Initialization is complete.
-  if (transaction.Commit() != SQLITE_OK)
+  if (!transaction.Commit()) {
+    db_.Close();
     return INIT_FAILURE;
-
-  // Initialize the statement cache and the scoper to automatically close it.
-  statement_cache_->set_db(db_);
-  scoper.Detach();
-  close_scoper_.Attach(&db_, &statement_cache_);
+  }
 
   // The following code is useful in debugging the thumbnail database. Upon
   // startup, it will spit out a file for each thumbnail in the database so you
@@ -111,12 +101,12 @@
   // into the string below (I recommend using a blank directory since there may
   // be a lot of files).
 #if 0
-  SQLStatement statement;
-  statement.prepare(db_, "SELECT id, image_data FROM favicons");
-  while (statement.step() == SQLITE_ROW) {
-    int idx = statement.column_int(0);
+  sql::Statement statement(db_.GetUniqueStatement(
+      "SELECT id, image_data FROM favicons"));
+  while (statement.Step()) {
+    int idx = statement.ColumnInt(0);
     std::vector<unsigned char> data;
-    statement.column_blob_as_vector(1, &data);
+    statement.ColumnBlobAsVector(1, &data);
 
     char filename[256];
     sprintf(filename, "<<< YOUR PATH HERE >>>\\%d.png", idx);
@@ -132,14 +122,14 @@
 }
 
 bool ThumbnailDatabase::InitThumbnailTable() {
-  if (!DoesSqliteTableExist(db_, "thumbnails")) {
-    if (sqlite3_exec(db_, "CREATE TABLE thumbnails ("
+  if (!db_.DoesTableExist("thumbnails")) {
+    if (!db_.Execute("CREATE TABLE thumbnails ("
         "url_id INTEGER PRIMARY KEY,"
         "boring_score DOUBLE DEFAULT 1.0,"
         "good_clipping INTEGER DEFAULT 0,"
         "at_top INTEGER DEFAULT 0,"
         "last_updated INTEGER DEFAULT 0,"
-        "data BLOB)", NULL, NULL, NULL) != SQLITE_OK)
+        "data BLOB)"))
       return false;
   }
   return true;
@@ -157,8 +147,7 @@
   };
 
   for (int i = 0; alterations[i] != NULL; ++i) {
-    if (sqlite3_exec(db_, alterations[i],
-                     NULL, NULL, NULL) != SQLITE_OK) {
+    if (!db_.Execute(alterations[i])) {
       NOTREACHED();
       return false;
     }
@@ -170,7 +159,7 @@
 }
 
 bool ThumbnailDatabase::RecreateThumbnailTable() {
-  if (sqlite3_exec(db_, "DROP TABLE thumbnails", NULL, NULL, NULL) != SQLITE_OK)
+  if (!db_.Execute("DROP TABLE thumbnails"))
     return false;
   return InitThumbnailTable();
 }
@@ -179,7 +168,7 @@
   // Note: if you update the schema, don't forget to update
   // CopyToTemporaryFaviconTable as well.
   const char* name = is_temporary ? "temp_favicons" : "favicons";
-  if (!DoesSqliteTableExist(db_, name)) {
+  if (!db_.DoesTableExist(name)) {
     std::string sql;
     sql.append("CREATE TABLE ");
     sql.append(name);
@@ -188,7 +177,7 @@
                "url LONGVARCHAR NOT NULL,"
                "last_updated INTEGER DEFAULT 0,"
                "image_data BLOB)");
-    if (sqlite3_exec(db_, sql.c_str(), NULL, NULL, NULL) != SQLITE_OK)
+    if (!db_.Execute(sql.c_str()))
       return false;
   }
   return true;
@@ -197,33 +186,21 @@
 void ThumbnailDatabase::InitFavIconsIndex() {
   // Add an index on the url column. We ignore errors. Since this is always
   // called during startup, the index will normally already exist.
-  sqlite3_exec(db_, "CREATE INDEX favicons_url ON favicons(url)",
-               NULL, NULL, NULL);
+  db_.Execute("CREATE INDEX favicons_url ON favicons(url)");
 }
 
 void ThumbnailDatabase::BeginTransaction() {
-  DCHECK(db_);
-  if (transaction_nesting_ == 0) {
-    int rv = sqlite3_exec(db_, "BEGIN TRANSACTION", NULL, NULL, NULL);
-    DCHECK(rv == SQLITE_OK) << "Failed to begin transaction";
-  }
-  transaction_nesting_++;
+  db_.BeginTransaction();
 }
 
 void ThumbnailDatabase::CommitTransaction() {
-  DCHECK(db_);
-  DCHECK(transaction_nesting_ > 0) << "Committing too many transaction";
-  transaction_nesting_--;
-  if (transaction_nesting_ == 0) {
-    int rv = sqlite3_exec(db_, "COMMIT", NULL, NULL, NULL);
-    DCHECK(rv == SQLITE_OK) << "Failed to commit transaction";
-  }
+  db_.CommitTransaction();
 }
 
 void ThumbnailDatabase::Vacuum() {
-  DCHECK(transaction_nesting_ == 0) <<
+  DCHECK(db_.transaction_nesting() == 0) <<
       "Can not have a transaction when vacuuming.";
-  sqlite3_exec(db_, "VACUUM", NULL, NULL, NULL);
+  db_.Execute("VACUUM");
 }
 
 void ThumbnailDatabase::SetPageThumbnail(
@@ -231,7 +208,7 @@
     URLID id,
     const SkBitmap& thumbnail,
     const ThumbnailScore& score,
-    const Time& time) {
+    base::Time time) {
   if (!thumbnail.isNull()) {
     bool add_thumbnail = true;
     ThumbnailScore current_score;
@@ -240,12 +217,11 @@
     }
 
     if (add_thumbnail) {
-      SQLITE_UNIQUE_STATEMENT(
-          statement, *statement_cache_,
+      sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
           "INSERT OR REPLACE INTO thumbnails "
           "(url_id, boring_score, good_clipping, at_top, last_updated, data) "
-          "VALUES (?,?,?,?,?,?)");
-      if (!statement.is_valid())
+          "VALUES (?,?,?,?,?,?)"));
+      if (!statement)
         return;
 
       // We use 90 quality (out of 100) which is pretty high, because
@@ -261,15 +237,15 @@
           &jpeg_data);
 
       if (encoded) {
-        statement->bind_int64(0, id);
-        statement->bind_double(1, score.boring_score);
-        statement->bind_bool(2, score.good_clipping);
-        statement->bind_bool(3, score.at_top);
-        statement->bind_int64(4, score.time_at_snapshot.ToTimeT());
-        statement->bind_blob(5, &jpeg_data[0],
-                             static_cast<int>(jpeg_data.size()));
-        if (statement->step() != SQLITE_DONE)
-          DLOG(WARNING) << "Unable to insert thumbnail";
+        statement.BindInt64(0, id);
+        statement.BindDouble(1, score.boring_score);
+        statement.BindBool(2, score.good_clipping);
+        statement.BindBool(3, score.at_top);
+        statement.BindInt64(4, score.time_at_snapshot.ToTimeT());
+        statement.BindBlob(5, &jpeg_data[0],
+                           static_cast<int>(jpeg_data.size()));
+        if (!statement.Run())
+          NOTREACHED() << db_.GetErrorMessage();
       }
 
       // Publish the thumbnail to any indexers listening to us.
@@ -278,55 +254,53 @@
         history_publisher_->PublishPageThumbnail(jpeg_data, url, time);
     }
   } else {
-    if ( !DeleteThumbnail(id) )
+    if (!DeleteThumbnail(id) )
       DLOG(WARNING) << "Unable to delete thumbnail";
   }
 }
 
 bool ThumbnailDatabase::GetPageThumbnail(URLID id,
                                          std::vector<unsigned char>* data) {
-  SQLITE_UNIQUE_STATEMENT(
-      statement, *statement_cache_,
-      "SELECT data FROM thumbnails WHERE url_id=?");
-  if (!statement.is_valid())
+  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+      "SELECT data FROM thumbnails WHERE url_id=?"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, id);
-  if (statement->step() != SQLITE_ROW)
+  statement.BindInt64(0, id);
+  if (!statement.Step())
     return false;  // don't have a thumbnail for this ID
 
-  return statement->column_blob_as_vector(0, data);
+  statement.ColumnBlobAsVector(0, data);
+  return true;
 }
 
 bool ThumbnailDatabase::DeleteThumbnail(URLID id) {
-  SQLITE_UNIQUE_STATEMENT(
-      statement, *statement_cache_,
-      "DELETE FROM thumbnails WHERE url_id = ?");
-  if (!statement.is_valid())
+  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+      "DELETE FROM thumbnails WHERE url_id = ?"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, id);
-  return statement->step() == SQLITE_DONE;
+  statement.BindInt64(0, id);
+  return statement.Run();
 }
 
-bool ThumbnailDatabase::ThumbnailScoreForId(
-    URLID id,
-    ThumbnailScore* score) {
+bool ThumbnailDatabase::ThumbnailScoreForId(URLID id,
+                                            ThumbnailScore* score) {
   // Fetch the current thumbnail's information to make sure we
   // aren't replacing a good thumbnail with one that's worse.
-  SQLITE_UNIQUE_STATEMENT(
-      select_statement, *statement_cache_,
+  sql::Statement select_statement(db_.GetCachedStatement(SQL_FROM_HERE,
       "SELECT boring_score, good_clipping, at_top, last_updated "
-      "FROM thumbnails WHERE url_id=?");
-  if (!select_statement.is_valid()) {
+      "FROM thumbnails WHERE url_id=?"));
+  if (!select_statement) {
     NOTREACHED() << "Couldn't build select statement!";
   } else {
-    select_statement->bind_int64(0, id);
-    if (select_statement->step() == SQLITE_ROW) {
-      double current_boring_score = select_statement->column_double(0);
-      bool current_clipping = select_statement->column_bool(1);
-      bool current_at_top = select_statement->column_bool(2);
-      Time last_updated = Time::FromTimeT(select_statement->column_int64(3));
+    select_statement.BindInt64(0, id);
+    if (select_statement.Step()) {
+      double current_boring_score = select_statement.ColumnDouble(0);
+      bool current_clipping = select_statement.ColumnBool(1);
+      bool current_at_top = select_statement.ColumnBool(2);
+      base::Time last_updated =
+          base::Time::FromTimeT(select_statement.ColumnInt64(3));
       *score = ThumbnailScore(current_boring_score, current_clipping,
                               current_at_top, last_updated);
       return true;
@@ -338,131 +312,125 @@
 
 bool ThumbnailDatabase::SetFavIcon(URLID icon_id,
                                    const std::vector<unsigned char>& icon_data,
-                                   Time time) {
+                                   base::Time time) {
   DCHECK(icon_id);
   if (icon_data.size()) {
-    SQLITE_UNIQUE_STATEMENT(
-        statement, *statement_cache_,
-        "UPDATE favicons SET image_data=?, last_updated=? WHERE id=?");
-    if (!statement.is_valid())
+    sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+        "UPDATE favicons SET image_data=?, last_updated=? WHERE id=?"));
+    if (!statement)
       return 0;
 
-    statement->bind_blob(0, &icon_data.front(),
-                        static_cast<int>(icon_data.size()));
-    statement->bind_int64(1, time.ToTimeT());
-    statement->bind_int64(2, icon_id);
-    return statement->step() == SQLITE_DONE;
+    statement.BindBlob(0, &icon_data.front(),
+                       static_cast<int>(icon_data.size()));
+    statement.BindInt64(1, time.ToTimeT());
+    statement.BindInt64(2, icon_id);
+    return statement.Run();
   } else {
-    SQLITE_UNIQUE_STATEMENT(
-        statement, *statement_cache_,
-        "UPDATE favicons SET image_data=NULL, last_updated=? WHERE id=?");
-    if (!statement.is_valid())
+    sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+        "UPDATE favicons SET image_data=NULL, last_updated=? WHERE id=?"));
+    if (!statement)
       return 0;
 
-    statement->bind_int64(0, time.ToTimeT());
-    statement->bind_int64(1, icon_id);
-    return statement->step() == SQLITE_DONE;
+    statement.BindInt64(0, time.ToTimeT());
+    statement.BindInt64(1, icon_id);
+    return statement.Run();
   }
 }
 
 bool ThumbnailDatabase::SetFavIconLastUpdateTime(FavIconID icon_id,
-                                                 const Time& time) {
-  SQLITE_UNIQUE_STATEMENT(
-      statement, *statement_cache_,
-      "UPDATE favicons SET last_updated=? WHERE id=?");
-  if (!statement.is_valid())
+                                                 base::Time time) {
+  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+      "UPDATE favicons SET last_updated=? WHERE id=?"));
+  if (!statement)
     return 0;
 
-  statement->bind_int64(0, time.ToTimeT());
-  statement->bind_int64(1, icon_id);
-  return statement->step() == SQLITE_DONE;
+  statement.BindInt64(0, time.ToTimeT());
+  statement.BindInt64(1, icon_id);
+  return statement.Run();
 }
 
 FavIconID ThumbnailDatabase::GetFavIconIDForFavIconURL(const GURL& icon_url) {
-  SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_,
-                          "SELECT id FROM favicons WHERE url=?");
-  if (!statement.is_valid())
+  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+      "SELECT id FROM favicons WHERE url=?"));
+  if (!statement)
     return 0;
 
-  statement->bind_string(0, URLDatabase::GURLToDatabaseURL(icon_url));
-  if (statement->step() != SQLITE_ROW)
+  statement.BindString(0, URLDatabase::GURLToDatabaseURL(icon_url));
+  if (!statement.Step())
     return 0;  // not cached
 
-  return statement->column_int64(0);
+  return statement.ColumnInt64(0);
 }
 
 bool ThumbnailDatabase::GetFavIcon(
     FavIconID icon_id,
-    Time* last_updated,
+    base::Time* last_updated,
     std::vector<unsigned char>* png_icon_data,
     GURL* icon_url) {
   DCHECK(icon_id);
 
-  SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_,
-      "SELECT last_updated, image_data, url FROM favicons WHERE id=?");
-  if (!statement.is_valid())
+  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+      "SELECT last_updated, image_data, url FROM favicons WHERE id=?"));
+  if (!statement)
     return 0;
 
-  statement->bind_int64(0, icon_id);
+  statement.BindInt64(0, icon_id);
 
-  if (statement->step() != SQLITE_ROW) {
-    // No entry for the id.
-    return false;
-  }
+  if (!statement.Step())
+    return false;  // No entry for the id.
 
-  *last_updated = Time::FromTimeT(statement->column_int64(0));
-  if (statement->column_bytes(1) > 0)
-    statement->column_blob_as_vector(1, png_icon_data);
+  *last_updated = base::Time::FromTimeT(statement.ColumnInt64(0));
+  if (statement.ColumnByteLength(1) > 0)
+    statement.ColumnBlobAsVector(1, png_icon_data);
   if (icon_url)
-    *icon_url = GURL(statement->column_string(2));
+    *icon_url = GURL(statement.ColumnString(2));
 
   return true;
 }
 
 FavIconID ThumbnailDatabase::AddFavIcon(const GURL& icon_url) {
-  SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_,
-                          "INSERT INTO favicons (url) VALUES (?)");
-  if (!statement.is_valid())
+  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+      "INSERT INTO favicons (url) VALUES (?)"));
+  if (!statement)
     return 0;
 
-  statement->bind_string(0, URLDatabase::GURLToDatabaseURL(icon_url));
-  if (statement->step() != SQLITE_DONE)
+  statement.BindString(0, URLDatabase::GURLToDatabaseURL(icon_url));
+  if (!statement.Run())
     return 0;
-  return sqlite3_last_insert_rowid(db_);
+  return db_.GetLastInsertRowId();
 }
 
 bool ThumbnailDatabase::DeleteFavIcon(FavIconID id) {
-  SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_,
-                          "DELETE FROM favicons WHERE id = ?");
-  if (!statement.is_valid())
+  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+      "DELETE FROM favicons WHERE id = ?"));
+  if (!statement)
     return false;
-  statement->bind_int64(0, id);
-  return statement->step() == SQLITE_DONE;
+  statement.BindInt64(0, id);
+  return statement.Run();
 }
 
 FavIconID ThumbnailDatabase::CopyToTemporaryFavIconTable(FavIconID source) {
-  SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_,
+  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
       "INSERT INTO temp_favicons (url, last_updated, image_data)"
       "SELECT url, last_updated, image_data "
-      "FROM favicons WHERE id = ?");
-  if (!statement.is_valid())
+      "FROM favicons WHERE id = ?"));
+  if (!statement)
     return 0;
-  statement->bind_int64(0, source);
-  if (statement->step() != SQLITE_DONE)
+  statement.BindInt64(0, source);
+  if (!statement.Run())
     return 0;
 
   // We return the ID of the newly inserted favicon.
-  return sqlite3_last_insert_rowid(db_);
+  return db_.GetLastInsertRowId();
 }
 
 bool ThumbnailDatabase::CommitTemporaryFavIconTable() {
   // Delete the old favicons table.
-  if (sqlite3_exec(db_, "DROP TABLE favicons", NULL, NULL, NULL) != SQLITE_OK)
+  if (!db_.Execute("DROP TABLE favicons"))
     return false;
 
   // Rename the temporary one.
-  if (sqlite3_exec(db_, "ALTER TABLE temp_favicons RENAME TO favicons",
-                   NULL, NULL, NULL) != SQLITE_OK)
+  if (!db_.Execute("ALTER TABLE temp_favicons RENAME TO favicons"))
     return false;
 
   // The renamed table needs the index (the temporary table doesn't have one).
diff --git a/chrome/browser/history/thumbnail_database.h b/chrome/browser/history/thumbnail_database.h
index 7df5652..7fd92029 100644
--- a/chrome/browser/history/thumbnail_database.h
+++ b/chrome/browser/history/thumbnail_database.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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.
 
@@ -7,17 +7,18 @@
 
 #include <vector>
 
+#include "app/sql/connection.h"
+#include "app/sql/meta_table.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/history/url_database.h"  // For DBCloseScoper.
 #include "chrome/browser/meta_table_helper.h"
 
-struct sqlite3;
 class FilePath;
 struct ThumbnailScore;
 class SkBitmap;
-class SqliteStatementCache;
+
 namespace base {
-  class Time;
+class Time;
 }
 
 namespace history {
@@ -46,7 +47,7 @@
   void BeginTransaction();
   void CommitTransaction();
   int transaction_nesting() const {
-    return transaction_nesting_;
+    return db_.transaction_nesting();
   }
 
   // Vacuums the database. This will cause sqlite to defragment and collect
@@ -62,7 +63,7 @@
                         URLID id,
                         const SkBitmap& thumbnail,
                         const ThumbnailScore& score,
-                        const base::Time& time);
+                        base::Time time);
 
   // Retrieves thumbnail data for the given URL, returning true on success,
   // false if there is no such thumbnail or there was some other error.
@@ -90,7 +91,7 @@
                   base::Time time);
 
   // Sets the time the favicon was last updated.
-  bool SetFavIconLastUpdateTime(FavIconID icon_id, const base::Time& time);
+  bool SetFavIconLastUpdateTime(FavIconID icon_id, base::Time time);
 
   // Returns the id of the entry in the favicon database with the specified url.
   // Returns 0 if no entry exists for the specified url.
@@ -154,17 +155,8 @@
   // newly-renamed favicons table (formerly the temporary table with no index).
   void InitFavIconsIndex();
 
-  // Ensures that db_ and statement_cache_ are destroyed in the proper order.
-  DBCloseScoper close_scoper_;
-
-  // The database connection and the statement cache: MAY BE NULL if database
-  // init failed. These are cleaned up by the close_scoper_.
-  sqlite3* db_;
-  SqliteStatementCache* statement_cache_;
-
-  int transaction_nesting_;
-
-  MetaTableHelper meta_table_;
+  sql::Connection db_;
+  sql::MetaTable meta_table_;
 
   // This object is created and managed by the history backend. We maintain an
   // opaque pointer to the object for our use.
diff --git a/chrome/browser/history/url_database.cc b/chrome/browser/history/url_database.cc
index b15af5b..0a9115f3 100644
--- a/chrome/browser/history/url_database.cc
+++ b/chrome/browser/history/url_database.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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,20 +8,19 @@
 #include <limits>
 
 #include "app/l10n_util.h"
+#include "app/sql/connection.h"
+#include "app/sql/statement.h"
 #include "base/string_util.h"
-#include "chrome/common/sqlite_utils.h"
 #include "chrome/common/url_constants.h"
 #include "googleurl/src/gurl.h"
 
-using base::Time;
-
 namespace history {
 
 const char URLDatabase::kURLRowFields[] = HISTORY_URL_ROW_FIELDS;
 const int URLDatabase::kNumURLRowFields = 9;
 
 bool URLDatabase::URLEnumerator::GetNextURL(URLRow* r) {
-  if (statement_.step() == SQLITE_ROW) {
+  if (statement_.Step()) {
     FillURLRow(statement_, r);
     return true;
   }
@@ -42,16 +41,16 @@
 
 // Convenience to fill a history::URLRow. Must be in sync with the fields in
 // kURLRowFields.
-void URLDatabase::FillURLRow(SQLStatement& s, history::URLRow* i) {
+void URLDatabase::FillURLRow(sql::Statement& s, history::URLRow* i) {
   DCHECK(i);
-  i->id_ = s.column_int64(0);
-  i->url_ = GURL(s.column_string(1));
-  i->title_ = s.column_wstring(2);
-  i->visit_count_ = s.column_int(3);
-  i->typed_count_ = s.column_int(4);
-  i->last_visit_ = Time::FromInternalValue(s.column_int64(5));
-  i->hidden_ = s.column_int(6) != 0;
-  i->favicon_id_ = s.column_int64(7);
+  i->id_ = s.ColumnInt64(0);
+  i->url_ = GURL(s.ColumnString(1));
+  i->title_ = UTF8ToWide(s.ColumnString(2));
+  i->visit_count_ = s.ColumnInt(3);
+  i->typed_count_ = s.ColumnInt(4);
+  i->last_visit_ = base::Time::FromInternalValue(s.ColumnInt64(5));
+  i->hidden_ = s.ColumnInt(6) != 0;
+  i->favicon_id_ = s.ColumnInt64(7);
 }
 
 bool URLDatabase::GetURLRow(URLID url_id, URLRow* info) {
@@ -59,52 +58,52 @@
   // there are old URLs in the database that are empty that got in before
   // we added any checks. We should eventually be able to remove it
   // when all inputs are using GURL (which prohibit empty input).
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls WHERE id=?");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls WHERE id=?"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, url_id);
-  if (statement->step() == SQLITE_ROW) {
-    FillURLRow(*statement, info);
+  statement.BindInt64(0, url_id);
+  if (statement.Step()) {
+    FillURLRow(statement, info);
     return true;
   }
   return false;
 }
 
 URLID URLDatabase::GetRowForURL(const GURL& url, history::URLRow* info) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls WHERE url=?");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls WHERE url=?"));
+  if (!statement)
     return 0;
 
   std::string url_string = GURLToDatabaseURL(url);
-  statement->bind_string(0, url_string);
-  if (statement->step() != SQLITE_ROW)
+  statement.BindString(0, url_string);
+  if (!statement.Step())
     return 0; // no data
 
   if (info)
-    FillURLRow(*statement, info);
-  return statement->column_int64(0);
+    FillURLRow(statement, info);
+  return statement.ColumnInt64(0);
 }
 
 bool URLDatabase::UpdateURLRow(URLID url_id,
                                const history::URLRow& info) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "UPDATE urls SET title=?,visit_count=?,typed_count=?,last_visit_time=?,"
         "hidden=?,favicon_id=?"
-      "WHERE id=?");
-  if (!statement.is_valid())
+      "WHERE id=?"));
+  if (!statement)
     return false;
 
-  statement->bind_wstring(0, info.title());
-  statement->bind_int(1, info.visit_count());
-  statement->bind_int(2, info.typed_count());
-  statement->bind_int64(3, info.last_visit().ToInternalValue());
-  statement->bind_int(4, info.hidden() ? 1 : 0);
-  statement->bind_int64(5, info.favicon_id());
-  statement->bind_int64(6, url_id);
-  return statement->step() == SQLITE_DONE;
+  statement.BindString(0, WideToUTF8(info.title()));
+  statement.BindInt(1, info.visit_count());
+  statement.BindInt(2, info.typed_count());
+  statement.BindInt64(3, info.last_visit().ToInternalValue());
+  statement.BindInt(4, info.hidden() ? 1 : 0);
+  statement.BindInt64(5, info.favicon_id());
+  statement.BindInt64(6, url_id);
+  return statement.Run();
 }
 
 URLID URLDatabase::AddURLInternal(const history::URLRow& info,
@@ -128,44 +127,46 @@
   }
   #undef ADDURL_COMMON_SUFFIX
 
-  SqliteCompiledStatement statement(statement_name, 0, GetStatementCache(),
-                                    statement_sql);
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(
+      sql::StatementID(statement_name), statement_sql));
+  if (!statement) {
+    NOTREACHED() << GetDB().GetErrorMessage();
     return 0;
+  }
 
-  statement->bind_string(0, GURLToDatabaseURL(info.url()));
-  statement->bind_wstring(1, info.title());
-  statement->bind_int(2, info.visit_count());
-  statement->bind_int(3, info.typed_count());
-  statement->bind_int64(4, info.last_visit().ToInternalValue());
-  statement->bind_int(5, info.hidden() ? 1 : 0);
-  statement->bind_int64(6, info.favicon_id());
+  statement.BindString(0, GURLToDatabaseURL(info.url()));
+  statement.BindString(1, WideToUTF8(info.title()));
+  statement.BindInt(2, info.visit_count());
+  statement.BindInt(3, info.typed_count());
+  statement.BindInt64(4, info.last_visit().ToInternalValue());
+  statement.BindInt(5, info.hidden() ? 1 : 0);
+  statement.BindInt64(6, info.favicon_id());
 
-  if (statement->step() != SQLITE_DONE)
+  if (!statement.Run())
     return 0;
-  return sqlite3_last_insert_rowid(GetDB());
+  return GetDB().GetLastInsertRowId();
 }
 
 bool URLDatabase::DeleteURLRow(URLID id) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "DELETE FROM urls WHERE id = ?");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "DELETE FROM urls WHERE id = ?"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, id);
-  if (statement->step() != SQLITE_DONE)
+  statement.BindInt64(0, id);
+  if (!statement.Run())
     return false;
 
-    // And delete any keyword visits.
+  // And delete any keyword visits.
   if (!has_keyword_search_terms_)
     return true;
 
-  SQLITE_UNIQUE_STATEMENT(del_keyword_visit, GetStatementCache(),
-                          "DELETE FROM keyword_search_terms WHERE url_id=?");
-  if (!del_keyword_visit.is_valid())
+  sql::Statement del_keyword_visit(GetDB().GetCachedStatement(SQL_FROM_HERE,
+                          "DELETE FROM keyword_search_terms WHERE url_id=?"));
+  if (!del_keyword_visit)
     return false;
-  del_keyword_visit->bind_int64(0, id);
-  return (del_keyword_visit->step() == SQLITE_DONE);
+  del_keyword_visit.BindInt64(0, id);
+  return del_keyword_visit.Run();
 }
 
 bool URLDatabase::CreateTemporaryURLTable() {
@@ -181,14 +182,12 @@
   // supplimentary indices that the archived database doesn't need.
 
   // Swap the url table out and replace it with the temporary one.
-  if (sqlite3_exec(GetDB(), "DROP TABLE urls",
-                   NULL, NULL, NULL) != SQLITE_OK) {
-    NOTREACHED();
+  if (!GetDB().Execute("DROP TABLE urls")) {
+    NOTREACHED() << GetDB().GetErrorMessage();
     return false;
   }
-  if (sqlite3_exec(GetDB(), "ALTER TABLE temp_urls RENAME TO urls",
-                   NULL, NULL, NULL) != SQLITE_OK) {
-    NOTREACHED();
+  if (!GetDB().Execute("ALTER TABLE temp_urls RENAME TO urls")) {
+    NOTREACHED() << GetDB().GetErrorMessage();
     return false;
   }
 
@@ -206,8 +205,9 @@
   std::string sql("SELECT ");
   sql.append(kURLRowFields);
   sql.append(" FROM urls");
-  if (enumerator->statement_.prepare(GetDB(), sql.c_str()) != SQLITE_OK) {
-    NOTREACHED() << "Query statement prep failed";
+  enumerator->statement_.Assign(GetDB().GetUniqueStatement(sql.c_str()));
+  if (!enumerator->statement_) {
+    NOTREACHED() << GetDB().GetErrorMessage();
     return false;
   }
   enumerator->initialized_ = true;
@@ -215,13 +215,13 @@
 }
 
 bool URLDatabase::IsFavIconUsed(FavIconID favicon_id) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "SELECT id FROM urls WHERE favicon_id=? LIMIT 1");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "SELECT id FROM urls WHERE favicon_id=? LIMIT 1"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, favicon_id);
-  return statement->step() == SQLITE_ROW;
+  statement.BindInt64(0, favicon_id);
+  return statement.Step();
 }
 
 void URLDatabase::AutocompleteForPrefix(const std::wstring& prefix,
@@ -231,12 +231,12 @@
   // as bookmarks is no longer part of the db we no longer include the order
   // by clause.
   results->clear();
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls "
       "WHERE url >= ? AND url < ? AND hidden = 0 "
       "ORDER BY typed_count DESC, visit_count DESC, last_visit_time DESC "
-      "LIMIT ?");
-  if (!statement.is_valid())
+      "LIMIT ?"));
+  if (!statement)
     return;
 
   // We will find all strings between "prefix" and this string, which is prefix
@@ -247,13 +247,13 @@
   std::string end_query(prefix_utf8);
   end_query.push_back(std::numeric_limits<unsigned char>::max());
 
-  statement->bind_string(0, prefix_utf8);
-  statement->bind_string(1, end_query);
-  statement->bind_int(2, static_cast<int>(max_results));
+  statement.BindString(0, prefix_utf8);
+  statement.BindString(1, end_query);
+  statement.BindInt(2, static_cast<int>(max_results));
 
-  while (statement->step() == SQLITE_ROW) {
+  while (statement.Step()) {
     history::URLRow info;
-    FillURLRow(*statement, &info);
+    FillURLRow(statement, &info);
     if (info.url().is_valid())
       results->push_back(info);
   }
@@ -277,18 +277,18 @@
   sql.append(" ? AND url < :end AND url = substr(:end, 1, length(url)) "
              "AND hidden = 0 AND visit_count >= ? AND typed_count >= ? "
              "ORDER BY url LIMIT 1");
-  SQLStatement statement;
-  if (statement.prepare(GetDB(), sql.c_str()) != SQLITE_OK) {
-    NOTREACHED() << "select statement prep failed";
+  sql::Statement statement(GetDB().GetUniqueStatement(sql.c_str()));
+  if (!statement) {
+    NOTREACHED() << GetDB().GetErrorMessage();
     return false;
   }
 
-  statement.bind_string(0, base);
-  statement.bind_string(1, url);   // :end
-  statement.bind_int(2, min_visits);
-  statement.bind_int(3, min_typed);
+  statement.BindString(0, base);
+  statement.BindString(1, url);   // :end
+  statement.BindInt(2, min_visits);
+  statement.BindInt(3, min_typed);
 
-  if (statement.step() != SQLITE_ROW)
+  if (!statement.Step())
     return false;
 
   DCHECK(info);
@@ -298,33 +298,29 @@
 
 bool URLDatabase::InitKeywordSearchTermsTable() {
   has_keyword_search_terms_ = true;
-  if (!DoesSqliteTableExist(GetDB(), "keyword_search_terms")) {
-    if (sqlite3_exec(GetDB(), "CREATE TABLE keyword_search_terms ("
+  if (!GetDB().DoesTableExist("keyword_search_terms")) {
+    if (!GetDB().Execute("CREATE TABLE keyword_search_terms ("
         "keyword_id INTEGER NOT NULL,"      // ID of the TemplateURL.
         "url_id INTEGER NOT NULL,"          // ID of the url.
         "lower_term LONGVARCHAR NOT NULL,"  // The search term, in lower case.
-        "term LONGVARCHAR NOT NULL)",       // The actual search term.
-        NULL, NULL, NULL) != SQLITE_OK)
+        "term LONGVARCHAR NOT NULL)"))      // The actual search term.
       return false;
   }
 
   // For searching.
-  sqlite3_exec(GetDB(), "CREATE INDEX keyword_search_terms_index1 ON "
-               "keyword_search_terms (keyword_id, lower_term)",
-               NULL, NULL, NULL);
+  GetDB().Execute("CREATE INDEX keyword_search_terms_index1 ON "
+                  "keyword_search_terms (keyword_id, lower_term)");
 
   // For deletion.
-  sqlite3_exec(GetDB(), "CREATE INDEX keyword_search_terms_index2 ON "
-               "keyword_search_terms (url_id)",
-               NULL, NULL, NULL);
+  GetDB().Execute("CREATE INDEX keyword_search_terms_index2 ON "
+                  "keyword_search_terms (url_id)");
 
   return true;
 }
 
 bool URLDatabase::DropKeywordSearchTermsTable() {
   // This will implicitly delete the indices over the table.
-  return sqlite3_exec(GetDB(), "DROP TABLE keyword_search_terms",
-                      NULL, NULL, NULL) == SQLITE_OK;
+  return GetDB().Execute("DROP TABLE keyword_search_terms");
 }
 
 bool URLDatabase::SetKeywordSearchTermsForURL(URLID url_id,
@@ -332,39 +328,39 @@
                                               const std::wstring& term) {
   DCHECK(url_id && keyword_id && !term.empty());
 
-  SQLITE_UNIQUE_STATEMENT(exist_statement, GetStatementCache(),
+  sql::Statement exist_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT term FROM keyword_search_terms "
-      "WHERE keyword_id = ? AND url_id = ?");
-  if (!exist_statement.is_valid())
+      "WHERE keyword_id = ? AND url_id = ?"));
+  if (!exist_statement)
     return false;
-  exist_statement->bind_int64(0, keyword_id);
-  exist_statement->bind_int64(1, url_id);
-  if (exist_statement->step() == SQLITE_ROW)
+  exist_statement.BindInt64(0, keyword_id);
+  exist_statement.BindInt64(1, url_id);
+  if (exist_statement.Step())
     return true;  // Term already exists, no need to add it.
 
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "INSERT INTO keyword_search_terms (keyword_id, url_id, lower_term, term) "
-      "VALUES (?,?,?,?)");
-  if (!statement.is_valid())
+      "VALUES (?,?,?,?)"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, keyword_id);
-  statement->bind_int64(1, url_id);
-  statement->bind_wstring(2, l10n_util::ToLower(term));
-  statement->bind_wstring(3, term);
-  return (statement->step() == SQLITE_DONE);
+  statement.BindInt64(0, keyword_id);
+  statement.BindInt64(1, url_id);
+  statement.BindString(2, UTF16ToUTF8(l10n_util::ToLower(WideToUTF16(term))));
+  statement.BindString(3, WideToUTF8(term));
+  return statement.Run();
 }
 
 void URLDatabase::DeleteAllSearchTermsForKeyword(
     TemplateURL::IDType keyword_id) {
   DCHECK(keyword_id);
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "DELETE FROM keyword_search_terms WHERE keyword_id=?");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "DELETE FROM keyword_search_terms WHERE keyword_id=?"));
+  if (!statement)
     return;
 
-  statement->bind_int64(0, keyword_id);
-  statement->step();
+  statement.BindInt64(0, keyword_id);
+  statement.Run();
 }
 
 void URLDatabase::GetMostRecentKeywordSearchTerms(
@@ -379,30 +375,30 @@
     return;
 
   DCHECK(!prefix.empty());
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT DISTINCT kv.term, u.last_visit_time "
       "FROM keyword_search_terms kv "
       "JOIN urls u ON kv.url_id = u.id "
       "WHERE kv.keyword_id = ? AND kv.lower_term >= ? AND kv.lower_term < ? "
-      "ORDER BY u.last_visit_time DESC LIMIT ?");
-  if (!statement.is_valid())
+      "ORDER BY u.last_visit_time DESC LIMIT ?"));
+  if (!statement)
     return;
 
   // NOTE: Keep this ToLower() call in sync with search_provider.cc.
-  const std::wstring lower_prefix = l10n_util::ToLower(prefix);
+  string16 lower_prefix = l10n_util::ToLower(WideToUTF16(prefix));
   // This magic gives us a prefix search.
-  std::wstring next_prefix = lower_prefix;
+  string16 next_prefix = lower_prefix;
   next_prefix[next_prefix.size() - 1] =
       next_prefix[next_prefix.size() - 1] + 1;
-  statement->bind_int64(0, keyword_id);
-  statement->bind_wstring(1, lower_prefix);
-  statement->bind_wstring(2, next_prefix);
-  statement->bind_int(3, max_count);
+  statement.BindInt64(0, keyword_id);
+  statement.BindString(1, UTF16ToUTF8(lower_prefix));
+  statement.BindString(2, UTF16ToUTF8(next_prefix));
+  statement.BindInt(3, max_count);
 
   KeywordSearchTermVisit visit;
-  while (statement->step() == SQLITE_ROW) {
-    visit.term = statement->column_wstring(0);
-    visit.time = Time::FromInternalValue(statement->column_int64(1));
+  while (statement.Step()) {
+    visit.term = UTF8ToWide(statement.ColumnString(0));
+    visit.time = base::Time::FromInternalValue(statement.ColumnInt64(1));
     matches->push_back(visit);
   }
 }
@@ -417,7 +413,7 @@
 }
 
 bool URLDatabase::DropStarredIDFromURLs() {
-  if (!DoesSqliteColumnExist(GetDB(), "urls", "starred_id", NULL))
+  if (!GetDB().DoesColumnExist("urls", "starred_id"))
     return true;  // urls is already updated, no need to continue.
 
   // Create a temporary table to contain the new URLs table.
@@ -427,13 +423,12 @@
   }
 
   // Copy the contents.
-  const char* insert_statement =
+  if (!GetDB().Execute(
       "INSERT INTO temp_urls (id, url, title, visit_count, typed_count, "
       "last_visit_time, hidden, favicon_id) "
       "SELECT id, url, title, visit_count, typed_count, last_visit_time, "
-      "hidden, favicon_id FROM urls";
-  if (sqlite3_exec(GetDB(), insert_statement, NULL, NULL, NULL) != SQLITE_OK) {
-    NOTREACHED();
+      "hidden, favicon_id FROM urls")) {
+    NOTREACHED() << GetDB().GetErrorMessage();
     return false;
   }
 
@@ -448,7 +443,7 @@
 
 bool URLDatabase::CreateURLTable(bool is_temporary) {
   const char* name = is_temporary ? "temp_urls" : "urls";
-  if (DoesSqliteTableExist(GetDB(), name))
+  if (GetDB().DoesTableExist(name))
     return true;
 
   std::string sql;
@@ -464,21 +459,18 @@
       "hidden INTEGER DEFAULT 0 NOT NULL,"
       "favicon_id INTEGER DEFAULT 0 NOT NULL)");
 
-  return sqlite3_exec(GetDB(), sql.c_str(), NULL, NULL, NULL) == SQLITE_OK;
+  return GetDB().Execute(sql.c_str());
 }
 
 void URLDatabase::CreateMainURLIndex() {
   // Index over URLs so we can quickly look up based on URL.  Ignore errors as
   // this likely already exists (and the same below).
-  sqlite3_exec(GetDB(), "CREATE INDEX urls_url_index ON urls (url)", NULL, NULL,
-               NULL);
+  GetDB().Execute("CREATE INDEX urls_url_index ON urls (url)");
 }
 
 void URLDatabase::CreateSupplimentaryURLIndices() {
   // Add a favicon index.  This is useful when we delete urls.
-  sqlite3_exec(GetDB(),
-               "CREATE INDEX urls_favicon_id_INDEX ON urls (favicon_id)",
-               NULL, NULL, NULL);
+  GetDB().Execute("CREATE INDEX urls_favicon_id_INDEX ON urls (favicon_id)");
 }
 
 }  // namespace history
diff --git a/chrome/browser/history/url_database.h b/chrome/browser/history/url_database.h
index e44108f..6e2eca1 100644
--- a/chrome/browser/history/url_database.h
+++ b/chrome/browser/history/url_database.h
@@ -1,78 +1,25 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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_HISTORY_URL_DATABASE_H__
-#define CHROME_BROWSER_HISTORY_URL_DATABASE_H__
+#ifndef CHROME_BROWSER_HISTORY_URL_DATABASE_H_
+#define CHROME_BROWSER_HISTORY_URL_DATABASE_H_
 
+#include "app/sql/statement.h"
 #include "base/basictypes.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/search_engines/template_url.h"
-#include "chrome/common/sqlite_utils.h"
-
-// Temporary until DBCloseScoper moves elsewhere.
-#include "chrome/common/sqlite_compiled_statement.h"
 
 class GURL;
-struct sqlite3;
-class SqliteStatementCache;
+
+namespace sql {
+class Connection;
+}
 
 namespace history {
 
 class VisitDatabase;  // For friend statement.
 
-// This class is here temporarily.
-// TODO(brettw) Figure out a better place for this or obsolete it.
-//
-// Helper class that closes the DB, deletes the statement cache, and zeros out
-// the pointer when it goes out of scope, does nothing once success is called.
-//
-// Can either be used by the owner of the DB to automatically close it, or
-// during initialization so that it is automatically closed on failure.
-//
-// properly maintained by Init() on failure. If |statement_cache| is non NULL,
-// it is assumed to be bound with |db| and will be cleaned up before the
-// database is closed.
-class DBCloseScoper {
- public:
-  DBCloseScoper() : db_(NULL), statement_cache_(NULL) {
-  }
-
-  // The statement cache must be allocated on the heap. The DB must be
-  // allocated by sqlite.
-  DBCloseScoper(sqlite3** db, SqliteStatementCache** statement_cache)
-      : db_(db),
-        statement_cache_(statement_cache) {
-  }
-
-  ~DBCloseScoper() {
-    if (db_) {
-      if (*statement_cache_) {
-        delete *statement_cache_;
-        *statement_cache_ = NULL;
-      }
-
-      sqlite3_close(*db_);
-      *db_ = NULL;
-    }
-  }
-
-  void Attach(sqlite3** db, SqliteStatementCache** statement_cache) {
-    DCHECK(db_ == NULL && statement_cache_ == NULL);
-    db_ = db;
-    statement_cache_ = statement_cache;
-  }
-
-  void Detach() {
-    db_ = NULL;
-    statement_cache_ = NULL;
-  }
-
- private:
-  sqlite3** db_;
-  SqliteStatementCache** statement_cache_;
-};
-
 // Encapsulates an SQL database that holds URL info.  This is a subset of the
 // full history data.  We split this class' functionality out from the larger
 // HistoryDatabase class to support maintaining separate databases of URLs with
@@ -172,7 +119,7 @@
     friend class URLDatabase;
 
     bool initialized_;
-    SQLStatement statement_;
+    sql::Statement statement_;
   };
 
   // Initializes the given enumerator to enumerator all URLs in the database
@@ -277,20 +224,18 @@
 
   // Convenience to fill a history::URLRow. Must be in sync with the fields in
   // kHistoryURLRowFields.
-  static void FillURLRow(SQLStatement& s, URLRow* i);
+  static void FillURLRow(sql::Statement& s, URLRow* i);
 
-  // Returns the database and statement cache for the functions in this
-  // interface. The decendent of this class implements these functions to
-  // return its objects.
-  virtual sqlite3* GetDB() = 0;
-  virtual SqliteStatementCache& GetStatementCache() = 0;
+  // Returns the database for the functions in this interface. The decendent of
+  // this class implements these functions to return its objects.
+  virtual sql::Connection& GetDB() = 0;
 
  private:
   // True if InitKeywordSearchTermsTable() has been invoked. Not all subclasses
   // have keyword search terms.
   bool has_keyword_search_terms_;
 
-  DISALLOW_EVIL_CONSTRUCTORS(URLDatabase);
+  DISALLOW_COPY_AND_ASSIGN(URLDatabase);
 };
 
 // The fields and order expected by FillURLRow(). ID is guaranteed to be first
@@ -306,4 +251,4 @@
 
 }  // history
 
-#endif  // CHROME_BROWSER_HISTORY_URL_DATABASE_H__
+#endif  // CHROME_BROWSER_HISTORY_URL_DATABASE_H_
diff --git a/chrome/browser/history/url_database_unittest.cc b/chrome/browser/history/url_database_unittest.cc
index cb050190..0f0be54 100644
--- a/chrome/browser/history/url_database_unittest.cc
+++ b/chrome/browser/history/url_database_unittest.cc
@@ -1,14 +1,13 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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 "app/sql/connection.h"
 #include "base/file_path.h"
 #include "base/file_util.h"
 #include "base/path_service.h"
 #include "base/string_util.h"
 #include "chrome/browser/history/url_database.h"
-#include "chrome/common/sqlite_compiled_statement.h"
-#include "chrome/common/sqlite_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::Time;
@@ -35,7 +34,7 @@
 class URLDatabaseTest : public testing::Test,
                         public URLDatabase {
  public:
-  URLDatabaseTest() : db_(NULL), statement_cache_(NULL) {
+  URLDatabaseTest() {
   }
 
  private:
@@ -45,8 +44,7 @@
     PathService::Get(base::DIR_TEMP, &temp_dir);
     db_file_ = temp_dir.AppendASCII("URLTest.db");
 
-    EXPECT_EQ(SQLITE_OK, OpenSqliteDb(db_file_, &db_));
-    statement_cache_ = new SqliteStatementCache(db_);
+    EXPECT_TRUE(db_.Open(db_file_));
 
     // Initialize the tables for this test.
     CreateURLTable(false);
@@ -55,22 +53,17 @@
     InitKeywordSearchTermsTable();
   }
   void TearDown() {
-    delete statement_cache_;
-    sqlite3_close(db_);
+    db_.Close();
     file_util::Delete(db_file_, false);
   }
 
   // Provided for URL/VisitDatabase.
-  virtual sqlite3* GetDB() {
+  virtual sql::Connection& GetDB() {
     return db_;
   }
-  virtual SqliteStatementCache& GetStatementCache() {
-    return *statement_cache_;
-  }
 
   FilePath db_file_;
-  sqlite3* db_;
-  SqliteStatementCache* statement_cache_;
+  sql::Connection db_;
 };
 
 // Test add and query for the URL table in the HistoryDatabase
diff --git a/chrome/browser/history/visit_database.cc b/chrome/browser/history/visit_database.cc
index 862d574a..2f4b591 100644
--- a/chrome/browser/history/visit_database.cc
+++ b/chrome/browser/history/visit_database.cc
@@ -1,21 +1,21 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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/history/visit_database.h"
+
 #include <algorithm>
 #include <limits>
 #include <map>
 #include <set>
 
-#include "chrome/browser/history/visit_database.h"
-#include "chrome/browser/history/visit_log.h"
-
+#include "app/sql/connection.h"
+#include "app/sql/statement.h"
 #include "chrome/browser/history/url_database.h"
+#include "chrome/browser/history/visit_log.h"
 #include "chrome/common/page_transition_types.h"
 #include "chrome/common/url_constants.h"
 
-using base::Time;
-
 // Rows, in order, of the visit table.
 #define HISTORY_VISIT_ROW_FIELDS \
   " id,url,visit_time,from_visit,transition,segment_id,is_indexed "
@@ -29,8 +29,8 @@
 }
 
 bool VisitDatabase::InitVisitTable() {
-  if (!DoesSqliteTableExist(GetDB(), "visits")) {
-    if (sqlite3_exec(GetDB(), "CREATE TABLE visits("
+  if (!GetDB().DoesTableExist("visits")) {
+    if (!GetDB().Execute("CREATE TABLE visits("
         "id INTEGER PRIMARY KEY,"
         "url INTEGER NOT NULL," // key of the URL this corresponds to
         "visit_time INTEGER NOT NULL,"
@@ -38,64 +38,56 @@
         "transition INTEGER DEFAULT 0 NOT NULL,"
         "segment_id INTEGER,"
         // True when we have indexed data for this visit.
-        "is_indexed BOOLEAN)",
-        NULL, NULL, NULL) != SQLITE_OK)
+        "is_indexed BOOLEAN)"))
       return false;
-  } else if (!DoesSqliteColumnExist(GetDB(), "visits",
-                                    "is_indexed", "BOOLEAN")) {
+  } else if (!GetDB().DoesColumnExist("visits", "is_indexed")) {
     // Old versions don't have the is_indexed column, we can just add that and
     // not worry about different database revisions, since old ones will
     // continue to work.
     //
     // TODO(brettw) this should be removed once we think everybody has been
     // updated (added early Mar 2008).
-    if (sqlite3_exec(GetDB(),
-                     "ALTER TABLE visits ADD COLUMN is_indexed BOOLEAN",
-                     NULL, NULL, NULL) != SQLITE_OK)
+    if (!GetDB().Execute("ALTER TABLE visits ADD COLUMN is_indexed BOOLEAN"))
       return false;
   }
 
   // Index over url so we can quickly find visits for a page. This will just
   // fail if it already exists and we'll ignore it.
-  sqlite3_exec(GetDB(), "CREATE INDEX visits_url_index ON visits (url)",
-               NULL, NULL, NULL);
+  GetDB().Execute("CREATE INDEX visits_url_index ON visits (url)");
 
   // Create an index over from visits so that we can efficiently find
   // referrers and redirects. Ignore failures because it likely already exists.
-  sqlite3_exec(GetDB(), "CREATE INDEX visits_from_index ON visits (from_visit)",
-               NULL, NULL, NULL);
+  GetDB().Execute("CREATE INDEX visits_from_index ON visits (from_visit)");
 
   // Create an index over time so that we can efficiently find the visits in a
   // given time range (most history views are time-based). Ignore failures
   // because it likely already exists.
-  sqlite3_exec(GetDB(), "CREATE INDEX visits_time_index ON visits (visit_time)",
-               NULL, NULL, NULL);
+  GetDB().Execute("CREATE INDEX visits_time_index ON visits (visit_time)");
 
   return true;
 }
 
 bool VisitDatabase::DropVisitTable() {
   // This will also drop the indices over the table.
-  return sqlite3_exec(GetDB(), "DROP TABLE visits", NULL, NULL, NULL) ==
-      SQLITE_OK;
+  return GetDB().Execute("DROP TABLE visits");
 }
 
 // Must be in sync with HISTORY_VISIT_ROW_FIELDS.
 // static
-void VisitDatabase::FillVisitRow(SQLStatement& statement, VisitRow* visit) {
-  visit->visit_id = statement.column_int64(0);
-  visit->url_id = statement.column_int64(1);
-  visit->visit_time = Time::FromInternalValue(statement.column_int64(2));
-  visit->referring_visit = statement.column_int64(3);
-  visit->transition = PageTransition::FromInt(statement.column_int(4));
-  visit->segment_id = statement.column_int64(5);
-  visit->is_indexed = !!statement.column_int(6);
+void VisitDatabase::FillVisitRow(sql::Statement& statement, VisitRow* visit) {
+  visit->visit_id = statement.ColumnInt64(0);
+  visit->url_id = statement.ColumnInt64(1);
+  visit->visit_time = base::Time::FromInternalValue(statement.ColumnInt64(2));
+  visit->referring_visit = statement.ColumnInt64(3);
+  visit->transition = PageTransition::FromInt(statement.ColumnInt(4));
+  visit->segment_id = statement.ColumnInt64(5);
+  visit->is_indexed = !!statement.ColumnInt(6);
 }
 
 // static
-void VisitDatabase::FillVisitVector(SQLStatement& statement,
+void VisitDatabase::FillVisitVector(sql::Statement& statement,
                                     VisitVector* visits) {
-  while (statement.step() == SQLITE_ROW) {
+  while (statement.Step()) {
     history::VisitRow visit;
     FillVisitRow(statement, &visit);
     visits->push_back(visit);
@@ -103,62 +95,61 @@
 }
 
 VisitID VisitDatabase::AddVisit(VisitRow* visit) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "INSERT INTO visits "
       "(url, visit_time, from_visit, transition, segment_id, is_indexed) "
-      "VALUES (?,?,?,?,?,?)");
-  if (!statement.is_valid())
+      "VALUES (?,?,?,?,?,?)"));
+  if (!statement)
     return 0;
 
-  statement->bind_int64(0, visit->url_id);
-  statement->bind_int64(1, visit->visit_time.ToInternalValue());
-  statement->bind_int64(2, visit->referring_visit);
-  statement->bind_int64(3, visit->transition);
-  statement->bind_int64(4, visit->segment_id);
-  statement->bind_int64(5, visit->is_indexed);
+  statement.BindInt64(0, visit->url_id);
+  statement.BindInt64(1, visit->visit_time.ToInternalValue());
+  statement.BindInt64(2, visit->referring_visit);
+  statement.BindInt64(3, visit->transition);
+  statement.BindInt64(4, visit->segment_id);
+  statement.BindInt64(5, visit->is_indexed);
   AddEventToVisitLog(VisitLog::ADD_VISIT);
-  if (statement->step() != SQLITE_DONE)
+  if (!statement.Run())
     return 0;
 
-  visit->visit_id = sqlite3_last_insert_rowid(GetDB());
+  visit->visit_id = GetDB().GetLastInsertRowId();
   return visit->visit_id;
 }
 
 void VisitDatabase::DeleteVisit(const VisitRow& visit) {
   // Patch around this visit. Any visits that this went to will now have their
   // "source" be the deleted visit's source.
-  SQLITE_UNIQUE_STATEMENT(update_chain, GetStatementCache(),
-                          "UPDATE visits SET from_visit=? "
-                          "WHERE from_visit=?");
-  if (!update_chain.is_valid())
+  sql::Statement update_chain(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "UPDATE visits SET from_visit=? WHERE from_visit=?"));
+  if (!update_chain)
     return;
-  update_chain->bind_int64(0, visit.referring_visit);
-  update_chain->bind_int64(1, visit.visit_id);
+  update_chain.BindInt64(0, visit.referring_visit);
+  update_chain.BindInt64(1, visit.visit_id);
   AddEventToVisitLog(VisitLog::UPDATE_VISIT);
-  update_chain->step();
+  update_chain.Run();
 
   // Now delete the actual visit.
-  SQLITE_UNIQUE_STATEMENT(del, GetStatementCache(),
-                          "DELETE FROM visits WHERE id=?");
-  if (!del.is_valid())
+  sql::Statement del(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "DELETE FROM visits WHERE id=?"));
+  if (!del)
     return;
-  del->bind_int64(0, visit.visit_id);
+  del.BindInt64(0, visit.visit_id);
   AddEventToVisitLog(VisitLog::DELETE_VISIT);
-  del->step();
+  del.Run();
 }
 
 bool VisitDatabase::GetRowForVisit(VisitID visit_id, VisitRow* out_visit) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits WHERE id=?");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits WHERE id=?"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, visit_id);
+  statement.BindInt64(0, visit_id);
   AddEventToVisitLog(VisitLog::SELECT_VISIT);
-  if (statement->step() != SQLITE_ROW)
+  if (!statement.Step())
     return false;
 
-  FillVisitRow(*statement, out_visit);
+  FillVisitRow(statement, out_visit);
 
   // We got a different visit than we asked for, something is wrong.
   DCHECK_EQ(visit_id, out_visit->visit_id);
@@ -174,128 +165,130 @@
   if (visit.visit_id == visit.referring_visit)
     return false;
 
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "UPDATE visits SET "
       "url=?,visit_time=?,from_visit=?,transition=?,segment_id=?,is_indexed=? "
-      "WHERE id=?");
-  if (!statement.is_valid())
+      "WHERE id=?"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, visit.url_id);
-  statement->bind_int64(1, visit.visit_time.ToInternalValue());
-  statement->bind_int64(2, visit.referring_visit);
-  statement->bind_int64(3, visit.transition);
-  statement->bind_int64(4, visit.segment_id);
-  statement->bind_int64(5, visit.is_indexed);
-  statement->bind_int64(6, visit.visit_id);
+  statement.BindInt64(0, visit.url_id);
+  statement.BindInt64(1, visit.visit_time.ToInternalValue());
+  statement.BindInt64(2, visit.referring_visit);
+  statement.BindInt64(3, visit.transition);
+  statement.BindInt64(4, visit.segment_id);
+  statement.BindInt64(5, visit.is_indexed);
+  statement.BindInt64(6, visit.visit_id);
   AddEventToVisitLog(VisitLog::UPDATE_VISIT);
-  return statement->step() == SQLITE_DONE;
+  return statement.Run();
 }
 
 bool VisitDatabase::GetVisitsForURL(URLID url_id, VisitVector* visits) {
   visits->clear();
 
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT" HISTORY_VISIT_ROW_FIELDS
       "FROM visits "
       "WHERE url=? "
-      "ORDER BY visit_time ASC");
-  if (!statement.is_valid())
+      "ORDER BY visit_time ASC"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, url_id);
+  statement.BindInt64(0, url_id);
   AddEventToVisitLog(VisitLog::SELECT_VISIT);
-  FillVisitVector(*statement, visits);
+  FillVisitVector(statement, visits);
   return true;
 }
 
-void VisitDatabase::GetAllVisitsInRange(Time begin_time, Time end_time,
+void VisitDatabase::GetAllVisitsInRange(base::Time begin_time,
+                                        base::Time end_time,
                                         int max_results,
                                         VisitVector* visits) {
   visits->clear();
 
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits "
       "WHERE visit_time >= ? AND visit_time < ?"
-      "ORDER BY visit_time LIMIT ?");
-  if (!statement.is_valid())
+      "ORDER BY visit_time LIMIT ?"));
+  if (!statement)
     return;
 
   // See GetVisibleVisitsInRange for more info on how these times are bound.
   int64 end = end_time.ToInternalValue();
-  statement->bind_int64(0, begin_time.ToInternalValue());
-  statement->bind_int64(1, end ? end : std::numeric_limits<int64>::max());
-  statement->bind_int64(2,
+  statement.BindInt64(0, begin_time.ToInternalValue());
+  statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max());
+  statement.BindInt64(2,
       max_results ? max_results : std::numeric_limits<int64>::max());
 
   AddEventToVisitLog(VisitLog::SELECT_VISIT);
-  FillVisitVector(*statement, visits);
+  FillVisitVector(statement, visits);
 }
 
 void VisitDatabase::GetVisitsInRangeForTransition(
-    Time begin_time,
-    Time end_time,
+    base::Time begin_time,
+    base::Time end_time,
     int max_results,
     PageTransition::Type transition,
     VisitVector* visits) {
   DCHECK(visits);
   visits->clear();
 
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits "
       "WHERE visit_time >= ? AND visit_time < ? "
       "AND (transition & ?) == ?"
-      "ORDER BY visit_time LIMIT ?");
-  if (!statement.is_valid())
+      "ORDER BY visit_time LIMIT ?"));
+  if (!statement)
     return;
 
   // See GetVisibleVisitsInRange for more info on how these times are bound.
   int64 end = end_time.ToInternalValue();
-  statement->bind_int64(0, begin_time.ToInternalValue());
-  statement->bind_int64(1, end ? end : std::numeric_limits<int64>::max());
-  statement->bind_int(2, PageTransition::CORE_MASK);
-  statement->bind_int(3, transition);
-  statement->bind_int64(4,
+  statement.BindInt64(0, begin_time.ToInternalValue());
+  statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max());
+  statement.BindInt(2, PageTransition::CORE_MASK);
+  statement.BindInt(3, transition);
+  statement.BindInt64(4,
       max_results ? max_results : std::numeric_limits<int64>::max());
 
   AddEventToVisitLog(VisitLog::SELECT_VISIT);
-  FillVisitVector(*statement, visits);
+  FillVisitVector(statement, visits);
 }
 
-void VisitDatabase::GetVisibleVisitsInRange(Time begin_time, Time end_time,
+void VisitDatabase::GetVisibleVisitsInRange(base::Time begin_time,
+                                            base::Time end_time,
                                             bool most_recent_visit_only,
                                             int max_count,
                                             VisitVector* visits) {
   visits->clear();
   // The visit_time values can be duplicated in a redirect chain, so we sort
   // by id too, to ensure a consistent ordering just in case.
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits "
       "WHERE visit_time >= ? AND visit_time < ? "
       "AND (transition & ?) != 0 "  // CHAIN_END
       "AND (transition & ?) NOT IN (?, ?, ?) "  // NO SUBFRAME or
                                                 // KEYWORD_GENERATED
-      "ORDER BY visit_time DESC, id DESC");
-  if (!statement.is_valid())
+      "ORDER BY visit_time DESC, id DESC"));
+  if (!statement)
     return;
 
   // Note that we use min/max values for querying unlimited ranges of time using
   // the same statement. Since the time has an index, this will be about the
   // same amount of work as just doing a query for everything with no qualifier.
   int64 end = end_time.ToInternalValue();
-  statement->bind_int64(0, begin_time.ToInternalValue());
-  statement->bind_int64(1, end ? end : std::numeric_limits<int64>::max());
-  statement->bind_int(2, PageTransition::CHAIN_END);
-  statement->bind_int(3, PageTransition::CORE_MASK);
-  statement->bind_int(4, PageTransition::AUTO_SUBFRAME);
-  statement->bind_int(5, PageTransition::MANUAL_SUBFRAME);
-  statement->bind_int(6, PageTransition::KEYWORD_GENERATED);
+  statement.BindInt64(0, begin_time.ToInternalValue());
+  statement.BindInt64(1, end ? end : std::numeric_limits<int64>::max());
+  statement.BindInt(2, PageTransition::CHAIN_END);
+  statement.BindInt(3, PageTransition::CORE_MASK);
+  statement.BindInt(4, PageTransition::AUTO_SUBFRAME);
+  statement.BindInt(5, PageTransition::MANUAL_SUBFRAME);
+  statement.BindInt(6, PageTransition::KEYWORD_GENERATED);
 
   AddEventToVisitLog(VisitLog::SELECT_VISIT);
   std::set<URLID> found_urls;
-  while (statement->step() == SQLITE_ROW) {
+  while (statement.Step()) {
     VisitRow visit;
-    FillVisitRow(*statement, &visit);
+    FillVisitRow(statement, &visit);
     if (most_recent_visit_only) {
       // Make sure the URL this visit corresponds to is unique if required.
       if (found_urls.find(visit.url_id) != found_urls.end())
@@ -313,24 +306,24 @@
                                                 VisitRow* visit_row) {
   // The visit_time values can be duplicated in a redirect chain, so we sort
   // by id too, to ensure a consistent ordering just in case.
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits "
       "WHERE url=? "
       "ORDER BY visit_time DESC, id DESC "
-      "LIMIT 1");
-  if (!statement.is_valid())
+      "LIMIT 1"));
+  if (!statement)
     return 0;
 
-  statement->bind_int64(0, url_id);
+  statement.BindInt64(0, url_id);
   AddEventToVisitLog(VisitLog::SELECT_VISIT);
-  if (statement->step() != SQLITE_ROW)
+  if (!statement.Step())
     return 0;  // No visits for this URL.
 
   if (visit_row) {
-    FillVisitRow(*statement, visit_row);
+    FillVisitRow(statement, visit_row);
     return visit_row->visit_id;
   }
-  return statement->column_int64(0);
+  return statement.ColumnInt64(0);
 }
 
 bool VisitDatabase::GetMostRecentVisitsForURL(URLID url_id,
@@ -340,43 +333,43 @@
 
   // The visit_time values can be duplicated in a redirect chain, so we sort
   // by id too, to ensure a consistent ordering just in case.
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT" HISTORY_VISIT_ROW_FIELDS
       "FROM visits "
       "WHERE url=? "
       "ORDER BY visit_time DESC, id DESC "
-      "LIMIT ?");
-  if (!statement.is_valid())
+      "LIMIT ?"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, url_id);
-  statement->bind_int(1, max_results);
+  statement.BindInt64(0, url_id);
+  statement.BindInt(1, max_results);
   AddEventToVisitLog(VisitLog::SELECT_VISIT);
-  FillVisitVector(*statement, visits);
+  FillVisitVector(statement, visits);
   return true;
 }
 
 bool VisitDatabase::GetRedirectFromVisit(VisitID from_visit,
                                          VisitID* to_visit,
                                          GURL* to_url) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT v.id,u.url "
       "FROM visits v JOIN urls u ON v.url = u.id "
       "WHERE v.from_visit = ? "
-      "AND (v.transition & ?) != 0");  // IS_REDIRECT_MASK
-  if (!statement.is_valid())
+      "AND (v.transition & ?) != 0"));  // IS_REDIRECT_MASK
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, from_visit);
-  statement->bind_int(1, PageTransition::IS_REDIRECT_MASK);
+  statement.BindInt64(0, from_visit);
+  statement.BindInt(1, PageTransition::IS_REDIRECT_MASK);
 
   AddEventToVisitLog(VisitLog::SELECT_VISIT);
-  if (statement->step() != SQLITE_ROW)
+  if (!statement.Step())
     return false;  // No redirect from this visit.
   if (to_visit)
-    *to_visit = statement->column_int64(0);
+    *to_visit = statement.ColumnInt64(0);
   if (to_url)
-    *to_url = GURL(statement->column_string(1));
+    *to_url = GURL(statement.ColumnString(1));
   return true;
 }
 
@@ -391,24 +384,24 @@
     *from_visit = row.referring_visit;
 
   if (from_url) {
-    SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+    sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
         "SELECT u.url "
         "FROM visits v JOIN urls u ON v.url = u.id "
-        "WHERE v.id = ?");
-    statement->bind_int64(0, row.referring_visit);
+        "WHERE v.id = ?"));
+    statement.BindInt64(0, row.referring_visit);
 
     AddEventToVisitLog(VisitLog::SELECT_VISIT);
-    if (statement->step() != SQLITE_ROW)
+    if (!statement.Step())
       return false;
 
-    *from_url = GURL(statement->column_string(0));
+    *from_url = GURL(statement.ColumnString(0));
   }
   return true;
 }
 
 bool VisitDatabase::GetVisitCountToHost(const GURL& url,
                                         int* count,
-                                        Time* first_visit) {
+                                        base::Time* first_visit) {
   if (!url.SchemeIs(chrome::kHttpScheme) && !url.SchemeIs(chrome::kHttpsScheme))
     return false;
 
@@ -428,38 +421,37 @@
   std::string host_query_max = host_query_min;
   host_query_max[host_query_max.size() - 1] = '0';
 
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT MIN(v.visit_time), COUNT(*) "
       "FROM visits v INNER JOIN urls u ON v.url = u.id "
-      "WHERE (u.url >= ? AND u.url < ?)");
-  if (!statement.is_valid())
+      "WHERE (u.url >= ? AND u.url < ?)"));
+  if (!statement)
     return false;
 
-  statement->bind_string(0, host_query_min);
-  statement->bind_string(1, host_query_max);
+  statement.BindString(0, host_query_min);
+  statement.BindString(1, host_query_max);
 
   AddEventToVisitLog(VisitLog::SELECT_VISIT);
-  if (statement->step() != SQLITE_ROW) {
+  if (!statement.Step()) {
     // We've never been to this page before.
     *count = 0;
     return true;
   }
 
-  *first_visit = Time::FromInternalValue(statement->column_int64(0));
-  *count = statement->column_int(1);
+  *first_visit = base::Time::FromInternalValue(statement.ColumnInt64(0));
+  *count = statement.ColumnInt(1);
   return true;
 }
 
-bool VisitDatabase::GetStartDate(Time* first_visit) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "SELECT MIN(visit_time) FROM visits WHERE visit_time != 0");
+bool VisitDatabase::GetStartDate(base::Time* first_visit) {
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "SELECT MIN(visit_time) FROM visits WHERE visit_time != 0"));
   AddEventToVisitLog(VisitLog::SELECT_VISIT);
-  if (!statement.is_valid() || statement->step() != SQLITE_ROW ||
-      statement->column_int64(0) == 0) {
-    *first_visit = Time::Now();
+  if (!statement || !statement.Step() || statement.ColumnInt64(0) == 0) {
+    *first_visit = base::Time::Now();
     return false;
   }
-  *first_visit = Time::FromInternalValue(statement->column_int64(0));
+  *first_visit = base::Time::FromInternalValue(statement.ColumnInt64(0));
   return true;
 }
 
diff --git a/chrome/browser/history/visit_database.h b/chrome/browser/history/visit_database.h
index 9fa46010..8613ace 100644
--- a/chrome/browser/history/visit_database.h
+++ b/chrome/browser/history/visit_database.h
@@ -1,15 +1,16 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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_HISTORY_VISIT_DATABASE_H__
-#define CHROME_BROWSER_HISTORY_VISIT_DATABASE_H__
+#ifndef CHROME_BROWSER_HISTORY_VISIT_DATABASE_H_
+#define CHROME_BROWSER_HISTORY_VISIT_DATABASE_H_
 
 #include "chrome/browser/history/history_types.h"
 
-struct sqlite3;
-class SqliteStatementCache;
-class SQLStatement;
+namespace sql {
+class Connection;
+class Statement;
+}
 
 namespace history {
 
@@ -144,11 +145,8 @@
   bool GetStartDate(base::Time* first_visit);
 
  protected:
-  // Returns the database and statement cache for the functions in this
-  // interface. The decendent of this class implements these functions to
-  // return its objects.
-  virtual sqlite3* GetDB() = 0;
-  virtual SqliteStatementCache& GetStatementCache() = 0;
+  // Returns the database for the functions in this interface.
+  virtual sql::Connection& GetDB() = 0;
 
   // Called by the derived classes on initialization to make sure the tables
   // and indices are properly set up. Must be called before anything else.
@@ -156,16 +154,16 @@
 
   // Convenience to fill a VisitRow. Assumes the visit values are bound starting
   // at index 0.
-  static void FillVisitRow(SQLStatement& statement, VisitRow* visit);
+  static void FillVisitRow(sql::Statement& statement, VisitRow* visit);
 
   // Convenience to fill a VisitVector. Assumes that statement.step()
   // hasn't happened yet.
-  static void FillVisitVector(SQLStatement& statement, VisitVector* visits);
+  static void FillVisitVector(sql::Statement& statement, VisitVector* visits);
 
  private:
-  DISALLOW_EVIL_CONSTRUCTORS(VisitDatabase);
+  DISALLOW_COPY_AND_ASSIGN(VisitDatabase);
 };
 
 }  // history
 
-#endif  // CHROME_BROWSER_HISTORY_VISIT_DATABASE_H__
+#endif  // CHROME_BROWSER_HISTORY_VISIT_DATABASE_H_
diff --git a/chrome/browser/history/visit_database_unittest.cc b/chrome/browser/history/visit_database_unittest.cc
index 65197d1..aedb9e93 100644
--- a/chrome/browser/history/visit_database_unittest.cc
+++ b/chrome/browser/history/visit_database_unittest.cc
@@ -1,15 +1,14 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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 "app/sql/connection.h"
 #include "base/file_path.h"
 #include "base/file_util.h"
 #include "base/path_service.h"
 #include "base/string_util.h"
 #include "chrome/browser/history/url_database.h"
 #include "chrome/browser/history/visit_database.h"
-#include "chrome/common/sqlite_compiled_statement.h"
-#include "chrome/common/sqlite_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
@@ -36,7 +35,7 @@
                           public URLDatabase,
                           public VisitDatabase {
  public:
-  VisitDatabaseTest() : db_(NULL), statement_cache_(NULL) {
+  VisitDatabaseTest() {
   }
 
  private:
@@ -48,8 +47,7 @@
     db_file_ = temp_dir.AppendASCII("VisitTest.db");
     file_util::Delete(db_file_, false);
 
-    EXPECT_EQ(SQLITE_OK, OpenSqliteDb(db_file_, &db_));
-    statement_cache_ = new SqliteStatementCache(db_);
+    EXPECT_TRUE(db_.Open(db_file_));
 
     // Initialize the tables for this test.
     CreateURLTable(false);
@@ -58,23 +56,18 @@
     InitVisitTable();
   }
   void TearDown() {
-    delete statement_cache_;
-    sqlite3_close(db_);
+    db_.Close();
     file_util::Delete(db_file_, false);
     PlatformTest::TearDown();
   }
 
   // Provided for URL/VisitDatabase.
-  virtual sqlite3* GetDB() {
+  virtual sql::Connection& GetDB() {
     return db_;
   }
-  virtual SqliteStatementCache& GetStatementCache() {
-    return *statement_cache_;
-  }
 
   FilePath db_file_;
-  sqlite3* db_;
-  SqliteStatementCache* statement_cache_;
+  sql::Connection db_;
 };
 
 TEST_F(VisitDatabaseTest, Add) {
diff --git a/chrome/browser/history/visitsegment_database.cc b/chrome/browser/history/visitsegment_database.cc
index cf2cd3c..b18712b 100644
--- a/chrome/browser/history/visitsegment_database.cc
+++ b/chrome/browser/history/visitsegment_database.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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.
 
@@ -6,14 +6,12 @@
 
 #include <math.h>
 
+#include "app/sql/connection.h"
+#include "app/sql/statement.h"
 #include "base/logging.h"
 #include "base/stl_util-inl.h"
 #include "base/string_util.h"
 #include "chrome/browser/history/page_usage_data.h"
-#include "chrome/common/sqlite_compiled_statement.h"
-#include "chrome/common/sqlite_utils.h"
-
-using base::Time;
 
 // The following tables are used to store url segment information.
 //
@@ -40,19 +38,17 @@
 
 bool VisitSegmentDatabase::InitSegmentTables() {
   // Segments table.
-  if (!DoesSqliteTableExist(GetDB(), "segments")) {
-    if (sqlite3_exec(GetDB(), "CREATE TABLE segments ("
-                     "id INTEGER PRIMARY KEY,"
-                     "name VARCHAR,"
-                     "url_id INTEGER NON NULL,"
-                     "pres_index INTEGER DEFAULT -1 NOT NULL)",
-                     NULL, NULL, NULL) != SQLITE_OK) {
+  if (!GetDB().DoesTableExist("segments")) {
+    if (!GetDB().Execute("CREATE TABLE segments ("
+        "id INTEGER PRIMARY KEY,"
+        "name VARCHAR,"
+        "url_id INTEGER NON NULL,"
+        "pres_index INTEGER DEFAULT -1 NOT NULL)")) {
       NOTREACHED();
       return false;
     }
 
-    if (sqlite3_exec(GetDB(), "CREATE INDEX segments_name ON segments(name)",
-                     NULL, NULL, NULL) != SQLITE_OK) {
+    if (!GetDB().Execute("CREATE INDEX segments_name ON segments(name)")) {
       NOTREACHED();
       return false;
     }
@@ -60,33 +56,29 @@
 
   // This was added later, so we need to try to create it even if the table
   // already exists.
-  sqlite3_exec(GetDB(), "CREATE INDEX segments_url_id ON segments(url_id)",
-               NULL, NULL, NULL);
+  GetDB().Execute("CREATE INDEX segments_url_id ON segments(url_id)");
 
   // Segment usage table.
-  if (!DoesSqliteTableExist(GetDB(), "segment_usage")) {
-    if (sqlite3_exec(GetDB(), "CREATE TABLE segment_usage ("
-                     "id INTEGER PRIMARY KEY,"
-                     "segment_id INTEGER NOT NULL,"
-                     "time_slot INTEGER NOT NULL,"
-                     "visit_count INTEGER DEFAULT 0 NOT NULL)",
-                     NULL, NULL, NULL) != SQLITE_OK) {
+  if (!GetDB().DoesTableExist("segment_usage")) {
+    if (!GetDB().Execute("CREATE TABLE segment_usage ("
+        "id INTEGER PRIMARY KEY,"
+        "segment_id INTEGER NOT NULL,"
+        "time_slot INTEGER NOT NULL,"
+        "visit_count INTEGER DEFAULT 0 NOT NULL)")) {
       NOTREACHED();
       return false;
     }
-    if (sqlite3_exec(GetDB(),
-                     "CREATE INDEX segment_usage_time_slot_segment_id ON "
-                     "segment_usage(time_slot, segment_id)",
-                     NULL, NULL, NULL) != SQLITE_OK) {
+    if (!GetDB().Execute(
+        "CREATE INDEX segment_usage_time_slot_segment_id ON "
+        "segment_usage(time_slot, segment_id)")) {
       NOTREACHED();
       return false;
     }
   }
 
   // Added in a later version, so we always need to try to creat this index.
-  sqlite3_exec(GetDB(), "CREATE INDEX segments_usage_seg_id "
-                        "ON segment_usage(segment_id)",
-               NULL, NULL, NULL);
+  GetDB().Execute("CREATE INDEX segments_usage_seg_id "
+                  "ON segment_usage(segment_id)");
 
   // Presentation index table.
   //
@@ -95,11 +87,10 @@
   // If you need to add more columns, keep in mind that rows are currently
   // deleted when the presentation index is changed to -1.
   // See SetPagePresentationIndex() in this file
-  if (!DoesSqliteTableExist(GetDB(), "presentation")) {
-    if (sqlite3_exec(GetDB(), "CREATE TABLE presentation("
-                     "url_id INTEGER PRIMARY KEY,"
-                     "pres_index INTEGER NOT NULL)",
-                     NULL, NULL, NULL) != SQLITE_OK)
+  if (!GetDB().DoesTableExist("presentation")) {
+    if (!GetDB().Execute("CREATE TABLE presentation("
+        "url_id INTEGER PRIMARY KEY,"
+        "pres_index INTEGER NOT NULL)"))
       return false;
   }
   return true;
@@ -107,11 +98,8 @@
 
 bool VisitSegmentDatabase::DropSegmentTables() {
   // Dropping the tables will implicitly delete the indices.
-  return
-      sqlite3_exec(GetDB(), "DROP TABLE segments", NULL, NULL, NULL) ==
-          SQLITE_OK &&
-      sqlite3_exec(GetDB(), "DROP TABLE segment_usage", NULL, NULL, NULL) ==
-          SQLITE_OK;
+  return GetDB().Execute("DROP TABLE segments") &&
+         GetDB().Execute("DROP TABLE segment_usage");
 }
 
 // Note: the segment name is derived from the URL but is not a URL. It is
@@ -147,94 +135,94 @@
 
 SegmentID VisitSegmentDatabase::GetSegmentNamed(
     const std::string& segment_name) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "SELECT id FROM segments WHERE name = ?");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "SELECT id FROM segments WHERE name = ?"));
+  if (!statement)
     return 0;
 
-  statement->bind_string(0, segment_name);
-  if (statement->step() == SQLITE_ROW)
-    return statement->column_int64(0);
+  statement.BindString(0, segment_name);
+  if (statement.Step())
+    return statement.ColumnInt64(0);
   return 0;
 }
 
 bool VisitSegmentDatabase::UpdateSegmentRepresentationURL(SegmentID segment_id,
                                                           URLID url_id) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "UPDATE segments SET url_id = ? WHERE id = ?");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "UPDATE segments SET url_id = ? WHERE id = ?"));
+  if (!statement)
     return false;
 
-  statement->bind_int64(0, url_id);
-  statement->bind_int64(1, segment_id);
-  return statement->step() == SQLITE_DONE;
+  statement.BindInt64(0, url_id);
+  statement.BindInt64(1, segment_id);
+  return statement.Run();
 }
 
 URLID VisitSegmentDatabase::GetSegmentRepresentationURL(SegmentID segment_id) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "SELECT url_id FROM segments WHERE id = ?");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "SELECT url_id FROM segments WHERE id = ?"));
+  if (!statement)
     return 0;
 
-  statement->bind_int64(0, segment_id);
-  if (statement->step() == SQLITE_ROW)
-    return statement->column_int64(0);
+  statement.BindInt64(0, segment_id);
+  if (statement.Step())
+    return statement.ColumnInt64(0);
   return 0;
 }
 
 SegmentID VisitSegmentDatabase::CreateSegment(URLID url_id,
                                               const std::string& segment_name) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "INSERT INTO segments (name, url_id) VALUES (?,?)");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "INSERT INTO segments (name, url_id) VALUES (?,?)"));
+  if (!statement)
     return false;
 
-  statement->bind_string(0, segment_name);
-  statement->bind_int64(1, url_id);
-  if (statement->step() == SQLITE_DONE)
-    return sqlite3_last_insert_rowid(GetDB());
+  statement.BindString(0, segment_name);
+  statement.BindInt64(1, url_id);
+  if (statement.Run())
+    return GetDB().GetLastInsertRowId();
   return false;
 }
 
 bool VisitSegmentDatabase::IncreaseSegmentVisitCount(SegmentID segment_id,
-                                                     const Time& ts,
+                                                     base::Time ts,
                                                      int amount) {
-  Time t = ts.LocalMidnight();
+  base::Time t = ts.LocalMidnight();
 
-  SQLITE_UNIQUE_STATEMENT(select, GetStatementCache(),
+  sql::Statement select(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT id, visit_count FROM segment_usage "
-      "WHERE time_slot = ? AND segment_id = ?");
-  if (!select.is_valid())
+      "WHERE time_slot = ? AND segment_id = ?"));
+  if (!select)
     return false;
 
-  select->bind_int64(0, t.ToInternalValue());
-  select->bind_int64(1, segment_id);
-  if (select->step() == SQLITE_ROW) {
-    SQLITE_UNIQUE_STATEMENT(update, GetStatementCache(),
-        "UPDATE segment_usage SET visit_count = ? WHERE id = ?");
-    if (!update.is_valid())
+  select.BindInt64(0, t.ToInternalValue());
+  select.BindInt64(1, segment_id);
+  if (select.Step()) {
+    sql::Statement update(GetDB().GetCachedStatement(SQL_FROM_HERE,
+        "UPDATE segment_usage SET visit_count = ? WHERE id = ?"));
+    if (!update)
       return false;
 
-    update->bind_int64(0, select->column_int64(1) + static_cast<int64>(amount));
-    update->bind_int64(1, select->column_int64(0));
-    return update->step() == SQLITE_DONE;
+    update.BindInt64(0, select.ColumnInt64(1) + static_cast<int64>(amount));
+    update.BindInt64(1, select.ColumnInt64(0));
+    return update.Run();
 
   } else {
-    SQLITE_UNIQUE_STATEMENT(insert, GetStatementCache(),
+    sql::Statement insert(GetDB().GetCachedStatement(SQL_FROM_HERE,
         "INSERT INTO segment_usage "
-        "(segment_id, time_slot, visit_count) VALUES (?, ?, ?)");
-    if (!insert.is_valid())
+        "(segment_id, time_slot, visit_count) VALUES (?, ?, ?)"));
+    if (!insert)
       return false;
 
-    insert->bind_int64(0, segment_id);
-    insert->bind_int64(1, t.ToInternalValue());
-    insert->bind_int64(2, static_cast<int64>(amount));
-    return insert->step() == SQLITE_DONE;
+    insert.BindInt64(0, segment_id);
+    insert.BindInt64(1, t.ToInternalValue());
+    insert.BindInt64(2, static_cast<int64>(amount));
+    return insert.Run();
   }
 }
 
 void VisitSegmentDatabase::QuerySegmentUsage(
-    const Time& from_time,
+    base::Time from_time,
     int max_result_count,
     std::vector<PageUsageData*>* results) {
   // This function gathers the highest-ranked segments in two queries.
@@ -245,25 +233,25 @@
   // used to lock results into position.  But the rest of our code currently
   // does as well.
 
-  // Gather all the segment scores:
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+  // Gather all the segment scores.
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT segment_id, time_slot, visit_count "
       "FROM segment_usage WHERE time_slot >= ? "
-      "ORDER BY segment_id");
-  if (!statement.is_valid()) {
-    NOTREACHED();
+      "ORDER BY segment_id"));
+  if (!statement) {
+    NOTREACHED() << GetDB().GetErrorMessage();
     return;
   }
 
-  Time ts = from_time.LocalMidnight();
-  statement->bind_int64(0, ts.ToInternalValue());
+  base::Time ts = from_time.LocalMidnight();
+  statement.BindInt64(0, ts.ToInternalValue());
 
-  const Time now = Time::Now();
+  base::Time now = base::Time::Now();
   SegmentID last_segment_id = 0;
   PageUsageData* pud = NULL;
   float score = 0;
-  while (statement->step() == SQLITE_ROW) {
-    SegmentID segment_id = statement->column_int64(0);
+  while (statement.Step()) {
+    SegmentID segment_id = statement.ColumnInt64(0);
     if (segment_id != last_segment_id) {
       if (last_segment_id != 0) {
         pud->SetScore(score);
@@ -275,8 +263,9 @@
       last_segment_id = segment_id;
     }
 
-    const Time timeslot = Time::FromInternalValue(statement->column_int64(1));
-    const int visit_count = statement->column_int(2);
+    base::Time timeslot =
+        base::Time::FromInternalValue(statement.ColumnInt64(1));
+    int visit_count = statement.ColumnInt(2);
     int days_ago = (now - timeslot).InDays();
 
     // Score for this day in isolation.
@@ -304,89 +293,87 @@
   }
 
   // Now fetch the details about the entries we care about.
-  SQLITE_UNIQUE_STATEMENT(statement2, GetStatementCache(),
+  sql::Statement statement2(GetDB().GetCachedStatement(SQL_FROM_HERE,
       "SELECT urls.url, urls.title FROM urls "
       "JOIN segments ON segments.url_id = urls.id "
-      "WHERE segments.id = ?");
-  if (!statement2.is_valid()) {
-    NOTREACHED();
+      "WHERE segments.id = ?"));
+  if (!statement2) {
+    NOTREACHED() << GetDB().GetErrorMessage();
     return;
   }
   for (size_t i = 0; i < results->size(); ++i) {
     PageUsageData* pud = (*results)[i];
-    statement2->bind_int64(0, pud->GetID());
-    if (statement2->step() == SQLITE_ROW) {
-      std::string url;
-      std::wstring title;
-      statement2->column_string(0, &url);
-      statement2->column_wstring(1, &title);
-      pud->SetURL(GURL(url));
-      pud->SetTitle(WideToUTF16(title));
+    statement2.BindInt64(0, pud->GetID());
+    if (statement2.Step()) {
+      pud->SetURL(GURL(statement2.ColumnString(0)));
+      pud->SetTitle(UTF8ToUTF16(statement2.ColumnString(1)));
     }
-    statement2->reset();
+    statement2.Reset();
   }
 }
 
-void VisitSegmentDatabase::DeleteSegmentData(const Time& older_than) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "DELETE FROM segment_usage WHERE time_slot < ?");
-  if (!statement.is_valid())
+void VisitSegmentDatabase::DeleteSegmentData(base::Time older_than) {
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "DELETE FROM segment_usage WHERE time_slot < ?"));
+  if (!statement)
     return;
 
-  statement->bind_int64(0, older_than.LocalMidnight().ToInternalValue());
-  if (statement->step() != SQLITE_DONE)
+  statement.BindInt64(0, older_than.LocalMidnight().ToInternalValue());
+  if (!statement.Run())
     NOTREACHED();
 }
 
 void VisitSegmentDatabase::SetSegmentPresentationIndex(SegmentID segment_id,
                                                        int index) {
-  SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
-      "UPDATE segments SET pres_index = ? WHERE id = ?");
-  if (!statement.is_valid())
+  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "UPDATE segments SET pres_index = ? WHERE id = ?"));
+  if (!statement)
     return;
 
-  statement->bind_int(0, index);
-  statement->bind_int64(1, segment_id);
-  if (statement->step() != SQLITE_DONE)
+  statement.BindInt(0, index);
+  statement.BindInt64(1, segment_id);
+  if (!statement.Run())
     NOTREACHED();
+  else
+    DCHECK(GetDB().GetLastChangeCount() == 1);
 }
 
 bool VisitSegmentDatabase::DeleteSegmentForURL(URLID url_id) {
-  SQLITE_UNIQUE_STATEMENT(select, GetStatementCache(),
-      "SELECT id FROM segments WHERE url_id = ?");
-  if (!select.is_valid())
+  sql::Statement select(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "SELECT id FROM segments WHERE url_id = ?"));
+  if (!select)
     return false;
 
-  SQLITE_UNIQUE_STATEMENT(delete_seg, GetStatementCache(),
-      "DELETE FROM segments WHERE id = ?");
-  if (!delete_seg.is_valid())
+  sql::Statement delete_seg(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "DELETE FROM segments WHERE id = ?"));
+  if (!delete_seg)
     return false;
 
-  SQLITE_UNIQUE_STATEMENT(delete_usage, GetStatementCache(),
-      "DELETE FROM segment_usage WHERE segment_id = ?");
-  if (!delete_usage.is_valid())
+  sql::Statement delete_usage(GetDB().GetCachedStatement(SQL_FROM_HERE,
+      "DELETE FROM segment_usage WHERE segment_id = ?"));
+  if (!delete_usage)
     return false;
 
   bool r = true;
-  select->bind_int64(0, url_id);
+  select.BindInt64(0, url_id);
   // In theory there could not be more than one segment using that URL but we
   // loop anyway to cleanup any inconsistency.
-  while (select->step() == SQLITE_ROW) {
-    SegmentID segment_id = select->column_int64(0);
+  while (select.Step()) {
+    SegmentID segment_id = select.ColumnInt64(0);
 
-    delete_usage->bind_int64(0, segment_id);
-    if (delete_usage->step() != SQLITE_DONE) {
+    delete_usage.BindInt64(0, segment_id);
+    if (!delete_usage.Run()) {
       NOTREACHED();
       r = false;
     }
 
-    delete_seg->bind_int64(0, segment_id);
-    if (delete_seg->step() != SQLITE_DONE) {
+    delete_seg.BindInt64(0, segment_id);
+    if (!delete_seg.Run()) {
       NOTREACHED();
       r = false;
     }
-    delete_usage->reset();
-    delete_seg->reset();
+    delete_usage.Reset();
+    delete_seg.Reset();
   }
   return r;
 }
diff --git a/chrome/browser/history/visitsegment_database.h b/chrome/browser/history/visitsegment_database.h
index 0eb0a36f..16f04170 100644
--- a/chrome/browser/history/visitsegment_database.h
+++ b/chrome/browser/history/visitsegment_database.h
@@ -1,16 +1,18 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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_HISTORY_VISITSEGMENT_DATABASE_H__
-#define CHROME_BROWSER_HISTORY_VISITSEGMENT_DATABASE_H__
+#ifndef CHROME_BROWSER_HISTORY_VISITSEGMENT_DATABASE_H_
+#define CHROME_BROWSER_HISTORY_VISITSEGMENT_DATABASE_H_
 
 #include "base/basictypes.h"
 #include "chrome/browser/history/history_types.h"
 
 class PageUsageData;
-struct sqlite3;
-class SqliteStatementCache;
+
+namespace sql {
+class Connection;
+}
 
 namespace history {
 
@@ -45,19 +47,19 @@
 
   // Increase the segment visit count by the provided amount. Return true on
   // success.
-  bool IncreaseSegmentVisitCount(SegmentID segment_id, const base::Time& ts,
+  bool IncreaseSegmentVisitCount(SegmentID segment_id, base::Time ts,
                                  int amount);
 
   // Compute the segment usage since |from_time| using the provided aggregator.
   // A PageUsageData is added in |result| for the highest-scored segments up to
   // |max_result_count|.
-  void QuerySegmentUsage(const base::Time& from_time,
+  void QuerySegmentUsage(base::Time from_time,
                          int max_result_count,
                          std::vector<PageUsageData*>* result);
 
   // Delete all the segment usage data which is older than the provided time
   // stamp.
-  void DeleteSegmentData(const base::Time& older_than);
+  void DeleteSegmentData(base::Time older_than);
 
   // Change the presentation id for the segment identified by |segment_id|
   void SetSegmentPresentationIndex(SegmentID segment_id, int index);
@@ -67,11 +69,8 @@
   bool DeleteSegmentForURL(URLID url_id);
 
  protected:
-  // Returns the database and statement cache for the functions in this
-  // interface. The decendent of this class implements these functions to
-  // return its objects.
-  virtual sqlite3* GetDB() = 0;
-  virtual SqliteStatementCache& GetStatementCache() = 0;
+  // Returns the database for the functions in this interface.
+  virtual sql::Connection& GetDB() = 0;
 
   // Creates the tables used by this class if necessary. Returns true on
   // success.
@@ -81,9 +80,9 @@
   bool DropSegmentTables();
 
  private:
-  DISALLOW_EVIL_CONSTRUCTORS(VisitSegmentDatabase);
+  DISALLOW_COPY_AND_ASSIGN(VisitSegmentDatabase);
 };
 
 }  // namespace history
 
-#endif  // CHROME_BROWSER_HISTORY_VISITSEGMENT_DATABASE_H__
+#endif  // CHROME_BROWSER_HISTORY_VISITSEGMENT_DATABASE_H_
diff --git a/chrome/browser/net/sqlite_persistent_cookie_store.cc b/chrome/browser/net/sqlite_persistent_cookie_store.cc
index d8ec074..700caac5 100644
--- a/chrome/browser/net/sqlite_persistent_cookie_store.cc
+++ b/chrome/browser/net/sqlite_persistent_cookie_store.cc
@@ -330,7 +330,7 @@
 bool SQLitePersistentCookieStore::Load(
     std::vector<net::CookieMonster::KeyedCanonicalCookie>* cookies) {
   scoped_ptr<sql::Connection> db(new sql::Connection);
-  if (!db->Init(path_)) {
+  if (!db->Open(path_)) {
     NOTREACHED() << "Unable to open cookie DB.";
     return false;
   }
diff --git a/chrome/browser/search_engines/edit_search_engine_controller.cc b/chrome/browser/search_engines/edit_search_engine_controller.cc
index 110af38a3..22140c8 100644
--- a/chrome/browser/search_engines/edit_search_engine_controller.cc
+++ b/chrome/browser/search_engines/edit_search_engine_controller.cc
@@ -4,11 +4,13 @@
 
 #include "chrome/browser/search_engines/edit_search_engine_controller.h"
 
+#include "base/string_util.h"
 #include "chrome/browser/metrics/user_metrics.h"
 #include "chrome/browser/net/url_fixer_upper.h"
 #include "chrome/browser/profile.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_model.h"
+#include "googleurl/src/gurl.h"
 
 EditSearchEngineController::EditSearchEngineController(
     const TemplateURL* template_url,
diff --git a/chrome/browser/thumbnail_store.cc b/chrome/browser/thumbnail_store.cc
index 1e06bde..19cd9f3 100644
--- a/chrome/browser/thumbnail_store.cc
+++ b/chrome/browser/thumbnail_store.cc
@@ -7,6 +7,8 @@
 #include <string.h>
 #include <algorithm>
 
+#include "app/sql/statement.h"
+#include "app/sql/transaction.h"
 #include "base/basictypes.h"
 #include "base/file_util.h"
 #include "base/gfx/jpeg_codec.h"
@@ -17,15 +19,12 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profile.h"
 #include "chrome/common/pref_service.h"
-#include "chrome/common/sqlite_utils.h"
 #include "googleurl/src/gurl.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
 
 ThumbnailStore::ThumbnailStore()
     : cache_(NULL),
-      db_(NULL),
-      statement_cache_(NULL),
       hs_(NULL),
       url_blacklist_(NULL),
       disk_data_loaded_(false) {
@@ -294,24 +293,27 @@
 
 void ThumbnailStore::CommitCacheToDB(
     scoped_refptr<RefCountedVector<GURL> > urls_to_delete,
-    Cache* data) const {
+    Cache* data) {
   scoped_ptr<Cache> data_to_save(data);
-  if (!db_)
+  if (!db_.is_open())
     return;
 
   base::TimeTicks db_start = base::TimeTicks::Now();
 
-  int rv = sqlite3_exec(db_, "BEGIN TRANSACTION", NULL, NULL, NULL);
-  DCHECK(rv == SQLITE_OK) << "Failed to begin transaction";
+  sql::Transaction transaction(&db_);
+  if (!transaction.Begin())
+    return;
 
   // Delete old thumbnails.
   if (urls_to_delete.get()) {
     for (std::vector<GURL>::iterator it = urls_to_delete->data.begin();
         it != urls_to_delete->data.end(); ++it) {
-      SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_,
-          "DELETE FROM thumbnails WHERE url=?");
-      statement->bind_string(0, it->spec());
-      if (statement->step() != SQLITE_DONE)
+      sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+          "DELETE FROM thumbnails WHERE url=?"));
+      if (!statement)
+        return;
+      statement.BindString(0, it->spec());
+      if (!statement.Run())
         NOTREACHED();
     }
   }
@@ -320,26 +322,25 @@
   if (data_to_save.get()) {
     for (Cache::iterator it = data_to_save->begin();
          it != data_to_save->end(); ++it) {
-      SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_,
+      sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
           "INSERT OR REPLACE INTO thumbnails "
           "(url, boring_score, good_clipping, "
           "at_top, time_taken, data) "
-          "VALUES (?,?,?,?,?,?)");
-      statement->bind_string(0, it->first.spec());
-      statement->bind_double(1, it->second.score_.boring_score);
-      statement->bind_bool(2, it->second.score_.good_clipping);
-      statement->bind_bool(3, it->second.score_.at_top);
-      statement->bind_int64(4, it->second.score_.time_at_snapshot.
-                                  ToInternalValue());
-      statement->bind_blob(5, &it->second.data_->data[0],
-                           static_cast<int>(it->second.data_->data.size()));
-      if (statement->step() != SQLITE_DONE)
+          "VALUES (?,?,?,?,?,?)"));
+      statement.BindString(0, it->first.spec());
+      statement.BindDouble(1, it->second.score_.boring_score);
+      statement.BindBool(2, it->second.score_.good_clipping);
+      statement.BindBool(3, it->second.score_.at_top);
+      statement.BindInt64(4,
+          it->second.score_.time_at_snapshot.ToInternalValue());
+      statement.BindBlob(5, &it->second.data_->data[0],
+                          static_cast<int>(it->second.data_->data.size()));
+      if (!statement.Run())
         DLOG(WARNING) << "Unable to insert thumbnail for URL";
     }
   }
 
-  rv = sqlite3_exec(db_, "COMMIT", NULL, NULL, NULL);
-  DCHECK(rv == SQLITE_OK) << "Failed to commit transaction";
+  transaction.Commit();
 
   base::TimeDelta delta = base::TimeTicks::Now() - db_start;
   HISTOGRAM_TIMES("ThumbnailStore.WriteDBToDisk", delta);
@@ -347,39 +348,23 @@
 
 void ThumbnailStore::InitializeFromDB(const FilePath& db_name,
                                       MessageLoop* cb_loop) {
-  if (OpenSqliteDb(db_name, &db_) != SQLITE_OK)
+  db_.set_page_size(4096);
+  db_.set_cache_size(64);
+  db_.set_exclusive_locking();
+  if (!db_.Open(db_name))
     return;
 
-  // Use a large page size since the thumbnails we are storing are typically
-  // large, a small cache size since we cache in memory and don't go to disk
-  // often, and take exclusive access since nobody else uses this db.
-  sqlite3_exec(db_, "PRAGMA page_size=4096 "
-                    "PRAGMA cache_size=64 "
-                    "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, NULL);
-
-  statement_cache_ = new SqliteStatementCache;
-
-  // Use local DBCloseScoper so that if we cannot create the table and
-  // need to return, the |db_| and |statement_cache_| are closed properly.
-  history::DBCloseScoper scoper(&db_, &statement_cache_);
-
-  if (!DoesSqliteTableExist(db_, "thumbnails")) {
-    if (sqlite3_exec(db_, "CREATE TABLE thumbnails ("
+  if (!db_.DoesTableExist("thumbnails")) {
+    if (!db_.Execute("CREATE TABLE thumbnails ("
           "url LONGVARCHAR PRIMARY KEY,"
           "boring_score DOUBLE DEFAULT 1.0,"
           "good_clipping INTEGER DEFAULT 0,"
           "at_top INTEGER DEFAULT 0,"
           "time_taken INTEGER DEFAULT 0,"
-          "data BLOB)", NULL, NULL, NULL) != SQLITE_OK)
+          "data BLOB)"))
       return;
   }
 
-  statement_cache_->set_db(db_);
-
-  // Now we can use a DBCloseScoper at the object scope.
-  scoper.Detach();
-  close_scoper_.Attach(&db_, &statement_cache_);
-
   if (cb_loop)
     GetAllThumbnailsFromDisk(cb_loop);
 }
@@ -387,24 +372,26 @@
 void ThumbnailStore::GetAllThumbnailsFromDisk(MessageLoop* cb_loop) {
   Cache* cache = new Cache;
 
-  SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_,
-      "SELECT * FROM thumbnails");
+  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+      "SELECT * FROM thumbnails"));
+  if (!statement)
+    return;
 
-  while (statement->step() == SQLITE_ROW) {
+  while (statement.Step()) {
     // The URL
-    GURL url(statement->column_string(0));
+    GURL url(statement.ColumnString(0));
 
     // The score.
-    ThumbnailScore score(statement->column_double(1),      // Boring score
-                         statement->column_bool(2),        // Good clipping
-                         statement->column_bool(3),        // At top
+    ThumbnailScore score(statement.ColumnDouble(1),      // Boring score
+                         statement.ColumnBool(2),        // Good clipping
+                         statement.ColumnBool(3),        // At top
                          base::Time::FromInternalValue(
-                            statement->column_int64(4)));  // Time taken
+                            statement.ColumnInt64(4)));  // Time taken
 
     // The image.
     scoped_refptr<RefCountedBytes> data = new RefCountedBytes;
-    if (statement->column_blob_as_vector(5, &data->data))
-      (*cache)[url] = CacheEntry(data, score, false);
+    statement.ColumnBlobAsVector(5, &data->data);
+    (*cache)[url] = CacheEntry(data, score, false);
   }
 
   cb_loop->PostTask(FROM_HERE,
diff --git a/chrome/browser/thumbnail_store.h b/chrome/browser/thumbnail_store.h
index 143cbce..d54c5d4 100644
--- a/chrome/browser/thumbnail_store.h
+++ b/chrome/browser/thumbnail_store.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "app/sql/connection.h"
 #include "base/file_path.h"
 #include "base/message_loop.h"
 #include "base/ref_counted.h"
@@ -19,7 +20,6 @@
 #include "chrome/common/notification_service.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/ref_counted_util.h"
-#include "chrome/common/sqlite_compiled_statement.h"
 #include "chrome/common/thumbnail_score.h"
 #include "testing/gtest/include/gtest/gtest_prod.h"
 
@@ -154,7 +154,7 @@
   // cache entries to the DB.
   void CommitCacheToDB(
       scoped_refptr<RefCountedVector<GURL> > urls_to_delete,
-      Cache* data) const;
+      Cache* data);
 
   // Decide whether to store data ---------------------------------------------
 
@@ -175,9 +175,7 @@
   scoped_ptr<Cache> cache_;
 
   // The database holding the thumbnails on disk.
-  sqlite3* db_;
-  SqliteStatementCache* statement_cache_;
-  history::DBCloseScoper close_scoper_;
+  sql::Connection db_;
 
   // We hold a reference to the history service to query for most visited URLs
   // and redirect information.
diff --git a/chrome/browser/thumbnail_store_unittest.cc b/chrome/browser/thumbnail_store_unittest.cc
index cd8f146..cd249f38 100644
--- a/chrome/browser/thumbnail_store_unittest.cc
+++ b/chrome/browser/thumbnail_store_unittest.cc
@@ -9,6 +9,8 @@
 
 #include "chrome/browser/thumbnail_store.h"
 
+#include "app/sql/connection.h"
+#include "app/sql/statement.h"
 #include "base/time.h"
 #include "base/file_path.h"
 #include "base/file_util.h"
@@ -18,8 +20,6 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/ref_counted_util.h"
 #include "chrome/common/thumbnail_score.h"
-#include "chrome/common/sqlite_compiled_statement.h"
-#include "chrome/common/sqlite_utils.h"
 #include "chrome/tools/profiles/thumbnail-inl.h"
 #include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -186,17 +186,17 @@
   store_->cache_->clear();  // Clear it from the cache.
 
   // Read from the DB.
-  SQLITE_UNIQUE_STATEMENT(statement, *store_->statement_cache_,
-      "SELECT * FROM thumbnails");
-  EXPECT_TRUE(statement->step() == SQLITE_ROW);
-  GURL url(statement->column_string(0));
-  ThumbnailScore score(statement->column_double(1),
-                       statement->column_bool(2),
-                       statement->column_bool(3),
+  sql::Statement statement(store_->db_.GetUniqueStatement(
+      "SELECT * FROM thumbnails"));
+  EXPECT_TRUE(statement.Step());
+  GURL url(statement.ColumnString(0));
+  ThumbnailScore score(statement.ColumnDouble(1),
+                       statement.ColumnBool(2),
+                       statement.ColumnBool(3),
                        base::Time::FromInternalValue(
-                          statement->column_int64(4)));
+                          statement.ColumnInt64(4)));
   scoped_refptr<RefCountedBytes> data = new RefCountedBytes;
-  EXPECT_TRUE(statement->column_blob_as_vector(5, &data->data));
+  statement.ColumnBlobAsVector(5, &data->data);
 
   EXPECT_TRUE(url == url_);
   EXPECT_TRUE(score.Equals(score_));
diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc
index a704173..a4db1c9 100644
--- a/chrome/browser/webdata/web_database.cc
+++ b/chrome/browser/webdata/web_database.cc
@@ -147,7 +147,7 @@
   // database while we're running, and this will give somewhat improved perf.
   db_.set_exclusive_locking();
 
-  if (!db_.Init(db_name))
+  if (!db_.Open(db_name))
     return false;
 
   // Initialize various tables
diff --git a/chrome/browser/webdata/web_database.h b/chrome/browser/webdata/web_database.h
index b966938..acc8fbf1 100644
--- a/chrome/browser/webdata/web_database.h
+++ b/chrome/browser/webdata/web_database.h
@@ -11,9 +11,7 @@
 #include "app/sql/connection.h"
 #include "app/sql/meta_table.h"
 #include "base/basictypes.h"
-#include "chrome/browser/meta_table_helper.h"
 #include "chrome/browser/search_engines/template_url.h"
-#include "chrome/common/sqlite_utils.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "testing/gtest/include/gtest/gtest_prod.h"
 #include "webkit/glue/autofill_form.h"