Merge from Chromium at DEPS revision r167172

This commit was generated by merge_to_master.py.

Change-Id: Ib8d56fd5ae39a2d7e8c91dcd76cc6d13f25f2aab
diff --git a/sql/DEPS b/sql/DEPS
new file mode 100644
index 0000000..0f76c3a
--- /dev/null
+++ b/sql/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/sqlite",
+]
diff --git a/sql/OWNERS b/sql/OWNERS
new file mode 100644
index 0000000..1ea5750
--- /dev/null
+++ b/sql/OWNERS
@@ -0,0 +1,3 @@
+erikwright@chromium.org
+shess@chromium.org
+gbillock@chromium.org
diff --git a/sql/connection.cc b/sql/connection.cc
new file mode 100644
index 0000000..1de9fc5
--- /dev/null
+++ b/sql/connection.cc
@@ -0,0 +1,648 @@
+// Copyright (c) 2012 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 "sql/connection.h"
+
+#include <string.h>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
+#include "sql/statement.h"
+#include "third_party/sqlite/sqlite3.h"
+
+namespace {
+
+// Spin for up to a second waiting for the lock to clear when setting
+// up the database.
+// TODO(shess): Better story on this.  http://crbug.com/56559
+const int kBusyTimeoutSeconds = 1;
+
+class ScopedBusyTimeout {
+ public:
+  explicit ScopedBusyTimeout(sqlite3* db)
+      : db_(db) {
+  }
+  ~ScopedBusyTimeout() {
+    sqlite3_busy_timeout(db_, 0);
+  }
+
+  int SetTimeout(base::TimeDelta timeout) {
+    DCHECK_LT(timeout.InMilliseconds(), INT_MAX);
+    return sqlite3_busy_timeout(db_,
+                                static_cast<int>(timeout.InMilliseconds()));
+  }
+
+ private:
+  sqlite3* db_;
+};
+
+// Helper to "safely" enable writable_schema.  No error checking
+// because it is reasonable to just forge ahead in case of an error.
+// If turning it on fails, then most likely nothing will work, whereas
+// if turning it off fails, it only matters if some code attempts to
+// continue working with the database and tries to modify the
+// sqlite_master table (none of our code does this).
+class ScopedWritableSchema {
+ public:
+  explicit ScopedWritableSchema(sqlite3* db)
+      : db_(db) {
+    sqlite3_exec(db_, "PRAGMA writable_schema=1", NULL, NULL, NULL);
+  }
+  ~ScopedWritableSchema() {
+    sqlite3_exec(db_, "PRAGMA writable_schema=0", NULL, NULL, NULL);
+  }
+
+ private:
+  sqlite3* db_;
+};
+
+}  // namespace
+
+namespace sql {
+
+bool StatementID::operator<(const StatementID& other) const {
+  if (number_ != other.number_)
+    return number_ < other.number_;
+  return strcmp(str_, other.str_) < 0;
+}
+
+ErrorDelegate::~ErrorDelegate() {
+}
+
+Connection::StatementRef::StatementRef()
+    : connection_(NULL),
+      stmt_(NULL) {
+}
+
+Connection::StatementRef::StatementRef(sqlite3_stmt* stmt)
+    : connection_(NULL),
+      stmt_(stmt) {
+}
+
+Connection::StatementRef::StatementRef(Connection* connection,
+                                       sqlite3_stmt* stmt)
+    : connection_(connection),
+      stmt_(stmt) {
+  connection_->StatementRefCreated(this);
+}
+
+Connection::StatementRef::~StatementRef() {
+  if (connection_)
+    connection_->StatementRefDeleted(this);
+  Close();
+}
+
+void Connection::StatementRef::Close() {
+  if (stmt_) {
+    // Call to AssertIOAllowed() cannot go at the beginning of the function
+    // because Close() is called unconditionally from destructor to clean
+    // connection_. And if this is inactive statement this won't cause any
+    // disk access and destructor most probably will be called on thread
+    // not allowing disk access.
+    // TODO(paivanof@gmail.com): This should move to the beginning
+    // of the function. http://crbug.com/136655.
+    AssertIOAllowed();
+    sqlite3_finalize(stmt_);
+    stmt_ = NULL;
+  }
+  connection_ = NULL;  // The connection may be getting deleted.
+}
+
+Connection::Connection()
+    : db_(NULL),
+      page_size_(0),
+      cache_size_(0),
+      exclusive_locking_(false),
+      transaction_nesting_(0),
+      needs_rollback_(false),
+      in_memory_(false),
+      error_delegate_(NULL) {
+}
+
+Connection::~Connection() {
+  Close();
+}
+
+bool Connection::Open(const FilePath& path) {
+#if defined(OS_WIN)
+  return OpenInternal(WideToUTF8(path.value()));
+#elif defined(OS_POSIX)
+  return OpenInternal(path.value());
+#endif
+}
+
+bool Connection::OpenInMemory() {
+  in_memory_ = true;
+  return OpenInternal(":memory:");
+}
+
+void Connection::Close() {
+  // TODO(shess): Calling "PRAGMA journal_mode = DELETE" at this point
+  // will delete the -journal file.  For ChromiumOS or other more
+  // embedded systems, this is probably not appropriate, whereas on
+  // desktop it might make some sense.
+
+  // sqlite3_close() needs all prepared statements to be finalized.
+  // Release all cached statements, then assert that the client has
+  // released all statements.
+  statement_cache_.clear();
+  DCHECK(open_statements_.empty());
+
+  // Additionally clear the prepared statements, because they contain
+  // weak references to this connection.  This case has come up when
+  // error-handling code is hit in production.
+  ClearCache();
+
+  if (db_) {
+    // Call to AssertIOAllowed() cannot go at the beginning of the function
+    // because Close() must be called from destructor to clean
+    // statement_cache_, it won't cause any disk access and it most probably
+    // will happen on thread not allowing disk access.
+    // TODO(paivanof@gmail.com): This should move to the beginning
+    // of the function. http://crbug.com/136655.
+    AssertIOAllowed();
+    // TODO(shess): Histogram for failure.
+    sqlite3_close(db_);
+    db_ = NULL;
+  }
+}
+
+void Connection::Preload() {
+  AssertIOAllowed();
+
+  if (!db_) {
+    DLOG(FATAL) << "Cannot preload null db";
+    return;
+  }
+
+  // A statement must be open for the preload command to work. If the meta
+  // table doesn't exist, it probably means this is a new database and there
+  // is nothing to preload (so it's OK we do nothing).
+  if (!DoesTableExist("meta"))
+    return;
+  Statement dummy(GetUniqueStatement("SELECT * FROM meta"));
+  if (!dummy.Step())
+    return;
+
+#if !defined(USE_SYSTEM_SQLITE)
+  // This function is only defined in Chromium's version of sqlite.
+  // Do not call it when using system sqlite.
+  sqlite3_preload(db_);
+#endif
+}
+
+// Create an in-memory database with the existing database's page
+// size, then backup that database over the existing database.
+bool Connection::Raze() {
+  AssertIOAllowed();
+
+  if (!db_) {
+    DLOG(FATAL) << "Cannot raze null db";
+    return false;
+  }
+
+  if (transaction_nesting_ > 0) {
+    DLOG(FATAL) << "Cannot raze within a transaction";
+    return false;
+  }
+
+  sql::Connection null_db;
+  if (!null_db.OpenInMemory()) {
+    DLOG(FATAL) << "Unable to open in-memory database.";
+    return false;
+  }
+
+  if (page_size_) {
+    // Enforce SQLite restrictions on |page_size_|.
+    DCHECK(!(page_size_ & (page_size_ - 1)))
+        << " page_size_ " << page_size_ << " is not a power of two.";
+    const int kSqliteMaxPageSize = 32768;  // from sqliteLimit.h
+    DCHECK_LE(page_size_, kSqliteMaxPageSize);
+    const std::string sql = StringPrintf("PRAGMA page_size=%d", page_size_);
+    if (!null_db.Execute(sql.c_str()))
+      return false;
+  }
+
+#if defined(OS_ANDROID)
+  // Android compiles with SQLITE_DEFAULT_AUTOVACUUM.  Unfortunately,
+  // in-memory databases do not respect this define.
+  // TODO(shess): Figure out a way to set this without using platform
+  // specific code.  AFAICT from sqlite3.c, the only way to do it
+  // would be to create an actual filesystem database, which is
+  // unfortunate.
+  if (!null_db.Execute("PRAGMA auto_vacuum = 1"))
+    return false;
+#endif
+
+  // The page size doesn't take effect until a database has pages, and
+  // at this point the null database has none.  Changing the schema
+  // version will create the first page.  This will not affect the
+  // schema version in the resulting database, as SQLite's backup
+  // implementation propagates the schema version from the original
+  // connection to the new version of the database, incremented by one
+  // so that other readers see the schema change and act accordingly.
+  if (!null_db.Execute("PRAGMA schema_version = 1"))
+    return false;
+
+  // SQLite tracks the expected number of database pages in the first
+  // page, and if it does not match the total retrieved from a
+  // filesystem call, treats the database as corrupt.  This situation
+  // breaks almost all SQLite calls.  "PRAGMA writable_schema" can be
+  // used to hint to SQLite to soldier on in that case, specifically
+  // for purposes of recovery.  [See SQLITE_CORRUPT_BKPT case in
+  // sqlite3.c lockBtree().]
+  // TODO(shess): With this, "PRAGMA auto_vacuum" and "PRAGMA
+  // page_size" can be used to query such a database.
+  ScopedWritableSchema writable_schema(db_);
+
+  sqlite3_backup* backup = sqlite3_backup_init(db_, "main",
+                                               null_db.db_, "main");
+  if (!backup) {
+    DLOG(FATAL) << "Unable to start sqlite3_backup().";
+    return false;
+  }
+
+  // -1 backs up the entire database.
+  int rc = sqlite3_backup_step(backup, -1);
+  int pages = sqlite3_backup_pagecount(backup);
+  sqlite3_backup_finish(backup);
+
+  // The destination database was locked.
+  if (rc == SQLITE_BUSY) {
+    return false;
+  }
+
+  // The entire database should have been backed up.
+  if (rc != SQLITE_DONE) {
+    DLOG(FATAL) << "Unable to copy entire null database.";
+    return false;
+  }
+
+  // Exactly one page should have been backed up.  If this breaks,
+  // check this function to make sure assumptions aren't being broken.
+  DCHECK_EQ(pages, 1);
+
+  return true;
+}
+
+bool Connection::RazeWithTimout(base::TimeDelta timeout) {
+  if (!db_) {
+    DLOG(FATAL) << "Cannot raze null db";
+    return false;
+  }
+
+  ScopedBusyTimeout busy_timeout(db_);
+  busy_timeout.SetTimeout(timeout);
+  return Raze();
+}
+
+bool Connection::BeginTransaction() {
+  if (needs_rollback_) {
+    DCHECK_GT(transaction_nesting_, 0);
+
+    // When we're going to rollback, fail on this begin and don't actually
+    // mark us as entering the nested transaction.
+    return false;
+  }
+
+  bool success = true;
+  if (!transaction_nesting_) {
+    needs_rollback_ = false;
+
+    Statement begin(GetCachedStatement(SQL_FROM_HERE, "BEGIN TRANSACTION"));
+    if (!begin.Run())
+      return false;
+  }
+  transaction_nesting_++;
+  return success;
+}
+
+void Connection::RollbackTransaction() {
+  if (!transaction_nesting_) {
+    DLOG(FATAL) << "Rolling back a nonexistent transaction";
+    return;
+  }
+
+  transaction_nesting_--;
+
+  if (transaction_nesting_ > 0) {
+    // Mark the outermost transaction as needing rollback.
+    needs_rollback_ = true;
+    return;
+  }
+
+  DoRollback();
+}
+
+bool Connection::CommitTransaction() {
+  if (!transaction_nesting_) {
+    DLOG(FATAL) << "Rolling back a nonexistent transaction";
+    return false;
+  }
+  transaction_nesting_--;
+
+  if (transaction_nesting_ > 0) {
+    // Mark any nested transactions as failing after we've already got one.
+    return !needs_rollback_;
+  }
+
+  if (needs_rollback_) {
+    DoRollback();
+    return false;
+  }
+
+  Statement commit(GetCachedStatement(SQL_FROM_HERE, "COMMIT"));
+  return commit.Run();
+}
+
+int Connection::ExecuteAndReturnErrorCode(const char* sql) {
+  AssertIOAllowed();
+  if (!db_)
+    return false;
+  return sqlite3_exec(db_, sql, NULL, NULL, NULL);
+}
+
+bool Connection::Execute(const char* sql) {
+  int error = ExecuteAndReturnErrorCode(sql);
+  if (error != SQLITE_OK)
+    error = OnSqliteError(error, NULL);
+
+  // This needs to be a FATAL log because the error case of arriving here is
+  // that there's a malformed SQL statement. This can arise in development if
+  // a change alters the schema but not all queries adjust.
+  if (error == SQLITE_ERROR)
+    DLOG(FATAL) << "SQL Error in " << sql << ", " << GetErrorMessage();
+  return error == SQLITE_OK;
+}
+
+bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) {
+  if (!db_)
+    return false;
+
+  ScopedBusyTimeout busy_timeout(db_);
+  busy_timeout.SetTimeout(timeout);
+  return Execute(sql);
+}
+
+bool Connection::HasCachedStatement(const StatementID& id) const {
+  return statement_cache_.find(id) != statement_cache_.end();
+}
+
+scoped_refptr<Connection::StatementRef> Connection::GetCachedStatement(
+    const StatementID& id,
+    const char* sql) {
+  CachedStatementMap::iterator i = statement_cache_.find(id);
+  if (i != statement_cache_.end()) {
+    // Statement is in the cache. It should still be active (we're the only
+    // one invalidating cached statements, and we'll remove it from the cache
+    // if we do that. Make sure we reset it before giving out the cached one in
+    // case it still has some stuff bound.
+    DCHECK(i->second->is_valid());
+    sqlite3_reset(i->second->stmt());
+    return i->second;
+  }
+
+  scoped_refptr<StatementRef> statement = GetUniqueStatement(sql);
+  if (statement->is_valid())
+    statement_cache_[id] = statement;  // Only cache valid statements.
+  return statement;
+}
+
+scoped_refptr<Connection::StatementRef> Connection::GetUniqueStatement(
+    const char* sql) {
+  AssertIOAllowed();
+
+  if (!db_)
+    return new StatementRef();  // Return inactive statement.
+
+  sqlite3_stmt* stmt = NULL;
+  int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL);
+  if (rc != SQLITE_OK) {
+    // This is evidence of a syntax error in the incoming SQL.
+    DLOG(FATAL) << "SQL compile error " << GetErrorMessage();
+
+    // It could also be database corruption.
+    OnSqliteError(rc, NULL);
+    return new StatementRef();
+  }
+  return new StatementRef(this, stmt);
+}
+
+scoped_refptr<Connection::StatementRef> Connection::GetUntrackedStatement(
+    const char* sql) const {
+  if (!db_)
+    return new StatementRef();  // Return inactive statement.
+
+  sqlite3_stmt* stmt = NULL;
+  int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL);
+  if (rc != SQLITE_OK) {
+    // This is evidence of a syntax error in the incoming SQL.
+    DLOG(FATAL) << "SQL compile error " << GetErrorMessage();
+    return new StatementRef();
+  }
+  return new StatementRef(stmt);
+}
+
+bool Connection::IsSQLValid(const char* sql) {
+  AssertIOAllowed();
+  sqlite3_stmt* stmt = NULL;
+  if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK)
+    return false;
+
+  sqlite3_finalize(stmt);
+  return true;
+}
+
+bool Connection::DoesTableExist(const char* table_name) const {
+  return DoesTableOrIndexExist(table_name, "table");
+}
+
+bool Connection::DoesIndexExist(const char* index_name) const {
+  return DoesTableOrIndexExist(index_name, "index");
+}
+
+bool Connection::DoesTableOrIndexExist(
+    const char* name, const char* type) const {
+  const char* kSql = "SELECT name FROM sqlite_master WHERE type=? AND name=?";
+  Statement statement(GetUntrackedStatement(kSql));
+  statement.BindString(0, type);
+  statement.BindString(1, name);
+
+  return statement.Step();  // Table exists if any row was returned.
+}
+
+bool Connection::DoesColumnExist(const char* table_name,
+                                 const char* column_name) const {
+  std::string sql("PRAGMA TABLE_INFO(");
+  sql.append(table_name);
+  sql.append(")");
+
+  Statement statement(GetUntrackedStatement(sql.c_str()));
+  while (statement.Step()) {
+    if (!statement.ColumnString(1).compare(column_name))
+      return true;
+  }
+  return false;
+}
+
+int64 Connection::GetLastInsertRowId() const {
+  if (!db_) {
+    DLOG(FATAL) << "Illegal use of connection without a db";
+    return 0;
+  }
+  return sqlite3_last_insert_rowid(db_);
+}
+
+int Connection::GetLastChangeCount() const {
+  if (!db_) {
+    DLOG(FATAL) << "Illegal use of connection without a db";
+    return 0;
+  }
+  return sqlite3_changes(db_);
+}
+
+int Connection::GetErrorCode() const {
+  if (!db_)
+    return SQLITE_ERROR;
+  return sqlite3_errcode(db_);
+}
+
+int Connection::GetLastErrno() const {
+  if (!db_)
+    return -1;
+
+  int err = 0;
+  if (SQLITE_OK != sqlite3_file_control(db_, NULL, SQLITE_LAST_ERRNO, &err))
+    return -2;
+
+  return err;
+}
+
+const char* Connection::GetErrorMessage() const {
+  if (!db_)
+    return "sql::Connection has no connection.";
+  return sqlite3_errmsg(db_);
+}
+
+bool Connection::OpenInternal(const std::string& file_name) {
+  AssertIOAllowed();
+
+  if (db_) {
+    DLOG(FATAL) << "sql::Connection is already open.";
+    return false;
+  }
+
+  int err = sqlite3_open(file_name.c_str(), &db_);
+  if (err != SQLITE_OK) {
+    OnSqliteError(err, NULL);
+    Close();
+    db_ = NULL;
+    return false;
+  }
+
+  // Enable extended result codes to provide more color on I/O errors.
+  // Not having extended result codes is not a fatal problem, as
+  // Chromium code does not attempt to handle I/O errors anyhow.  The
+  // current implementation always returns SQLITE_OK, the DCHECK is to
+  // quickly notify someone if SQLite changes.
+  err = sqlite3_extended_result_codes(db_, 1);
+  DCHECK_EQ(err, SQLITE_OK) << "Could not enable extended result codes";
+
+  // If indicated, lock up the database before doing anything else, so
+  // that the following code doesn't have to deal with locking.
+  // TODO(shess): This code is brittle.  Find the cases where code
+  // doesn't request |exclusive_locking_| and audit that it does the
+  // right thing with SQLITE_BUSY, and that it doesn't make
+  // assumptions about who might change things in the database.
+  // http://crbug.com/56559
+  if (exclusive_locking_) {
+    // TODO(shess): This should probably be a full CHECK().  Code
+    // which requests exclusive locking but doesn't get it is almost
+    // certain to be ill-tested.
+    if (!Execute("PRAGMA locking_mode=EXCLUSIVE"))
+      DLOG(FATAL) << "Could not set locking mode: " << GetErrorMessage();
+  }
+
+  // http://www.sqlite.org/pragma.html#pragma_journal_mode
+  // DELETE (default) - delete -journal file to commit.
+  // TRUNCATE - truncate -journal file to commit.
+  // PERSIST - zero out header of -journal file to commit.
+  // journal_size_limit provides size to trim to in PERSIST.
+  // TODO(shess): Figure out if PERSIST and journal_size_limit really
+  // matter.  In theory, it keeps pages pre-allocated, so if
+  // transactions usually fit, it should be faster.
+  ignore_result(Execute("PRAGMA journal_mode = PERSIST"));
+  ignore_result(Execute("PRAGMA journal_size_limit = 16384"));
+
+  const base::TimeDelta kBusyTimeout =
+    base::TimeDelta::FromSeconds(kBusyTimeoutSeconds);
+
+  if (page_size_ != 0) {
+    // Enforce SQLite restrictions on |page_size_|.
+    DCHECK(!(page_size_ & (page_size_ - 1)))
+        << " page_size_ " << page_size_ << " is not a power of two.";
+    const int kSqliteMaxPageSize = 32768;  // from sqliteLimit.h
+    DCHECK_LE(page_size_, kSqliteMaxPageSize);
+    const std::string sql = StringPrintf("PRAGMA page_size=%d", page_size_);
+    if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout))
+      DLOG(FATAL) << "Could not set page size: " << GetErrorMessage();
+  }
+
+  if (cache_size_ != 0) {
+    const std::string sql = StringPrintf("PRAGMA cache_size=%d", cache_size_);
+    if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout))
+      DLOG(FATAL) << "Could not set cache size: " << GetErrorMessage();
+  }
+
+  if (!ExecuteWithTimeout("PRAGMA secure_delete=ON", kBusyTimeout)) {
+    DLOG(FATAL) << "Could not enable secure_delete: " << GetErrorMessage();
+    Close();
+    return false;
+  }
+
+  return true;
+}
+
+void Connection::DoRollback() {
+  Statement rollback(GetCachedStatement(SQL_FROM_HERE, "ROLLBACK"));
+  rollback.Run();
+  needs_rollback_ = false;
+}
+
+void Connection::StatementRefCreated(StatementRef* ref) {
+  DCHECK(open_statements_.find(ref) == open_statements_.end());
+  open_statements_.insert(ref);
+}
+
+void Connection::StatementRefDeleted(StatementRef* ref) {
+  StatementRefSet::iterator i = open_statements_.find(ref);
+  if (i == open_statements_.end())
+    DLOG(FATAL) << "Could not find statement";
+  else
+    open_statements_.erase(i);
+}
+
+void Connection::ClearCache() {
+  statement_cache_.clear();
+
+  // The cache clear will get most statements. There may be still be references
+  // to some statements that are held by others (including one-shot statements).
+  // This will deactivate them so they can't be used again.
+  for (StatementRefSet::iterator i = open_statements_.begin();
+       i != open_statements_.end(); ++i)
+    (*i)->Close();
+}
+
+int Connection::OnSqliteError(int err, sql::Statement *stmt) {
+  if (error_delegate_.get())
+    return error_delegate_->OnError(err, this, stmt);
+  // The default handling is to assert on debug and to ignore on release.
+  DLOG(FATAL) << GetErrorMessage();
+  return err;
+}
+
+}  // namespace sql
diff --git a/sql/connection.h b/sql/connection.h
new file mode 100644
index 0000000..8cf4d71
--- /dev/null
+++ b/sql/connection.h
@@ -0,0 +1,465 @@
+// Copyright (c) 2012 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 SQL_CONNECTION_H_
+#define SQL_CONNECTION_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time.h"
+#include "sql/sql_export.h"
+
+class FilePath;
+struct sqlite3;
+struct sqlite3_stmt;
+
+namespace sql {
+
+class Statement;
+
+// Uniquely identifies a statement. There are two modes of operation:
+//
+// - In the most common mode, you will use the source file and line number to
+//   identify your statement. This is a convienient way to get uniqueness for
+//   a statement that is only used in one place. Use the SQL_FROM_HERE macro
+//   to generate a StatementID.
+//
+// - In the "custom" mode you may use the statement from different places or
+//   need to manage it yourself for whatever reason. In this case, you should
+//   make up your own unique name and pass it to the StatementID. This name
+//   must be a static string, since this object only deals with pointers and
+//   assumes the underlying string doesn't change or get deleted.
+//
+// This object is copyable and assignable using the compiler-generated
+// operator= and copy constructor.
+class StatementID {
+ public:
+  // Creates a uniquely named statement with the given file ane line number.
+  // Normally you will use SQL_FROM_HERE instead of calling yourself.
+  StatementID(const char* file, int line)
+      : number_(line),
+        str_(file) {
+  }
+
+  // Creates a uniquely named statement with the given user-defined name.
+  explicit StatementID(const char* unique_name)
+      : number_(-1),
+        str_(unique_name) {
+  }
+
+  // This constructor is unimplemented and will generate a linker error if
+  // called. It is intended to try to catch people dynamically generating
+  // a statement name that will be deallocated and will cause a crash later.
+  // All strings must be static and unchanging!
+  explicit StatementID(const std::string& dont_ever_do_this);
+
+  // We need this to insert into our map.
+  bool operator<(const StatementID& other) const;
+
+ private:
+  int number_;
+  const char* str_;
+};
+
+#define SQL_FROM_HERE sql::StatementID(__FILE__, __LINE__)
+
+class Connection;
+
+// ErrorDelegate defines the interface to implement error handling and recovery
+// for sqlite operations. This allows the rest of the classes to return true or
+// false while the actual error code and causing statement are delivered using
+// the OnError() callback.
+// The tipical usage is to centralize the code designed to handle database
+// corruption, low-level IO errors or locking violations.
+class SQL_EXPORT ErrorDelegate {
+ public:
+  virtual ~ErrorDelegate();
+
+  // |error| is an sqlite result code as seen in sqlite3.h. |connection| is the
+  // db connection where the error happened and |stmt| is 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 and the original statement succesfuly
+  // re-tried then returning SQLITE_OK is appropriate; otherwise it is
+  // recommended that you return the original |error| or the appropriate error
+  // code.
+  virtual int OnError(int error, Connection* connection, Statement* stmt) = 0;
+};
+
+class SQL_EXPORT Connection {
+ private:
+  class StatementRef;  // Forward declaration, see real one below.
+
+ public:
+  // 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 database. This
+  // must be called before Init(), and will only have an effect on new
+  // databases.
+  //
+  // From sqlite.org: "The page size must be a power of two greater than or
+  // equal to 512 and less than or equal to SQLITE_MAX_PAGE_SIZE. The maximum
+  // value for SQLITE_MAX_PAGE_SIZE is 32768."
+  void set_page_size(int page_size) { page_size_ = page_size; }
+
+  // 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 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
+  // normal" flag because of some additional requirements sqlite puts on this
+  // transaition (requires another access to the DB) and because we don't
+  // actually need it.
+  //
+  // Exclusive mode means that the database is not unlocked at the end of each
+  // 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 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 Open(). If not set, the default is to ignore errors on
+  // release and assert on debug builds.
+  // Takes ownership of |delegate|.
+  void set_error_delegate(ErrorDelegate* delegate) {
+    error_delegate_.reset(delegate);
+  }
+
+  // Initialization ------------------------------------------------------------
+
+  // Initializes the SQL connection for the given file, returning true if the
+  // file could be opened. You can call this or OpenInMemory.
+  bool Open(const FilePath& path) WARN_UNUSED_RESULT;
+
+  // 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 can call this or Open.
+  bool OpenInMemory() WARN_UNUSED_RESULT;
+
+  // 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
+  // any other functions after closing it. It is permissable to call Close on
+  // an uninitialized or already-closed database.
+  void Close();
+
+  // Pre-loads the first <cache-size> pages into the cache from the file.
+  // If you expect to soon use a substantial portion of the database, this
+  // is much more efficient than allowing the pages to be populated organically
+  // since there is no per-page hard drive seeking. If the file is larger than
+  // the cache, the last part that doesn't fit in the cache will be brought in
+  // organically.
+  //
+  // This function assumes your class is using a meta table on the current
+  // database, as it openes a transaction on the meta table to force the
+  // database to be initialized. You should feel free to initialize the meta
+  // table after calling preload since the meta table will already be in the
+  // database if it exists, and if it doesn't exist, the database won't
+  // generally exist either.
+  void Preload();
+
+  // Raze the database to the ground.  This approximates creating a
+  // fresh database from scratch, within the constraints of SQLite's
+  // locking protocol (locks and open handles can make doing this with
+  // filesystem operations problematic).  Returns true if the database
+  // was razed.
+  //
+  // false is returned if the database is locked by some other
+  // process.  RazeWithTimeout() may be used if appropriate.
+  //
+  // NOTE(shess): Raze() will DCHECK in the following situations:
+  // - database is not open.
+  // - the connection has a transaction open.
+  // - a SQLite issue occurs which is structural in nature (like the
+  //   statements used are broken).
+  // Since Raze() is expected to be called in unexpected situations,
+  // these all return false, since it is unlikely that the caller
+  // could fix them.
+  //
+  // The database's page size is taken from |page_size_|.  The
+  // existing database's |auto_vacuum| setting is lost (the
+  // possibility of corruption makes it unreliable to pull it from the
+  // existing database).  To re-enable on the empty database requires
+  // running "PRAGMA auto_vacuum = 1;" then "VACUUM".
+  //
+  // NOTE(shess): For Android, SQLITE_DEFAULT_AUTOVACUUM is set to 1,
+  // so Raze() sets auto_vacuum to 1.
+  //
+  // TODO(shess): Raze() needs a connection so cannot clear SQLITE_NOTADB.
+  // TODO(shess): Bake auto_vacuum into Connection's API so it can
+  // just pick up the default.
+  bool Raze();
+  bool RazeWithTimout(base::TimeDelta timeout);
+
+  // Transactions --------------------------------------------------------------
+
+  // Transaction management. We maintain a virtual transaction stack to emulate
+  // nested transactions since sqlite can't do nested transactions. The
+  // limitation is you can't roll back a sub transaction: if any transaction
+  // fails, all transactions open will also be rolled back. Any nested
+  // transactions after one has rolled back will return fail for Begin(). If
+  // Begin() fails, you must not call Commit or Rollback().
+  //
+  // Normally you should use sql::Transaction to manage a transaction, which
+  // will scope it to a C++ context.
+  bool BeginTransaction();
+  void RollbackTransaction();
+  bool CommitTransaction();
+
+  // Returns the current transaction nesting, which will be 0 if there are
+  // no open transactions.
+  int transaction_nesting() const { return transaction_nesting_; }
+
+  // Statements ----------------------------------------------------------------
+
+  // Executes the given SQL string, returning true on success. This is
+  // normally used for simple, 1-off statements that don't take any bound
+  // parameters and don't return any data (e.g. CREATE TABLE).
+  //
+  // This will DCHECK if the |sql| contains errors.
+  //
+  // Do not use ignore_result() to ignore all errors.  Use
+  // ExecuteAndReturnErrorCode() and ignore only specific errors.
+  bool Execute(const char* sql) WARN_UNUSED_RESULT;
+
+  // Like Execute(), but returns the error code given by SQLite.
+  int ExecuteAndReturnErrorCode(const char* sql) WARN_UNUSED_RESULT;
+
+  // Returns true if we have a statement with the given identifier already
+  // cached. This is normally not necessary to call, but can be useful if the
+  // caller has to dynamically build up SQL to avoid doing so if it's already
+  // cached.
+  bool HasCachedStatement(const StatementID& id) const;
+
+  // Returns a statement for the given SQL using the statement cache. It can
+  // take a nontrivial amount of work to parse and compile a statement, so
+  // keeping commonly-used ones around for future use is important for
+  // performance.
+  //
+  // If the |sql| has an error, an invalid, inert StatementRef is returned (and
+  // the code will crash in debug). The caller must deal with this eventuality,
+  // either by checking validity of the |sql| before calling, by correctly
+  // handling the return of an inert statement, or both.
+  //
+  // The StatementID and the SQL must always correspond to one-another. The
+  // ID is the lookup into the cache, so crazy things will happen if you use
+  // different SQL with the same ID.
+  //
+  // You will normally use the SQL_FROM_HERE macro to generate a statement
+  // ID associated with the current line of code. This gives uniqueness without
+  // you having to manage unique names. See StatementID above for more.
+  //
+  // Example:
+  //   sql::Statement stmt(connection_.GetCachedStatement(
+  //       SQL_FROM_HERE, "SELECT * FROM foo"));
+  //   if (!stmt)
+  //     return false;  // Error creating statement.
+  scoped_refptr<StatementRef> GetCachedStatement(const StatementID& id,
+                                                 const char* sql);
+
+  // Used to check a |sql| statement for syntactic validity. If the statement is
+  // valid SQL, returns true.
+  bool IsSQLValid(const char* sql);
+
+  // Returns a non-cached statement for the given SQL. Use this for SQL that
+  // is only executed once or only rarely (there is overhead associated with
+  // keeping a statement cached).
+  //
+  // See GetCachedStatement above for examples and error information.
+  scoped_refptr<StatementRef> GetUniqueStatement(const char* sql);
+
+  // Info querying -------------------------------------------------------------
+
+  // Returns true if the given table exists.
+  bool DoesTableExist(const char* table_name) const;
+
+  // Returns true if the given index exists.
+  bool DoesIndexExist(const char* index_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;
+
+  // Returns sqlite's internal ID for the last inserted row. Valid only
+  // immediately after an insert.
+  int64 GetLastInsertRowId() const;
+
+  // Returns sqlite's count of the number of rows modified by the last
+  // statement executed. Will be 0 if no statement has executed or the database
+  // is closed.
+  int GetLastChangeCount() const;
+
+  // Errors --------------------------------------------------------------------
+
+  // Returns the error code associated with the last sqlite operation.
+  int GetErrorCode() const;
+
+  // Returns the errno associated with GetErrorCode().  See
+  // SQLITE_LAST_ERRNO in SQLite documentation.
+  int GetLastErrno() const;
+
+  // Returns a pointer to a statically allocated string associated with the
+  // last sqlite operation.
+  const char* GetErrorMessage() const;
+
+ private:
+  // Statement accesses StatementRef which we don't want to expose to everybody
+  // (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);
+
+  // Check whether the current thread is allowed to make IO calls, but only
+  // if database wasn't open in memory. Function is inlined to be a no-op in
+  // official build.
+  void AssertIOAllowed() {
+    if (!in_memory_)
+      base::ThreadRestrictions::AssertIOAllowed();
+  }
+
+  // Internal helper for DoesTableExist and DoesIndexExist.
+  bool DoesTableOrIndexExist(const char* name, const char* type) const;
+
+  // 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
+  // by just keeping a refptr to these objects.
+  //
+  // A statement ref can be valid, in which case it can be used, or invalid to
+  // indicate that the statement hasn't been created yet, has an error, or has
+  // been destroyed.
+  //
+  // The Connection may revoke a StatementRef in some error cases, so callers
+  // should always check validity before using.
+  class SQL_EXPORT StatementRef : public base::RefCounted<StatementRef> {
+   public:
+    // Default constructor initializes to an invalid statement.
+    StatementRef();
+    explicit StatementRef(sqlite3_stmt* stmt);
+    StatementRef(Connection* connection, sqlite3_stmt* stmt);
+
+    // When true, the statement can be used.
+    bool is_valid() const { return !!stmt_; }
+
+    // If we've not been linked to a connection, this will be NULL. Guaranteed
+    // non-NULL when is_valid().
+    Connection* connection() const { return connection_; }
+
+    // Returns the sqlite statement if any. If the statement is not active,
+    // this will return NULL.
+    sqlite3_stmt* stmt() const { return stmt_; }
+
+    // Destroys the compiled statement and marks it NULL. The statement will
+    // no longer be active.
+    void Close();
+
+    // Check whether the current thread is allowed to make IO calls, but only
+    // if database wasn't open in memory.
+    void AssertIOAllowed() { if (connection_) connection_->AssertIOAllowed(); }
+
+   private:
+    friend class base::RefCounted<StatementRef>;
+
+    ~StatementRef();
+
+    Connection* connection_;
+    sqlite3_stmt* stmt_;
+
+    DISALLOW_COPY_AND_ASSIGN(StatementRef);
+  };
+  friend class StatementRef;
+
+  // Executes a rollback statement, ignoring all transaction state. Used
+  // internally in the transaction management code.
+  void DoRollback();
+
+  // Called by a StatementRef when it's being created or destroyed. See
+  // open_statements_ below.
+  void StatementRefCreated(StatementRef* ref);
+  void StatementRefDeleted(StatementRef* ref);
+
+  // Frees all cached statements from statement_cache_.
+  void ClearCache();
+
+  // Called by Statement objects when an sqlite function returns an error.
+  // The return value is the error code reflected back to client code.
+  int OnSqliteError(int err, Statement* stmt);
+
+  // Like |Execute()|, but retries if the database is locked.
+  bool ExecuteWithTimeout(const char* sql, base::TimeDelta ms_timeout)
+      WARN_UNUSED_RESULT;
+
+  // Internal helper for const functions.  Like GetUniqueStatement(),
+  // except the statement is not entered into open_statements_,
+  // allowing this function to be const.  Open statements can block
+  // closing the database, so only use in cases where the last ref is
+  // released before close could be called (which should always be the
+  // case for const functions).
+  scoped_refptr<StatementRef> GetUntrackedStatement(const char* sql) const;
+
+  // The actual sqlite database. Will be NULL before Init has been called or if
+  // Init resulted in an error.
+  sqlite3* db_;
+
+  // Parameters we'll configure in sqlite before doing anything else. Zero means
+  // use the default value.
+  int page_size_;
+  int cache_size_;
+  bool exclusive_locking_;
+
+  // All cached statements. Keeping a reference to these statements means that
+  // they'll remain active.
+  typedef std::map<StatementID, scoped_refptr<StatementRef> >
+      CachedStatementMap;
+  CachedStatementMap statement_cache_;
+
+  // A list of all StatementRefs we've given out. Each ref must register with
+  // us when it's created or destroyed. This allows us to potentially close
+  // any open statements when we encounter an error.
+  typedef std::set<StatementRef*> StatementRefSet;
+  StatementRefSet open_statements_;
+
+  // Number of currently-nested transactions.
+  int transaction_nesting_;
+
+  // True if any of the currently nested transactions have been rolled back.
+  // When we get to the outermost transaction, this will determine if we do
+  // a rollback instead of a commit.
+  bool needs_rollback_;
+
+  // True if database is open with OpenInMemory(), False if database is open
+  // with Open().
+  bool in_memory_;
+
+  // This object handles errors resulting from all forms of executing sqlite
+  // commands or statements. It can be null which means default handling.
+  scoped_ptr<ErrorDelegate> error_delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(Connection);
+};
+
+}  // namespace sql
+
+#endif  // SQL_CONNECTION_H_
diff --git a/sql/connection_unittest.cc b/sql/connection_unittest.cc
new file mode 100644
index 0000000..8036409
--- /dev/null
+++ b/sql/connection_unittest.cc
@@ -0,0 +1,297 @@
+// Copyright (c) 2012 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 "base/file_util.h"
+#include "base/scoped_temp_dir.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/meta_table.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/sqlite/sqlite3.h"
+
+class SQLConnectionTest : public testing::Test {
+ public:
+  SQLConnectionTest() {}
+
+  void SetUp() {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(db_.Open(db_path()));
+  }
+
+  void TearDown() {
+    db_.Close();
+  }
+
+  sql::Connection& db() { return db_; }
+
+  FilePath db_path() {
+    return temp_dir_.path().AppendASCII("SQLConnectionTest.db");
+  }
+
+ private:
+  ScopedTempDir temp_dir_;
+  sql::Connection db_;
+};
+
+TEST_F(SQLConnectionTest, Execute) {
+  // Valid statement should return true.
+  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
+  EXPECT_EQ(SQLITE_OK, db().GetErrorCode());
+
+  // Invalid statement should fail.
+  ASSERT_EQ(SQLITE_ERROR,
+            db().ExecuteAndReturnErrorCode("CREATE TAB foo (a, b"));
+  EXPECT_EQ(SQLITE_ERROR, db().GetErrorCode());
+}
+
+TEST_F(SQLConnectionTest, ExecuteWithErrorCode) {
+  ASSERT_EQ(SQLITE_OK,
+            db().ExecuteAndReturnErrorCode("CREATE TABLE foo (a, b)"));
+  ASSERT_EQ(SQLITE_ERROR,
+            db().ExecuteAndReturnErrorCode("CREATE TABLE TABLE"));
+  ASSERT_EQ(SQLITE_ERROR,
+            db().ExecuteAndReturnErrorCode(
+                "INSERT INTO foo(a, b) VALUES (1, 2, 3, 4)"));
+}
+
+TEST_F(SQLConnectionTest, CachedStatement) {
+  sql::StatementID id1("foo", 12);
+
+  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
+  ASSERT_TRUE(db().Execute("INSERT INTO foo(a, b) VALUES (12, 13)"));
+
+  // Create a new cached statement.
+  {
+    sql::Statement s(db().GetCachedStatement(id1, "SELECT a FROM foo"));
+    ASSERT_TRUE(s.is_valid());
+
+    ASSERT_TRUE(s.Step());
+    EXPECT_EQ(12, s.ColumnInt(0));
+  }
+
+  // The statement should be cached still.
+  EXPECT_TRUE(db().HasCachedStatement(id1));
+
+  {
+    // Get the same statement using different SQL. This should ignore our
+    // SQL and use the cached one (so it will be valid).
+    sql::Statement s(db().GetCachedStatement(id1, "something invalid("));
+    ASSERT_TRUE(s.is_valid());
+
+    ASSERT_TRUE(s.Step());
+    EXPECT_EQ(12, s.ColumnInt(0));
+  }
+
+  // Make sure other statements aren't marked as cached.
+  EXPECT_FALSE(db().HasCachedStatement(SQL_FROM_HERE));
+}
+
+TEST_F(SQLConnectionTest, IsSQLValidTest) {
+  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
+  ASSERT_TRUE(db().IsSQLValid("SELECT a FROM foo"));
+  ASSERT_FALSE(db().IsSQLValid("SELECT no_exist FROM foo"));
+}
+
+TEST_F(SQLConnectionTest, DoesStuffExist) {
+  // Test DoesTableExist.
+  EXPECT_FALSE(db().DoesTableExist("foo"));
+  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
+  EXPECT_TRUE(db().DoesTableExist("foo"));
+
+  // Should be case sensitive.
+  EXPECT_FALSE(db().DoesTableExist("FOO"));
+
+  // Test DoesColumnExist.
+  EXPECT_FALSE(db().DoesColumnExist("foo", "bar"));
+  EXPECT_TRUE(db().DoesColumnExist("foo", "a"));
+
+  // Testing for a column on a nonexistent table.
+  EXPECT_FALSE(db().DoesColumnExist("bar", "b"));
+}
+
+TEST_F(SQLConnectionTest, GetLastInsertRowId) {
+  ASSERT_TRUE(db().Execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"));
+
+  ASSERT_TRUE(db().Execute("INSERT INTO foo (value) VALUES (12)"));
+
+  // Last insert row ID should be valid.
+  int64 row = db().GetLastInsertRowId();
+  EXPECT_LT(0, row);
+
+  // It should be the primary key of the row we just inserted.
+  sql::Statement s(db().GetUniqueStatement("SELECT value FROM foo WHERE id=?"));
+  s.BindInt64(0, row);
+  ASSERT_TRUE(s.Step());
+  EXPECT_EQ(12, s.ColumnInt(0));
+}
+
+TEST_F(SQLConnectionTest, Rollback) {
+  ASSERT_TRUE(db().BeginTransaction());
+  ASSERT_TRUE(db().BeginTransaction());
+  EXPECT_EQ(2, db().transaction_nesting());
+  db().RollbackTransaction();
+  EXPECT_FALSE(db().CommitTransaction());
+  EXPECT_TRUE(db().BeginTransaction());
+}
+
+// Test that sql::Connection::Raze() results in a database without the
+// tables from the original database.
+TEST_F(SQLConnectionTest, Raze) {
+  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
+  ASSERT_TRUE(db().Execute(kCreateSql));
+  ASSERT_TRUE(db().Execute("INSERT INTO foo (value) VALUES (12)"));
+
+  int pragma_auto_vacuum = 0;
+  {
+    sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum"));
+    ASSERT_TRUE(s.Step());
+    pragma_auto_vacuum = s.ColumnInt(0);
+    ASSERT_TRUE(pragma_auto_vacuum == 0 || pragma_auto_vacuum == 1);
+  }
+
+  // If auto_vacuum is set, there's an extra page to maintain a freelist.
+  const int kExpectedPageCount = 2 + pragma_auto_vacuum;
+
+  {
+    sql::Statement s(db().GetUniqueStatement("PRAGMA page_count"));
+    ASSERT_TRUE(s.Step());
+    EXPECT_EQ(kExpectedPageCount, s.ColumnInt(0));
+  }
+
+  {
+    sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master"));
+    ASSERT_TRUE(s.Step());
+    EXPECT_EQ("table", s.ColumnString(0));
+    EXPECT_EQ("foo", s.ColumnString(1));
+    EXPECT_EQ("foo", s.ColumnString(2));
+    // Table "foo" is stored in the last page of the file.
+    EXPECT_EQ(kExpectedPageCount, s.ColumnInt(3));
+    EXPECT_EQ(kCreateSql, s.ColumnString(4));
+  }
+
+  ASSERT_TRUE(db().Raze());
+
+  {
+    sql::Statement s(db().GetUniqueStatement("PRAGMA page_count"));
+    ASSERT_TRUE(s.Step());
+    EXPECT_EQ(1, s.ColumnInt(0));
+  }
+
+  {
+    sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master"));
+    ASSERT_FALSE(s.Step());
+  }
+
+  {
+    sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum"));
+    ASSERT_TRUE(s.Step());
+    // The new database has the same auto_vacuum as a fresh database.
+    EXPECT_EQ(pragma_auto_vacuum, s.ColumnInt(0));
+  }
+}
+
+// Test that Raze() maintains page_size.
+TEST_F(SQLConnectionTest, RazePageSize) {
+  // Fetch the default page size and double it for use in this test.
+  // Scoped to release statement before Close().
+  int default_page_size = 0;
+  {
+    sql::Statement s(db().GetUniqueStatement("PRAGMA page_size"));
+    ASSERT_TRUE(s.Step());
+    default_page_size = s.ColumnInt(0);
+  }
+  ASSERT_GT(default_page_size, 0);
+  const int kPageSize = 2 * default_page_size;
+
+  // Re-open the database to allow setting the page size.
+  db().Close();
+  db().set_page_size(kPageSize);
+  ASSERT_TRUE(db().Open(db_path()));
+
+  // page_size should match the indicated value.
+  sql::Statement s(db().GetUniqueStatement("PRAGMA page_size"));
+  ASSERT_TRUE(s.Step());
+  ASSERT_EQ(kPageSize, s.ColumnInt(0));
+
+  // After raze, page_size should still match the indicated value.
+  ASSERT_TRUE(db().Raze());
+  s.Reset(true);
+  ASSERT_TRUE(s.Step());
+  ASSERT_EQ(kPageSize, s.ColumnInt(0));
+}
+
+// Test that Raze() results are seen in other connections.
+TEST_F(SQLConnectionTest, RazeMultiple) {
+  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
+  ASSERT_TRUE(db().Execute(kCreateSql));
+
+  sql::Connection other_db;
+  ASSERT_TRUE(other_db.Open(db_path()));
+
+  // Check that the second connection sees the table.
+  const char *kTablesQuery = "SELECT COUNT(*) FROM sqlite_master";
+  sql::Statement s(other_db.GetUniqueStatement(kTablesQuery));
+  ASSERT_TRUE(s.Step());
+  ASSERT_EQ(1, s.ColumnInt(0));
+  ASSERT_FALSE(s.Step());  // Releases the shared lock.
+
+  ASSERT_TRUE(db().Raze());
+
+  // The second connection sees the updated database.
+  s.Reset(true);
+  ASSERT_TRUE(s.Step());
+  ASSERT_EQ(0, s.ColumnInt(0));
+}
+
+TEST_F(SQLConnectionTest, RazeLocked) {
+  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
+  ASSERT_TRUE(db().Execute(kCreateSql));
+
+  // Open a transaction and write some data in a second connection.
+  // This will acquire a PENDING or EXCLUSIVE transaction, which will
+  // cause the raze to fail.
+  sql::Connection other_db;
+  ASSERT_TRUE(other_db.Open(db_path()));
+  ASSERT_TRUE(other_db.BeginTransaction());
+  const char* kInsertSql = "INSERT INTO foo VALUES (1, 'data')";
+  ASSERT_TRUE(other_db.Execute(kInsertSql));
+
+  ASSERT_FALSE(db().Raze());
+
+  // Works after COMMIT.
+  ASSERT_TRUE(other_db.CommitTransaction());
+  ASSERT_TRUE(db().Raze());
+
+  // Re-create the database.
+  ASSERT_TRUE(db().Execute(kCreateSql));
+  ASSERT_TRUE(db().Execute(kInsertSql));
+
+  // An unfinished read transaction in the other connection also
+  // blocks raze.
+  const char *kQuery = "SELECT COUNT(*) FROM foo";
+  sql::Statement s(other_db.GetUniqueStatement(kQuery));
+  ASSERT_TRUE(s.Step());
+  ASSERT_FALSE(db().Raze());
+
+  // Complete the statement unlocks the database.
+  ASSERT_FALSE(s.Step());
+  ASSERT_TRUE(db().Raze());
+}
+
+#if defined(OS_ANDROID)
+TEST_F(SQLConnectionTest, SetTempDirForSQL) {
+
+  sql::MetaTable meta_table;
+  // Below call needs a temporary directory in sqlite3
+  // On Android, it can pass only when the temporary directory is set.
+  // Otherwise, sqlite3 doesn't find the correct directory to store
+  // temporary files and will report the error 'unable to open
+  // database file'.
+  ASSERT_TRUE(meta_table.Init(&db(), 4, 4));
+}
+#endif
+
+// TODO(shess): Spin up a background thread to hold other_db, to more
+// closely match real life.  That would also allow testing
+// RazeWithTimeout().
diff --git a/sql/diagnostic_error_delegate.h b/sql/diagnostic_error_delegate.h
new file mode 100644
index 0000000..78b3d9d
--- /dev/null
+++ b/sql/diagnostic_error_delegate.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 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 SQL_DIAGNOSTIC_ERROR_DELEGATE_H_
+#define SQL_DIAGNOSTIC_ERROR_DELEGATE_H_
+
+#include "base/logging.h"
+#include "sql/connection.h"
+#include "sql/error_delegate_util.h"
+#include "sql/sql_export.h"
+
+namespace sql {
+
+// This class handles the exceptional sqlite errors that we might encounter
+// if for example the db is corrupted. Right now we just generate a UMA
+// histogram for release and an assert for debug builds.
+// See error_delegate_util.h for an explanation as to why this class is a
+// template.
+template <class UniqueT>
+class DiagnosticErrorDelegate : public ErrorDelegate {
+ public:
+  DiagnosticErrorDelegate() {}
+  virtual ~DiagnosticErrorDelegate() {}
+
+  virtual int OnError(int error, Connection* connection,
+                      Statement* stmt) {
+    LogAndRecordErrorInHistogram<UniqueT>(error, connection);
+    return error;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DiagnosticErrorDelegate);
+};
+
+}  // namespace sql
+
+#endif  // SQL_DIAGNOSTIC_ERROR_DELEGATE_H_
diff --git a/sql/error_delegate_util.cc b/sql/error_delegate_util.cc
new file mode 100644
index 0000000..37fe006
--- /dev/null
+++ b/sql/error_delegate_util.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 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 "sql/error_delegate_util.h"
+
+#include "third_party/sqlite/sqlite3.h"
+
+namespace sql {
+
+bool IsErrorCatastrophic(int error) {
+  switch (error) {
+    case SQLITE_DONE:
+    case SQLITE_OK:
+      // Theoretically, the wrapped delegate might have resolved the error, and
+      // we would end up here.
+      return false;
+
+    case SQLITE_CORRUPT:
+    case SQLITE_NOTADB:
+      // Highly unlikely we would ever recover from these.
+      return true;
+
+    case SQLITE_CANTOPEN:
+      // TODO(erikwright): Figure out what this means.
+      return false;
+
+    case SQLITE_IOERR:
+      // This could be broken blocks, in which case deleting the DB would be a
+      // good idea. But it might also be transient.
+      // TODO(erikwright): Figure out if we can distinguish between the two,
+      // or determine through metrics analysis to what extent these failures are
+      // transient.
+      return false;
+
+    case SQLITE_BUSY:
+      // Presumably transient.
+      return false;
+
+    case SQLITE_TOOBIG:
+    case SQLITE_FULL:
+    case SQLITE_NOMEM:
+      // Not a problem with the database.
+      return false;
+
+    case SQLITE_READONLY:
+      // Presumably either transient or we don't have the privileges to
+      // move/delete the file anyway.
+      return false;
+
+    case SQLITE_CONSTRAINT:
+    case SQLITE_ERROR:
+      // These probgably indicate a programming error or a migration failure
+      // that we prefer not to mask.
+      return false;
+
+    case SQLITE_LOCKED:
+    case SQLITE_INTERNAL:
+    case SQLITE_PERM:
+    case SQLITE_ABORT:
+    case SQLITE_INTERRUPT:
+    case SQLITE_NOTFOUND:
+    case SQLITE_PROTOCOL:
+    case SQLITE_EMPTY:
+    case SQLITE_SCHEMA:
+    case SQLITE_MISMATCH:
+    case SQLITE_MISUSE:
+    case SQLITE_NOLFS:
+    case SQLITE_AUTH:
+    case SQLITE_FORMAT:
+    case SQLITE_RANGE:
+    case SQLITE_ROW:
+      // None of these appear in error reports, so for now let's not try to
+      // guess at how to handle them.
+      return false;
+  }
+  return false;
+}
+
+}  // namespace sql
diff --git a/sql/error_delegate_util.h b/sql/error_delegate_util.h
new file mode 100644
index 0000000..6b90ccf
--- /dev/null
+++ b/sql/error_delegate_util.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 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 SQL_ERROR_DELEGATE_UTIL_H_
+#define SQL_ERROR_DELEGATE_UTIL_H_
+
+#include "base/metrics/histogram.h"
+#include "sql/connection.h"
+#include "sql/sql_export.h"
+
+namespace sql {
+
+// Returns true if it is highly unlikely that the database can recover from
+// |error|.
+SQL_EXPORT bool IsErrorCatastrophic(int error);
+
+// Log error in console in debug mode and generate a UMA histogram in release
+// mode for |error| for |UniqueT::name()|.
+// This function is templated because histograms need to be singletons. That is
+// why they are always static at the function scope. The template parameter
+// makes the compiler create unique functions that don't share the same static
+// variable.
+template <class UniqueT>
+void LogAndRecordErrorInHistogram(int error,
+                                  sql::Connection* connection) {
+  LOG(ERROR) << "sqlite error " << error
+             << ", errno " << connection->GetLastErrno()
+             << ": " << connection->GetErrorMessage();
+
+  // Trim off the extended error codes.
+  error &= 0xff;
+
+  // The histogram values from sqlite result codes currently go from 1 to 26
+  // but 50 gives them room to grow.
+  UMA_HISTOGRAM_ENUMERATION(UniqueT::name(), error, 50);
+}
+
+}  // namespace sql
+
+#endif  // SQL_ERROR_DELEGATE_UTIL_H_
diff --git a/sql/init_status.h b/sql/init_status.h
new file mode 100644
index 0000000..8002b43
--- /dev/null
+++ b/sql/init_status.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef APP_SQL_INIT_STATUS_H_
+#define APP_SQL_INIT_STATUS_H_
+
+namespace sql {
+
+// Used as the return value for some databases' init functions.
+enum InitStatus {
+  INIT_OK,
+
+  // Some error, usually I/O related opening the file.
+  INIT_FAILURE,
+
+  // The database is from a future version of the app and cannot be read.
+  INIT_TOO_NEW,
+};
+
+}  // namespace sql
+
+#endif  // APP_SQL_INIT_STATUS_H_
diff --git a/sql/meta_table.cc b/sql/meta_table.cc
new file mode 100644
index 0000000..45f4ee0
--- /dev/null
+++ b/sql/meta_table.cc
@@ -0,0 +1,153 @@
+// Copyright (c) 2012 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 "sql/meta_table.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace sql {
+
+// Key used in our meta table for version numbers.
+static const char kVersionKey[] = "version";
+static const char kCompatibleVersionKey[] = "last_compatible_version";
+
+MetaTable::MetaTable() : db_(NULL) {
+}
+
+MetaTable::~MetaTable() {
+}
+
+// static
+bool MetaTable::DoesTableExist(sql::Connection* db) {
+  DCHECK(db);
+  return db->DoesTableExist("meta");
+}
+
+bool MetaTable::Init(Connection* db, int version, int compatible_version) {
+  DCHECK(!db_ && db);
+  db_ = db;
+
+  // If values stored are null or missing entirely, 0 will be reported.
+  // Require new clients to start with a greater initial version.
+  DCHECK_GT(version, 0);
+  DCHECK_GT(compatible_version, 0);
+
+  // Make sure the table is created an populated atomically.
+  sql::Transaction transaction(db_);
+  if (!transaction.Begin())
+    return false;
+
+  if (!DoesTableExist(db)) {
+    if (!db_->Execute("CREATE TABLE meta"
+        "(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR)"))
+      return false;
+
+    // Note: there is no index over the meta table. We currently only have a
+    // couple of keys, so it doesn't matter. If we start storing more stuff in
+    // there, we should create an index.
+    SetVersionNumber(version);
+    SetCompatibleVersionNumber(compatible_version);
+  }
+  return transaction.Commit();
+}
+
+void MetaTable::Reset() {
+  db_ = NULL;
+}
+
+void MetaTable::SetVersionNumber(int version) {
+  DCHECK_GT(version, 0);
+  SetValue(kVersionKey, version);
+}
+
+int MetaTable::GetVersionNumber() {
+  int version = 0;
+  return GetValue(kVersionKey, &version) ? version : 0;
+}
+
+void MetaTable::SetCompatibleVersionNumber(int version) {
+  DCHECK_GT(version, 0);
+  SetValue(kCompatibleVersionKey, version);
+}
+
+int MetaTable::GetCompatibleVersionNumber() {
+  int version = 0;
+  return GetValue(kCompatibleVersionKey, &version) ? version : 0;
+}
+
+bool MetaTable::SetValue(const char* key, const std::string& value) {
+  Statement s;
+  PrepareSetStatement(&s, key);
+  s.BindString(1, value);
+  return s.Run();
+}
+
+bool MetaTable::SetValue(const char* key, int value) {
+  Statement s;
+  PrepareSetStatement(&s, key);
+  s.BindInt(1, value);
+  return s.Run();
+}
+
+bool MetaTable::SetValue(const char* key, int64 value) {
+  Statement s;
+  PrepareSetStatement(&s, key);
+  s.BindInt64(1, value);
+  return s.Run();
+}
+
+bool MetaTable::GetValue(const char* key, std::string* value) {
+  Statement s;
+  if (!PrepareGetStatement(&s, key))
+    return false;
+
+  *value = s.ColumnString(0);
+  return true;
+}
+
+bool MetaTable::GetValue(const char* key, int* value) {
+  Statement s;
+  if (!PrepareGetStatement(&s, key))
+    return false;
+
+  *value = s.ColumnInt(0);
+  return true;
+}
+
+bool MetaTable::GetValue(const char* key, int64* value) {
+  Statement s;
+  if (!PrepareGetStatement(&s, key))
+    return false;
+
+  *value = s.ColumnInt64(0);
+  return true;
+}
+
+bool MetaTable::DeleteKey(const char* key) {
+  DCHECK(db_);
+  Statement s(db_->GetUniqueStatement("DELETE FROM meta WHERE key=?"));
+  s.BindCString(0, key);
+  return s.Run();
+}
+
+void MetaTable::PrepareSetStatement(Statement* statement, const char* key) {
+  DCHECK(db_ && statement);
+  statement->Assign(db_->GetCachedStatement(SQL_FROM_HERE,
+      "INSERT OR REPLACE INTO meta (key,value) VALUES (?,?)"));
+  statement->BindCString(0, key);
+}
+
+bool MetaTable::PrepareGetStatement(Statement* statement, const char* key) {
+  DCHECK(db_ && statement);
+  statement->Assign(db_->GetCachedStatement(SQL_FROM_HERE,
+      "SELECT value FROM meta WHERE key=?"));
+  statement->BindCString(0, key);
+  return statement->Step();
+}
+
+}  // namespace sql
diff --git a/sql/meta_table.h b/sql/meta_table.h
new file mode 100644
index 0000000..0f4ee72
--- /dev/null
+++ b/sql/meta_table.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 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 SQL_META_TABLE_H_
+#define SQL_META_TABLE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "sql/sql_export.h"
+
+namespace sql {
+
+class Connection;
+class Statement;
+
+class SQL_EXPORT MetaTable {
+ public:
+  MetaTable();
+  ~MetaTable();
+
+  // Returns true if the 'meta' table exists.
+  static bool DoesTableExist(Connection* db);
+
+  // Initializes the MetaTableHelper, creating the meta table if necessary. For
+  // new tables, it will initialize the version number to |version| and the
+  // compatible version number to |compatible_version|.  Versions must be
+  // greater than 0 to distinguish missing versions (see GetVersionNumber()).
+  bool Init(Connection* db, int version, int compatible_version);
+
+  // Resets this MetaTable object, making another call to Init() possible.
+  void Reset();
+
+  // The version number of the database. This should be the version number of
+  // the creator of the file. The version number will be 0 if there is no
+  // previously set version number.
+  //
+  // See also Get/SetCompatibleVersionNumber().
+  void SetVersionNumber(int version);
+  int GetVersionNumber();
+
+  // The compatible version number is the lowest version of the code that this
+  // database can be read by. If there are minor changes or additions, old
+  // versions of the code can still work with the database without failing.
+  //
+  // For example, if an optional column is added to a table in version 3, the
+  // new code will set the version to 3, and the compatible version to 2, since
+  // the code expecting version 2 databases can still read and write the table.
+  //
+  // Rule of thumb: check the version number when you're upgrading, but check
+  // the compatible version number to see if you can read the file at all. If
+  // it's larger than you code is expecting, fail.
+  //
+  // The compatible version number will be 0 if there is no previously set
+  // compatible version number.
+  void SetCompatibleVersionNumber(int version);
+  int GetCompatibleVersionNumber();
+
+  // Set the given arbitrary key with the given data. Returns true on success.
+  bool SetValue(const char* key, const std::string& value);
+  bool SetValue(const char* key, int value);
+  bool SetValue(const char* key, int64 value);
+
+  // Retrieves the value associated with the given key. This will use sqlite's
+  // type conversion rules. It will return true on success.
+  bool GetValue(const char* key, std::string* value);
+  bool GetValue(const char* key, int* value);
+  bool GetValue(const char* key, int64* value);
+
+  // Deletes the key from the table.
+  bool DeleteKey(const char* key);
+
+ private:
+  // Conveniences to prepare the two types of statements used by
+  // MetaTableHelper.
+  void PrepareSetStatement(Statement* statement, const char* key);
+  bool PrepareGetStatement(Statement* statement, const char* key);
+
+  Connection* db_;
+
+  DISALLOW_COPY_AND_ASSIGN(MetaTable);
+};
+
+}  // namespace sql
+
+#endif  // SQL_META_TABLE_H_
diff --git a/sql/run_all_unittests.cc b/sql/run_all_unittests.cc
new file mode 100644
index 0000000..969b091
--- /dev/null
+++ b/sql/run_all_unittests.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 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 "base/test/main_hook.h"
+#include "base/test/test_suite.h"
+
+int main(int argc, char** argv) {
+  MainHook hook(main, argc, argv);
+  return base::TestSuite(argc, argv).Run();
+}
diff --git a/sql/sql.gyp b/sql/sql.gyp
new file mode 100644
index 0000000..86962b3
--- /dev/null
+++ b/sql/sql.gyp
@@ -0,0 +1,89 @@
+# Copyright (c) 2012 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.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'targets': [
+    {
+      'target_name': 'sql',
+      'type': '<(component)',
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../third_party/sqlite/sqlite.gyp:sqlite',
+      ],
+      'defines': [ 'SQL_IMPLEMENTATION' ],
+      'sources': [
+        'connection.cc',
+        'connection.h',
+        'diagnostic_error_delegate.h',
+        'error_delegate_util.cc',
+        'error_delegate_util.h',
+        'init_status.h',
+        'meta_table.cc',
+        'meta_table.h',
+        'statement.cc',
+        'statement.h',
+        'transaction.cc',
+        'transaction.h',
+      ],
+    },
+    {
+      'target_name': 'sql_unittests',
+      'type': '<(gtest_target_type)',
+      'dependencies': [
+        'sql',
+        '../base/base.gyp:test_support_base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'run_all_unittests.cc',
+        'connection_unittest.cc',
+        'sqlite_features_unittest.cc',
+        'statement_unittest.cc',
+        'transaction_unittest.cc',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'conditions': [
+        ['os_posix==1 and OS!="mac" and OS!="ios"', {
+          'conditions': [
+            ['linux_use_tcmalloc==1', {
+              'dependencies': [
+                '../base/allocator/allocator.gyp:allocator',
+              ],
+            }],
+          ],
+        }],
+        ['OS == "android" and gtest_target_type == "shared_library"', {
+          'dependencies': [
+            '../testing/android/native_test.gyp:native_test_native_code',
+          ],
+        }],
+      ],
+    },
+  ],
+  'conditions': [
+    # Special target to wrap a gtest_target_type==shared_library
+    # sql_unittests into an android apk for execution.
+    ['OS == "android" and gtest_target_type == "shared_library"', {
+      'targets': [
+        {
+          'target_name': 'sql_unittests_apk',
+          'type': 'none',
+          'dependencies': [
+            'sql_unittests',
+          ],
+          'variables': {
+            'test_suite_name': 'sql_unittests',
+            'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)sql_unittests<(SHARED_LIB_SUFFIX)',
+          },
+          'includes': [ '../build/apk_test.gypi' ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/sql/sql.target.mk b/sql/sql.target.mk
new file mode 100644
index 0000000..029beef
--- /dev/null
+++ b/sql/sql.target.mk
@@ -0,0 +1,153 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := sql_sql_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+	sql/connection.cc \
+	sql/error_delegate_util.cc \
+	sql/meta_table.cc \
+	sql/statement.cc \
+	sql/transaction.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS := \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-mthumb \
+	-march=armv7-a \
+	-mtune=cortex-a8 \
+	-mfloat-abi=softfp \
+	-mfpu=vfpv3-d16 \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-mthumb-interwork \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-Wno-error=extra \
+	-Wno-error=ignored-qualifiers \
+	-Wno-error=type-limits \
+	-Wno-error=non-virtual-dtor \
+	-Wno-error=sign-promo \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_CFLAGS_C :=
+
+MY_DEFS := \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_PEPPER_THREADING' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DUSE_SKIA=1' \
+	'-DSQL_IMPLEMENTATION' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_SYMBOLS_ID=""' \
+	'-DANDROID_UPSTREAM_BRINGUP=1' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+LOCAL_CFLAGS := $(MY_CFLAGS_C) $(MY_CFLAGS) $(MY_DEFS)
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/sqlite \
+	$(GYP_ABS_ANDROID_TOP_DIR)/frameworks/wilhelm/include \
+	$(GYP_ABS_ANDROID_TOP_DIR)/bionic \
+	$(GYP_ABS_ANDROID_TOP_DIR)/external/stlport/stlport
+
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES)
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-Wno-error=c++0x-compat
+
+### Rules for final target.
+
+LOCAL_LDFLAGS := \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections
+
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: sql_sql_gyp
+
+# Alias gyp target name.
+.PHONY: sql
+sql: sql_sql_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/sql/sql_export.h b/sql/sql_export.h
new file mode 100644
index 0000000..7ab3355
--- /dev/null
+++ b/sql/sql_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SQL_EXPORT_H_
+#define SQL_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(SQL_IMPLEMENTATION)
+#define SQL_EXPORT __declspec(dllexport)
+#else
+#define SQL_EXPORT __declspec(dllimport)
+#endif  // defined(SQL_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(SQL_IMPLEMENTATION)
+#define SQL_EXPORT __attribute__((visibility("default")))
+#else
+#define SQL_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define SQL_EXPORT
+#endif
+
+#endif  // SQL_EXPORT_H_
diff --git a/sql/sqlite_features_unittest.cc b/sql/sqlite_features_unittest.cc
new file mode 100644
index 0000000..7e750e9
--- /dev/null
+++ b/sql/sqlite_features_unittest.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2012 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 <string>
+
+#include "base/file_util.h"
+#include "base/scoped_temp_dir.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/sqlite/sqlite3.h"
+
+// Test that certain features are/are-not enabled in our SQLite.
+
+namespace {
+
+class StatementErrorHandler : public sql::ErrorDelegate {
+ public:
+  StatementErrorHandler(int* error, std::string* sql_text)
+    : error_(error),
+      sql_text_(sql_text) {}
+
+  virtual ~StatementErrorHandler() {}
+
+  virtual int OnError(int error, sql::Connection* connection,
+                      sql::Statement* stmt) OVERRIDE {
+    *error_ = error;
+    const char* sql_txt = stmt ? stmt->GetSQLStatement() : NULL;
+    *sql_text_ = sql_txt ? sql_txt : "no statement available";
+    return error;
+  }
+
+ private:
+  int* error_;
+  std::string* sql_text_;
+
+ DISALLOW_COPY_AND_ASSIGN(StatementErrorHandler);
+};
+
+class SQLiteFeaturesTest : public testing::Test {
+ public:
+  SQLiteFeaturesTest() : error_(SQLITE_OK) {}
+
+  void SetUp() {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(db_.Open(temp_dir_.path().AppendASCII("SQLStatementTest.db")));
+
+    // The error delegate will set |error_| and |sql_text_| when any sqlite
+    // statement operation returns an error code.
+    db_.set_error_delegate(new StatementErrorHandler(&error_, &sql_text_));
+  }
+
+  void TearDown() {
+    // If any error happened the original sql statement can be found in
+    // |sql_text_|.
+    EXPECT_EQ(SQLITE_OK, error_);
+    db_.Close();
+  }
+
+  sql::Connection& db() { return db_; }
+
+  int sqlite_error() const {
+    return error_;
+  }
+
+ private:
+  ScopedTempDir temp_dir_;
+  sql::Connection db_;
+
+  // The error code of the most recent error.
+  int error_;
+  // Original statement which has caused the error.
+  std::string sql_text_;
+};
+
+// Do not include fts1 support, it is not useful, and nobody is
+// looking at it.
+TEST_F(SQLiteFeaturesTest, NoFTS1) {
+  ASSERT_EQ(SQLITE_ERROR, db().ExecuteAndReturnErrorCode(
+      "CREATE VIRTUAL TABLE foo USING fts1(x)"));
+}
+
+#if !defined(OS_IOS)
+// fts2 is used for older history files, so we're signed on for keeping our
+// version up-to-date.  iOS does not include fts2, so this test does not run on
+// iOS.
+// TODO(shess): Think up a crazy way to get out from having to support
+// this forever.
+TEST_F(SQLiteFeaturesTest, FTS2) {
+  ASSERT_TRUE(db().Execute("CREATE VIRTUAL TABLE foo USING fts2(x)"));
+}
+#endif
+
+// fts3 is used for current history files, and also for WebDatabase.
+TEST_F(SQLiteFeaturesTest, FTS3) {
+  ASSERT_TRUE(db().Execute("CREATE VIRTUAL TABLE foo USING fts3(x)"));
+}
+
+}  // namespace
diff --git a/sql/statement.cc b/sql/statement.cc
new file mode 100644
index 0000000..84dfd2e
--- /dev/null
+++ b/sql/statement.cc
@@ -0,0 +1,314 @@
+// Copyright (c) 2012 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 "sql/statement.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "third_party/sqlite/sqlite3.h"
+
+namespace sql {
+
+// This empty constructor initializes our reference with an empty one so that
+// we don't have to NULL-check the ref_ to see if the statement is valid: we
+// only have to check the ref's validity bit.
+Statement::Statement()
+    : ref_(new Connection::StatementRef),
+      succeeded_(false) {
+}
+
+Statement::Statement(scoped_refptr<Connection::StatementRef> ref)
+    : ref_(ref),
+      succeeded_(false) {
+}
+
+Statement::~Statement() {
+  // Free the resources associated with this statement. We assume there's only
+  // one statement active for a given sqlite3_stmt at any time, so this won't
+  // mess with anything.
+  Reset(true);
+}
+
+void Statement::Assign(scoped_refptr<Connection::StatementRef> ref) {
+  Reset(true);
+  ref_ = ref;
+}
+
+void Statement::Clear() {
+  Assign(new Connection::StatementRef);
+  succeeded_ = false;
+}
+
+bool Statement::CheckValid() const {
+  if (!is_valid())
+    DLOG(FATAL) << "Cannot call mutating statements on an invalid statement.";
+  return is_valid();
+}
+
+bool Statement::Run() {
+  ref_->AssertIOAllowed();
+  if (!CheckValid())
+    return false;
+
+  return CheckError(sqlite3_step(ref_->stmt())) == SQLITE_DONE;
+}
+
+bool Statement::Step() {
+  ref_->AssertIOAllowed();
+  if (!CheckValid())
+    return false;
+
+  return CheckError(sqlite3_step(ref_->stmt())) == SQLITE_ROW;
+}
+
+void Statement::Reset(bool clear_bound_vars) {
+  ref_->AssertIOAllowed();
+  if (is_valid()) {
+    // We don't call CheckError() here because sqlite3_reset() returns
+    // the last error that Step() caused thereby generating a second
+    // spurious error callback.
+    if (clear_bound_vars)
+      sqlite3_clear_bindings(ref_->stmt());
+    sqlite3_reset(ref_->stmt());
+  }
+
+  succeeded_ = false;
+}
+
+bool Statement::Succeeded() const {
+  if (!is_valid())
+    return false;
+
+  return succeeded_;
+}
+
+bool Statement::BindNull(int col) {
+  if (!is_valid())
+    return false;
+
+  return CheckOk(sqlite3_bind_null(ref_->stmt(), col + 1));
+}
+
+bool Statement::BindBool(int col, bool val) {
+  return BindInt(col, val ? 1 : 0);
+}
+
+bool Statement::BindInt(int col, int val) {
+  if (!is_valid())
+    return false;
+
+  return CheckOk(sqlite3_bind_int(ref_->stmt(), col + 1, val));
+}
+
+bool Statement::BindInt64(int col, int64 val) {
+  if (!is_valid())
+    return false;
+
+  return CheckOk(sqlite3_bind_int64(ref_->stmt(), col + 1, val));
+}
+
+bool Statement::BindDouble(int col, double val) {
+  if (!is_valid())
+    return false;
+
+  return CheckOk(sqlite3_bind_double(ref_->stmt(), col + 1, val));
+}
+
+bool Statement::BindCString(int col, const char* val) {
+  if (!is_valid())
+    return false;
+
+  return CheckOk(
+      sqlite3_bind_text(ref_->stmt(), col + 1, val, -1, SQLITE_TRANSIENT));
+}
+
+bool Statement::BindString(int col, const std::string& val) {
+  if (!is_valid())
+    return false;
+
+  return CheckOk(sqlite3_bind_text(ref_->stmt(),
+                                   col + 1,
+                                   val.data(),
+                                   val.size(),
+                                   SQLITE_TRANSIENT));
+}
+
+bool Statement::BindString16(int col, const string16& value) {
+  return BindString(col, UTF16ToUTF8(value));
+}
+
+bool Statement::BindBlob(int col, const void* val, int val_len) {
+  if (!is_valid())
+    return false;
+
+  return CheckOk(
+      sqlite3_bind_blob(ref_->stmt(), col + 1, val, val_len, SQLITE_TRANSIENT));
+}
+
+int Statement::ColumnCount() const {
+  if (!is_valid())
+    return 0;
+
+  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));
+}
+
+ColType Statement::DeclaredColumnType(int col) const {
+  std::string column_type(sqlite3_column_decltype(ref_->stmt(), col));
+  StringToLowerASCII(&column_type);
+
+  if (column_type == "integer")
+    return COLUMN_TYPE_INTEGER;
+  else if (column_type == "float")
+    return COLUMN_TYPE_FLOAT;
+  else if (column_type == "text")
+    return COLUMN_TYPE_TEXT;
+  else if (column_type == "blob")
+    return COLUMN_TYPE_BLOB;
+
+  return COLUMN_TYPE_NULL;
+}
+
+bool Statement::ColumnBool(int col) const {
+  return !!ColumnInt(col);
+}
+
+int Statement::ColumnInt(int col) const {
+  if (!CheckValid())
+    return 0;
+
+  return sqlite3_column_int(ref_->stmt(), col);
+}
+
+int64 Statement::ColumnInt64(int col) const {
+  if (!CheckValid())
+    return 0;
+
+  return sqlite3_column_int64(ref_->stmt(), col);
+}
+
+double Statement::ColumnDouble(int col) const {
+  if (!CheckValid())
+    return 0;
+
+  return sqlite3_column_double(ref_->stmt(), col);
+}
+
+std::string Statement::ColumnString(int col) const {
+  if (!CheckValid())
+    return "";
+
+  const char* str = reinterpret_cast<const char*>(
+      sqlite3_column_text(ref_->stmt(), col));
+  int len = sqlite3_column_bytes(ref_->stmt(), col);
+
+  std::string result;
+  if (str && len > 0)
+    result.assign(str, len);
+  return result;
+}
+
+string16 Statement::ColumnString16(int col) const {
+  if (!CheckValid())
+    return string16();
+
+  std::string s = ColumnString(col);
+  return !s.empty() ? UTF8ToUTF16(s) : string16();
+}
+
+int Statement::ColumnByteLength(int col) const {
+  if (!CheckValid())
+    return 0;
+
+  return sqlite3_column_bytes(ref_->stmt(), col);
+}
+
+const void* Statement::ColumnBlob(int col) const {
+  if (!CheckValid())
+    return NULL;
+
+  return sqlite3_column_blob(ref_->stmt(), col);
+}
+
+bool Statement::ColumnBlobAsString(int col, std::string* blob) {
+  if (!CheckValid())
+    return false;
+
+  const void* p = ColumnBlob(col);
+  size_t len = ColumnByteLength(col);
+  blob->resize(len);
+  if (blob->size() != len) {
+    return false;
+  }
+  blob->assign(reinterpret_cast<const char*>(p), len);
+  return true;
+}
+
+bool Statement::ColumnBlobAsString16(int col, string16* val) const {
+  if (!CheckValid())
+    return false;
+
+  const void* data = ColumnBlob(col);
+  size_t len = ColumnByteLength(col) / sizeof(char16);
+  val->resize(len);
+  if (val->size() != len)
+    return false;
+  val->assign(reinterpret_cast<const char16*>(data), len);
+  return true;
+}
+
+bool Statement::ColumnBlobAsVector(int col, std::vector<char>* val) const {
+  val->clear();
+
+  if (!CheckValid())
+    return false;
+
+  const void* data = sqlite3_column_blob(ref_->stmt(), col);
+  int len = sqlite3_column_bytes(ref_->stmt(), col);
+  if (data && len > 0) {
+    val->resize(len);
+    memcpy(&(*val)[0], data, len);
+  }
+  return true;
+}
+
+bool Statement::ColumnBlobAsVector(
+    int col,
+    std::vector<unsigned char>* val) const {
+  return ColumnBlobAsVector(col, reinterpret_cast< std::vector<char>* >(val));
+}
+
+const char* Statement::GetSQLStatement() {
+  return sqlite3_sql(ref_->stmt());
+}
+
+bool Statement::CheckOk(int err) const {
+  // Binding to a non-existent variable is evidence of a serious error.
+  // TODO(gbillock,shess): make this invalidate the statement so it
+  // can't wreak havoc.
+  if (err == SQLITE_RANGE)
+    DLOG(FATAL) << "Bind value out of range";
+  return err == SQLITE_OK;
+}
+
+int Statement::CheckError(int err) {
+  // Please don't add DCHECKs here, OnSqliteError() already has them.
+  succeeded_ = (err == SQLITE_OK || err == SQLITE_ROW || err == SQLITE_DONE);
+  if (!succeeded_ && is_valid())
+    return ref_->connection()->OnSqliteError(err, this);
+  return err;
+}
+
+}  // namespace sql
diff --git a/sql/statement.h b/sql/statement.h
new file mode 100644
index 0000000..bd00b0d
--- /dev/null
+++ b/sql/statement.h
@@ -0,0 +1,189 @@
+// Copyright (c) 2012 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 SQL_STATEMENT_H_
+#define SQL_STATEMENT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/string16.h"
+#include "sql/connection.h"
+#include "sql/sql_export.h"
+
+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(...));
+//   s.BindInt(0, a);
+//   if (s.Step())
+//     return s.ColumnString(0);
+//
+//   If there are errors getting the statement, the statement will be inert; no
+//   mutating or database-access methods will work. If you need to check for
+//   validity, use:
+//   if (!s.is_valid())
+//     return false;
+//
+// Step() and Run() just return true to signal success. If you want to handle
+// specific errors such as database corruption, install an error handler in
+// in the connection object using set_error_delegate().
+class SQL_EXPORT Statement {
+ public:
+  // Creates an uninitialized statement. The statement will be invalid until
+  // you initialize it via Assign.
+  Statement();
+
+  explicit Statement(scoped_refptr<Connection::StatementRef> ref);
+  ~Statement();
+
+  // Initializes this object with the given statement, which may or may not
+  // be valid. Use is_valid() to check if it's OK.
+  void Assign(scoped_refptr<Connection::StatementRef> ref);
+
+  // Resets the statement to an uninitialized state corrosponding to
+  // the default constructor, releasing the StatementRef.
+  void Clear();
+
+  // Returns true if the statement can be executed. All functions can still
+  // be used if the statement is invalid, but they will return failure or some
+  // default value. This is because the statement can become invalid in the
+  // middle of executing a command if there is a serious error and the database
+  // has to be reset.
+  bool is_valid() const { return ref_->is_valid(); }
+
+  // Running -------------------------------------------------------------------
+
+  // Executes the statement, returning true on success. This is like Step but
+  // for when there is no output, like an INSERT statement.
+  bool Run();
+
+  // Executes the statement, returning true if there is a row of data returned.
+  // You can keep calling Step() until it returns false to iterate through all
+  // the rows in your result set.
+  //
+  // When Step returns false, the result is either that there is no more data
+  // or there is an error. This makes it most convenient for loop usage. If you
+  // need to disambiguate these cases, use Succeeded().
+  //
+  // Typical example:
+  //   while (s.Step()) {
+  //     ...
+  //   }
+  //   return s.Succeeded();
+  bool Step();
+
+  // Resets the statement to its initial condition. This includes any current
+  // result row, and also the bound variables if the |clear_bound_vars| is true.
+  void Reset(bool clear_bound_vars);
+
+  // Returns true if the last executed thing in this statement succeeded. If
+  // there was no last executed thing or the statement is invalid, this will
+  // return false.
+  bool Succeeded() const;
+
+  // Binding -------------------------------------------------------------------
+
+  // These all take a 0-based argument index and return true on success. You
+  // may not always care about the return value (they'll DCHECK if they fail).
+  // 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);
+  bool BindCString(int col, const char* val);
+  bool BindString(int col, const std::string& val);
+  bool BindString16(int col, const string16& value);
+  bool BindBlob(int col, const void* value, int value_len);
+
+  // Retrieving ----------------------------------------------------------------
+
+  // 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;
+  ColType DeclaredColumnType(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;
+  std::string ColumnString(int col) const;
+  string16 ColumnString16(int col) const;
+
+  // When reading a blob, you can get a raw pointer to the underlying data,
+  // along with the length, or you can just ask us to copy the blob into a
+  // vector. Danger! ColumnBlob may return NULL if there is no data!
+  int ColumnByteLength(int col) const;
+  const void* ColumnBlob(int col) const;
+  bool ColumnBlobAsString(int col, std::string* blob);
+  bool ColumnBlobAsString16(int col, string16* val) const;
+  bool ColumnBlobAsVector(int col, std::vector<char>* val) const;
+  bool ColumnBlobAsVector(int col, std::vector<unsigned char>* val) const;
+
+  // Diagnostics --------------------------------------------------------------
+
+  // Returns the original text of sql statement. Do not keep a pointer to it.
+  const char* GetSQLStatement();
+
+ private:
+  // This is intended to check for serious errors and report them to the
+  // connection object. It takes a sqlite error code, and returns the same
+  // code. Currently this function just updates the succeeded flag, but will be
+  // enhanced in the future to do the notification.
+  int CheckError(int err);
+
+  // Contraction for checking an error code against SQLITE_OK. Does not set the
+  // succeeded flag.
+  bool CheckOk(int err) const;
+
+  // Should be called by all mutating methods to check that the statement is
+  // valid. Returns true if the statement is valid. DCHECKS and returns false
+  // if it is not.
+  // The reason for this is to handle two specific cases in which a Statement
+  // may be invalid. The first case is that the programmer made an SQL error.
+  // Those cases need to be DCHECKed so that we are guaranteed to find them
+  // before release. The second case is that the computer has an error (probably
+  // out of disk space) which is prohibiting the correct operation of the
+  // database. Our testing apparatus should not exhibit this defect, but release
+  // situations may. Therefore, the code is handling disjoint situations in
+  // release and test. In test, we're ensuring correct SQL. In release, we're
+  // ensuring that contracts are honored in error edge cases.
+  bool CheckValid() const;
+
+  // The actual sqlite statement. This may be unique to us, or it may be cached
+  // by the connection, which is why it's refcounted. This pointer is
+  // guaranteed non-NULL.
+  scoped_refptr<Connection::StatementRef> ref_;
+
+  // See Succeeded() for what this holds.
+  bool succeeded_;
+
+  DISALLOW_COPY_AND_ASSIGN(Statement);
+};
+
+}  // namespace sql
+
+#endif  // SQL_STATEMENT_H_
diff --git a/sql/statement_unittest.cc b/sql/statement_unittest.cc
new file mode 100644
index 0000000..a7a23d8
--- /dev/null
+++ b/sql/statement_unittest.cc
@@ -0,0 +1,152 @@
+// Copyright (c) 2012 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 <string>
+
+#include "base/file_util.h"
+#include "base/scoped_temp_dir.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/sqlite/sqlite3.h"
+
+namespace {
+
+class StatementErrorHandler : public sql::ErrorDelegate {
+ public:
+  StatementErrorHandler(int* error, std::string* sql_text)
+    : error_(error),
+      sql_text_(sql_text) {}
+
+  virtual ~StatementErrorHandler() {}
+
+  virtual int OnError(int error, sql::Connection* connection,
+                      sql::Statement* stmt) OVERRIDE {
+    *error_ = error;
+    const char* sql_txt = stmt ? stmt->GetSQLStatement() : NULL;
+    *sql_text_ = sql_txt ? sql_txt : "no statement available";
+    return error;
+  }
+
+ private:
+  int* error_;
+  std::string* sql_text_;
+
+ DISALLOW_COPY_AND_ASSIGN(StatementErrorHandler);
+};
+
+class SQLStatementTest : public testing::Test {
+ public:
+  SQLStatementTest() : error_(SQLITE_OK) {}
+
+  void SetUp() {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(db_.Open(temp_dir_.path().AppendASCII("SQLStatementTest.db")));
+    // The error delegate will set |error_| and |sql_text_| when any sqlite
+    // statement operation returns an error code.
+    db_.set_error_delegate(new StatementErrorHandler(&error_, &sql_text_));
+  }
+
+  void TearDown() {
+    // If any error happened the original sql statement can be found in
+    // |sql_text_|.
+    EXPECT_EQ(SQLITE_OK, error_);
+    db_.Close();
+  }
+
+  sql::Connection& db() { return db_; }
+
+  int sqlite_error() const { return error_; }
+
+  void ResetError() {
+    error_ = SQLITE_OK;
+    sql_text_.clear();
+  }
+
+ private:
+  ScopedTempDir temp_dir_;
+  sql::Connection db_;
+
+  // The error code of the most recent error.
+  int error_;
+  // Original statement which caused the error.
+  std::string sql_text_;
+};
+
+}  // namespace
+
+TEST_F(SQLStatementTest, Assign) {
+  sql::Statement s;
+  EXPECT_FALSE(s.is_valid());
+
+  s.Assign(db().GetUniqueStatement("CREATE TABLE foo (a, b)"));
+  EXPECT_TRUE(s.is_valid());
+}
+
+TEST_F(SQLStatementTest, Run) {
+  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
+  ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (3, 12)"));
+
+  sql::Statement s(db().GetUniqueStatement("SELECT b FROM foo WHERE a=?"));
+  EXPECT_FALSE(s.Succeeded());
+
+  // Stepping it won't work since we haven't bound the value.
+  EXPECT_FALSE(s.Step());
+
+  // Run should fail since this produces output, and we should use Step(). This
+  // gets a bit wonky since sqlite says this is OK so succeeded is set.
+  s.Reset(true);
+  s.BindInt(0, 3);
+  EXPECT_FALSE(s.Run());
+  EXPECT_EQ(SQLITE_ROW, db().GetErrorCode());
+  EXPECT_TRUE(s.Succeeded());
+
+  // Resetting it should put it back to the previous state (not runnable).
+  s.Reset(true);
+  EXPECT_FALSE(s.Succeeded());
+
+  // Binding and stepping should produce one row.
+  s.BindInt(0, 3);
+  EXPECT_TRUE(s.Step());
+  EXPECT_TRUE(s.Succeeded());
+  EXPECT_EQ(12, s.ColumnInt(0));
+  EXPECT_FALSE(s.Step());
+  EXPECT_TRUE(s.Succeeded());
+}
+
+TEST_F(SQLStatementTest, BasicErrorCallback) {
+  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a INTEGER PRIMARY KEY, b)"));
+  EXPECT_EQ(SQLITE_OK, sqlite_error());
+  // Insert in the foo table the primary key. It is an error to insert
+  // something other than an number. This error causes the error callback
+  // handler to be called with SQLITE_MISMATCH as error code.
+  sql::Statement s(db().GetUniqueStatement("INSERT INTO foo (a) VALUES (?)"));
+  EXPECT_TRUE(s.is_valid());
+  s.BindCString(0, "bad bad");
+  EXPECT_FALSE(s.Run());
+  EXPECT_EQ(SQLITE_MISMATCH, sqlite_error());
+  ResetError();
+}
+
+TEST_F(SQLStatementTest, Reset) {
+  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
+  ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (3, 12)"));
+  ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (4, 13)"));
+
+  sql::Statement s(db().GetUniqueStatement(
+      "SELECT b FROM foo WHERE a = ? "));
+  s.BindInt(0, 3);
+  ASSERT_TRUE(s.Step());
+  EXPECT_EQ(12, s.ColumnInt(0));
+  ASSERT_FALSE(s.Step());
+
+  s.Reset(false);
+  // Verify that we can get all rows again.
+  ASSERT_TRUE(s.Step());
+  EXPECT_EQ(12, s.ColumnInt(0));
+  EXPECT_FALSE(s.Step());
+
+  s.Reset(true);
+  ASSERT_FALSE(s.Step());
+}
diff --git a/sql/transaction.cc b/sql/transaction.cc
new file mode 100644
index 0000000..06bcbeb
--- /dev/null
+++ b/sql/transaction.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sql/transaction.h"
+
+#include "base/logging.h"
+#include "sql/connection.h"
+
+namespace sql {
+
+Transaction::Transaction(Connection* connection)
+    : connection_(connection),
+      is_open_(false) {
+}
+
+Transaction::~Transaction() {
+  if (is_open_)
+    connection_->RollbackTransaction();
+}
+
+bool Transaction::Begin() {
+  if (is_open_) {
+    NOTREACHED() << "Beginning a transaction twice!";
+    return false;
+  }
+  is_open_ = connection_->BeginTransaction();
+  return is_open_;
+}
+
+void Transaction::Rollback() {
+  if (!is_open_) {
+    NOTREACHED() << "Attempting to roll back a nonexistent transaction. "
+                 << "Did you remember to call Begin() and check its return?";
+    return;
+  }
+  is_open_ = false;
+  connection_->RollbackTransaction();
+}
+
+bool Transaction::Commit() {
+  if (!is_open_) {
+    NOTREACHED() << "Attempting to commit a nonexistent transaction. "
+                 << "Did you remember to call Begin() and check its return?";
+    return false;
+  }
+  is_open_ = false;
+  return connection_->CommitTransaction();
+}
+
+}  // namespace sql
diff --git a/sql/transaction.h b/sql/transaction.h
new file mode 100644
index 0000000..788a002
--- /dev/null
+++ b/sql/transaction.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 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 SQL_TRANSACTION_H_
+#define SQL_TRANSACTION_H_
+
+#include "base/basictypes.h"
+#include "sql/sql_export.h"
+
+namespace sql {
+
+class Connection;
+
+class SQL_EXPORT Transaction {
+ public:
+  // Creates the scoped transaction object. You MUST call Begin() to begin the
+  // transaction. If you have begun a transaction and not committed it, the
+  // constructor will roll back the transaction. If you want to commit, you
+  // need to manually call Commit before this goes out of scope.
+  //
+  // Nested transactions are supported. See sql::Connection::BeginTransaction
+  // for details.
+  explicit Transaction(Connection* connection);
+  ~Transaction();
+
+  // Returns true when there is a transaction that has been successfully begun.
+  bool is_open() const { return is_open_; }
+
+  // Begins the transaction. This uses the default sqlite "deferred" transaction
+  // type, which means that the DB lock is lazily acquired the next time the
+  // database is accessed, not in the begin transaction command.
+  //
+  // Returns false on failure. Note that if this fails, you shouldn't do
+  // anything you expect to be actually transactional, because it won't be!
+  bool Begin();
+
+  // Rolls back the transaction. This will happen automatically if you do
+  // nothing when the transaction goes out of scope.
+  void Rollback();
+
+  // Commits the transaction, returning true on success. This will return
+  // false if sqlite could not commit it, or if another transaction in the
+  // same outermost transaction has been rolled back (which necessitates a
+  // rollback of all transactions in that outermost one).
+  bool Commit();
+
+ private:
+  Connection* connection_;
+
+  // True when the transaction is open, false when it's already been committed
+  // or rolled back.
+  bool is_open_;
+
+  DISALLOW_COPY_AND_ASSIGN(Transaction);
+};
+
+}  // namespace sql
+
+#endif  // SQL_TRANSACTION_H_
diff --git a/sql/transaction_unittest.cc b/sql/transaction_unittest.cc
new file mode 100644
index 0000000..f306a5c
--- /dev/null
+++ b/sql/transaction_unittest.cc
@@ -0,0 +1,133 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+#include "base/scoped_temp_dir.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/sqlite/sqlite3.h"
+
+class SQLTransactionTest : public testing::Test {
+ public:
+  SQLTransactionTest() {}
+
+  void SetUp() {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(db_.Open(
+        temp_dir_.path().AppendASCII("SQLTransactionTest.db")));
+
+    ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
+  }
+
+  void TearDown() {
+    db_.Close();
+  }
+
+  sql::Connection& db() { return db_; }
+
+  // Returns the number of rows in table "foo".
+  int CountFoo() {
+    sql::Statement count(db().GetUniqueStatement("SELECT count(*) FROM foo"));
+    count.Step();
+    return count.ColumnInt(0);
+  }
+
+ private:
+  ScopedTempDir temp_dir_;
+  sql::Connection db_;
+};
+
+TEST_F(SQLTransactionTest, Commit) {
+  {
+    sql::Transaction t(&db());
+    EXPECT_FALSE(t.is_open());
+    EXPECT_TRUE(t.Begin());
+    EXPECT_TRUE(t.is_open());
+
+    EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
+
+    t.Commit();
+    EXPECT_FALSE(t.is_open());
+  }
+
+  EXPECT_EQ(1, CountFoo());
+}
+
+TEST_F(SQLTransactionTest, Rollback) {
+  // Test some basic initialization, and that rollback runs when you exit the
+  // scope.
+  {
+    sql::Transaction t(&db());
+    EXPECT_FALSE(t.is_open());
+    EXPECT_TRUE(t.Begin());
+    EXPECT_TRUE(t.is_open());
+
+    EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
+  }
+
+  // Nothing should have been committed since it was implicitly rolled back.
+  EXPECT_EQ(0, CountFoo());
+
+  // Test explicit rollback.
+  sql::Transaction t2(&db());
+  EXPECT_FALSE(t2.is_open());
+  EXPECT_TRUE(t2.Begin());
+
+  EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
+  t2.Rollback();
+  EXPECT_FALSE(t2.is_open());
+
+  // Nothing should have been committed since it was explicitly rolled back.
+  EXPECT_EQ(0, CountFoo());
+}
+
+// Rolling back any part of a transaction should roll back all of them.
+TEST_F(SQLTransactionTest, NestedRollback) {
+  EXPECT_EQ(0, db().transaction_nesting());
+
+  // Outermost transaction.
+  {
+    sql::Transaction outer(&db());
+    EXPECT_TRUE(outer.Begin());
+    EXPECT_EQ(1, db().transaction_nesting());
+
+    // The first inner one gets committed.
+    {
+      sql::Transaction inner1(&db());
+      EXPECT_TRUE(inner1.Begin());
+      EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
+      EXPECT_EQ(2, db().transaction_nesting());
+
+      inner1.Commit();
+      EXPECT_EQ(1, db().transaction_nesting());
+    }
+
+    // One row should have gotten inserted.
+    EXPECT_EQ(1, CountFoo());
+
+    // The second inner one gets rolled back.
+    {
+      sql::Transaction inner2(&db());
+      EXPECT_TRUE(inner2.Begin());
+      EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
+      EXPECT_EQ(2, db().transaction_nesting());
+
+      inner2.Rollback();
+      EXPECT_EQ(1, db().transaction_nesting());
+    }
+
+    // A third inner one will fail in Begin since one has already been rolled
+    // back.
+    EXPECT_EQ(1, db().transaction_nesting());
+    {
+      sql::Transaction inner3(&db());
+      EXPECT_FALSE(inner3.Begin());
+      EXPECT_EQ(1, db().transaction_nesting());
+    }
+  }
+  EXPECT_EQ(0, db().transaction_nesting());
+  EXPECT_EQ(0, CountFoo());
+}