dom/indexedDB/IDBTransaction.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "base/basictypes.h"
     9 #include "IDBTransaction.h"
    11 #include "nsIAppShell.h"
    12 #include "nsIScriptContext.h"
    14 #include "mozilla/dom/quota/QuotaManager.h"
    15 #include "mozilla/storage.h"
    16 #include "nsDOMClassInfoID.h"
    17 #include "mozilla/dom/DOMStringList.h"
    18 #include "mozilla/EventDispatcher.h"
    19 #include "nsPIDOMWindow.h"
    20 #include "nsProxyRelease.h"
    21 #include "nsThreadUtils.h"
    22 #include "nsWidgetsCID.h"
    24 #include "AsyncConnectionHelper.h"
    25 #include "DatabaseInfo.h"
    26 #include "IDBCursor.h"
    27 #include "IDBEvents.h"
    28 #include "IDBFactory.h"
    29 #include "IDBObjectStore.h"
    30 #include "IndexedDatabaseManager.h"
    31 #include "ProfilerHelpers.h"
    32 #include "ReportInternalError.h"
    33 #include "TransactionThreadPool.h"
    35 #include "ipc/IndexedDBChild.h"
    37 #define SAVEPOINT_NAME "savepoint"
    39 using namespace mozilla;
    40 using namespace mozilla::dom;
    41 USING_INDEXEDDB_NAMESPACE
    42 using mozilla::dom::quota::QuotaManager;
    43 using mozilla::ErrorResult;
    45 namespace {
    47 NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
    49 #ifdef MOZ_ENABLE_PROFILER_SPS
    50 uint64_t gNextTransactionSerialNumber = 1;
    51 #endif
    53 PLDHashOperator
    54 DoomCachedStatements(const nsACString& aQuery,
    55                      nsCOMPtr<mozIStorageStatement>& aStatement,
    56                      void* aUserArg)
    57 {
    58   CommitHelper* helper = static_cast<CommitHelper*>(aUserArg);
    59   helper->AddDoomedObject(aStatement);
    60   return PL_DHASH_REMOVE;
    61 }
    63 // This runnable doesn't actually do anything beyond "prime the pump" and get
    64 // transactions in the right order on the transaction thread pool.
    65 class StartTransactionRunnable : public nsIRunnable
    66 {
    67 public:
    68   NS_DECL_ISUPPORTS
    70   NS_IMETHOD Run()
    71   {
    72     // NOP
    73     return NS_OK;
    74   }
    75 };
    77 // Could really use those NS_REFCOUNTING_HAHA_YEAH_RIGHT macros here.
    78 NS_IMETHODIMP_(MozExternalRefCountType) StartTransactionRunnable::AddRef()
    79 {
    80   return 2;
    81 }
    83 NS_IMETHODIMP_(MozExternalRefCountType) StartTransactionRunnable::Release()
    84 {
    85   return 1;
    86 }
    88 NS_IMPL_QUERY_INTERFACE(StartTransactionRunnable, nsIRunnable)
    90 } // anonymous namespace
    93 // static
    94 already_AddRefed<IDBTransaction>
    95 IDBTransaction::CreateInternal(IDBDatabase* aDatabase,
    96                                const Sequence<nsString>& aObjectStoreNames,
    97                                Mode aMode,
    98                                bool aDispatchDelayed,
    99                                bool aIsVersionChangeTransactionChild)
   100 {
   101   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   102   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess() || !aDispatchDelayed,
   103                "No support for delayed-dispatch transactions in child "
   104                "process!");
   105   NS_ASSERTION(!aIsVersionChangeTransactionChild ||
   106                (!IndexedDatabaseManager::IsMainProcess() &&
   107                 aMode == IDBTransaction::VERSION_CHANGE),
   108                "Busted logic!");
   110   nsRefPtr<IDBTransaction> transaction = new IDBTransaction(aDatabase);
   112   transaction->SetScriptOwner(aDatabase->GetScriptOwner());
   113   transaction->mDatabase = aDatabase;
   114   transaction->mMode = aMode;
   115   transaction->mDatabaseInfo = aDatabase->Info();
   116   transaction->mObjectStoreNames.AppendElements(aObjectStoreNames);
   117   transaction->mObjectStoreNames.Sort();
   119   IndexedDBTransactionChild* actor = nullptr;
   121   if (IndexedDatabaseManager::IsMainProcess()) {
   122     if (aMode != IDBTransaction::VERSION_CHANGE) {
   123       TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
   124       NS_ENSURE_TRUE(pool, nullptr);
   126       static StartTransactionRunnable sStartTransactionRunnable;
   127       pool->Dispatch(transaction, &sStartTransactionRunnable, false, nullptr);
   128     }
   129   }
   130   else if (!aIsVersionChangeTransactionChild) {
   131     IndexedDBDatabaseChild* dbActor = aDatabase->GetActorChild();
   132     NS_ASSERTION(dbActor, "Must have an actor here!");
   134     ipc::NormalTransactionParams params;
   135     params.names().AppendElements(aObjectStoreNames);
   136     params.mode() = aMode;
   138     actor = new IndexedDBTransactionChild();
   140     dbActor->SendPIndexedDBTransactionConstructor(actor, params);
   141   }
   143   if (!aDispatchDelayed) {
   144     nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
   145     NS_ENSURE_TRUE(appShell, nullptr);
   147     nsresult rv = appShell->RunBeforeNextEvent(transaction);
   148     NS_ENSURE_SUCCESS(rv, nullptr);
   150     transaction->mCreating = true;
   151   }
   153   if (actor) {
   154     NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   155     actor->SetTransaction(transaction);
   156   }
   158   return transaction.forget();
   159 }
   161 IDBTransaction::IDBTransaction(IDBDatabase* aDatabase)
   162 : IDBWrapperCache(aDatabase),
   163   mReadyState(IDBTransaction::INITIAL),
   164   mMode(IDBTransaction::READ_ONLY),
   165   mPendingRequests(0),
   166   mSavepointCount(0),
   167   mActorChild(nullptr),
   168   mActorParent(nullptr),
   169   mAbortCode(NS_OK),
   170 #ifdef MOZ_ENABLE_PROFILER_SPS
   171   mSerialNumber(gNextTransactionSerialNumber++),
   172 #endif
   173   mCreating(false)
   174 #ifdef DEBUG
   175   , mFiredCompleteOrAbort(false)
   176 #endif
   177 {
   178   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   179 }
   181 IDBTransaction::~IDBTransaction()
   182 {
   183   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   184   NS_ASSERTION(!mPendingRequests, "Should have no pending requests here!");
   185   NS_ASSERTION(!mSavepointCount, "Should have released them all!");
   186   NS_ASSERTION(!mConnection, "Should have called CommitOrRollback!");
   187   NS_ASSERTION(!mCreating, "Should have been cleared already!");
   188   NS_ASSERTION(mFiredCompleteOrAbort, "Should have fired event!");
   190   NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
   191   if (mActorChild) {
   192     NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   193     mActorChild->Send__delete__(mActorChild);
   194     NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
   195   }
   196 }
   198 void
   199 IDBTransaction::OnNewRequest()
   200 {
   201   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   202   if (!mPendingRequests) {
   203     NS_ASSERTION(mReadyState == IDBTransaction::INITIAL,
   204                  "Reusing a transaction!");
   205     mReadyState = IDBTransaction::LOADING;
   206   }
   207   ++mPendingRequests;
   208 }
   210 void
   211 IDBTransaction::OnRequestFinished()
   212 {
   213   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   214   NS_ASSERTION(mPendingRequests, "Mismatched calls!");
   215   --mPendingRequests;
   216   if (!mPendingRequests) {
   217     NS_ASSERTION(NS_FAILED(mAbortCode) || mReadyState == IDBTransaction::LOADING,
   218                  "Bad state!");
   219     mReadyState = IDBTransaction::COMMITTING;
   220     CommitOrRollback();
   221   }
   222 }
   224 void
   225 IDBTransaction::OnRequestDisconnected()
   226 {
   227   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   228   NS_ASSERTION(mPendingRequests, "Mismatched calls!");
   229   --mPendingRequests;
   230 }
   232 void
   233 IDBTransaction::RemoveObjectStore(const nsAString& aName)
   234 {
   235   NS_ASSERTION(mMode == IDBTransaction::VERSION_CHANGE,
   236                "Only remove object stores on VERSION_CHANGE transactions");
   238   mDatabaseInfo->RemoveObjectStore(aName);
   240   for (uint32_t i = 0; i < mCreatedObjectStores.Length(); i++) {
   241     if (mCreatedObjectStores[i]->Name() == aName) {
   242       nsRefPtr<IDBObjectStore> objectStore = mCreatedObjectStores[i];
   243       mCreatedObjectStores.RemoveElementAt(i);
   244       mDeletedObjectStores.AppendElement(objectStore);
   245       break;
   246     }
   247   }
   248 }
   250 void
   251 IDBTransaction::SetTransactionListener(IDBTransactionListener* aListener)
   252 {
   253   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   254   NS_ASSERTION(!mListener, "Shouldn't already have a listener!");
   255   mListener = aListener;
   256 }
   258 nsresult
   259 IDBTransaction::CommitOrRollback()
   260 {
   261   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   263   if (!IndexedDatabaseManager::IsMainProcess()) {
   264     if (mActorChild) {
   265       mActorChild->SendAllRequestsFinished();
   266     }
   268     return NS_OK;
   269   }
   271   nsRefPtr<CommitHelper> helper =
   272     new CommitHelper(this, mListener, mCreatedObjectStores);
   274   TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
   275   NS_ENSURE_STATE(pool);
   277   mCachedStatements.Enumerate(DoomCachedStatements, helper);
   278   NS_ASSERTION(!mCachedStatements.Count(), "Statements left!");
   280   nsresult rv = pool->Dispatch(this, helper, true, helper);
   281   NS_ENSURE_SUCCESS(rv, rv);
   283   return NS_OK;
   284 }
   286 bool
   287 IDBTransaction::StartSavepoint()
   288 {
   289   NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
   290   NS_PRECONDITION(mConnection, "No connection!");
   292   nsCOMPtr<mozIStorageStatement> stmt = GetCachedStatement(NS_LITERAL_CSTRING(
   293     "SAVEPOINT " SAVEPOINT_NAME
   294   ));
   295   NS_ENSURE_TRUE(stmt, false);
   297   mozStorageStatementScoper scoper(stmt);
   299   nsresult rv = stmt->Execute();
   300   NS_ENSURE_SUCCESS(rv, false);
   302   if (IsWriteAllowed()) {
   303     mUpdateFileRefcountFunction->StartSavepoint();
   304   }
   306   ++mSavepointCount;
   308   return true;
   309 }
   311 nsresult
   312 IDBTransaction::ReleaseSavepoint()
   313 {
   314   NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
   315   NS_PRECONDITION(mConnection, "No connection!");
   317   NS_ASSERTION(mSavepointCount, "Mismatch!");
   319   nsCOMPtr<mozIStorageStatement> stmt = GetCachedStatement(NS_LITERAL_CSTRING(
   320     "RELEASE SAVEPOINT " SAVEPOINT_NAME
   321   ));
   322   NS_ENSURE_TRUE(stmt, NS_OK);
   324   mozStorageStatementScoper scoper(stmt);
   326   nsresult rv = stmt->Execute();
   327   NS_ENSURE_SUCCESS(rv, NS_OK);
   329   if (IsWriteAllowed()) {
   330     mUpdateFileRefcountFunction->ReleaseSavepoint();
   331   }
   333   --mSavepointCount;
   335   return NS_OK;
   336 }
   338 void
   339 IDBTransaction::RollbackSavepoint()
   340 {
   341   NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
   342   NS_PRECONDITION(mConnection, "No connection!");
   344   NS_ASSERTION(mSavepointCount == 1, "Mismatch!");
   345   mSavepointCount = 0;
   347   nsCOMPtr<mozIStorageStatement> stmt = GetCachedStatement(NS_LITERAL_CSTRING(
   348     "ROLLBACK TO SAVEPOINT " SAVEPOINT_NAME
   349   ));
   350   NS_ENSURE_TRUE_VOID(stmt);
   352   mozStorageStatementScoper scoper(stmt);
   354   nsresult rv = stmt->Execute();
   355   NS_ENSURE_SUCCESS_VOID(rv);
   357   if (IsWriteAllowed()) {
   358     mUpdateFileRefcountFunction->RollbackSavepoint();
   359   }
   360 }
   362 nsresult
   363 IDBTransaction::GetOrCreateConnection(mozIStorageConnection** aResult)
   364 {
   365   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
   366   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   368   PROFILER_LABEL("IndexedDB", "IDBTransaction::GetOrCreateConnection");
   370   if (mDatabase->IsInvalidated()) {
   371     return NS_ERROR_NOT_AVAILABLE;
   372   }
   374   if (!mConnection) {
   375     nsCOMPtr<mozIStorageConnection> connection =
   376       IDBFactory::GetConnection(mDatabase->FilePath(), mDatabase->Type(),
   377                                 mDatabase->Group(), mDatabase->Origin());
   378     NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE);
   380     nsresult rv;
   382     nsRefPtr<UpdateRefcountFunction> function;
   383     nsCString beginTransaction;
   384     if (mMode != IDBTransaction::READ_ONLY) {
   385       function = new UpdateRefcountFunction(Database()->Manager());
   386       NS_ENSURE_TRUE(function, NS_ERROR_OUT_OF_MEMORY);
   388       rv = connection->CreateFunction(
   389         NS_LITERAL_CSTRING("update_refcount"), 2, function);
   390       NS_ENSURE_SUCCESS(rv, rv);
   392       beginTransaction.AssignLiteral("BEGIN IMMEDIATE TRANSACTION;");
   393     }
   394     else {
   395       beginTransaction.AssignLiteral("BEGIN TRANSACTION;");
   396     }
   398     nsCOMPtr<mozIStorageStatement> stmt;
   399     rv = connection->CreateStatement(beginTransaction, getter_AddRefs(stmt));
   400     NS_ENSURE_SUCCESS(rv, rv);
   402     rv = stmt->Execute();
   403     NS_ENSURE_SUCCESS(rv, rv);
   405     function.swap(mUpdateFileRefcountFunction);
   406     connection.swap(mConnection);
   407   }
   409   nsCOMPtr<mozIStorageConnection> result(mConnection);
   410   result.forget(aResult);
   411   return NS_OK;
   412 }
   414 already_AddRefed<mozIStorageStatement>
   415 IDBTransaction::GetCachedStatement(const nsACString& aQuery)
   416 {
   417   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
   418   NS_ASSERTION(!aQuery.IsEmpty(), "Empty sql statement!");
   419   NS_ASSERTION(mConnection, "No connection!");
   421   nsCOMPtr<mozIStorageStatement> stmt;
   423   if (!mCachedStatements.Get(aQuery, getter_AddRefs(stmt))) {
   424     nsresult rv = mConnection->CreateStatement(aQuery, getter_AddRefs(stmt));
   425 #ifdef DEBUG
   426     if (NS_FAILED(rv)) {
   427       nsCString error;
   428       error.AppendLiteral("The statement `");
   429       error.Append(aQuery);
   430       error.AppendLiteral("` failed to compile with the error message `");
   431       nsCString msg;
   432       (void)mConnection->GetLastErrorString(msg);
   433       error.Append(msg);
   434       error.AppendLiteral("`.");
   435       NS_ERROR(error.get());
   436     }
   437 #endif
   438     NS_ENSURE_SUCCESS(rv, nullptr);
   440     mCachedStatements.Put(aQuery, stmt);
   441   }
   443   return stmt.forget();
   444 }
   446 bool
   447 IDBTransaction::IsOpen() const
   448 {
   449   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   451   // If we haven't started anything then we're open.
   452   if (mReadyState == IDBTransaction::INITIAL) {
   453     return true;
   454   }
   456   // If we've already started then we need to check to see if we still have the
   457   // mCreating flag set. If we do (i.e. we haven't returned to the event loop
   458   // from the time we were created) then we are open. Otherwise check the
   459   // currently running transaction to see if it's the same. We only allow other
   460   // requests to be made if this transaction is currently running.
   461   if (mReadyState == IDBTransaction::LOADING) {
   462     if (mCreating) {
   463       return true;
   464     }
   466     if (AsyncConnectionHelper::GetCurrentTransaction() == this) {
   467       return true;
   468     }
   469   }
   471   return false;
   472 }
   474 already_AddRefed<IDBObjectStore>
   475 IDBTransaction::GetOrCreateObjectStore(const nsAString& aName,
   476                                        ObjectStoreInfo* aObjectStoreInfo,
   477                                        bool aCreating)
   478 {
   479   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   480   NS_ASSERTION(aObjectStoreInfo, "Null pointer!");
   481   NS_ASSERTION(!aCreating || GetMode() == IDBTransaction::VERSION_CHANGE,
   482                "How else can we create here?!");
   484   nsRefPtr<IDBObjectStore> retval;
   486   for (uint32_t index = 0; index < mCreatedObjectStores.Length(); index++) {
   487     nsRefPtr<IDBObjectStore>& objectStore = mCreatedObjectStores[index];
   488     if (objectStore->Name() == aName) {
   489       retval = objectStore;
   490       return retval.forget();
   491     }
   492   }
   494   retval = IDBObjectStore::Create(this, aObjectStoreInfo, mDatabaseInfo->id,
   495                                   aCreating);
   497   mCreatedObjectStores.AppendElement(retval);
   499   return retval.forget();
   500 }
   502 already_AddRefed<FileInfo>
   503 IDBTransaction::GetFileInfo(nsIDOMBlob* aBlob)
   504 {
   505   nsRefPtr<FileInfo> fileInfo;
   506   mCreatedFileInfos.Get(aBlob, getter_AddRefs(fileInfo));
   507   return fileInfo.forget();
   508 }
   510 void
   511 IDBTransaction::AddFileInfo(nsIDOMBlob* aBlob, FileInfo* aFileInfo)
   512 {
   513   mCreatedFileInfos.Put(aBlob, aFileInfo);
   514 }
   516 void
   517 IDBTransaction::ClearCreatedFileInfos()
   518 {
   519   mCreatedFileInfos.Clear();
   520 }
   522 nsresult
   523 IDBTransaction::AbortInternal(nsresult aAbortCode,
   524                               already_AddRefed<DOMError> aError)
   525 {
   526   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   528   nsRefPtr<DOMError> error = aError;
   530   if (IsFinished()) {
   531     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   532   }
   534   if (mActorChild) {
   535     NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   536     mActorChild->SendAbort(aAbortCode);
   537   }
   539   bool needToCommitOrRollback = mReadyState == IDBTransaction::INITIAL;
   541   mAbortCode = aAbortCode;
   542   mReadyState = IDBTransaction::DONE;
   543   mError = error.forget();
   545   if (GetMode() == IDBTransaction::VERSION_CHANGE) {
   546     // If a version change transaction is aborted, we must revert the world
   547     // back to its previous state.
   548     mDatabase->RevertToPreviousState();
   550     DatabaseInfo* dbInfo = mDatabase->Info();
   552     for (uint32_t i = 0; i < mCreatedObjectStores.Length(); i++) {
   553       nsRefPtr<IDBObjectStore>& objectStore = mCreatedObjectStores[i];
   554       ObjectStoreInfo* info = dbInfo->GetObjectStore(objectStore->Name());
   556       if (!info) {
   557         info = new ObjectStoreInfo(*objectStore->Info());
   558         info->indexes.Clear();
   559       }
   561       objectStore->SetInfo(info);
   562     }
   564     for (uint32_t i = 0; i < mDeletedObjectStores.Length(); i++) {
   565       nsRefPtr<IDBObjectStore>& objectStore = mDeletedObjectStores[i];
   566       ObjectStoreInfo* info = dbInfo->GetObjectStore(objectStore->Name());
   568       if (!info) {
   569         info = new ObjectStoreInfo(*objectStore->Info());
   570         info->indexes.Clear();
   571       }
   573       objectStore->SetInfo(info);
   574     }
   576     // and then the db must be closed
   577     mDatabase->Close();
   578   }
   580   // Fire the abort event if there are no outstanding requests. Otherwise the
   581   // abort event will be fired when all outstanding requests finish.
   582   if (needToCommitOrRollback) {
   583     return CommitOrRollback();
   584   }
   586   return NS_OK;
   587 }
   589 nsresult
   590 IDBTransaction::Abort(IDBRequest* aRequest)
   591 {
   592   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   593   NS_ASSERTION(aRequest, "This is undesirable.");
   595   ErrorResult rv;
   596   nsRefPtr<DOMError> error = aRequest->GetError(rv);
   598   return AbortInternal(aRequest->GetErrorCode(), error.forget());
   599 }
   601 nsresult
   602 IDBTransaction::Abort(nsresult aErrorCode)
   603 {
   604   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   606   nsRefPtr<DOMError> error = new DOMError(GetOwner(), aErrorCode);
   607   return AbortInternal(aErrorCode, error.forget());
   608 }
   610 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBTransaction)
   612 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBTransaction,
   613                                                   IDBWrapperCache)
   614   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDatabase)
   615   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
   616   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCreatedObjectStores)
   617   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeletedObjectStores)
   618 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   620 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBTransaction, IDBWrapperCache)
   621   // Don't unlink mDatabase!
   622   NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
   623   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCreatedObjectStores)
   624   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeletedObjectStores)
   625 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   627 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBTransaction)
   628   NS_INTERFACE_MAP_ENTRY(nsIRunnable)
   629 NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
   631 NS_IMPL_ADDREF_INHERITED(IDBTransaction, IDBWrapperCache)
   632 NS_IMPL_RELEASE_INHERITED(IDBTransaction, IDBWrapperCache)
   634 JSObject*
   635 IDBTransaction::WrapObject(JSContext* aCx)
   636 {
   637   return IDBTransactionBinding::Wrap(aCx, this);
   638 }
   640 mozilla::dom::IDBTransactionMode
   641 IDBTransaction::GetMode(ErrorResult& aRv) const
   642 {
   643   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   645   switch (mMode) {
   646     case READ_ONLY:
   647       return mozilla::dom::IDBTransactionMode::Readonly;
   649     case READ_WRITE:
   650       return mozilla::dom::IDBTransactionMode::Readwrite;
   652     case VERSION_CHANGE:
   653       return mozilla::dom::IDBTransactionMode::Versionchange;
   655     case MODE_INVALID:
   656     default:
   657       aRv.Throw(NS_ERROR_UNEXPECTED);
   658       return mozilla::dom::IDBTransactionMode::Readonly;
   659   }
   660 }
   662 DOMError*
   663 IDBTransaction::GetError(ErrorResult& aRv)
   664 {
   665   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   667   if (IsOpen()) {
   668     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   669     return nullptr;
   670   }
   672   return mError;
   673 }
   675 already_AddRefed<DOMStringList>
   676 IDBTransaction::GetObjectStoreNames(ErrorResult& aRv)
   677 {
   678   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   680   nsRefPtr<DOMStringList> list(new DOMStringList());
   682   if (mMode == IDBTransaction::VERSION_CHANGE) {
   683     mDatabaseInfo->GetObjectStoreNames(list->StringArray());
   684   }
   685   else {
   686     list->StringArray() = mObjectStoreNames;
   687   }
   689   return list.forget();
   690 }
   692 already_AddRefed<IDBObjectStore>
   693 IDBTransaction::ObjectStore(const nsAString& aName, ErrorResult& aRv)
   694 {
   695   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   697   if (IsFinished()) {
   698     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   699     return nullptr;
   700   }
   702   ObjectStoreInfo* info = nullptr;
   704   if (mMode == IDBTransaction::VERSION_CHANGE ||
   705       mObjectStoreNames.Contains(aName)) {
   706     info = mDatabaseInfo->GetObjectStore(aName);
   707   }
   709   if (!info) {
   710     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
   711     return nullptr;
   712   }
   714   nsRefPtr<IDBObjectStore> objectStore =
   715     GetOrCreateObjectStore(aName, info, false);
   716   if (!objectStore) {
   717     IDB_WARNING("Failed to get or create object store!");
   718     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   719     return nullptr;
   720   }
   722   return objectStore.forget();
   723 }
   725 nsresult
   726 IDBTransaction::PreHandleEvent(EventChainPreVisitor& aVisitor)
   727 {
   728   aVisitor.mCanHandle = true;
   729   aVisitor.mParentTarget = mDatabase;
   730   return NS_OK;
   731 }
   733 NS_IMETHODIMP
   734 IDBTransaction::Run()
   735 {
   736   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   738   // We're back at the event loop, no longer newborn.
   739   mCreating = false;
   741   // Maybe set the readyState to DONE if there were no requests generated.
   742   if (mReadyState == IDBTransaction::INITIAL) {
   743     mReadyState = IDBTransaction::DONE;
   745     if (NS_FAILED(CommitOrRollback())) {
   746       NS_WARNING("Failed to commit!");
   747     }
   748   }
   750   return NS_OK;
   751 }
   753 CommitHelper::CommitHelper(
   754               IDBTransaction* aTransaction,
   755               IDBTransactionListener* aListener,
   756               const nsTArray<nsRefPtr<IDBObjectStore> >& aUpdatedObjectStores)
   757 : mTransaction(aTransaction),
   758   mListener(aListener),
   759   mAbortCode(aTransaction->mAbortCode)
   760 {
   761   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   763   mConnection.swap(aTransaction->mConnection);
   764   mUpdateFileRefcountFunction.swap(aTransaction->mUpdateFileRefcountFunction);
   766   for (uint32_t i = 0; i < aUpdatedObjectStores.Length(); i++) {
   767     ObjectStoreInfo* info = aUpdatedObjectStores[i]->Info();
   768     if (info->comittedAutoIncrementId != info->nextAutoIncrementId) {
   769       mAutoIncrementObjectStores.AppendElement(aUpdatedObjectStores[i]);
   770     }
   771   }
   772 }
   774 CommitHelper::CommitHelper(IDBTransaction* aTransaction,
   775                            nsresult aAbortCode)
   776 : mTransaction(aTransaction),
   777   mAbortCode(aAbortCode)
   778 {
   779   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   780 }
   782 CommitHelper::~CommitHelper()
   783 {
   784 }
   786 NS_IMPL_ISUPPORTS(CommitHelper, nsIRunnable)
   788 NS_IMETHODIMP
   789 CommitHelper::Run()
   790 {
   791   if (NS_IsMainThread()) {
   792     PROFILER_MAIN_THREAD_LABEL("IndexedDB", "CommitHelper::Run");
   794     NS_ASSERTION(mDoomedObjects.IsEmpty(), "Didn't release doomed objects!");
   796     mTransaction->mReadyState = IDBTransaction::DONE;
   798     // Release file infos on the main thread, so they will eventually get
   799     // destroyed on correct thread.
   800     mTransaction->ClearCreatedFileInfos();
   801     if (mUpdateFileRefcountFunction) {
   802       mUpdateFileRefcountFunction->ClearFileInfoEntries();
   803       mUpdateFileRefcountFunction = nullptr;
   804     }
   806     nsCOMPtr<nsIDOMEvent> event;
   807     if (NS_FAILED(mAbortCode)) {
   808       if (mTransaction->GetMode() == IDBTransaction::VERSION_CHANGE) {
   809         // This will make the database take a snapshot of it's DatabaseInfo
   810         mTransaction->Database()->Close();
   811         // Then remove the info from the hash as it contains invalid data.
   812         DatabaseInfo::Remove(mTransaction->Database()->Id());
   813       }
   815       event = CreateGenericEvent(mTransaction,
   816                                  NS_LITERAL_STRING(ABORT_EVT_STR),
   817                                  eDoesBubble, eNotCancelable);
   819       // The transaction may already have an error object (e.g. if one of the
   820       // requests failed).  If it doesn't, and it wasn't aborted
   821       // programmatically, create one now.
   822       if (!mTransaction->mError &&
   823           mAbortCode != NS_ERROR_DOM_INDEXEDDB_ABORT_ERR) {
   824         mTransaction->mError = new DOMError(mTransaction->GetOwner(), mAbortCode);
   825       }
   826     }
   827     else {
   828       event = CreateGenericEvent(mTransaction,
   829                                  NS_LITERAL_STRING(COMPLETE_EVT_STR),
   830                                  eDoesNotBubble, eNotCancelable);
   831     }
   832     IDB_ENSURE_TRUE(event, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   834     if (mListener) {
   835       mListener->NotifyTransactionPreComplete(mTransaction);
   836     }
   838     IDB_PROFILER_MARK("IndexedDB Transaction %llu: Complete (rv = %lu)",
   839                       "IDBTransaction[%llu] MT Complete",
   840                       mTransaction->GetSerialNumber(), mAbortCode);
   842     bool dummy;
   843     if (NS_FAILED(mTransaction->DispatchEvent(event, &dummy))) {
   844       NS_WARNING("Dispatch failed!");
   845     }
   847 #ifdef DEBUG
   848     mTransaction->mFiredCompleteOrAbort = true;
   849 #endif
   851     if (mListener) {
   852       mListener->NotifyTransactionPostComplete(mTransaction);
   853     }
   855     mTransaction = nullptr;
   857     return NS_OK;
   858   }
   860   PROFILER_LABEL("IndexedDB", "CommitHelper::Run");
   862   IDBDatabase* database = mTransaction->Database();
   863   if (database->IsInvalidated()) {
   864     IDB_REPORT_INTERNAL_ERR();
   865     mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   866   }
   868   if (mConnection) {
   869     QuotaManager::SetCurrentWindow(database->GetOwner());
   871     if (NS_SUCCEEDED(mAbortCode) && mUpdateFileRefcountFunction &&
   872         NS_FAILED(mUpdateFileRefcountFunction->WillCommit(mConnection))) {
   873       IDB_REPORT_INTERNAL_ERR();
   874       mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   875     }
   877     if (NS_SUCCEEDED(mAbortCode) && NS_FAILED(WriteAutoIncrementCounts())) {
   878       IDB_REPORT_INTERNAL_ERR();
   879       mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   880     }
   882     if (NS_SUCCEEDED(mAbortCode)) {
   883       NS_NAMED_LITERAL_CSTRING(release, "COMMIT TRANSACTION");
   884       nsresult rv = mConnection->ExecuteSimpleSQL(release);
   885       if (NS_SUCCEEDED(rv)) {
   886         if (mUpdateFileRefcountFunction) {
   887           mUpdateFileRefcountFunction->DidCommit();
   888         }
   889         CommitAutoIncrementCounts();
   890       }
   891       else if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) {
   892         // mozstorage translates SQLITE_FULL to NS_ERROR_FILE_NO_DEVICE_SPACE,
   893         // which we know better as NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR.
   894         mAbortCode = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   895       }
   896       else {
   897         IDB_REPORT_INTERNAL_ERR();
   898         mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   899       }
   900     }
   902     if (NS_FAILED(mAbortCode)) {
   903       if (mUpdateFileRefcountFunction) {
   904         mUpdateFileRefcountFunction->DidAbort();
   905       }
   906       RevertAutoIncrementCounts();
   907       NS_NAMED_LITERAL_CSTRING(rollback, "ROLLBACK TRANSACTION");
   908       if (NS_FAILED(mConnection->ExecuteSimpleSQL(rollback))) {
   909         NS_WARNING("Failed to rollback transaction!");
   910       }
   911     }
   912   }
   914   mDoomedObjects.Clear();
   916   if (mConnection) {
   917     if (mUpdateFileRefcountFunction) {
   918       nsresult rv = mConnection->RemoveFunction(
   919         NS_LITERAL_CSTRING("update_refcount"));
   920       if (NS_FAILED(rv)) {
   921         NS_WARNING("Failed to remove function!");
   922       }
   923     }
   925     mConnection->Close();
   926     mConnection = nullptr;
   928     QuotaManager::SetCurrentWindow(nullptr);
   929   }
   931   return NS_OK;
   932 }
   934 nsresult
   935 CommitHelper::WriteAutoIncrementCounts()
   936 {
   937   nsCOMPtr<mozIStorageStatement> stmt;
   938   nsresult rv;
   939   for (uint32_t i = 0; i < mAutoIncrementObjectStores.Length(); i++) {
   940     ObjectStoreInfo* info = mAutoIncrementObjectStores[i]->Info();
   941     if (!stmt) {
   942       rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
   943         "UPDATE object_store SET auto_increment = :ai "
   944         "WHERE id = :osid;"), getter_AddRefs(stmt));
   945       NS_ENSURE_SUCCESS(rv, rv);
   946     }
   947     else {
   948       stmt->Reset();
   949     }
   951     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), info->id);
   952     NS_ENSURE_SUCCESS(rv, rv);
   954     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("ai"),
   955                                info->nextAutoIncrementId);
   956     NS_ENSURE_SUCCESS(rv, rv);
   958     rv = stmt->Execute();
   959     NS_ENSURE_SUCCESS(rv, rv);
   960   }
   962   return NS_OK;
   963 }
   965 void
   966 CommitHelper::CommitAutoIncrementCounts()
   967 {
   968   for (uint32_t i = 0; i < mAutoIncrementObjectStores.Length(); i++) {
   969     ObjectStoreInfo* info = mAutoIncrementObjectStores[i]->Info();
   970     info->comittedAutoIncrementId = info->nextAutoIncrementId;
   971   }
   972 }
   974 void
   975 CommitHelper::RevertAutoIncrementCounts()
   976 {
   977   for (uint32_t i = 0; i < mAutoIncrementObjectStores.Length(); i++) {
   978     ObjectStoreInfo* info = mAutoIncrementObjectStores[i]->Info();
   979     info->nextAutoIncrementId = info->comittedAutoIncrementId;
   980   }
   981 }
   983 NS_IMPL_ISUPPORTS(UpdateRefcountFunction, mozIStorageFunction)
   985 NS_IMETHODIMP
   986 UpdateRefcountFunction::OnFunctionCall(mozIStorageValueArray* aValues,
   987                                        nsIVariant** _retval)
   988 {
   989   *_retval = nullptr;
   991   uint32_t numEntries;
   992   nsresult rv = aValues->GetNumEntries(&numEntries);
   993   NS_ENSURE_SUCCESS(rv, rv);
   994   NS_ASSERTION(numEntries == 2, "unexpected number of arguments");
   996 #ifdef DEBUG
   997   int32_t type1 = mozIStorageValueArray::VALUE_TYPE_NULL;
   998   aValues->GetTypeOfIndex(0, &type1);
  1000   int32_t type2 = mozIStorageValueArray::VALUE_TYPE_NULL;
  1001   aValues->GetTypeOfIndex(1, &type2);
  1003   NS_ASSERTION(!(type1 == mozIStorageValueArray::VALUE_TYPE_NULL &&
  1004                  type2 == mozIStorageValueArray::VALUE_TYPE_NULL),
  1005                "Shouldn't be called!");
  1006 #endif
  1008   rv = ProcessValue(aValues, 0, eDecrement);
  1009   NS_ENSURE_SUCCESS(rv, rv);
  1011   rv = ProcessValue(aValues, 1, eIncrement);
  1012   NS_ENSURE_SUCCESS(rv, rv);
  1014   return NS_OK;
  1017 nsresult
  1018 UpdateRefcountFunction::WillCommit(mozIStorageConnection* aConnection)
  1020   DatabaseUpdateFunction function(aConnection, this);
  1022   mFileInfoEntries.EnumerateRead(DatabaseUpdateCallback, &function);
  1024   nsresult rv = function.ErrorCode();
  1025   NS_ENSURE_SUCCESS(rv, rv);
  1027   rv = CreateJournals();
  1028   NS_ENSURE_SUCCESS(rv, rv);
  1030   return NS_OK;
  1033 void
  1034 UpdateRefcountFunction::DidCommit()
  1036   mFileInfoEntries.EnumerateRead(FileInfoUpdateCallback, nullptr);
  1038   nsresult rv = RemoveJournals(mJournalsToRemoveAfterCommit);
  1039   NS_ENSURE_SUCCESS_VOID(rv);
  1042 void
  1043 UpdateRefcountFunction::DidAbort()
  1045   nsresult rv = RemoveJournals(mJournalsToRemoveAfterAbort);
  1046   NS_ENSURE_SUCCESS_VOID(rv);
  1049 nsresult
  1050 UpdateRefcountFunction::ProcessValue(mozIStorageValueArray* aValues,
  1051                                      int32_t aIndex,
  1052                                      UpdateType aUpdateType)
  1054   int32_t type;
  1055   aValues->GetTypeOfIndex(aIndex, &type);
  1056   if (type == mozIStorageValueArray::VALUE_TYPE_NULL) {
  1057     return NS_OK;
  1060   nsString ids;
  1061   aValues->GetString(aIndex, ids);
  1063   nsTArray<int64_t> fileIds;
  1064   nsresult rv = IDBObjectStore::ConvertFileIdsToArray(ids, fileIds);
  1065   NS_ENSURE_SUCCESS(rv, rv);
  1067   for (uint32_t i = 0; i < fileIds.Length(); i++) {
  1068     int64_t id = fileIds.ElementAt(i);
  1070     FileInfoEntry* entry;
  1071     if (!mFileInfoEntries.Get(id, &entry)) {
  1072       nsRefPtr<FileInfo> fileInfo = mFileManager->GetFileInfo(id);
  1073       NS_ASSERTION(fileInfo, "Shouldn't be null!");
  1075       nsAutoPtr<FileInfoEntry> newEntry(new FileInfoEntry(fileInfo));
  1076       mFileInfoEntries.Put(id, newEntry);
  1077       entry = newEntry.forget();
  1080     if (mInSavepoint) {
  1081       mSavepointEntriesIndex.Put(id, entry);
  1084     switch (aUpdateType) {
  1085       case eIncrement:
  1086         entry->mDelta++;
  1087         if (mInSavepoint) {
  1088           entry->mSavepointDelta++;
  1090         break;
  1091       case eDecrement:
  1092         entry->mDelta--;
  1093         if (mInSavepoint) {
  1094           entry->mSavepointDelta--;
  1096         break;
  1097       default:
  1098         NS_NOTREACHED("Unknown update type!");
  1102   return NS_OK;
  1105 nsresult
  1106 UpdateRefcountFunction::CreateJournals()
  1108   nsCOMPtr<nsIFile> journalDirectory = mFileManager->GetJournalDirectory();
  1109   NS_ENSURE_TRUE(journalDirectory, NS_ERROR_FAILURE);
  1111   for (uint32_t i = 0; i < mJournalsToCreateBeforeCommit.Length(); i++) {
  1112     int64_t id = mJournalsToCreateBeforeCommit[i];
  1114     nsCOMPtr<nsIFile> file =
  1115       mFileManager->GetFileForId(journalDirectory, id);
  1116     NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
  1118     nsresult rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
  1119     NS_ENSURE_SUCCESS(rv, rv);
  1121     mJournalsToRemoveAfterAbort.AppendElement(id);
  1124   return NS_OK;
  1127 nsresult
  1128 UpdateRefcountFunction::RemoveJournals(const nsTArray<int64_t>& aJournals)
  1130   nsCOMPtr<nsIFile> journalDirectory = mFileManager->GetJournalDirectory();
  1131   NS_ENSURE_TRUE(journalDirectory, NS_ERROR_FAILURE);
  1133   for (uint32_t index = 0; index < aJournals.Length(); index++) {
  1134     nsCOMPtr<nsIFile> file =
  1135       mFileManager->GetFileForId(journalDirectory, aJournals[index]);
  1136     NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
  1138     if (NS_FAILED(file->Remove(false))) {
  1139       NS_WARNING("Failed to removed journal!");
  1143   return NS_OK;
  1146 PLDHashOperator
  1147 UpdateRefcountFunction::DatabaseUpdateCallback(const uint64_t& aKey,
  1148                                                FileInfoEntry* aValue,
  1149                                                void* aUserArg)
  1151   if (!aValue->mDelta) {
  1152     return PL_DHASH_NEXT;
  1155   DatabaseUpdateFunction* function =
  1156     static_cast<DatabaseUpdateFunction*>(aUserArg);
  1158   if (!function->Update(aKey, aValue->mDelta)) {
  1159     return PL_DHASH_STOP;
  1162   return PL_DHASH_NEXT;
  1165 PLDHashOperator
  1166 UpdateRefcountFunction::FileInfoUpdateCallback(const uint64_t& aKey,
  1167                                                FileInfoEntry* aValue,
  1168                                                void* aUserArg)
  1170   if (aValue->mDelta) {
  1171     aValue->mFileInfo->UpdateDBRefs(aValue->mDelta);
  1174   return PL_DHASH_NEXT;
  1177 PLDHashOperator
  1178 UpdateRefcountFunction::RollbackSavepointCallback(const uint64_t& aKey,
  1179                                                   FileInfoEntry* aValue,
  1180                                                   void* aUserArg)
  1182   aValue->mDelta -= aValue->mSavepointDelta;
  1184   return PL_DHASH_NEXT;
  1187 bool
  1188 UpdateRefcountFunction::DatabaseUpdateFunction::Update(int64_t aId,
  1189                                                        int32_t aDelta)
  1191   nsresult rv = UpdateInternal(aId, aDelta);
  1192   if (NS_FAILED(rv)) {
  1193     mErrorCode = rv;
  1194     return false;
  1197   return true;
  1200 nsresult
  1201 UpdateRefcountFunction::DatabaseUpdateFunction::UpdateInternal(int64_t aId,
  1202                                                                int32_t aDelta)
  1204   nsresult rv;
  1206   if (!mUpdateStatement) {
  1207     rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
  1208       "UPDATE file SET refcount = refcount + :delta WHERE id = :id"
  1209     ), getter_AddRefs(mUpdateStatement));
  1210     NS_ENSURE_SUCCESS(rv, rv);
  1213   mozStorageStatementScoper updateScoper(mUpdateStatement);
  1215   rv = mUpdateStatement->BindInt32ByName(NS_LITERAL_CSTRING("delta"), aDelta);
  1216   NS_ENSURE_SUCCESS(rv, rv);
  1218   rv = mUpdateStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"), aId);
  1219   NS_ENSURE_SUCCESS(rv, rv);
  1221   rv = mUpdateStatement->Execute();
  1222   NS_ENSURE_SUCCESS(rv, rv);
  1224   int32_t rows;
  1225   rv = mConnection->GetAffectedRows(&rows);
  1226   NS_ENSURE_SUCCESS(rv, rv);
  1228   if (rows > 0) {
  1229     if (!mSelectStatement) {
  1230       rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
  1231         "SELECT id FROM file where id = :id"
  1232       ), getter_AddRefs(mSelectStatement));
  1233       NS_ENSURE_SUCCESS(rv, rv);
  1236     mozStorageStatementScoper selectScoper(mSelectStatement);
  1238     rv = mSelectStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"), aId);
  1239     NS_ENSURE_SUCCESS(rv, rv);
  1241     bool hasResult;
  1242     rv = mSelectStatement->ExecuteStep(&hasResult);
  1243     NS_ENSURE_SUCCESS(rv, rv);
  1245     if (!hasResult) {
  1246       // Don't have to create the journal here, we can create all at once,
  1247       // just before commit
  1248       mFunction->mJournalsToCreateBeforeCommit.AppendElement(aId);
  1251     return NS_OK;
  1254   if (!mInsertStatement) {
  1255     rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
  1256       "INSERT INTO file (id, refcount) VALUES(:id, :delta)"
  1257     ), getter_AddRefs(mInsertStatement));
  1258     NS_ENSURE_SUCCESS(rv, rv);
  1261   mozStorageStatementScoper insertScoper(mInsertStatement);
  1263   rv = mInsertStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"), aId);
  1264   NS_ENSURE_SUCCESS(rv, rv);
  1266   rv = mInsertStatement->BindInt32ByName(NS_LITERAL_CSTRING("delta"), aDelta);
  1267   NS_ENSURE_SUCCESS(rv, rv);
  1269   rv = mInsertStatement->Execute();
  1270   NS_ENSURE_SUCCESS(rv, rv);
  1272   mFunction->mJournalsToRemoveAfterCommit.AppendElement(aId);
  1274   return NS_OK;

mercurial