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 180413 d3613979347679285841cab438875f86cc7ad622
parent 180412 9fab567879bcdca54be1ef6180c77d72f878fd51
child 180414 528a58952f8c2389ec7d59bf31ad15a4eb420f13
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersasuth
bugs914070
milestone31.0a1
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);
   }