The sql::Connection error callback can use sql::Recovery to "fix" the database. Unfortunately, since the error callback can run at an arbitrary time, it is impossible to suitably fix the entire state of the connection - any in-progress statements or cached data may be invalidated by the recovery process. So sql::Recovery poisons the database handle (closes the database and causes future calls to return errors).
As a special case, Open() retries a single time if the handle is poisoned during Open(). This is a special case because by definition there cannot be any derived state before the database is opened.
Unfortunately, the recovery process clears the error callback to prevent recursion, which means that in this special case the Open() can succeed without an error callback.
My intuition is that this isn't a huge issue. Most of the error callback cases don't actually do much other than attempted recovery. In this case, recovery was attempted and must have failed, so most likely the missing error callback wouldn't improve things.
I'll think on the right fix. I'm not sure if it would be better to have Open() restore the error callback, or maybe the error callback could restore itself. Or maybe sql::Recovery could be revised to only use bare sqlite3_*() calls, removing the potential for infinite recursion.
Comment 1 by sh...@chromium.org
, Jun 21 2017