LCOV - code coverage report
Current view: directory - dom/indexedDB - IDBCursor.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 405 352 86.9 %
Date: 2012-06-02 Functions: 46 42 91.3 %

       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                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Indexed Database.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * The Mozilla Foundation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Ben Turner <bent.mozilla@gmail.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "IDBCursor.h"
      41                 : 
      42                 : #include "mozilla/storage.h"
      43                 : #include "nsComponentManagerUtils.h"
      44                 : #include "nsContentUtils.h"
      45                 : #include "nsDOMClassInfoID.h"
      46                 : #include "nsEventDispatcher.h"
      47                 : #include "nsJSUtils.h"
      48                 : #include "nsThreadUtils.h"
      49                 : 
      50                 : #include "AsyncConnectionHelper.h"
      51                 : #include "IDBEvents.h"
      52                 : #include "IDBIndex.h"
      53                 : #include "IDBObjectStore.h"
      54                 : #include "IDBTransaction.h"
      55                 : #include "TransactionThreadPool.h"
      56                 : 
      57                 : USING_INDEXEDDB_NAMESPACE
      58                 : 
      59                 : namespace {
      60                 : 
      61                 : inline
      62                 : already_AddRefed<IDBRequest>
      63                 : GenerateRequest(IDBCursor* aCursor)
      64                 : {
      65                 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
      66                 :   IDBDatabase* database = aCursor->Transaction()->Database();
      67                 :   return IDBRequest::Create(aCursor, database, aCursor->Transaction());
      68                 : }
      69                 : 
      70                 : } // anonymous namespace
      71                 : 
      72                 : BEGIN_INDEXEDDB_NAMESPACE
      73                 : 
      74                 : class ContinueHelper : public AsyncConnectionHelper
      75                 : {
      76                 : public:
      77            1778 :   ContinueHelper(IDBCursor* aCursor,
      78                 :                  PRInt32 aCount)
      79                 :   : AsyncConnectionHelper(aCursor->mTransaction, aCursor->mRequest),
      80            1778 :     mCursor(aCursor), mCount(aCount)
      81                 :   {
      82            1778 :     NS_ASSERTION(aCount > 0, "Must have a count!");
      83            1778 :   }
      84                 : 
      85            1778 :   ~ContinueHelper()
      86            3556 :   {
      87            1778 :     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
      88            3556 :   }
      89                 : 
      90                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
      91                 :   nsresult GetSuccessResult(JSContext* aCx,
      92                 :                             jsval* aVal);
      93                 : 
      94            1778 :   void ReleaseMainThreadObjects()
      95                 :   {
      96            1778 :     mCursor = nsnull;
      97            1778 :     AsyncConnectionHelper::ReleaseMainThreadObjects();
      98            1778 :   }
      99                 : 
     100                 : protected:
     101                 :   virtual nsresult
     102                 :   BindArgumentsToStatement(mozIStorageStatement* aStatement) = 0;
     103                 : 
     104                 :   virtual nsresult
     105                 :   GatherResultsFromStatement(mozIStorageStatement* aStatement) = 0;
     106                 : 
     107                 : protected:
     108                 :   nsRefPtr<IDBCursor> mCursor;
     109                 :   PRInt32 mCount;
     110                 :   Key mKey;
     111                 :   Key mObjectKey;
     112                 :   StructuredCloneReadInfo mCloneReadInfo;
     113                 : };
     114                 : 
     115                 : class ContinueObjectStoreHelper : public ContinueHelper
     116            5292 : {
     117                 : public:
     118            1323 :   ContinueObjectStoreHelper(IDBCursor* aCursor,
     119                 :                             PRUint32 aCount)
     120            1323 :   : ContinueHelper(aCursor, aCount)
     121            1323 :   { }
     122                 : 
     123                 : private:
     124                 :   nsresult BindArgumentsToStatement(mozIStorageStatement* aStatement);
     125                 :   nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
     126                 : };
     127                 : 
     128                 : class ContinueIndexHelper : public ContinueHelper
     129            1472 : {
     130                 : public:
     131             455 :   ContinueIndexHelper(IDBCursor* aCursor,
     132                 :                       PRUint32 aCount)
     133             455 :   : ContinueHelper(aCursor, aCount)
     134             455 :   { }
     135                 : 
     136                 : private:
     137                 :   nsresult BindArgumentsToStatement(mozIStorageStatement* aStatement);
     138                 :   nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
     139                 : };
     140                 : 
     141                 : class ContinueIndexObjectHelper : public ContinueIndexHelper
     142             696 : {
     143                 : public:
     144             174 :   ContinueIndexObjectHelper(IDBCursor* aCursor,
     145                 :                             PRUint32 aCount)
     146             174 :   : ContinueIndexHelper(aCursor, aCount)
     147             174 :   { }
     148                 : 
     149                 : private:
     150                 :   nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
     151                 : };
     152                 : 
     153                 : END_INDEXEDDB_NAMESPACE
     154                 : 
     155                 : // static
     156                 : already_AddRefed<IDBCursor>
     157              38 : IDBCursor::Create(IDBRequest* aRequest,
     158                 :                   IDBTransaction* aTransaction,
     159                 :                   IDBObjectStore* aObjectStore,
     160                 :                   Direction aDirection,
     161                 :                   const Key& aRangeKey,
     162                 :                   const nsACString& aContinueQuery,
     163                 :                   const nsACString& aContinueToQuery,
     164                 :                   const Key& aKey,
     165                 :                   StructuredCloneReadInfo& aCloneReadInfo)
     166                 : {
     167              38 :   NS_ASSERTION(aObjectStore, "Null pointer!");
     168              38 :   NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
     169                 : 
     170                 :   nsRefPtr<IDBCursor> cursor =
     171                 :     IDBCursor::CreateCommon(aRequest, aTransaction, aObjectStore, aDirection,
     172              76 :                             aRangeKey, aContinueQuery, aContinueToQuery);
     173              38 :   NS_ASSERTION(cursor, "This shouldn't fail!");
     174                 : 
     175              38 :   cursor->mObjectStore = aObjectStore;
     176              38 :   cursor->mType = OBJECTSTORE;
     177              38 :   cursor->mKey = aKey;
     178              38 :   cursor->mCloneReadInfo.Swap(aCloneReadInfo);
     179                 : 
     180              38 :   return cursor.forget();
     181                 : }
     182                 : 
     183                 : // static
     184                 : already_AddRefed<IDBCursor>
     185              74 : IDBCursor::Create(IDBRequest* aRequest,
     186                 :                   IDBTransaction* aTransaction,
     187                 :                   IDBIndex* aIndex,
     188                 :                   Direction aDirection,
     189                 :                   const Key& aRangeKey,
     190                 :                   const nsACString& aContinueQuery,
     191                 :                   const nsACString& aContinueToQuery,
     192                 :                   const Key& aKey,
     193                 :                   const Key& aObjectKey)
     194                 : {
     195              74 :   NS_ASSERTION(aIndex, "Null pointer!");
     196              74 :   NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
     197              74 :   NS_ASSERTION(!aObjectKey.IsUnset(), "Bad key!");
     198                 : 
     199                 :   nsRefPtr<IDBCursor> cursor =
     200                 :     IDBCursor::CreateCommon(aRequest, aTransaction, aIndex->ObjectStore(),
     201                 :                             aDirection, aRangeKey, aContinueQuery,
     202             148 :                             aContinueToQuery);
     203              74 :   NS_ASSERTION(cursor, "This shouldn't fail!");
     204                 : 
     205              74 :   cursor->mIndex = aIndex;
     206              74 :   cursor->mType = INDEXKEY;
     207              74 :   cursor->mKey = aKey,
     208              74 :   cursor->mObjectKey = aObjectKey;
     209                 : 
     210              74 :   return cursor.forget();
     211                 : }
     212                 : 
     213                 : // static
     214                 : already_AddRefed<IDBCursor>
     215              51 : IDBCursor::Create(IDBRequest* aRequest,
     216                 :                   IDBTransaction* aTransaction,
     217                 :                   IDBIndex* aIndex,
     218                 :                   Direction aDirection,
     219                 :                   const Key& aRangeKey,
     220                 :                   const nsACString& aContinueQuery,
     221                 :                   const nsACString& aContinueToQuery,
     222                 :                   const Key& aKey,
     223                 :                   const Key& aObjectKey,
     224                 :                   StructuredCloneReadInfo& aCloneReadInfo)
     225                 : {
     226              51 :   NS_ASSERTION(aIndex, "Null pointer!");
     227              51 :   NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
     228                 : 
     229                 :   nsRefPtr<IDBCursor> cursor =
     230                 :     IDBCursor::CreateCommon(aRequest, aTransaction, aIndex->ObjectStore(),
     231                 :                             aDirection, aRangeKey, aContinueQuery,
     232             102 :                             aContinueToQuery);
     233              51 :   NS_ASSERTION(cursor, "This shouldn't fail!");
     234                 : 
     235              51 :   cursor->mObjectStore = aIndex->ObjectStore();
     236              51 :   cursor->mIndex = aIndex;
     237              51 :   cursor->mType = INDEXOBJECT;
     238              51 :   cursor->mKey = aKey;
     239              51 :   cursor->mObjectKey = aObjectKey;
     240              51 :   cursor->mCloneReadInfo.Swap(aCloneReadInfo);
     241                 : 
     242              51 :   return cursor.forget();
     243                 : }
     244                 : 
     245                 : // static
     246                 : nsresult
     247              16 : IDBCursor::ParseDirection(const nsAString& aDirection, Direction* aResult)
     248                 : {
     249              16 :   if (aDirection.EqualsLiteral("next")) {
     250               4 :     *aResult = NEXT;
     251                 :   }
     252              12 :   else if (aDirection.EqualsLiteral("nextunique")) {
     253               2 :     *aResult = NEXT_UNIQUE;
     254                 :   }
     255              10 :   else if (aDirection.EqualsLiteral("prev")) {
     256               8 :     *aResult = PREV;
     257                 :   }
     258               2 :   else if (aDirection.EqualsLiteral("prevunique")) {
     259               2 :     *aResult = PREV_UNIQUE;
     260                 :   }
     261                 :   else {
     262               0 :     return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
     263                 :   }
     264                 :   
     265              16 :   return NS_OK;
     266                 : }
     267                 : 
     268                 : // static
     269                 : already_AddRefed<IDBCursor>
     270             163 : IDBCursor::CreateCommon(IDBRequest* aRequest,
     271                 :                         IDBTransaction* aTransaction,
     272                 :                         IDBObjectStore* aObjectStore,
     273                 :                         Direction aDirection,
     274                 :                         const Key& aRangeKey,
     275                 :                         const nsACString& aContinueQuery,
     276                 :                         const nsACString& aContinueToQuery)
     277                 : {
     278             163 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     279             163 :   NS_ASSERTION(aRequest, "Null pointer!");
     280             163 :   NS_ASSERTION(aTransaction, "Null pointer!");
     281             163 :   NS_ASSERTION(aObjectStore, "Null pointer!");
     282             163 :   NS_ASSERTION(!aContinueQuery.IsEmpty(), "Empty query!");
     283             163 :   NS_ASSERTION(!aContinueToQuery.IsEmpty(), "Empty query!");
     284                 : 
     285             326 :   nsRefPtr<IDBCursor> cursor = new IDBCursor();
     286                 : 
     287             163 :   IDBDatabase* database = aTransaction->Database();
     288             163 :   cursor->mScriptOwner = database->GetScriptOwner();
     289                 : 
     290             163 :   if (cursor->mScriptOwner) {
     291             163 :     if (NS_FAILED(NS_HOLD_JS_OBJECTS(cursor, IDBCursor))) {
     292               0 :       return nsnull;
     293                 :     }
     294                 : 
     295             163 :     cursor->mRooted = true;
     296                 :   }
     297                 : 
     298             163 :   cursor->mRequest = aRequest;
     299             163 :   cursor->mTransaction = aTransaction;
     300             163 :   cursor->mObjectStore = aObjectStore;
     301             163 :   cursor->mDirection = aDirection;
     302             163 :   cursor->mContinueQuery = aContinueQuery;
     303             163 :   cursor->mContinueToQuery = aContinueToQuery;
     304             163 :   cursor->mRangeKey = aRangeKey;
     305                 : 
     306             163 :   return cursor.forget();
     307                 : }
     308                 : 
     309             163 : IDBCursor::IDBCursor()
     310                 : : mScriptOwner(nsnull),
     311                 :   mType(OBJECTSTORE),
     312                 :   mDirection(IDBCursor::NEXT),
     313                 :   mCachedKey(JSVAL_VOID),
     314                 :   mCachedPrimaryKey(JSVAL_VOID),
     315                 :   mCachedValue(JSVAL_VOID),
     316                 :   mHaveCachedKey(false),
     317                 :   mHaveCachedPrimaryKey(false),
     318                 :   mHaveCachedValue(false),
     319                 :   mRooted(false),
     320                 :   mContinueCalled(false),
     321             163 :   mHaveValue(true)
     322                 : {
     323             163 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     324             163 : }
     325                 : 
     326             326 : IDBCursor::~IDBCursor()
     327                 : {
     328             163 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     329                 : 
     330             163 :   if (mRooted) {
     331             155 :     NS_DROP_JS_OBJECTS(this, IDBCursor);
     332                 :   }
     333             163 :   IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
     334             163 : }
     335                 : 
     336                 : nsresult
     337            1788 : IDBCursor::ContinueInternal(const Key& aKey,
     338                 :                             PRInt32 aCount)
     339                 : {
     340            1788 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     341            1788 :   NS_ASSERTION(aCount > 0, "Must have a count!");
     342                 : 
     343            1788 :   if (!mTransaction->IsOpen()) {
     344               0 :     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
     345                 :   }
     346                 : 
     347            1788 :   if (!mHaveValue || mContinueCalled) {
     348              10 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
     349                 :   }
     350                 : 
     351            1778 :   mContinueToKey = aKey;
     352                 : 
     353                 : #ifdef DEBUG
     354                 :   {
     355            3556 :     nsAutoString readyState;
     356            1778 :     if (NS_FAILED(mRequest->GetReadyState(readyState))) {
     357               0 :       NS_ERROR("This should never fail!");
     358                 :     }
     359            1778 :     NS_ASSERTION(readyState.EqualsLiteral("done"), "Should be DONE!");
     360                 :   }
     361                 : #endif
     362                 : 
     363            1778 :   mRequest->Reset();
     364                 : 
     365            3556 :   nsRefPtr<ContinueHelper> helper;
     366            1778 :   switch (mType) {
     367                 :     case OBJECTSTORE:
     368            1323 :       helper = new ContinueObjectStoreHelper(this, aCount);
     369            1323 :       break;
     370                 : 
     371                 :     case INDEXKEY:
     372             281 :       helper = new ContinueIndexHelper(this, aCount);
     373             281 :       break;
     374                 : 
     375                 :     case INDEXOBJECT:
     376             174 :       helper = new ContinueIndexObjectHelper(this, aCount);
     377             174 :       break;
     378                 : 
     379                 :     default:
     380               0 :       NS_NOTREACHED("Unknown cursor type!");
     381                 :   }
     382                 : 
     383            1778 :   nsresult rv = helper->DispatchToTransactionPool();
     384            1778 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     385                 : 
     386            1778 :   mContinueCalled = true;
     387            1778 :   return NS_OK;
     388                 : }
     389                 : 
     390            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor)
     391                 : 
     392               8 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor)
     393               8 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
     394               8 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mRequest,
     395                 :                                                        nsIDOMEventTarget)
     396               8 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTransaction,
     397                 :                                                        nsIDOMEventTarget)
     398               8 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mObjectStore)
     399               8 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mIndex)
     400               8 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     401                 : 
     402             221 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
     403             221 :   NS_ASSERTION(tmp->mHaveCachedKey || JSVAL_IS_VOID(tmp->mCachedKey),
     404                 :                "Should have a cached key");
     405             221 :   NS_ASSERTION(tmp->mHaveCachedPrimaryKey ||
     406                 :                JSVAL_IS_VOID(tmp->mCachedPrimaryKey),
     407                 :                "Should have a cached primary key");
     408             221 :   NS_ASSERTION(tmp->mHaveCachedValue || JSVAL_IS_VOID(tmp->mCachedValue),
     409                 :                "Should have a cached value");
     410             221 :   if (tmp->mScriptOwner) {
     411             221 :     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(tmp->mScriptOwner,
     412                 :                                                "mScriptOwner")
     413                 :   }
     414             221 :   if (JSVAL_IS_GCTHING(tmp->mCachedKey)) {
     415               0 :     void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedKey);
     416               0 :     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedKey")
     417                 :   }
     418             221 :   if (JSVAL_IS_GCTHING(tmp->mCachedPrimaryKey)) {
     419               0 :     void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedPrimaryKey);
     420               0 :     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedPrimaryKey")
     421                 :   }
     422             221 :   if (JSVAL_IS_GCTHING(tmp->mCachedValue)) {
     423              48 :     void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedValue);
     424              48 :     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedValue")
     425                 :   }
     426             221 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     427                 : 
     428               8 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor)
     429                 :   // Don't unlink mObjectStore, mIndex, or mTransaction!
     430               8 :   if (tmp->mRooted) {
     431               8 :     NS_DROP_JS_OBJECTS(tmp, IDBCursor);
     432               8 :     tmp->mScriptOwner = nsnull;
     433               8 :     tmp->mCachedKey = JSVAL_VOID;
     434               8 :     tmp->mCachedPrimaryKey = JSVAL_VOID;
     435               8 :     tmp->mCachedValue = JSVAL_VOID;
     436               8 :     tmp->mHaveCachedKey = false;
     437               8 :     tmp->mHaveCachedPrimaryKey = false;
     438               8 :     tmp->mHaveCachedValue = false;
     439               8 :     tmp->mRooted = false;
     440               8 :     tmp->mHaveValue = false;
     441                 :   }
     442               8 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRequest)
     443               8 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     444                 : 
     445           17084 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBCursor)
     446           11184 :   NS_INTERFACE_MAP_ENTRY(nsIIDBCursor)
     447            8238 :   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIDBCursorWithValue, mType != INDEXKEY)
     448            7541 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(IDBCursorWithValue,
     449                 :                                                    mType != INDEXKEY)
     450            7452 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(IDBCursor,
     451                 :                                                    mType == INDEXKEY)
     452            7378 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     453            5592 : NS_INTERFACE_MAP_END
     454                 : 
     455            7378 : NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBCursor)
     456            7541 : NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor)
     457                 : 
     458                 : DOMCI_DATA(IDBCursor, IDBCursor)
     459                 : DOMCI_DATA(IDBCursorWithValue, IDBCursor)
     460                 : 
     461                 : NS_IMETHODIMP
     462               0 : IDBCursor::GetDirection(nsAString& aDirection)
     463                 : {
     464               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     465                 : 
     466               0 :   switch(mDirection) {
     467                 :     case NEXT:
     468               0 :       aDirection.AssignLiteral("next");
     469               0 :       break;
     470                 :     case NEXT_UNIQUE:
     471               0 :       aDirection.AssignLiteral("nextunique");
     472               0 :       break;
     473                 :     case PREV:
     474               0 :       aDirection.AssignLiteral("prev");
     475               0 :       break;
     476                 :     case PREV_UNIQUE:
     477               0 :       aDirection.AssignLiteral("prevunique");
     478                 :   }
     479                 : 
     480               0 :   return NS_OK;
     481                 : }
     482                 : 
     483                 : NS_IMETHODIMP
     484               0 : IDBCursor::GetSource(nsISupports** aSource)
     485                 : {
     486               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     487                 : 
     488                 :   return mType == OBJECTSTORE ?
     489               0 :          CallQueryInterface(mObjectStore, aSource) :
     490               0 :          CallQueryInterface(mIndex, aSource);
     491                 : }
     492                 : 
     493                 : NS_IMETHODIMP
     494             659 : IDBCursor::GetKey(JSContext* aCx,
     495                 :                   jsval* aKey)
     496                 : {
     497             659 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     498                 : 
     499             659 :   NS_ASSERTION(!mKey.IsUnset() || !mHaveValue, "Bad key!");
     500                 : 
     501             659 :   if (!mHaveValue) {
     502               0 :     *aKey = JSVAL_VOID;
     503               0 :     return NS_OK;
     504                 :   }
     505                 : 
     506             659 :   if (!mHaveCachedKey) {
     507             429 :     if (!mRooted) {
     508               0 :       NS_HOLD_JS_OBJECTS(this, IDBCursor);
     509               0 :       mRooted = true;
     510                 :     }
     511                 : 
     512             858 :     JSAutoRequest ar(aCx);
     513                 : 
     514             429 :     nsresult rv = mKey.ToJSVal(aCx, &mCachedKey);
     515             429 :     NS_ENSURE_SUCCESS(rv, rv);
     516                 : 
     517             858 :     mHaveCachedKey = true;
     518                 :   }
     519                 : 
     520             659 :   *aKey = mCachedKey;
     521             659 :   return NS_OK;
     522                 : }
     523                 : 
     524                 : NS_IMETHODIMP
     525             469 : IDBCursor::GetPrimaryKey(JSContext* aCx,
     526                 :                          jsval* aValue)
     527                 : {
     528             469 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     529                 : 
     530             469 :   if (!mHaveValue) {
     531               0 :     *aValue = JSVAL_VOID;
     532               0 :     return NS_OK;
     533                 :   }
     534                 : 
     535             469 :   if (!mHaveCachedPrimaryKey) {
     536             365 :     if (!mRooted) {
     537               0 :       NS_HOLD_JS_OBJECTS(this, IDBCursor);
     538               0 :       mRooted = true;
     539                 :     }
     540                 : 
     541             730 :     JSAutoRequest ar(aCx);
     542                 : 
     543             365 :     NS_ASSERTION(mType == OBJECTSTORE ? !mKey.IsUnset() :
     544                 :                                         !mObjectKey.IsUnset(), "Bad key!");
     545                 : 
     546             365 :     const Key& key = mType == OBJECTSTORE ? mKey : mObjectKey;
     547                 : 
     548             365 :     nsresult rv = key.ToJSVal(aCx, &mCachedPrimaryKey);
     549             365 :     NS_ENSURE_SUCCESS(rv, rv);
     550                 : 
     551             730 :     mHaveCachedPrimaryKey = true;
     552                 :   }
     553                 : 
     554             469 :   *aValue = mCachedPrimaryKey;
     555             469 :   return NS_OK;
     556                 : }
     557                 : 
     558                 : NS_IMETHODIMP
     559             697 : IDBCursor::GetValue(JSContext* aCx,
     560                 :                     jsval* aValue)
     561                 : {
     562             697 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     563             697 :   NS_ASSERTION(mType != INDEXKEY, "GetValue shouldn't exist on index keys");
     564                 : 
     565             697 :   if (!mHaveValue) {
     566               0 :     *aValue = JSVAL_VOID;
     567               0 :     return NS_OK;
     568                 :   }
     569                 : 
     570             697 :   if (!mHaveCachedValue) {
     571             288 :     if (!mRooted) {
     572               0 :       NS_HOLD_JS_OBJECTS(this, IDBCursor);
     573               0 :       mRooted = true;
     574                 :     }
     575                 : 
     576             288 :     if (!IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, &mCachedValue)) {
     577               0 :       mCachedValue = JSVAL_VOID;
     578               0 :       return NS_ERROR_DOM_DATA_CLONE_ERR;
     579                 :     }
     580                 : 
     581             288 :     mCloneReadInfo.mCloneBuffer.clear();
     582             288 :     mHaveCachedValue = true;
     583                 :   }
     584                 : 
     585             697 :   *aValue = mCachedValue;
     586             697 :   return NS_OK;
     587                 : }
     588                 : 
     589                 : NS_IMETHODIMP
     590            1782 : IDBCursor::Continue(const jsval &aKey,
     591                 :                     JSContext* aCx)
     592                 : {
     593            1782 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     594                 : 
     595            3564 :   Key key;
     596            1782 :   nsresult rv = key.SetFromJSVal(aCx, aKey);
     597            1782 :   NS_ENSURE_SUCCESS(rv, rv);
     598                 : 
     599            1782 :   if (!key.IsUnset()) {
     600               7 :     switch (mDirection) {
     601                 :       case IDBCursor::NEXT:
     602                 :       case IDBCursor::NEXT_UNIQUE:
     603               7 :         if (key <= mKey) {
     604               0 :           return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     605                 :         }
     606               7 :         break;
     607                 : 
     608                 :       case IDBCursor::PREV:
     609                 :       case IDBCursor::PREV_UNIQUE:
     610               0 :         if (key >= mKey) {
     611               0 :           return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     612                 :         }
     613               0 :         break;
     614                 : 
     615                 :       default:
     616               0 :         NS_NOTREACHED("Unknown direction type!");
     617                 :     }
     618                 :   }
     619                 : 
     620            1782 :   return ContinueInternal(key, 1);
     621                 : }
     622                 : 
     623                 : NS_IMETHODIMP
     624              21 : IDBCursor::Update(const jsval& aValue,
     625                 :                   JSContext* aCx,
     626                 :                   nsIIDBRequest** _retval)
     627                 : {
     628              21 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     629                 : 
     630              21 :   if (!mTransaction->IsOpen()) {
     631               0 :     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
     632                 :   }
     633                 : 
     634              21 :   if (!mTransaction->IsWriteAllowed()) {
     635               0 :     return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
     636                 :   }
     637                 : 
     638              21 :   if (!mHaveValue || mType == INDEXKEY) {
     639               0 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
     640                 :   }
     641                 : 
     642              21 :   NS_ASSERTION(mObjectStore, "This cannot be null!");
     643              21 :   NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
     644              21 :   NS_ASSERTION(mType != INDEXOBJECT || !mObjectKey.IsUnset(), "Bad key!");
     645                 : 
     646                 :   nsresult rv;
     647                 : 
     648              42 :   JSAutoRequest ar(aCx);
     649                 : 
     650              21 :   Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
     651                 : 
     652              21 :   if (!mObjectStore->KeyPath().IsEmpty()) {
     653                 :     // This has to be an object.
     654              14 :     if (JSVAL_IS_PRIMITIVE(aValue)) {
     655               0 :       return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     656                 :     }
     657                 : 
     658                 :     // Make sure the object given has the correct keyPath value set on it.
     659              14 :     const nsString& keyPath = mObjectStore->KeyPath();
     660                 : 
     661                 :     jsval prop;
     662                 :     JSBool ok = JS_GetUCProperty(aCx, JSVAL_TO_OBJECT(aValue),
     663              14 :                                  reinterpret_cast<const jschar*>(keyPath.get()),
     664              28 :                                  keyPath.Length(), &prop);
     665              14 :     NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     666                 : 
     667              28 :     Key key;
     668              14 :     rv = key.SetFromJSVal(aCx, prop);
     669              14 :     if (NS_FAILED(rv)) {
     670               0 :       return rv;
     671                 :     }
     672                 : 
     673              14 :     if (key != objectKey) {
     674               0 :       return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     675                 :     }
     676                 : 
     677              14 :     return mObjectStore->Put(aValue, JSVAL_VOID, aCx, 0, _retval);
     678                 :   }
     679                 : 
     680                 :   jsval keyVal;
     681               7 :   rv = objectKey.ToJSVal(aCx, &keyVal);
     682               7 :   NS_ENSURE_SUCCESS(rv, rv);
     683                 : 
     684               7 :   return mObjectStore->Put(aValue, keyVal, aCx, 1, _retval);
     685                 : }
     686                 : 
     687                 : NS_IMETHODIMP
     688               9 : IDBCursor::Delete(JSContext* aCx,
     689                 :                   nsIIDBRequest** _retval)
     690                 : {
     691               9 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     692                 : 
     693               9 :   if (!mTransaction->IsOpen()) {
     694               0 :     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
     695                 :   }
     696                 : 
     697               9 :   if (!mTransaction->IsWriteAllowed()) {
     698               0 :     return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
     699                 :   }
     700                 : 
     701               9 :   if (!mHaveValue || mType == INDEXKEY) {
     702               0 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
     703                 :   }
     704                 : 
     705               9 :   NS_ASSERTION(mObjectStore, "This cannot be null!");
     706               9 :   NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
     707                 : 
     708               9 :   Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
     709                 : 
     710                 :   jsval key;
     711               9 :   nsresult rv = objectKey.ToJSVal(aCx, &key);
     712               9 :   NS_ENSURE_SUCCESS(rv, rv);
     713                 : 
     714               9 :   return mObjectStore->Delete(key, aCx, _retval);
     715                 : }
     716                 : 
     717                 : NS_IMETHODIMP
     718               6 : IDBCursor::Advance(PRInt32 aCount)
     719                 : {
     720               6 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     721                 : 
     722               6 :   if (aCount < 1) {
     723               0 :     return NS_ERROR_DOM_TYPE_ERR;
     724                 :   }
     725                 : 
     726              12 :   Key key;
     727               6 :   return ContinueInternal(key, aCount);
     728                 : }
     729                 : 
     730                 : nsresult
     731            1778 : ContinueHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
     732                 : {
     733                 :   // We need to pick a query based on whether or not the cursor's mContinueToKey
     734                 :   // is set. If it is unset then othing was passed to continue so we'll grab the
     735                 :   // next item in the database that is greater than (less than, if we're running
     736                 :   // a PREV cursor) the current key. If it is set then a key was passed to
     737                 :   // continue so we'll grab the next item in the database that is greater than
     738                 :   // (less than, if we're running a PREV cursor) or equal to the key that was
     739                 :   // specified.
     740                 : 
     741            3556 :   nsCAutoString query;
     742            1778 :   if (mCursor->mContinueToKey.IsUnset()) {
     743            1771 :     query.Assign(mCursor->mContinueQuery);
     744                 :   }
     745                 :   else {
     746               7 :     query.Assign(mCursor->mContinueToQuery);
     747                 :   }
     748            1778 :   NS_ASSERTION(!query.IsEmpty(), "Bad query!");
     749                 : 
     750            1778 :   query.AppendInt(mCount);
     751                 : 
     752            3556 :   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
     753            1778 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     754                 : 
     755            3556 :   mozStorageStatementScoper scoper(stmt);
     756                 : 
     757            1778 :   nsresult rv = BindArgumentsToStatement(stmt);
     758            1778 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     759                 : 
     760            1778 :   NS_ASSERTION(mCount > 0, "Not ok!");
     761                 : 
     762                 :   bool hasResult;
     763            3495 :   for (PRInt32 index = 0; index < mCount; index++) {
     764            1872 :     rv = stmt->ExecuteStep(&hasResult);
     765            1872 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     766                 : 
     767            1872 :     if (!hasResult) {
     768             155 :       break;
     769                 :     }
     770                 :   }
     771                 : 
     772            1778 :   if (hasResult) {
     773            1623 :     rv = GatherResultsFromStatement(stmt);
     774            1623 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     775                 :   }
     776                 :   else {
     777             155 :     mKey.Unset();
     778                 :   }
     779                 : 
     780            1778 :   return NS_OK;
     781                 : }
     782                 : 
     783                 : nsresult
     784            1778 : ContinueHelper::GetSuccessResult(JSContext* aCx,
     785                 :                                  jsval* aVal)
     786                 : {
     787                 :   // Remove cached stuff from last time.
     788            1778 :   mCursor->mCachedKey = JSVAL_VOID;
     789            1778 :   mCursor->mCachedPrimaryKey = JSVAL_VOID;
     790            1778 :   mCursor->mCachedValue = JSVAL_VOID;
     791            1778 :   mCursor->mHaveCachedKey = false;
     792            1778 :   mCursor->mHaveCachedPrimaryKey = false;
     793            1778 :   mCursor->mHaveCachedValue = false;
     794            1778 :   mCursor->mContinueCalled = false;
     795                 : 
     796            1778 :   if (mKey.IsUnset()) {
     797             155 :     mCursor->mHaveValue = false;
     798             155 :     *aVal = JSVAL_VOID;
     799                 :   }
     800                 :   else {
     801            1623 :     NS_ASSERTION(mCursor->mType == IDBCursor::OBJECTSTORE ||
     802                 :                  !mObjectKey.IsUnset(), "Bad key!");
     803                 : 
     804                 :     // Set new values.
     805            1623 :     mCursor->mKey = mKey;
     806            1623 :     mCursor->mObjectKey = mObjectKey;
     807            1623 :     mCursor->mContinueToKey.Unset();
     808                 : 
     809            1623 :     mCursor->mCloneReadInfo.Swap(mCloneReadInfo);
     810            1623 :     mCloneReadInfo.mCloneBuffer.clear();
     811                 : 
     812            1623 :     nsresult rv = WrapNative(aCx, mCursor, aVal);
     813            1623 :     NS_ENSURE_SUCCESS(rv, rv);
     814                 :   }
     815                 : 
     816            1778 :   return NS_OK;
     817                 : }
     818                 : 
     819                 : nsresult
     820            1323 : ContinueObjectStoreHelper::BindArgumentsToStatement(
     821                 :                                                mozIStorageStatement* aStatement)
     822                 : {
     823                 :   // Bind object store id.
     824            1323 :   nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"),
     825            1323 :                                             mCursor->mObjectStore->Id());
     826            1323 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     827                 : 
     828            2646 :   NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
     829            2646 :   NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
     830                 : 
     831                 :   // Bind current key.
     832            1323 :   const Key& currentKey = mCursor->mContinueToKey.IsUnset() ?
     833            1320 :                           mCursor->mKey :
     834            2643 :                           mCursor->mContinueToKey;
     835                 : 
     836            1323 :   rv = currentKey.BindToStatement(aStatement, currentKeyName);
     837            1323 :   NS_ENSURE_SUCCESS(rv, rv);
     838                 : 
     839                 :   // Bind range key if it is specified.
     840            1323 :   const Key& rangeKey = mCursor->mRangeKey;
     841                 : 
     842            1323 :   if (!rangeKey.IsUnset()) {
     843               9 :     rv = rangeKey.BindToStatement(aStatement, rangeKeyName);
     844               9 :     NS_ENSURE_SUCCESS(rv, rv);
     845                 :   }
     846                 : 
     847            1323 :   return NS_OK;
     848                 : }
     849                 : 
     850                 : nsresult
     851            1289 : ContinueObjectStoreHelper::GatherResultsFromStatement(
     852                 :                                                mozIStorageStatement* aStatement)
     853                 : {
     854                 :   // Figure out what kind of key we have next.
     855            1289 :   nsresult rv = mKey.SetFromStatement(aStatement, 0);
     856            1289 :   NS_ENSURE_SUCCESS(rv, rv);
     857                 : 
     858                 :   rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(aStatement, 1, 2,
     859            1289 :     mDatabase->Manager(), mCloneReadInfo);
     860            1289 :   NS_ENSURE_SUCCESS(rv, rv);
     861                 : 
     862            1289 :   return NS_OK;
     863                 : }
     864                 : 
     865                 : nsresult
     866             455 : ContinueIndexHelper::BindArgumentsToStatement(mozIStorageStatement* aStatement)
     867                 : {
     868                 :   // Bind index id.
     869             455 :   nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"),
     870             455 :                                             mCursor->mIndex->Id());
     871             455 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     872                 : 
     873             910 :   NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
     874                 : 
     875                 :   // Bind current key.
     876             455 :   const Key& currentKey = mCursor->mContinueToKey.IsUnset() ?
     877             451 :                           mCursor->mKey :
     878             906 :                           mCursor->mContinueToKey;
     879                 : 
     880             455 :   rv = currentKey.BindToStatement(aStatement, currentKeyName);
     881             455 :   NS_ENSURE_SUCCESS(rv, rv);
     882                 : 
     883                 :   // Bind range key if it is specified.
     884             455 :   if (!mCursor->mRangeKey.IsUnset()) {
     885             276 :     NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
     886             138 :     rv = mCursor->mRangeKey.BindToStatement(aStatement, rangeKeyName);
     887             138 :     NS_ENSURE_SUCCESS(rv, rv);
     888                 :   }
     889                 : 
     890                 :   // Bind object key if duplicates are allowed and we're not continuing to a
     891                 :   // specific key.
     892             938 :   if ((mCursor->mDirection == IDBCursor::NEXT ||
     893              40 :        mCursor->mDirection == IDBCursor::PREV) &&
     894             443 :        mCursor->mContinueToKey.IsUnset()) {
     895             439 :     NS_ASSERTION(!mCursor->mObjectKey.IsUnset(), "Bad key!");
     896                 : 
     897             878 :     NS_NAMED_LITERAL_CSTRING(objectKeyName, "object_key");
     898             439 :     rv = mCursor->mObjectKey.BindToStatement(aStatement, objectKeyName);
     899             439 :     NS_ENSURE_SUCCESS(rv, rv);
     900                 :   }
     901                 : 
     902             455 :   return NS_OK;
     903                 : }
     904                 : 
     905                 : nsresult
     906             207 : ContinueIndexHelper::GatherResultsFromStatement(
     907                 :                                                mozIStorageStatement* aStatement)
     908                 : {
     909             207 :   nsresult rv = mKey.SetFromStatement(aStatement, 0);
     910             207 :   NS_ENSURE_SUCCESS(rv, rv);
     911                 : 
     912             207 :   rv = mObjectKey.SetFromStatement(aStatement, 1);
     913             207 :   NS_ENSURE_SUCCESS(rv, rv);
     914                 : 
     915             207 :   return NS_OK;
     916                 : }
     917                 : 
     918                 : nsresult
     919             127 : ContinueIndexObjectHelper::GatherResultsFromStatement(
     920                 :                                                mozIStorageStatement* aStatement)
     921                 : {
     922             127 :   nsresult rv = mKey.SetFromStatement(aStatement, 0);
     923             127 :   NS_ENSURE_SUCCESS(rv, rv);
     924                 : 
     925             127 :   rv = mObjectKey.SetFromStatement(aStatement, 1);
     926             127 :   NS_ENSURE_SUCCESS(rv, rv);
     927                 : 
     928                 :   rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(aStatement, 2, 3,
     929             127 :     mDatabase->Manager(), mCloneReadInfo);
     930             127 :   NS_ENSURE_SUCCESS(rv, rv);
     931                 : 
     932             127 :   return NS_OK;
     933            4392 : }

Generated by: LCOV version 1.7