[sql] Retry post-poison open as soon as possible.

sql::Connection::Open() retries the open if the handle is poisoned by
the error callback.  The assumption is that the error callback likely
razed or recovered the database, and since there can be no outstanding
statements the open can be safely retried.  This change adds this
handling to call which attempts to probe the database for basic
validity.

BUG=none

Review-Url: https://codereview.chromium.org/2258703004
Cr-Commit-Position: refs/heads/master@{#413292}
diff --git a/sql/connection.cc b/sql/connection.cc
index 9c7cb7d..d55c352 100644
--- a/sql/connection.cc
+++ b/sql/connection.cc
@@ -1693,15 +1693,28 @@
   err = sqlite3_extended_result_codes(db_, 1);
   DCHECK_EQ(err, SQLITE_OK) << "Could not enable extended result codes";
 
-  // sqlite3_open() does not actually read the database file (unless a
-  // hot journal is found).  Successfully executing this pragma on an
-  // existing database requires a valid header on page 1.
+  // sqlite3_open() does not actually read the database file (unless a hot
+  // journal is found).  Successfully executing this pragma on an existing
+  // database requires a valid header on page 1.  ExecuteAndReturnErrorCode() to
+  // get the error code before error callback (potentially) overwrites.
   // TODO(shess): For now, just probing to see what the lay of the
   // land is.  If it's mostly SQLITE_NOTADB, then the database should
   // be razed.
   err = ExecuteAndReturnErrorCode("PRAGMA auto_vacuum");
-  if (err != SQLITE_OK)
+  if (err != SQLITE_OK) {
     UMA_HISTOGRAM_SPARSE_SLOWLY("Sqlite.OpenProbeFailure", err);
+    OnSqliteError(err, nullptr, "PRAGMA auto_vacuum");
+
+    // Retry or bail out if the error handler poisoned the handle.
+    // TODO(shess): Move this handling to one place (see also sqlite3_open and
+    // secure_delete).  Possibly a wrapper function?
+    if (poisoned_) {
+      Close();
+      if (retry_flag == RETRY_ON_POISON)
+        return OpenInternal(file_name, NO_RETRY);
+      return false;
+    }
+  }
 
 #if defined(OS_IOS) && defined(USE_SYSTEM_SQLITE)
   // The version of SQLite shipped with iOS doesn't enable ICU, which includes