Merge from Chromium at DEPS revision r212014

This commit was generated by merge_to_master.py.

Change-Id: Ie0f261e9682cd8abea1eea1e51beab83d5eea21a
diff --git a/sql/connection.cc b/sql/connection.cc
index a11bc72..95d09c2 100644
--- a/sql/connection.cc
+++ b/sql/connection.cc
@@ -18,6 +18,10 @@
 #include "sql/statement.h"
 #include "third_party/sqlite/sqlite3.h"
 
+#if defined(OS_IOS) && defined(USE_SYSTEM_SQLITE)
+#include "third_party/sqlite/src/ext/icu/sqliteicu.h"
+#endif
+
 namespace {
 
 // Spin for up to a second waiting for the lock to clear when setting
@@ -64,6 +68,32 @@
   sqlite3* db_;
 };
 
+// Helper to wrap the sqlite3_backup_*() step of Raze().  Return
+// SQLite error code from running the backup step.
+int BackupDatabase(sqlite3* src, sqlite3* dst, const char* db_name) {
+  DCHECK_NE(src, dst);
+  sqlite3_backup* backup = sqlite3_backup_init(dst, db_name, src, db_name);
+  if (!backup) {
+    // Since this call only sets things up, this indicates a gross
+    // error in SQLite.
+    DLOG(FATAL) << "Unable to start sqlite3_backup(): " << sqlite3_errmsg(dst);
+    return sqlite3_errcode(dst);
+  }
+
+  // -1 backs up the entire database.
+  int rc = sqlite3_backup_step(backup, -1);
+  int pages = sqlite3_backup_pagecount(backup);
+  sqlite3_backup_finish(backup);
+
+  // If successful, exactly one page should have been backed up.  If
+  // this breaks, check this function to make sure assumptions aren't
+  // being broken.
+  if (rc == SQLITE_DONE)
+    DCHECK_EQ(pages, 1);
+
+  return rc;
+}
+
 }  // namespace
 
 namespace sql {
@@ -164,15 +194,15 @@
   }
 
 #if defined(OS_WIN)
-  return OpenInternal(WideToUTF8(path.value()));
+  return OpenInternal(WideToUTF8(path.value()), RETRY_ON_POISON);
 #elif defined(OS_POSIX)
-  return OpenInternal(path.value());
+  return OpenInternal(path.value(), RETRY_ON_POISON);
 #endif
 }
 
 bool Connection::OpenInMemory() {
   in_memory_ = true;
-  return OpenInternal(":memory:");
+  return OpenInternal(":memory:", NO_RETRY);
 }
 
 void Connection::CloseInternal(bool forced) {
@@ -208,8 +238,8 @@
     AssertIOAllowed();
     // TODO(shess): Histogram for failure.
     sqlite3_close(db_);
-    db_ = NULL;
   }
+  db_ = NULL;
 }
 
 void Connection::Close() {
@@ -313,33 +343,54 @@
   // 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);
+  const char* kMain = "main";
+  int rc = BackupDatabase(null_db.db_, db_, kMain);
+  UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.RazeDatabase",rc);
 
   // The destination database was locked.
   if (rc == SQLITE_BUSY) {
     return false;
   }
 
+  // SQLITE_NOTADB can happen if page 1 of db_ exists, but is not
+  // formatted correctly.  SQLITE_IOERR_SHORT_READ can happen if db_
+  // isn't even big enough for one page.  Either way, reach in and
+  // truncate it before trying again.
+  // TODO(shess): Maybe it would be worthwhile to just truncate from
+  // the get-go?
+  if (rc == SQLITE_NOTADB || rc == SQLITE_IOERR_SHORT_READ) {
+    sqlite3_file* file = NULL;
+    rc = sqlite3_file_control(db_, "main", SQLITE_FCNTL_FILE_POINTER, &file);
+    if (rc != SQLITE_OK) {
+      DLOG(FATAL) << "Failure getting file handle.";
+      return false;
+    } else if (!file) {
+      DLOG(FATAL) << "File handle is empty.";
+      return false;
+    }
+
+    rc = file->pMethods->xTruncate(file, 0);
+    if (rc != SQLITE_OK) {
+      UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.RazeDatabaseTruncate",rc);
+      DLOG(FATAL) << "Failed to truncate file.";
+      return false;
+    }
+
+    rc = BackupDatabase(null_db.db_, db_, kMain);
+    UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.RazeDatabase2",rc);
+
+    if (rc != SQLITE_DONE) {
+      DLOG(FATAL) << "Failed retrying Raze().";
+    }
+  }
+
   // The entire database should have been backed up.
   if (rc != SQLITE_DONE) {
+    // TODO(shess): Figure out which other cases can happen.
     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;
 }
 
@@ -394,13 +445,13 @@
   base::FilePath journal_path(path.value() + FILE_PATH_LITERAL("-journal"));
   base::FilePath wal_path(path.value() + FILE_PATH_LITERAL("-wal"));
 
-  base::Delete(journal_path, false);
-  base::Delete(wal_path, false);
-  base::Delete(path, false);
+  base::DeleteFile(journal_path, false);
+  base::DeleteFile(wal_path, false);
+  base::DeleteFile(path, false);
 
-  return !file_util::PathExists(journal_path) &&
-      !file_util::PathExists(wal_path) &&
-      !file_util::PathExists(path);
+  return !base::PathExists(journal_path) &&
+      !base::PathExists(wal_path) &&
+      !base::PathExists(path);
 }
 
 bool Connection::BeginTransaction() {
@@ -648,7 +699,8 @@
   return sqlite3_errmsg(db_);
 }
 
-bool Connection::OpenInternal(const std::string& file_name) {
+bool Connection::OpenInternal(const std::string& file_name,
+                              Connection::Retry retry_flag) {
   AssertIOAllowed();
 
   if (db_) {
@@ -663,6 +715,7 @@
   // TODO(shess): Revise is_open() to consider poisoned_, and review
   // to see if any non-testing code even depends on it.
   DLOG_IF(FATAL, poisoned_) << "sql::Connection is already open.";
+  poisoned_ = false;
 
   int err = sqlite3_open(file_name.c_str(), &db_);
   if (err != SQLITE_OK) {
@@ -671,8 +724,11 @@
     UMA_HISTOGRAM_ENUMERATION("Sqlite.OpenFailure", err & 0xff, 50);
 
     OnSqliteError(err, NULL);
+    bool was_poisoned = poisoned_;
     Close();
-    db_ = NULL;
+
+    if (was_poisoned && retry_flag == RETRY_ON_POISON)
+      return OpenInternal(file_name, NO_RETRY);
     return false;
   }
 
@@ -701,6 +757,13 @@
   err = sqlite3_extended_result_codes(db_, 1);
   DCHECK_EQ(err, SQLITE_OK) << "Could not enable extended result codes";
 
+#if defined(OS_IOS) && defined(USE_SYSTEM_SQLITE)
+  // The version of SQLite shipped with iOS doesn't enable ICU, which includes
+  // REGEXP support. Add it in dynamically.
+  err = sqlite3IcuInit(db_);
+  DCHECK_EQ(err, SQLITE_OK) << "Could not enable ICU support";
+#endif  // OS_IOS && USE_SYSTEM_SQLITE
+
   // 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
@@ -747,7 +810,10 @@
   }
 
   if (!ExecuteWithTimeout("PRAGMA secure_delete=ON", kBusyTimeout)) {
+    bool was_poisoned = poisoned_;
     Close();
+    if (was_poisoned && retry_flag == RETRY_ON_POISON)
+      return OpenInternal(file_name, NO_RETRY);
     return false;
   }
 
@@ -801,7 +867,10 @@
              << ": " << GetErrorMessage();
 
   if (!error_callback_.is_null()) {
-    error_callback_.Run(err, stmt);
+    // Fire from a copy of the callback in case of reentry into
+    // re/set_error_callback().
+    // TODO(shess): <http://crbug.com/254584>
+    ErrorCallback(error_callback_).Run(err, stmt);
     return err;
   }
 
diff --git a/sql/connection.h b/sql/connection.h
index a2e8f67..1c4d72c 100644
--- a/sql/connection.h
+++ b/sql/connection.h
@@ -125,6 +125,9 @@
   void set_error_callback(const ErrorCallback& callback) {
     error_callback_ = callback;
   }
+  bool has_error_callback() const {
+    return !error_callback_.is_null();
+  }
   void reset_error_callback() {
     error_callback_.Reset();
   }
@@ -357,7 +360,14 @@
   // 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);
+  //
+  // |retry_flag| controls retrying the open if the error callback
+  // addressed errors using RazeAndClose().
+  enum Retry {
+    NO_RETRY = 0,
+    RETRY_ON_POISON
+  };
+  bool OpenInternal(const std::string& file_name, Retry retry_flag);
 
   // Internal close function used by Close() and RazeAndClose().
   // |forced| indicates that orderly-shutdown checks should not apply.
diff --git a/sql/connection_unittest.cc b/sql/connection_unittest.cc
index 1afd2dd..8cf32fb 100644
--- a/sql/connection_unittest.cc
+++ b/sql/connection_unittest.cc
@@ -2,16 +2,75 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/bind.h"
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "sql/connection.h"
 #include "sql/meta_table.h"
 #include "sql/statement.h"
+#include "sql/test/error_callback_support.h"
 #include "sql/test/scoped_error_ignorer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/sqlite/sqlite3.h"
 
+namespace {
+
+// Helper to return the count of items in sqlite_master.  Return -1 in
+// case of error.
+int SqliteMasterCount(sql::Connection* db) {
+  const char* kMasterCount = "SELECT COUNT(*) FROM sqlite_master";
+  sql::Statement s(db->GetUniqueStatement(kMasterCount));
+  return s.Step() ? s.ColumnInt(0) : -1;
+}
+
+// Track the number of valid references which share the same pointer.
+// This is used to allow testing an implicitly use-after-free case by
+// explicitly having the ref count live longer than the object.
+class RefCounter {
+ public:
+  RefCounter(size_t* counter)
+      : counter_(counter) {
+    (*counter_)++;
+  }
+  RefCounter(const RefCounter& other)
+      : counter_(other.counter_) {
+    (*counter_)++;
+  }
+  ~RefCounter() {
+    (*counter_)--;
+  }
+
+ private:
+  size_t* counter_;
+
+  DISALLOW_ASSIGN(RefCounter);
+};
+
+// Empty callback for implementation of ErrorCallbackSetHelper().
+void IgnoreErrorCallback(int error, sql::Statement* stmt) {
+}
+
+void ErrorCallbackSetHelper(sql::Connection* db,
+                            size_t* counter,
+                            const RefCounter& r,
+                            int error, sql::Statement* stmt) {
+  // The ref count should not go to zero when changing the callback.
+  EXPECT_GT(*counter, 0u);
+  db->set_error_callback(base::Bind(&IgnoreErrorCallback));
+  EXPECT_GT(*counter, 0u);
+}
+
+void ErrorCallbackResetHelper(sql::Connection* db,
+                              size_t* counter,
+                              const RefCounter& r,
+                              int error, sql::Statement* stmt) {
+  // The ref count should not go to zero when clearing the callback.
+  EXPECT_GT(*counter, 0u);
+  db->reset_error_callback();
+  EXPECT_GT(*counter, 0u);
+}
+
 class SQLConnectionTest : public testing::Test {
  public:
   SQLConnectionTest() {}
@@ -31,6 +90,12 @@
     return temp_dir_.path().AppendASCII("SQLConnectionTest.db");
   }
 
+  // Handle errors by blowing away the database.
+  void RazeErrorCallback(int expected_error, int error, sql::Statement* stmt) {
+    EXPECT_EQ(expected_error, error);
+    db_.RazeAndClose();
+  }
+
  private:
   base::ScopedTempDir temp_dir_;
   sql::Connection db_;
@@ -150,6 +215,61 @@
   ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
 }
 
+TEST_F(SQLConnectionTest, ErrorCallback) {
+  const char* kCreateSql = "CREATE TABLE foo (id INTEGER UNIQUE)";
+  ASSERT_TRUE(db().Execute(kCreateSql));
+  ASSERT_TRUE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
+
+  int error = SQLITE_OK;
+  {
+    sql::ScopedErrorCallback sec(
+        &db(), base::Bind(&sql::CaptureErrorCallback, &error));
+
+    // Inserting something other than a number into the primary key
+    // should result in the callback seeing SQLITE_MISMATCH.
+    EXPECT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
+    EXPECT_EQ(SQLITE_CONSTRAINT, error);
+  }
+
+  // Callback is no longer in force due to reset.
+  {
+    error = SQLITE_OK;
+    sql::ScopedErrorIgnorer ignore_errors;
+    ignore_errors.IgnoreError(SQLITE_CONSTRAINT);
+    ASSERT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
+    ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
+    EXPECT_EQ(SQLITE_OK, error);
+  }
+
+  // base::Bind() can curry arguments to be passed by const reference
+  // to the callback function.  If the callback function causes
+  // re/set_error_callback() to be called, the storage for those
+  // arguments can be deleted.
+  //
+  // RefCounter() counts how many objects are live using an external
+  // count.  The same counter is passed to the callback, so that it
+  // can check directly even if the RefCounter object is no longer
+  // live.
+  {
+    size_t count = 0;
+    sql::ScopedErrorCallback sec(
+        &db(), base::Bind(&ErrorCallbackSetHelper,
+                          &db(), &count, RefCounter(&count)));
+
+    EXPECT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
+  }
+
+  // Same test, but reset_error_callback() case.
+  {
+    size_t count = 0;
+    sql::ScopedErrorCallback sec(
+        &db(), base::Bind(&ErrorCallbackResetHelper,
+                          &db(), &count, RefCounter(&count)));
+
+    EXPECT_FALSE(db().Execute("INSERT INTO foo (id) VALUES (12)"));
+  }
+}
+
 // Test that sql::Connection::Raze() results in a database without the
 // tables from the original database.
 TEST_F(SQLConnectionTest, Raze) {
@@ -193,10 +313,7 @@
     EXPECT_EQ(1, s.ColumnInt(0));
   }
 
-  {
-    sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master"));
-    ASSERT_FALSE(s.Step());
-  }
+  ASSERT_EQ(0, SqliteMasterCount(&db()));
 
   {
     sql::Statement s(db().GetUniqueStatement("PRAGMA auto_vacuum"));
@@ -245,18 +362,12 @@
   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_EQ(1, SqliteMasterCount(&other_db));
 
   ASSERT_TRUE(db().Raze());
 
   // The second connection sees the updated database.
-  s.Reset(true);
-  ASSERT_TRUE(s.Step());
-  ASSERT_EQ(0, s.ColumnInt(0));
+  ASSERT_EQ(0, SqliteMasterCount(&other_db));
 }
 
 TEST_F(SQLConnectionTest, RazeLocked) {
@@ -294,6 +405,145 @@
   ASSERT_TRUE(db().Raze());
 }
 
+// Verify that Raze() can handle an empty file.  SQLite should treat
+// this as an empty database.
+TEST_F(SQLConnectionTest, RazeEmptyDB) {
+  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
+  ASSERT_TRUE(db().Execute(kCreateSql));
+  db().Close();
+
+  {
+    file_util::ScopedFILE file(file_util::OpenFile(db_path(), "r+"));
+    ASSERT_TRUE(file.get() != NULL);
+    ASSERT_EQ(0, fseek(file.get(), 0, SEEK_SET));
+    ASSERT_TRUE(file_util::TruncateFile(file.get()));
+  }
+
+  ASSERT_TRUE(db().Open(db_path()));
+  ASSERT_TRUE(db().Raze());
+  EXPECT_EQ(0, SqliteMasterCount(&db()));
+}
+
+// Verify that Raze() can handle a file of junk.
+TEST_F(SQLConnectionTest, RazeNOTADB) {
+  db().Close();
+  sql::Connection::Delete(db_path());
+  ASSERT_FALSE(base::PathExists(db_path()));
+
+  {
+    file_util::ScopedFILE file(file_util::OpenFile(db_path(), "w"));
+    ASSERT_TRUE(file.get() != NULL);
+
+    const char* kJunk = "This is the hour of our discontent.";
+    fputs(kJunk, file.get());
+  }
+  ASSERT_TRUE(base::PathExists(db_path()));
+
+  // SQLite will successfully open the handle, but will fail with
+  // SQLITE_IOERR_SHORT_READ on pragma statemenets which read the
+  // header.
+  {
+    sql::ScopedErrorIgnorer ignore_errors;
+    ignore_errors.IgnoreError(SQLITE_IOERR_SHORT_READ);
+    EXPECT_TRUE(db().Open(db_path()));
+    ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
+  }
+  EXPECT_TRUE(db().Raze());
+  db().Close();
+
+  // Now empty, the open should open an empty database.
+  EXPECT_TRUE(db().Open(db_path()));
+  EXPECT_EQ(0, SqliteMasterCount(&db()));
+}
+
+// Verify that Raze() can handle a database overwritten with garbage.
+TEST_F(SQLConnectionTest, RazeNOTADB2) {
+  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
+  ASSERT_TRUE(db().Execute(kCreateSql));
+  ASSERT_EQ(1, SqliteMasterCount(&db()));
+  db().Close();
+
+  {
+    file_util::ScopedFILE file(file_util::OpenFile(db_path(), "r+"));
+    ASSERT_TRUE(file.get() != NULL);
+    ASSERT_EQ(0, fseek(file.get(), 0, SEEK_SET));
+
+    const char* kJunk = "This is the hour of our discontent.";
+    fputs(kJunk, file.get());
+  }
+
+  // SQLite will successfully open the handle, but will fail with
+  // SQLITE_NOTADB on pragma statemenets which attempt to read the
+  // corrupted header.
+  {
+    sql::ScopedErrorIgnorer ignore_errors;
+    ignore_errors.IgnoreError(SQLITE_NOTADB);
+    EXPECT_TRUE(db().Open(db_path()));
+    ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
+  }
+  EXPECT_TRUE(db().Raze());
+  db().Close();
+
+  // Now empty, the open should succeed with an empty database.
+  EXPECT_TRUE(db().Open(db_path()));
+  EXPECT_EQ(0, SqliteMasterCount(&db()));
+}
+
+// Test that a callback from Open() can raze the database.  This is
+// essential for cases where the Open() can fail entirely, so the
+// Raze() cannot happen later.  Additionally test that when the
+// callback does this during Open(), the open is retried and succeeds.
+//
+// Most corruptions seen in the wild seem to happen when two pages in
+// the database were not written transactionally (the transaction
+// changed both, but one wasn't successfully written for some reason).
+// A special case of that is when the header indicates that the
+// database contains more pages than are in the file.  This breaks
+// things at a very basic level, verify that Raze() can handle it.
+TEST_F(SQLConnectionTest, RazeCallbackReopen) {
+  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
+  ASSERT_TRUE(db().Execute(kCreateSql));
+  ASSERT_EQ(1, SqliteMasterCount(&db()));
+  int page_size = 0;
+  {
+    sql::Statement s(db().GetUniqueStatement("PRAGMA page_size"));
+    ASSERT_TRUE(s.Step());
+    page_size = s.ColumnInt(0);
+  }
+  db().Close();
+
+  // Trim a single page from the end of the file.
+  {
+    file_util::ScopedFILE file(file_util::OpenFile(db_path(), "r+"));
+    ASSERT_TRUE(file.get() != NULL);
+    ASSERT_EQ(0, fseek(file.get(), -page_size, SEEK_END));
+    ASSERT_TRUE(file_util::TruncateFile(file.get()));
+  }
+
+  // Open() will succeed, even though the PRAGMA calls within will
+  // fail with SQLITE_CORRUPT, as will this PRAGMA.
+  {
+    sql::ScopedErrorIgnorer ignore_errors;
+    ignore_errors.IgnoreError(SQLITE_CORRUPT);
+    ASSERT_TRUE(db().Open(db_path()));
+    ASSERT_FALSE(db().Execute("PRAGMA auto_vacuum"));
+    db().Close();
+    ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
+  }
+
+  db().set_error_callback(base::Bind(&SQLConnectionTest::RazeErrorCallback,
+                                     base::Unretained(this),
+                                     SQLITE_CORRUPT));
+
+  // When the PRAGMA calls in Open() raise SQLITE_CORRUPT, the error
+  // callback will call RazeAndClose().  Open() will then fail and be
+  // retried.  The second Open() on the empty database will succeed
+  // cleanly.
+  ASSERT_TRUE(db().Open(db_path()));
+  ASSERT_TRUE(db().Execute("PRAGMA auto_vacuum"));
+  EXPECT_EQ(0, SqliteMasterCount(&db()));
+}
+
 // Basic test of RazeAndClose() operation.
 TEST_F(SQLConnectionTest, RazeAndClose) {
   const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
@@ -307,10 +557,7 @@
   ASSERT_FALSE(db().is_open());
   db().Close();
   ASSERT_TRUE(db().Open(db_path()));
-  {
-    sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master"));
-    ASSERT_FALSE(s.Step());
-  }
+  ASSERT_EQ(0, SqliteMasterCount(&db()));
 
   // Test that RazeAndClose() can break transactions.
   ASSERT_TRUE(db().Execute(kCreateSql));
@@ -321,10 +568,7 @@
   ASSERT_FALSE(db().CommitTransaction());
   db().Close();
   ASSERT_TRUE(db().Open(db_path()));
-  {
-    sql::Statement s(db().GetUniqueStatement("SELECT * FROM sqlite_master"));
-    ASSERT_FALSE(s.Step());
-  }
+  ASSERT_EQ(0, SqliteMasterCount(&db()));
 }
 
 // Test that various operations fail without crashing after
@@ -419,10 +663,12 @@
   // Should have both a main database file and a journal file because
   // of journal_mode PERSIST.
   base::FilePath journal(db_path().value() + FILE_PATH_LITERAL("-journal"));
-  ASSERT_TRUE(file_util::PathExists(db_path()));
-  ASSERT_TRUE(file_util::PathExists(journal));
+  ASSERT_TRUE(base::PathExists(db_path()));
+  ASSERT_TRUE(base::PathExists(journal));
 
   sql::Connection::Delete(db_path());
-  EXPECT_FALSE(file_util::PathExists(db_path()));
-  EXPECT_FALSE(file_util::PathExists(journal));
+  EXPECT_FALSE(base::PathExists(db_path()));
+  EXPECT_FALSE(base::PathExists(journal));
 }
+
+}  // namespace
diff --git a/sql/sql.gyp b/sql/sql.gyp
index 944defd..2e8fc18 100644
--- a/sql/sql.gyp
+++ b/sql/sql.gyp
@@ -55,6 +55,8 @@
         '../base/base.gyp:base',
       ],
       'sources': [
+        'test/error_callback_support.cc',
+        'test/error_callback_support.h',
         'test/scoped_error_ignorer.cc',
         'test/scoped_error_ignorer.h',
       ],
diff --git a/sql/sql.target.darwin-arm.mk b/sql/sql.target.darwin-arm.mk
index 0eb909f..214df24 100644
--- a/sql/sql.target.darwin-arm.mk
+++ b/sql/sql.target.darwin-arm.mk
@@ -66,8 +66,9 @@
 MY_DEFS_Debug := \
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
-	'-DUSE_LINUX_BREAKPAD' \
 	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
@@ -149,8 +150,9 @@
 MY_DEFS_Release := \
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
-	'-DUSE_LINUX_BREAKPAD' \
 	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
diff --git a/sql/sql.target.darwin-mips.mk b/sql/sql.target.darwin-mips.mk
index 66b9d20..1a63837 100644
--- a/sql/sql.target.darwin-mips.mk
+++ b/sql/sql.target.darwin-mips.mk
@@ -66,6 +66,8 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
@@ -147,6 +149,8 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
diff --git a/sql/sql.target.darwin-x86.mk b/sql/sql.target.darwin-x86.mk
index ada2ff0..5625a1c 100644
--- a/sql/sql.target.darwin-x86.mk
+++ b/sql/sql.target.darwin-x86.mk
@@ -68,8 +68,9 @@
 MY_DEFS_Debug := \
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
-	'-DUSE_LINUX_BREAKPAD' \
 	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
@@ -154,8 +155,9 @@
 MY_DEFS_Release := \
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
-	'-DUSE_LINUX_BREAKPAD' \
 	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
diff --git a/sql/sql.target.linux-arm.mk b/sql/sql.target.linux-arm.mk
index 0eb909f..214df24 100644
--- a/sql/sql.target.linux-arm.mk
+++ b/sql/sql.target.linux-arm.mk
@@ -66,8 +66,9 @@
 MY_DEFS_Debug := \
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
-	'-DUSE_LINUX_BREAKPAD' \
 	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
@@ -149,8 +150,9 @@
 MY_DEFS_Release := \
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
-	'-DUSE_LINUX_BREAKPAD' \
 	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
diff --git a/sql/sql.target.linux-mips.mk b/sql/sql.target.linux-mips.mk
index 66b9d20..1a63837 100644
--- a/sql/sql.target.linux-mips.mk
+++ b/sql/sql.target.linux-mips.mk
@@ -66,6 +66,8 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
@@ -147,6 +149,8 @@
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
 	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
diff --git a/sql/sql.target.linux-x86.mk b/sql/sql.target.linux-x86.mk
index ada2ff0..5625a1c 100644
--- a/sql/sql.target.linux-x86.mk
+++ b/sql/sql.target.linux-x86.mk
@@ -68,8 +68,9 @@
 MY_DEFS_Debug := \
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
-	'-DUSE_LINUX_BREAKPAD' \
 	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
@@ -154,8 +155,9 @@
 MY_DEFS_Release := \
 	'-DANGLE_DX11' \
 	'-D_FILE_OFFSET_BITS=64' \
-	'-DUSE_LINUX_BREAKPAD' \
 	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
 	'-DDISABLE_NACL' \
 	'-DCHROMIUM_BUILD' \
 	'-DUSE_LIBJPEG_TURBO=1' \
diff --git a/sql/statement_unittest.cc b/sql/statement_unittest.cc
index 3d32862..c5217aa 100644
--- a/sql/statement_unittest.cc
+++ b/sql/statement_unittest.cc
@@ -9,55 +9,29 @@
 #include "base/files/scoped_temp_dir.h"
 #include "sql/connection.h"
 #include "sql/statement.h"
+#include "sql/test/error_callback_support.h"
+#include "sql/test/scoped_error_ignorer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/sqlite/sqlite3.h"
 
 namespace {
 
-void CaptureErrorCallback(int* error_pointer, std::string* sql_text,
-                          int error, sql::Statement* stmt) {
-  *error_pointer = error;
-  const char* text = stmt ? stmt->GetSQLStatement() : NULL;
-  *sql_text = text ? text : "no statement available";
-}
-
 class SQLStatementTest : public testing::Test {
  public:
-  SQLStatementTest() : error_(SQLITE_OK) {}
-
   virtual 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_callback(base::Bind(&CaptureErrorCallback,
-                                      &error_, &sql_text_));
   }
 
   virtual 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:
   base::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
@@ -101,9 +75,14 @@
   EXPECT_TRUE(s.Succeeded());
 }
 
-TEST_F(SQLStatementTest, BasicErrorCallback) {
+// Error callback called for error running a statement.
+TEST_F(SQLStatementTest, ErrorCallback) {
   ASSERT_TRUE(db().Execute("CREATE TABLE foo (a INTEGER PRIMARY KEY, b)"));
-  EXPECT_EQ(SQLITE_OK, sqlite_error());
+
+  int error = SQLITE_OK;
+  sql::ScopedErrorCallback sec(
+      &db(), base::Bind(&sql::CaptureErrorCallback, &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.
@@ -111,8 +90,21 @@
   EXPECT_TRUE(s.is_valid());
   s.BindCString(0, "bad bad");
   EXPECT_FALSE(s.Run());
-  EXPECT_EQ(SQLITE_MISMATCH, sqlite_error());
-  ResetError();
+  EXPECT_EQ(SQLITE_MISMATCH, error);
+}
+
+// Error ignorer works for error running a statement.
+TEST_F(SQLStatementTest, ScopedIgnoreError) {
+  ASSERT_TRUE(db().Execute("CREATE TABLE foo (a INTEGER PRIMARY KEY, b)"));
+
+  sql::Statement s(db().GetUniqueStatement("INSERT INTO foo (a) VALUES (?)"));
+  EXPECT_TRUE(s.is_valid());
+
+  sql::ScopedErrorIgnorer ignore_errors;
+  ignore_errors.IgnoreError(SQLITE_MISMATCH);
+  s.BindCString(0, "bad bad");
+  ASSERT_FALSE(s.Run());
+  ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
 }
 
 TEST_F(SQLStatementTest, Reset) {
diff --git a/sql/test/error_callback_support.cc b/sql/test/error_callback_support.cc
new file mode 100644
index 0000000..9f0e22f
--- /dev/null
+++ b/sql/test/error_callback_support.cc
@@ -0,0 +1,28 @@
+// Copyright 2013 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/test/error_callback_support.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sql {
+
+void CaptureErrorCallback(int* error_pointer, int error, sql::Statement* stmt) {
+  *error_pointer = error;
+}
+
+ScopedErrorCallback::ScopedErrorCallback(
+    sql::Connection* db,
+    const sql::Connection::ErrorCallback& cb)
+    : db_(db) {
+  // Make sure someone isn't trying to nest things.
+  EXPECT_FALSE(db_->has_error_callback());
+  db_->set_error_callback(cb);
+}
+
+ScopedErrorCallback::~ScopedErrorCallback() {
+  db_->reset_error_callback();
+}
+
+}  // namespace
diff --git a/sql/test/error_callback_support.h b/sql/test/error_callback_support.h
new file mode 100644
index 0000000..3026857
--- /dev/null
+++ b/sql/test/error_callback_support.h
@@ -0,0 +1,36 @@
+// Copyright 2013 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_TEST_ERROR_CALLBACK_SUPPORT_H_
+#define SQL_TEST_ERROR_CALLBACK_SUPPORT_H_
+
+#include "sql/connection.h"
+
+namespace sql {
+
+// Helper to capture any errors into a local variable for testing.
+// For instance:
+//   int error = SQLITE_OK;
+//   ScopedErrorCallback sec(db, base::Bind(&CaptureErrorCallback, &error));
+//   // Provoke SQLITE_CONSTRAINT on db.
+//   EXPECT_EQ(SQLITE_CONSTRAINT, error);
+void CaptureErrorCallback(int* error_pointer, int error, sql::Statement* stmt);
+
+// Helper to set db's error callback and then reset it when it goes
+// out of scope.
+class ScopedErrorCallback {
+ public:
+  ScopedErrorCallback(sql::Connection* db,
+                      const sql::Connection::ErrorCallback& cb);
+  ~ScopedErrorCallback();
+
+ private:
+  sql::Connection* db_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedErrorCallback);
+};
+
+}  // namespace sql
+
+#endif  // SQL_TEST_ERROR_CALLBACK_SUPPORT_H_