Bug 914070 - Part 1 - Remove native connection getters from Storage connection. r=asuth
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 24 Apr 2014 11:54:09 +0200
changeset 198490 d3613979347679285841cab438875f86cc7ad622
parent 198489 9fab567879bcdca54be1ef6180c77d72f878fd51
child 198491 528a58952f8c2389ec7d59bf31ad15a4eb420f13
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs914070
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 914070 - Part 1 - Remove native connection getters from Storage connection. r=asuth
storage/src/StorageBaseStatementInternal.cpp
storage/src/StorageBaseStatementInternal.h
storage/src/mozStorageAsyncStatement.cpp
storage/src/mozStorageAsyncStatement.h
storage/src/mozStorageAsyncStatementExecution.cpp
storage/src/mozStorageAsyncStatementExecution.h
storage/src/mozStorageConnection.cpp
storage/src/mozStorageConnection.h
storage/src/mozStorageService.cpp
storage/src/mozStorageStatement.cpp
storage/src/mozStorageStatement.h
storage/src/mozStorageStatementData.h
storage/test/test_asyncStatementExecution_transaction.cpp
--- a/storage/src/StorageBaseStatementInternal.cpp
+++ b/storage/src/StorageBaseStatementInternal.cpp
@@ -189,18 +189,18 @@ StorageBaseStatementInternal::ExecuteAsy
   // actual logic is very simple, we now roll our own.
   nsTArray<StatementData> stmts(1);
   StatementData data;
   nsresult rv = getAsynchronousStatementData(data);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(stmts.AppendElement(data), NS_ERROR_OUT_OF_MEMORY);
 
   // Dispatch to the background
-  return AsyncExecuteStatements::execute(stmts, mDBConnection, aCallback,
-                                         _stmt);
+  return AsyncExecuteStatements::execute(stmts, mDBConnection,
+                                         mNativeConnection, aCallback, _stmt);
 }
 
 NS_IMETHODIMP
 StorageBaseStatementInternal::EscapeStringForLIKE(
   const nsAString &aValue,
   const char16_t aEscapeChar,
   nsAString &_escapedString
 )
--- a/storage/src/StorageBaseStatementInternal.h
+++ b/storage/src/StorageBaseStatementInternal.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_storage_StorageBaseStatementInternal_h_
 #define mozilla_storage_StorageBaseStatementInternal_h_
 
 #include "nsISupports.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 
+struct sqlite3;
 struct sqlite3_stmt;
 class mozIStorageError;
 class mozIStorageBindingParamsArray;
 class mozIStorageBindingParams;
 class mozIStorageStatementCallback;
 class mozIStoragePendingStatement;
 
 namespace mozilla {
@@ -92,16 +93,17 @@ public:
   virtual already_AddRefed<mozIStorageBindingParams> newBindingParams(
     mozIStorageBindingParamsArray *aOwner
   ) = 0;
 
 protected: // mix-in bits are protected
   StorageBaseStatementInternal();
 
   nsRefPtr<Connection> mDBConnection;
+  sqlite3 *mNativeConnection;
 
   /**
    * Our asynchronous statement.
    *
    * For Statement this is populated by the first invocation to
    * getAsyncStatement.
    *
    * For AsyncStatement, this is null at creation time and initialized by the
--- a/storage/src/mozStorageAsyncStatement.cpp
+++ b/storage/src/mozStorageAsyncStatement.cpp
@@ -126,23 +126,24 @@ static AsyncStatementClassInfo sAsyncSta
 AsyncStatement::AsyncStatement()
 : StorageBaseStatementInternal()
 , mFinalized(false)
 {
 }
 
 nsresult
 AsyncStatement::initialize(Connection *aDBConnection,
+                           sqlite3 *aNativeConnection,
                            const nsACString &aSQLStatement)
 {
-  NS_ASSERTION(aDBConnection, "No database connection given!");
-  NS_ASSERTION(aDBConnection->GetNativeConnection(),
-               "We should never be called with a null sqlite3 database!");
+  MOZ_ASSERT(aDBConnection, "No database connection given!");
+  MOZ_ASSERT(aNativeConnection, "No native connection given!");
 
   mDBConnection = aDBConnection;
+  mNativeConnection = aNativeConnection;
   mSQLString = aSQLStatement;
 
   PR_LOG(gStorageLog, PR_LOG_NOTICE, ("Inited async statement '%s' (0x%p)",
                                       mSQLString.get()));
 
 #ifdef DEBUG
   // We want to try and test for LIKE and that consumers are using
   // escapeStringForLIKE instead of just trusting user input.  The idea to
@@ -299,17 +300,17 @@ AsyncStatement::getAsyncStatement(sqlite
                "We should only be called on the async thread!");
 #endif
 
   if (!mAsyncStatement) {
     int rc = mDBConnection->prepareStatement(mSQLString, &mAsyncStatement);
     if (rc != SQLITE_OK) {
       PR_LOG(gStorageLog, PR_LOG_ERROR,
              ("Sqlite statement prepare error: %d '%s'", rc,
-              ::sqlite3_errmsg(mDBConnection->GetNativeConnection())));
+              ::sqlite3_errmsg(mNativeConnection)));
       PR_LOG(gStorageLog, PR_LOG_ERROR,
              ("Statement was: '%s'", mSQLString.get()));
       *_stmt = nullptr;
       return rc;
     }
     PR_LOG(gStorageLog, PR_LOG_NOTICE, ("Initialized statement '%s' (0x%p)",
                                         mSQLString.get(),
                                         mAsyncStatement));
--- a/storage/src/mozStorageAsyncStatement.h
+++ b/storage/src/mozStorageAsyncStatement.h
@@ -40,20 +40,23 @@ public:
   AsyncStatement();
 
   /**
    * Initializes the object on aDBConnection by preparing the SQL statement
    * given by aSQLStatement.
    *
    * @param aDBConnection
    *        The Connection object this statement is associated with.
+   * @param aNativeConnection
+   *        The native Sqlite connection this statement is associated with.
    * @param aSQLStatement
    *        The SQL statement to prepare that this object will represent.
    */
   nsresult initialize(Connection *aDBConnection,
+                      sqlite3 *aNativeConnection,
                       const nsACString &aSQLStatement);
 
   /**
    * Obtains and transfers ownership of the array of parameters that are bound
    * to this statment.  This can be null.
    */
   inline already_AddRefed<BindingParamsArray> bindingParamsArray()
   {
--- a/storage/src/mozStorageAsyncStatementExecution.cpp
+++ b/storage/src/mozStorageAsyncStatementExecution.cpp
@@ -158,22 +158,24 @@ private:
 
 ////////////////////////////////////////////////////////////////////////////////
 //// AsyncExecuteStatements
 
 /* static */
 nsresult
 AsyncExecuteStatements::execute(StatementDataArray &aStatements,
                                 Connection *aConnection,
+                                sqlite3 *aNativeConnection,
                                 mozIStorageStatementCallback *aCallback,
                                 mozIStoragePendingStatement **_stmt)
 {
   // Create our event to run in the background
   nsRefPtr<AsyncExecuteStatements> event =
-    new AsyncExecuteStatements(aStatements, aConnection, aCallback);
+    new AsyncExecuteStatements(aStatements, aConnection, aNativeConnection,
+                               aCallback);
   NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
 
   // Dispatch it to the background
   nsIEventTarget *target = aConnection->getAsyncExecutionTarget();
 
   // If we don't have a valid target, this is a bug somewhere else. In the past,
   // this assert found cases where a Run method would schedule a new statement
   // without checking if asyncClose had been called. The caller must prevent
@@ -189,18 +191,20 @@ AsyncExecuteStatements::execute(Statemen
 
   // Return it as the pending statement object and track it.
   NS_ADDREF(*_stmt = event);
   return NS_OK;
 }
 
 AsyncExecuteStatements::AsyncExecuteStatements(StatementDataArray &aStatements,
                                                Connection *aConnection,
+                                               sqlite3 *aNativeConnection,
                                                mozIStorageStatementCallback *aCallback)
 : mConnection(aConnection)
+, mNativeConnection(aNativeConnection)
 , mTransactionManager(nullptr)
 , mCallback(aCallback)
 , mCallingThread(::do_GetCurrentThread())
 , mMaxWait(TimeDuration::FromMilliseconds(MAX_MILLISECONDS_BETWEEN_RESULTS))
 , mIntervalStart(TimeStamp::Now())
 , mState(PENDING)
 , mCancelRequested(false)
 , mMutex(aConnection->sharedAsyncExecutionMutex)
@@ -359,18 +363,19 @@ AsyncExecuteStatements::executeStatement
     }
 
     // Set an error state.
     mState = ERROR;
     Telemetry::Accumulate(Telemetry::MOZ_STORAGE_ASYNC_REQUESTS_SUCCESS, false);
 
     // Construct the error message before giving up the mutex (which we cannot
     // hold during the call to notifyError).
-    sqlite3 *db = mConnection->GetNativeConnection();
-    nsCOMPtr<mozIStorageError> errorObj(new Error(rc, ::sqlite3_errmsg(db)));
+    nsCOMPtr<mozIStorageError> errorObj(
+      new Error(rc, ::sqlite3_errmsg(mNativeConnection))
+    );
     // We cannot hold the DB mutex while calling notifyError.
     SQLiteMutexAutoUnlock unlockedScope(mDBMutex);
     (void)notifyError(errorObj);
 
     // Finally, indicate that we should stop processing.
     return false;
   }
 }
@@ -587,19 +592,18 @@ AsyncExecuteStatements::Run()
       SQLiteMutexAutoLock lockedScope(mDBMutex);
 
       int rc = mStatements[i].getSqliteStatement(&stmt);
       if (rc != SQLITE_OK) {
         // Set our error state.
         mState = ERROR;
 
         // Build the error object; can't call notifyError with the lock held
-        sqlite3 *db = mConnection->GetNativeConnection();
         nsCOMPtr<mozIStorageError> errorObj(
-          new Error(rc, ::sqlite3_errmsg(db))
+          new Error(rc, ::sqlite3_errmsg(mNativeConnection))
         );
         {
           // We cannot hold the DB mutex and call notifyError.
           SQLiteMutexAutoUnlock unlockedScope(mDBMutex);
           (void)notifyError(errorObj);
         }
         break;
       }
--- a/storage/src/mozStorageAsyncStatementExecution.h
+++ b/storage/src/mozStorageAsyncStatementExecution.h
@@ -61,23 +61,26 @@ public:
    * Executes a statement in the background, and passes results back to the
    * caller.
    *
    * @param aStatements
    *        The statements to execute and possibly bind in the background.
    *        Ownership is transfered from the caller.
    * @param aConnection
    *        The connection that created the statements to execute.
+   * @param aNativeConnection
+   *        The native Sqlite connection that created the statements to execute.
    * @param aCallback
    *        The callback that is notified of results, completion, and errors.
    * @param _stmt
    *        The handle to control the execution of the statements.
    */
   static nsresult execute(StatementDataArray &aStatements,
                           Connection *aConnection,
+                          sqlite3 *aNativeConnection,
                           mozIStorageStatementCallback *aCallback,
                           mozIStoragePendingStatement **_stmt);
 
   /**
    * Indicates when events on the calling thread should run or not.  Certain
    * events posted back to the calling thread should call this see if they
    * should run or not.
    *
@@ -85,16 +88,17 @@ public:
    *
    * @returns true if the event should notify still, false otherwise.
    */
   bool shouldNotify();
 
 private:
   AsyncExecuteStatements(StatementDataArray &aStatements,
                          Connection *aConnection,
+                         sqlite3 *aNativeConnection,
                          mozIStorageStatementCallback *aCallback);
 
   /**
    * Binds and then executes a given statement until completion, an error
    * occurs, or we are canceled.  If aLastStatement is true, we should set
    * mState accordingly.
    *
    * @pre mMutex is not held
@@ -182,16 +186,17 @@ private:
    * transaction.
    *
    * @return true if an explicit transaction is needed, false otherwise.
    */
   bool statementsNeedTransaction();
 
   StatementDataArray mStatements;
   nsRefPtr<Connection> mConnection;
+  sqlite3 *mNativeConnection;
   mozStorageAsyncTransaction *mTransactionManager;
   mozIStorageStatementCallback *mCallback;
   nsCOMPtr<nsIThread> mCallingThread;
   nsRefPtr<ResultSet> mResultSet;
 
   /**
    * The maximum amount of time we want to wait between results.  Defined by
    * MAX_MILLISECONDS_BETWEEN_RESULTS and set at construction.
--- a/storage/src/mozStorageConnection.cpp
+++ b/storage/src/mozStorageConnection.cpp
@@ -514,16 +514,28 @@ NS_IMETHODIMP_(MozExternalRefCountType) 
     NS_ASSERT_OWNINGTHREAD(Connection);
 #endif
     delete (this);
     return 0;
   }
   return count;
 }
 
+int32_t
+Connection::getSqliteRuntimeStatus(int32_t aStatusOption, int32_t* aMaxValue)
+{
+  MOZ_ASSERT(mDBConn, "A connection must exist at this point");
+  int curr = 0, max = 0;
+  DebugOnly<int> rc = ::sqlite3_db_status(mDBConn, aStatusOption, &curr, &max, 0);
+  MOZ_ASSERT(NS_SUCCEEDED(convertResultCode(rc)));
+  if (aMaxValue)
+    *aMaxValue = max;
+  return curr;
+}
+
 nsIEventTarget *
 Connection::getAsyncExecutionTarget()
 {
   MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
 
   // If we are shutting down the asynchronous thread, don't hand out any more
   // references to the thread.
   if (mAsyncExecutionThreadShuttingDown)
@@ -1330,17 +1342,17 @@ Connection::CreateStatement(const nsACSt
                             mozIStorageStatement **_stmt)
 {
   NS_ENSURE_ARG_POINTER(_stmt);
   if (!mDBConn) return NS_ERROR_NOT_INITIALIZED;
 
   nsRefPtr<Statement> statement(new Statement());
   NS_ENSURE_TRUE(statement, NS_ERROR_OUT_OF_MEMORY);
 
-  nsresult rv = statement->initialize(this, aSQLStatement);
+  nsresult rv = statement->initialize(this, mDBConn, aSQLStatement);
   NS_ENSURE_SUCCESS(rv, rv);
 
   Statement *rawPtr;
   statement.forget(&rawPtr);
   *_stmt = rawPtr;
   return NS_OK;
 }
 
@@ -1349,17 +1361,17 @@ Connection::CreateAsyncStatement(const n
                                  mozIStorageAsyncStatement **_stmt)
 {
   NS_ENSURE_ARG_POINTER(_stmt);
   if (!mDBConn) return NS_ERROR_NOT_INITIALIZED;
 
   nsRefPtr<AsyncStatement> statement(new AsyncStatement());
   NS_ENSURE_TRUE(statement, NS_ERROR_OUT_OF_MEMORY);
 
-  nsresult rv = statement->initialize(this, aSQLStatement);
+  nsresult rv = statement->initialize(this, mDBConn, aSQLStatement);
   NS_ENSURE_SUCCESS(rv, rv);
 
   AsyncStatement *rawPtr;
   statement.forget(&rawPtr);
   *_stmt = rawPtr;
   return NS_OK;
 }
 
@@ -1391,17 +1403,18 @@ Connection::ExecuteAsync(mozIStorageBase
     NS_ASSERTION(stmt->getOwner() == this,
                  "Statement must be from this database connection!");
 
     // Now append it to our array.
     NS_ENSURE_TRUE(stmts.AppendElement(data), NS_ERROR_OUT_OF_MEMORY);
   }
 
   // Dispatch to the background
-  return AsyncExecuteStatements::execute(stmts, this, aCallback, _handle);
+  return AsyncExecuteStatements::execute(stmts, this, mDBConn, aCallback,
+                                         _handle);
 }
 
 NS_IMETHODIMP
 Connection::ExecuteSimpleSQLAsync(const nsACString &aSQLStatement,
                                   mozIStorageStatementCallback *aCallback,
                                   mozIStoragePendingStatement **_handle)
 {
   if (!NS_IsMainThread()) {
--- a/storage/src/mozStorageConnection.h
+++ b/storage/src/mozStorageConnection.h
@@ -91,19 +91,39 @@ public:
    * Creates the connection to the database.
    *
    * @param aFileURL
    *        The nsIFileURL of the location of the database to open, or create if it
    *        does not exist.
    */
   nsresult initialize(nsIFileURL *aFileURL);
 
-  // fetch the native handle
-  sqlite3 *GetNativeConnection() { return mDBConn; }
-  operator sqlite3 *() const { return mDBConn; }
+  /**
+   * Fetches runtime status information for this connection.
+   *
+   * @param aStatusOption One of the SQLITE_DBSTATUS options defined at
+   *        http://www.sqlite.org/c3ref/c_dbstatus_options.html
+   * @param [optional] aMaxValue if provided, will be set to the highest
+   *        istantaneous value.
+   * @return the current value for the specified option.
+   */
+  int32_t getSqliteRuntimeStatus(int32_t aStatusOption,
+                                 int32_t* aMaxValue=nullptr);
+  /**
+   * Registers/unregisters a commit hook callback.
+   *
+   * @param aCallbackFn a callback function to be invoked on transactions
+   *        commit.  Pass nullptr to unregister the current callback.
+   * @param [optional] aData if provided, will be passed to the callback.
+   * @see http://sqlite.org/c3ref/commit_hook.html
+   */
+  void setCommitHook(int (*aCallbackFn)(void *) , void *aData=nullptr) {
+    MOZ_ASSERT(mDBConn, "A connection must exist at this point");
+    ::sqlite3_commit_hook(mDBConn, aCallbackFn, aData);
+  };
 
   /**
    * Lazily creates and returns a background execution thread.  In the future,
    * the thread may be re-claimed if left idle, so you should call this
    * method just before you dispatch and not save the reference.
    *
    * @returns an event target suitable for asynchronous statement execution.
    */
@@ -257,29 +277,29 @@ private:
    *
    * This variable should be accessed while holding the
    * mAsyncExecutionMutex.
    */
   bool mAsyncExecutionThreadShuttingDown;
 
   /**
    * Tracks if we have a transaction in progress or not.  Access protected by
-   * mDBMutex.
+   * sharedDBMutex.
    */
   bool mTransactionInProgress;
 
   /**
    * Stores the mapping of a given function by name to its instance.  Access is
-   * protected by mDBMutex.
+   * protected by sharedDBMutex.
    */
   nsDataHashtable<nsCStringHashKey, FunctionInfo> mFunctions;
 
   /**
    * Stores the registered progress handler for the database connection.  Access
-   * is protected by mDBMutex.
+   * is protected by sharedDBMutex.
    */
   nsCOMPtr<mozIStorageProgressHandler> mProgressHandler;
 
   /**
    * Stores the flags we passed to sqlite3_open_v2.
    */
   const int mFlags;
 
--- a/storage/src/mozStorageService.cpp
+++ b/storage/src/mozStorageService.cpp
@@ -89,38 +89,34 @@ StorageSQLiteDistinguishedAmount()
  * @param aOption
  *        The SQLite constant for getting the measurement.
  * @param aTotal
  *        The accumulator for the measurement.
  */
 nsresult
 ReportConn(nsIHandleReportCallback *aHandleReport,
            nsISupports *aData,
-           sqlite3 *aConn,
+           Connection *aConn,
            const nsACString &aPathHead,
            const nsACString &aKind,
            const nsACString &aDesc,
-           int aOption,
+           int32_t aOption,
            size_t *aTotal)
 {
   nsCString path(aPathHead);
   path.Append(aKind);
   path.AppendLiteral("-used");
 
-  int curr = 0, max = 0;
-  int rc = ::sqlite3_db_status(aConn, aOption, &curr, &max, 0);
-  nsresult rv = convertResultCode(rc);
+  int32_t val = aConn->getSqliteRuntimeStatus(aOption);
+  nsresult rv = aHandleReport->Callback(EmptyCString(), path,
+                                        nsIMemoryReporter::KIND_HEAP,
+                                        nsIMemoryReporter::UNITS_BYTES,
+                                        int64_t(val), aDesc, aData);
   NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aHandleReport->Callback(EmptyCString(), path,
-                               nsIMemoryReporter::KIND_HEAP,
-                               nsIMemoryReporter::UNITS_BYTES, int64_t(curr),
-                               aDesc, aData);
-  NS_ENSURE_SUCCESS(rv, rv);
-  *aTotal += curr;
+  *aTotal += val;
 
   return NS_OK;
 }
 
 // Warning: To get a Connection's measurements requires holding its lock.
 // There may be a delay getting the lock if another thread is accessing the
 // Connection.  This isn't very nice if CollectReports is called from the main
 // thread!  But at the time of writing this function is only called when
@@ -150,33 +146,33 @@ Service::CollectReports(nsIHandleReportC
       pathHead.Append(conn->getFilename());
       pathHead.AppendLiteral("/");
 
       SQLiteMutexAutoLock lockedScope(conn->sharedDBMutex);
 
       NS_NAMED_LITERAL_CSTRING(stmtDesc,
         "Memory (approximate) used by all prepared statements used by "
         "connections to this database.");
-      rv = ReportConn(aHandleReport, aData, *conn.get(), pathHead,
+      rv = ReportConn(aHandleReport, aData, conn, pathHead,
                       NS_LITERAL_CSTRING("stmt"), stmtDesc,
                       SQLITE_DBSTATUS_STMT_USED, &totalConnSize);
       NS_ENSURE_SUCCESS(rv, rv);
 
       NS_NAMED_LITERAL_CSTRING(cacheDesc,
         "Memory (approximate) used by all pager caches used by connections "
         "to this database.");
-      rv = ReportConn(aHandleReport, aData, *conn.get(), pathHead,
+      rv = ReportConn(aHandleReport, aData, conn, pathHead,
                       NS_LITERAL_CSTRING("cache"), cacheDesc,
                       SQLITE_DBSTATUS_CACHE_USED, &totalConnSize);
       NS_ENSURE_SUCCESS(rv, rv);
 
       NS_NAMED_LITERAL_CSTRING(schemaDesc,
         "Memory (approximate) used to store the schema for all databases "
         "associated with connections to this database.");
-      rv = ReportConn(aHandleReport, aData, *conn.get(), pathHead,
+      rv = ReportConn(aHandleReport, aData, conn, pathHead,
                       NS_LITERAL_CSTRING("schema"), schemaDesc,
                       SQLITE_DBSTATUS_SCHEMA_USED, &totalConnSize);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
 #ifdef MOZ_DMD
     if (::sqlite3_memory_used() != int64_t(gSqliteMemoryUsed)) {
       NS_WARNING("memory consumption reported by SQLite doesn't match "
--- a/storage/src/mozStorageStatement.cpp
+++ b/storage/src/mozStorageStatement.cpp
@@ -130,40 +130,40 @@ Statement::Statement()
 , mDBStatement(nullptr)
 , mColumnNames()
 , mExecuting(false)
 {
 }
 
 nsresult
 Statement::initialize(Connection *aDBConnection,
+                      sqlite3 *aNativeConnection,
                       const nsACString &aSQLStatement)
 {
-  NS_ASSERTION(aDBConnection, "No database connection given!");
-  NS_ASSERTION(!mDBStatement, "Statement already initialized!");
-
-  DebugOnly<sqlite3 *> db = aDBConnection->GetNativeConnection();
-  NS_ASSERTION(db, "We should never be called with a null sqlite3 database!");
+  MOZ_ASSERT(aDBConnection, "No database connection given!");
+  MOZ_ASSERT(!mDBStatement, "Statement already initialized!");
+  MOZ_ASSERT(aNativeConnection, "No native connection given!");
 
   int srv = aDBConnection->prepareStatement(PromiseFlatCString(aSQLStatement),
                                             &mDBStatement);
   if (srv != SQLITE_OK) {
       PR_LOG(gStorageLog, PR_LOG_ERROR,
              ("Sqlite statement prepare error: %d '%s'", srv,
-              ::sqlite3_errmsg(db)));
+              ::sqlite3_errmsg(aNativeConnection)));
       PR_LOG(gStorageLog, PR_LOG_ERROR,
              ("Statement was: '%s'", PromiseFlatCString(aSQLStatement).get()));
       return NS_ERROR_FAILURE;
     }
 
   PR_LOG(gStorageLog, PR_LOG_NOTICE, ("Initialized statement '%s' (0x%p)",
                                       PromiseFlatCString(aSQLStatement).get(),
                                       mDBStatement));
 
   mDBConnection = aDBConnection;
+  mNativeConnection = aNativeConnection;
   mParamCount = ::sqlite3_bind_parameter_count(mDBStatement);
   mResultColumnCount = ::sqlite3_column_count(mDBStatement);
   mColumnNames.Clear();
 
   for (uint32_t i = 0; i < mResultColumnCount; i++) {
       const char *name = ::sqlite3_column_name(mDBStatement, i);
       (void)mColumnNames.AppendElement(nsDependentCString(name));
   }
@@ -330,17 +330,17 @@ MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(
 
 NS_IMETHODIMP
 Statement::Clone(mozIStorageStatement **_statement)
 {
   nsRefPtr<Statement> statement(new Statement());
   NS_ENSURE_TRUE(statement, NS_ERROR_OUT_OF_MEMORY);
 
   nsAutoCString sql(::sqlite3_sql(mDBStatement));
-  nsresult rv = statement->initialize(mDBConnection, sql);
+  nsresult rv = statement->initialize(mDBConnection, mNativeConnection, sql);
   NS_ENSURE_SUCCESS(rv, rv);
 
   statement.forget(_statement);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Statement::Finalize()
--- a/storage/src/mozStorageStatement.h
+++ b/storage/src/mozStorageStatement.h
@@ -42,20 +42,23 @@ public:
   Statement();
 
   /**
    * Initializes the object on aDBConnection by preparing the SQL statement
    * given by aSQLStatement.
    *
    * @param aDBConnection
    *        The Connection object this statement is associated with.
+   * @param aNativeConnection
+   *        The native Sqlite connection this statement is associated with.
    * @param aSQLStatement
    *        The SQL statement to prepare that this object will represent.
    */
   nsresult initialize(Connection *aDBConnection,
+                      sqlite3* aNativeConnection,
                       const nsACString &aSQLStatement);
 
 
   /**
    * Obtains the native statement pointer.
    */
   inline sqlite3_stmt *nativeStatement() { return mDBStatement; }
 
--- a/storage/src/mozStorageStatementData.h
+++ b/storage/src/mozStorageStatementData.h
@@ -67,25 +67,16 @@ public:
     }
     *_stmt = mStatement;
     return SQLITE_OK;
   }
 
   operator BindingParamsArray *() const { return mParamsArray; }
 
   /**
-   * Provide the ability to coerce back to a sqlite3 * connection for purposes 
-   * of getting an error message out of it.
-   */
-  operator sqlite3 *() const
-  {
-    return mStatementOwner->getOwner()->GetNativeConnection();
-  }
-
-  /**
    * NULLs out our sqlite3_stmt (it is held by the owner) after reseting it and
    * clear all bindings to it.  This is expected to occur on the async thread.
    */
   inline void reset()
   {
     NS_PRECONDITION(mStatementOwner, "Must have a statement owner!");
 #ifdef DEBUG
     {
--- a/storage/test/test_asyncStatementExecution_transaction.cpp
+++ b/storage/test/test_asyncStatementExecution_transaction.cpp
@@ -43,29 +43,29 @@ int commit_hook(void *aArg)
 void
 check_transaction(mozIStorageConnection *aDB,
                   mozIStorageBaseStatement **aStmts,
                   uint32_t aStmtsLen,
                   bool aTransactionExpected)
 {
   // -- install a transaction commit hook.
   int commit = 0;
-  ::sqlite3_commit_hook(*static_cast<Connection *>(aDB), commit_hook, &commit);
+  static_cast<Connection *>(aDB)->setCommitHook(commit_hook, &commit);
 
   nsRefPtr<AsyncStatementSpinner> asyncSpin(new AsyncStatementSpinner());
   nsCOMPtr<mozIStoragePendingStatement> asyncPend;
   do_check_success(aDB->ExecuteAsync(aStmts, aStmtsLen, asyncSpin,
                                      getter_AddRefs(asyncPend)));
   do_check_true(asyncPend);
 
   // -- complete the execution
   asyncSpin->SpinUntilCompleted();
 
   // -- uninstall the transaction commit hook.
-  ::sqlite3_commit_hook(*static_cast<Connection *>(aDB), nullptr, nullptr);
+  static_cast<Connection *>(aDB)->setCommitHook(nullptr);
 
   // -- check transaction
   do_check_eq(aTransactionExpected, !!commit);
 
   // -- check that only one transaction was created.
   if (aTransactionExpected) {
     do_check_eq(1, commit);
   }