LCOV - code coverage report
Current view: directory - dom/indexedDB - IDBObjectStore.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1261 994 78.8 %
Date: 2012-06-02 Functions: 112 103 92.0 %

       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 "IDBObjectStore.h"
      41                 : 
      42                 : #include "nsIJSContextStack.h"
      43                 : 
      44                 : #include "jsfriendapi.h"
      45                 : #include "mozilla/dom/StructuredCloneTags.h"
      46                 : #include "mozilla/storage.h"
      47                 : #include "nsCharSeparatedTokenizer.h"
      48                 : #include "nsContentUtils.h"
      49                 : #include "nsDOMClassInfo.h"
      50                 : #include "nsDOMFile.h"
      51                 : #include "nsDOMLists.h"
      52                 : #include "nsEventDispatcher.h"
      53                 : #include "nsJSUtils.h"
      54                 : #include "nsServiceManagerUtils.h"
      55                 : #include "nsThreadUtils.h"
      56                 : #include "snappy/snappy.h"
      57                 : #include "test_quota.h"
      58                 : #include "xpcpublic.h"
      59                 : 
      60                 : #include "AsyncConnectionHelper.h"
      61                 : #include "IDBCursor.h"
      62                 : #include "IDBEvents.h"
      63                 : #include "IDBIndex.h"
      64                 : #include "IDBKeyRange.h"
      65                 : #include "IDBTransaction.h"
      66                 : #include "DatabaseInfo.h"
      67                 : #include "DictionaryHelpers.h"
      68                 : 
      69                 : #define FILE_COPY_BUFFER_SIZE 32768
      70                 : 
      71                 : USING_INDEXEDDB_NAMESPACE
      72                 : 
      73                 : namespace {
      74                 : 
      75                 : class AddHelper : public AsyncConnectionHelper
      76                 : {
      77                 : public:
      78            1837 :   AddHelper(IDBTransaction* aTransaction,
      79                 :             IDBRequest* aRequest,
      80                 :             IDBObjectStore* aObjectStore,
      81                 :             StructuredCloneWriteInfo& aCloneWriteInfo,
      82                 :             const Key& aKey,
      83                 :             bool aOverwrite,
      84                 :             nsTArray<IndexUpdateInfo>& aIndexUpdateInfo)
      85                 :   : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
      86            1837 :     mKey(aKey), mOverwrite(aOverwrite)
      87                 :   {
      88            1837 :     mCloneWriteInfo.Swap(aCloneWriteInfo);
      89            1837 :     mIndexUpdateInfo.SwapElements(aIndexUpdateInfo);
      90            1837 :   }
      91                 : 
      92            3674 :   ~AddHelper()
      93            3674 :   {
      94            1837 :     IDBObjectStore::ClearStructuredCloneBuffer(mCloneWriteInfo.mCloneBuffer);
      95            7348 :   }
      96                 : 
      97                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
      98                 :   nsresult GetSuccessResult(JSContext* aCx,
      99                 :                             jsval* aVal);
     100                 : 
     101            1837 :   void ReleaseMainThreadObjects()
     102                 :   {
     103            1837 :     mObjectStore = nsnull;
     104            1837 :     IDBObjectStore::ClearStructuredCloneBuffer(mCloneWriteInfo.mCloneBuffer);
     105            1837 :     AsyncConnectionHelper::ReleaseMainThreadObjects();
     106            1837 :   }
     107                 : 
     108                 : private:
     109                 :   // In-params.
     110                 :   nsRefPtr<IDBObjectStore> mObjectStore;
     111                 : 
     112                 :   // These may change in the autoincrement case.
     113                 :   StructuredCloneWriteInfo mCloneWriteInfo;
     114                 :   Key mKey;
     115                 :   const bool mOverwrite;
     116                 :   nsTArray<IndexUpdateInfo> mIndexUpdateInfo;
     117                 : };
     118                 : 
     119                 : class GetHelper : public AsyncConnectionHelper
     120                 : {
     121                 : public:
     122             199 :   GetHelper(IDBTransaction* aTransaction,
     123                 :             IDBRequest* aRequest,
     124                 :             IDBObjectStore* aObjectStore,
     125                 :             IDBKeyRange* aKeyRange)
     126                 :   : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
     127             199 :     mKeyRange(aKeyRange)
     128             199 :   { }
     129                 : 
     130             372 :   ~GetHelper()
     131             398 :   {
     132             199 :     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
     133             744 :   }
     134                 : 
     135                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
     136                 :   nsresult GetSuccessResult(JSContext* aCx,
     137                 :                             jsval* aVal);
     138                 : 
     139             199 :   void ReleaseMainThreadObjects()
     140                 :   {
     141             199 :     mObjectStore = nsnull;
     142             199 :     mKeyRange = nsnull;
     143             199 :     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
     144             199 :     AsyncConnectionHelper::ReleaseMainThreadObjects();
     145             199 :   }
     146                 : 
     147                 : protected:
     148                 :   // In-params.
     149                 :   nsRefPtr<IDBObjectStore> mObjectStore;
     150                 :   nsRefPtr<IDBKeyRange> mKeyRange;
     151                 : 
     152                 : private:
     153                 :   // Out-params.
     154                 :   StructuredCloneReadInfo mCloneReadInfo;
     155                 : };
     156                 : 
     157                 : class DeleteHelper : public GetHelper
     158             104 : {
     159                 : public:
     160              26 :   DeleteHelper(IDBTransaction* aTransaction,
     161                 :                IDBRequest* aRequest,
     162                 :                IDBObjectStore* aObjectStore,
     163                 :                IDBKeyRange* aKeyRange)
     164              26 :   : GetHelper(aTransaction, aRequest, aObjectStore, aKeyRange)
     165              26 :   { }
     166                 : 
     167                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
     168                 :   nsresult GetSuccessResult(JSContext* aCx,
     169                 :                             jsval* aVal);
     170                 : };
     171                 : 
     172                 : class ClearHelper : public AsyncConnectionHelper
     173              40 : {
     174                 : public:
     175              10 :   ClearHelper(IDBTransaction* aTransaction,
     176                 :               IDBRequest* aRequest,
     177                 :               IDBObjectStore* aObjectStore)
     178              10 :   : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore)
     179              10 :   { }
     180                 : 
     181                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
     182                 : 
     183              10 :   void ReleaseMainThreadObjects()
     184                 :   {
     185              10 :     mObjectStore = nsnull;
     186              10 :     AsyncConnectionHelper::ReleaseMainThreadObjects();
     187              10 :   }
     188                 : 
     189                 : protected:
     190                 :   // In-params.
     191                 :   nsRefPtr<IDBObjectStore> mObjectStore;
     192                 : };
     193                 : 
     194                 : class OpenCursorHelper : public AsyncConnectionHelper
     195                 : {
     196                 : public:
     197              47 :   OpenCursorHelper(IDBTransaction* aTransaction,
     198                 :                    IDBRequest* aRequest,
     199                 :                    IDBObjectStore* aObjectStore,
     200                 :                    IDBKeyRange* aKeyRange,
     201                 :                    IDBCursor::Direction aDirection)
     202                 :   : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
     203              47 :     mKeyRange(aKeyRange), mDirection(aDirection)
     204              47 :   { }
     205                 : 
     206              94 :   ~OpenCursorHelper()
     207              94 :   {
     208              47 :     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
     209             188 :   }
     210                 : 
     211                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
     212                 :   nsresult GetSuccessResult(JSContext* aCx,
     213                 :                             jsval* aVal);
     214                 : 
     215              47 :   void ReleaseMainThreadObjects()
     216                 :   {
     217              47 :     mObjectStore = nsnull;
     218              47 :     mKeyRange = nsnull;
     219              47 :     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
     220              47 :     AsyncConnectionHelper::ReleaseMainThreadObjects();
     221              47 :   }
     222                 : 
     223                 : private:
     224                 :   // In-params.
     225                 :   nsRefPtr<IDBObjectStore> mObjectStore;
     226                 :   nsRefPtr<IDBKeyRange> mKeyRange;
     227                 :   const IDBCursor::Direction mDirection;
     228                 : 
     229                 :   // Out-params.
     230                 :   Key mKey;
     231                 :   StructuredCloneReadInfo mCloneReadInfo;
     232                 :   nsCString mContinueQuery;
     233                 :   nsCString mContinueToQuery;
     234                 :   Key mRangeKey;
     235                 : };
     236                 : 
     237                 : class CreateIndexHelper : public AsyncConnectionHelper
     238             340 : {
     239                 : public:
     240                 :   CreateIndexHelper(IDBTransaction* aTransaction, IDBIndex* aIndex);
     241                 : 
     242                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
     243                 : 
     244              84 :   nsresult OnSuccess()
     245                 :   {
     246              84 :     return NS_OK;
     247                 :   }
     248                 : 
     249               1 :   void OnError()
     250                 :   {
     251               1 :     NS_ASSERTION(mTransaction->IsAborted(), "How else can this fail?!");
     252               1 :   }
     253                 : 
     254              85 :   void ReleaseMainThreadObjects()
     255                 :   {
     256              85 :     mIndex = nsnull;
     257              85 :     AsyncConnectionHelper::ReleaseMainThreadObjects();
     258              85 :   }
     259                 : 
     260                 : private:
     261                 :   nsresult InsertDataFromObjectStore(mozIStorageConnection* aConnection);
     262                 : 
     263                 :   static void DestroyTLSEntry(void* aPtr);
     264                 : 
     265                 :   static PRUintn sTLSIndex;
     266                 : 
     267                 :   // In-params.
     268                 :   nsRefPtr<IDBIndex> mIndex;
     269                 : };
     270                 : 
     271                 : PRUintn CreateIndexHelper::sTLSIndex = PRUintn(BAD_TLS_INDEX);
     272                 : 
     273                 : class DeleteIndexHelper : public AsyncConnectionHelper
     274              96 : {
     275                 : public:
     276              24 :   DeleteIndexHelper(IDBTransaction* aTransaction,
     277                 :                     const nsAString& aName,
     278                 :                     IDBObjectStore* aObjectStore)
     279                 :   : AsyncConnectionHelper(aTransaction, nsnull), mName(aName),
     280              24 :     mObjectStore(aObjectStore)
     281              24 :   { }
     282                 : 
     283                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
     284                 : 
     285              24 :   nsresult OnSuccess()
     286                 :   {
     287              24 :     return NS_OK;
     288                 :   }
     289                 : 
     290               0 :   void OnError()
     291                 :   {
     292               0 :     NS_ASSERTION(mTransaction->IsAborted(), "How else can this fail?!");
     293               0 :   }
     294                 : 
     295              24 :   void ReleaseMainThreadObjects()
     296                 :   {
     297              24 :     mObjectStore = nsnull;
     298              24 :     AsyncConnectionHelper::ReleaseMainThreadObjects();
     299              24 :   }
     300                 : 
     301                 : private:
     302                 :   // In-params
     303                 :   nsString mName;
     304                 :   nsRefPtr<IDBObjectStore> mObjectStore;
     305                 : };
     306                 : 
     307                 : class GetAllHelper : public AsyncConnectionHelper
     308                 : {
     309                 : public:
     310              17 :   GetAllHelper(IDBTransaction* aTransaction,
     311                 :                IDBRequest* aRequest,
     312                 :                IDBObjectStore* aObjectStore,
     313                 :                IDBKeyRange* aKeyRange,
     314                 :                const PRUint32 aLimit)
     315                 :   : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
     316              17 :     mKeyRange(aKeyRange), mLimit(aLimit)
     317              17 :   { }
     318                 : 
     319              34 :   ~GetAllHelper()
     320              34 :   {
     321              17 :     for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
     322                 :       IDBObjectStore::ClearStructuredCloneBuffer(
     323               0 :         mCloneReadInfos[index].mCloneBuffer);
     324                 :     }
     325              68 :   }
     326                 : 
     327                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
     328                 :   nsresult GetSuccessResult(JSContext* aCx,
     329                 :                             jsval* aVal);
     330                 : 
     331              17 :   void ReleaseMainThreadObjects()
     332                 :   {
     333              17 :     mObjectStore = nsnull;
     334              17 :     mKeyRange = nsnull;
     335              17 :     for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
     336                 :       IDBObjectStore::ClearStructuredCloneBuffer(
     337               0 :         mCloneReadInfos[index].mCloneBuffer);
     338                 :     }
     339              17 :     AsyncConnectionHelper::ReleaseMainThreadObjects();
     340              17 :   }
     341                 : 
     342                 : protected:
     343                 :   // In-params.
     344                 :   nsRefPtr<IDBObjectStore> mObjectStore;
     345                 :   nsRefPtr<IDBKeyRange> mKeyRange;
     346                 :   const PRUint32 mLimit;
     347                 : 
     348                 : private:
     349                 :   // Out-params.
     350                 :   nsTArray<StructuredCloneReadInfo> mCloneReadInfos;
     351                 : };
     352                 : 
     353                 : class CountHelper : public AsyncConnectionHelper
     354             128 : {
     355                 : public:
     356              32 :   CountHelper(IDBTransaction* aTransaction,
     357                 :               IDBRequest* aRequest,
     358                 :               IDBObjectStore* aObjectStore,
     359                 :               IDBKeyRange* aKeyRange)
     360                 :   : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
     361              32 :     mKeyRange(aKeyRange), mCount(0)
     362              32 :   { }
     363                 : 
     364                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
     365                 :   nsresult GetSuccessResult(JSContext* aCx,
     366                 :                             jsval* aVal);
     367                 : 
     368              32 :   void ReleaseMainThreadObjects()
     369                 :   {
     370              32 :     mObjectStore = nsnull;
     371              32 :     mKeyRange = nsnull;
     372              32 :     AsyncConnectionHelper::ReleaseMainThreadObjects();
     373              32 :   }
     374                 : 
     375                 : protected:
     376                 :   nsRefPtr<IDBObjectStore> mObjectStore;
     377                 :   nsRefPtr<IDBKeyRange> mKeyRange;
     378                 : 
     379                 : private:
     380                 :   PRUint64 mCount;
     381                 : };
     382                 : 
     383                 : NS_STACK_CLASS
     384                 : class AutoRemoveIndex
     385                 : {
     386                 : public:
     387              85 :   AutoRemoveIndex(ObjectStoreInfo* aObjectStoreInfo,
     388                 :                   const nsAString& aIndexName)
     389              85 :   : mObjectStoreInfo(aObjectStoreInfo), mIndexName(aIndexName)
     390              85 :   { }
     391                 : 
     392              85 :   ~AutoRemoveIndex()
     393              85 :   {
     394              85 :     if (mObjectStoreInfo) {
     395               0 :       for (PRUint32 i = 0; i < mObjectStoreInfo->indexes.Length(); i++) {
     396               0 :         if (mObjectStoreInfo->indexes[i].name == mIndexName) {
     397               0 :           mObjectStoreInfo->indexes.RemoveElementAt(i);
     398               0 :           break;
     399                 :         }
     400                 :       }
     401                 :     }
     402              85 :   }
     403                 : 
     404              85 :   void forget()
     405                 :   {
     406              85 :     mObjectStoreInfo = nsnull;
     407              85 :   }
     408                 : 
     409                 : private:
     410                 :   ObjectStoreInfo* mObjectStoreInfo;
     411                 :   nsString mIndexName;
     412                 : };
     413                 : 
     414                 : inline
     415                 : bool
     416           10223 : IgnoreWhitespace(PRUnichar c)
     417                 : {
     418           10223 :   return false;
     419                 : }
     420                 : 
     421                 : typedef nsCharSeparatedTokenizerTemplate<IgnoreWhitespace> KeyPathTokenizer;
     422                 : 
     423                 : inline
     424                 : nsresult
     425             628 : GetJSValFromKeyPath(JSContext* aCx,
     426                 :                     jsval aVal,
     427                 :                     const nsAString& aKeyPath,
     428                 :                     jsval& aKey)
     429                 : {
     430             628 :   NS_ASSERTION(aCx, "Null pointer!");
     431                 :   // aVal can be primitive iff the key path is empty.
     432             628 :   NS_ASSERTION(IDBObjectStore::IsValidKeyPath(aCx, aKeyPath),
     433                 :                "This will explode!");
     434                 : 
     435             628 :   KeyPathTokenizer tokenizer(aKeyPath, '.');
     436                 : 
     437             628 :   jsval intermediate = aVal;
     438            1879 :   while (tokenizer.hasMoreTokens()) {
     439            1246 :     const nsDependentSubstring& token = tokenizer.nextToken();
     440                 : 
     441             623 :     NS_ASSERTION(!token.IsEmpty(), "Should be a valid keypath");
     442                 : 
     443             623 :     const jschar* keyPathChars = token.BeginReading();
     444             623 :     const size_t keyPathLen = token.Length();
     445                 : 
     446             623 :     if (JSVAL_IS_PRIMITIVE(intermediate)) {
     447               0 :       intermediate = JSVAL_VOID;
     448                 :       break;
     449                 :     }
     450                 : 
     451                 :     JSBool ok = JS_GetUCProperty(aCx, JSVAL_TO_OBJECT(intermediate),
     452             623 :                                  keyPathChars, keyPathLen, &intermediate);
     453             623 :     NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     454                 :   }
     455                 :   
     456             628 :   aKey = intermediate;
     457             628 :   return NS_OK;
     458                 : }
     459                 : 
     460                 : inline
     461                 : nsresult
     462             260 : GetKeyFromValue(JSContext* aCx,
     463                 :                 jsval aVal,
     464                 :                 const nsAString& aKeyPath,
     465                 :                 Key& aKey)
     466                 : {
     467                 :   jsval key;
     468             260 :   nsresult rv = GetJSValFromKeyPath(aCx, aVal, aKeyPath, key);
     469             260 :   NS_ENSURE_SUCCESS(rv, rv);
     470                 : 
     471             260 :   if (NS_FAILED(aKey.SetFromJSVal(aCx, key))) {
     472               8 :     aKey.Unset();
     473                 :   }
     474                 : 
     475             260 :   return NS_OK;
     476                 : }
     477                 : 
     478                 : inline
     479                 : nsresult
     480               0 : GetKeyFromValue(JSContext* aCx,
     481                 :                 jsval aVal,
     482                 :                 const nsTArray<nsString>& aKeyPathArray,
     483                 :                 Key& aKey)
     484                 : {
     485               0 :   NS_ASSERTION(!aKeyPathArray.IsEmpty(),
     486                 :                "Should not use empty keyPath array");
     487               0 :   for (PRUint32 i = 0; i < aKeyPathArray.Length(); ++i) {
     488                 :     jsval key;
     489               0 :     nsresult rv = GetJSValFromKeyPath(aCx, aVal, aKeyPathArray[i], key);
     490               0 :     NS_ENSURE_SUCCESS(rv, rv);
     491                 : 
     492               0 :     if (NS_FAILED(aKey.AppendArrayItem(aCx, i == 0, key))) {
     493               0 :       NS_ASSERTION(aKey.IsUnset(), "Encoding error should unset");
     494               0 :       return NS_OK;
     495                 :     }
     496                 :   }
     497                 : 
     498               0 :   aKey.FinishArray();
     499                 : 
     500               0 :   return NS_OK;
     501                 : }
     502                 : 
     503                 : 
     504                 : inline
     505                 : already_AddRefed<IDBRequest>
     506            2142 : GenerateRequest(IDBObjectStore* aObjectStore)
     507                 : {
     508            2142 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     509            2142 :   IDBDatabase* database = aObjectStore->Transaction()->Database();
     510                 :   return IDBRequest::Create(aObjectStore, database,
     511            2142 :                             aObjectStore->Transaction());
     512                 : }
     513                 : 
     514                 : JSClass gDummyPropClass = {
     515                 :   "dummy", 0,
     516                 :   JS_PropertyStub,  JS_PropertyStub,
     517                 :   JS_PropertyStub,  JS_StrictPropertyStub,
     518                 :   JS_EnumerateStub, JS_ResolveStub,
     519                 :   JS_ConvertStub, JS_FinalizeStub,
     520                 :   JSCLASS_NO_OPTIONAL_MEMBERS
     521                 : };
     522                 : 
     523                 : } // anonymous namespace
     524                 : 
     525                 : // static
     526                 : already_AddRefed<IDBObjectStore>
     527             667 : IDBObjectStore::Create(IDBTransaction* aTransaction,
     528                 :                        ObjectStoreInfo* aStoreInfo,
     529                 :                        nsIAtom* aDatabaseId)
     530                 : {
     531             667 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     532                 : 
     533            1334 :   nsRefPtr<IDBObjectStore> objectStore = new IDBObjectStore();
     534                 : 
     535             667 :   objectStore->mTransaction = aTransaction;
     536             667 :   objectStore->mName = aStoreInfo->name;
     537             667 :   objectStore->mId = aStoreInfo->id;
     538             667 :   objectStore->mKeyPath = aStoreInfo->keyPath;
     539             667 :   objectStore->mKeyPathArray = aStoreInfo->keyPathArray;
     540             667 :   objectStore->mAutoIncrement = !!aStoreInfo->nextAutoIncrementId;
     541             667 :   objectStore->mDatabaseId = aDatabaseId;
     542             667 :   objectStore->mInfo = aStoreInfo;
     543                 : 
     544             667 :   return objectStore.forget();
     545                 : }
     546                 : 
     547                 : // static
     548                 : bool
     549             843 : IDBObjectStore::IsValidKeyPath(JSContext* aCx,
     550                 :                                const nsAString& aKeyPath)
     551                 : {
     552             843 :   NS_ASSERTION(!aKeyPath.IsVoid(), "What?");
     553                 : 
     554             843 :   KeyPathTokenizer tokenizer(aKeyPath, '.');
     555                 : 
     556            2523 :   while (tokenizer.hasMoreTokens()) {
     557            1674 :     nsString token(tokenizer.nextToken());
     558                 : 
     559             837 :     if (!token.Length()) {
     560               0 :       return false;
     561                 :     }
     562                 : 
     563                 :     jsval stringVal;
     564             837 :     if (!xpc::StringToJsval(aCx, token, &stringVal)) {
     565               0 :       return false;
     566                 :     }
     567                 : 
     568             837 :     NS_ASSERTION(JSVAL_IS_STRING(stringVal), "This should never happen");
     569             837 :     JSString* str = JSVAL_TO_STRING(stringVal);
     570                 : 
     571             837 :     JSBool isIdentifier = JS_FALSE;
     572             837 :     if (!JS_IsIdentifier(aCx, str, &isIdentifier) || !isIdentifier) {
     573               0 :       return false;
     574                 :     }
     575                 :   }
     576                 : 
     577                 :   // If the very last character was a '.', the tokenizer won't give us an empty
     578                 :   // token, but the keyPath is still invalid.
     579            1680 :   if (!aKeyPath.IsEmpty() &&
     580             837 :       aKeyPath.CharAt(aKeyPath.Length() - 1) == '.') {
     581               0 :     return false;
     582                 :   }
     583                 : 
     584             843 :   return true;
     585                 : }
     586                 : 
     587                 : // static
     588                 : nsresult
     589             368 : IDBObjectStore::AppendIndexUpdateInfo(PRInt64 aIndexID,
     590                 :                                       const nsAString& aKeyPath,
     591                 :                                       const nsTArray<nsString>& aKeyPathArray,
     592                 :                                       bool aUnique,
     593                 :                                       bool aMultiEntry,
     594                 :                                       JSContext* aCx,
     595                 :                                       jsval aVal,
     596                 :                                       nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
     597                 : {
     598                 :   nsresult rv;
     599             368 :   if (!aKeyPathArray.IsEmpty()) {
     600               0 :     Key arrayKey;
     601               0 :     rv = GetKeyFromValue(aCx, aVal, aKeyPathArray, arrayKey);
     602               0 :     NS_ENSURE_SUCCESS(rv, rv);
     603                 : 
     604               0 :     if (!arrayKey.IsUnset()) {
     605               0 :       IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
     606               0 :       updateInfo->indexId = aIndexID;
     607               0 :       updateInfo->indexUnique = aUnique;
     608               0 :       updateInfo->value = arrayKey;
     609                 :     }
     610                 : 
     611               0 :     return NS_OK;
     612                 :   }
     613                 : 
     614                 :   jsval key;
     615             368 :   rv = GetJSValFromKeyPath(aCx, aVal, aKeyPath, key);
     616             368 :   NS_ENSURE_SUCCESS(rv, rv);
     617                 : 
     618             406 :   if (aMultiEntry && !JSVAL_IS_PRIMITIVE(key) &&
     619              38 :       JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(key))) {
     620              35 :     JSObject* array = JSVAL_TO_OBJECT(key);
     621                 :     uint32_t arrayLength;
     622              35 :     if (!JS_GetArrayLength(aCx, array, &arrayLength)) {
     623               0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     624                 :     }
     625                 : 
     626             148 :     for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
     627                 :       jsval arrayItem;
     628             113 :       if (!JS_GetElement(aCx, array, arrayIndex, &arrayItem)) {
     629               0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     630                 :       }
     631                 : 
     632             226 :       Key value;
     633             205 :       if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) ||
     634              92 :           value.IsUnset()) {
     635                 :         // Not a value we can do anything with, ignore it.
     636              30 :         continue;
     637                 :       }
     638                 : 
     639              83 :       IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
     640              83 :       updateInfo->indexId = aIndexID;
     641              83 :       updateInfo->indexUnique = aUnique;
     642              83 :       updateInfo->value = value;
     643                 :     }
     644                 :   }
     645                 :   else {
     646             666 :     Key value;
     647             656 :     if (NS_FAILED(value.SetFromJSVal(aCx, key)) ||
     648             323 :         value.IsUnset()) {
     649                 :       // Not a value we can do anything with, ignore it.
     650              43 :       return NS_OK;
     651                 :     }
     652                 : 
     653             290 :     IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
     654             290 :     updateInfo->indexId = aIndexID;
     655             290 :     updateInfo->indexUnique = aUnique;
     656             623 :     updateInfo->value = value;
     657                 :   }
     658                 : 
     659             325 :   return NS_OK;
     660                 : }
     661                 : 
     662                 : // static
     663                 : nsresult
     664             309 : IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
     665                 :                               PRInt64 aObjectStoreId,
     666                 :                               const Key& aObjectStoreKey,
     667                 :                               bool aOverwrite,
     668                 :                               PRInt64 aObjectDataId,
     669                 :                               const nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
     670                 : {
     671             618 :   nsCOMPtr<mozIStorageStatement> stmt;
     672                 :   nsresult rv;
     673                 : 
     674             309 :   NS_ASSERTION(aObjectDataId != LL_MININT, "Bad objectData id!");
     675                 : 
     676             618 :   NS_NAMED_LITERAL_CSTRING(objectDataId, "object_data_id");
     677                 : 
     678             309 :   if (aOverwrite) {
     679                 :     stmt = aTransaction->GetCachedStatement(
     680                 :       "DELETE FROM unique_index_data "
     681                 :       "WHERE object_data_id = :object_data_id; "
     682                 :       "DELETE FROM index_data "
     683              60 :       "WHERE object_data_id = :object_data_id");
     684                 : 
     685             120 :     mozStorageStatementScoper scoper(stmt);
     686                 : 
     687              60 :     rv = stmt->BindInt64ByName(objectDataId, aObjectDataId);
     688              60 :     NS_ENSURE_SUCCESS(rv, rv);
     689                 : 
     690              60 :     rv = stmt->Execute();
     691              60 :     NS_ENSURE_SUCCESS(rv, rv);
     692                 :   }
     693                 : 
     694             309 :   PRUint32 infoCount = aUpdateInfoArray.Length();
     695             671 :   for (PRUint32 i = 0; i < infoCount; i++) {
     696             369 :     const IndexUpdateInfo& updateInfo = aUpdateInfoArray[i];
     697                 : 
     698                 :     // Insert new values.
     699                 : 
     700                 :     stmt = updateInfo.indexUnique ?
     701                 :       aTransaction->GetCachedStatement(
     702                 :         "INSERT INTO unique_index_data "
     703                 :           "(index_id, object_data_id, object_data_key, value) "
     704                 :         "VALUES (:index_id, :object_data_id, :object_data_key, :value)") :
     705                 :       aTransaction->GetCachedStatement(
     706                 :         "INSERT OR IGNORE INTO index_data ("
     707                 :           "index_id, object_data_id, object_data_key, value) "
     708             369 :         "VALUES (:index_id, :object_data_id, :object_data_key, :value)");
     709                 : 
     710             369 :     NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE);
     711                 : 
     712             738 :     mozStorageStatementScoper scoper4(stmt);
     713                 : 
     714             738 :     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
     715             369 :                                updateInfo.indexId);
     716             369 :     NS_ENSURE_SUCCESS(rv, rv);
     717                 : 
     718             369 :     rv = stmt->BindInt64ByName(objectDataId, aObjectDataId);
     719             369 :     NS_ENSURE_SUCCESS(rv, rv);
     720                 : 
     721                 :     rv = aObjectStoreKey.BindToStatement(stmt,
     722             369 :                                          NS_LITERAL_CSTRING("object_data_key"));
     723             369 :     NS_ENSURE_SUCCESS(rv, rv);
     724                 : 
     725             369 :     rv = updateInfo.value.BindToStatement(stmt, NS_LITERAL_CSTRING("value"));
     726             369 :     NS_ENSURE_SUCCESS(rv, rv);
     727                 : 
     728             369 :     rv = stmt->Execute();
     729             369 :     if (rv == NS_ERROR_STORAGE_CONSTRAINT && updateInfo.indexUnique) {
     730                 :       // If we're inserting multiple entries for the same unique index, then
     731                 :       // we might have failed to insert due to colliding with another entry for
     732                 :       // the same index in which case we should ignore it.
     733                 :       
     734              55 :       for (PRInt32 j = (PRInt32)i - 1;
     735              24 :            j >= 0 && aUpdateInfoArray[j].indexId == updateInfo.indexId;
     736                 :            --j) {
     737              24 :         if (updateInfo.value == aUpdateInfoArray[j].value) {
     738                 :           // We found a key with the same value for the same index. So we
     739                 :           // must have had a collision with a value we just inserted.
     740              18 :           rv = NS_OK;
     741              18 :           break;
     742                 :         }
     743                 :       }
     744                 :     }
     745                 : 
     746             369 :     if (NS_FAILED(rv)) {
     747               7 :       return rv;
     748                 :     }
     749                 :   }
     750                 : 
     751             302 :   return NS_OK;
     752                 : }
     753                 : 
     754                 : // static
     755                 : nsresult
     756            1970 : IDBObjectStore::GetStructuredCloneReadInfoFromStatement(
     757                 :                                            mozIStorageStatement* aStatement,
     758                 :                                            PRUint32 aDataIndex,
     759                 :                                            PRUint32 aFileIdsIndex,
     760                 :                                            FileManager* aFileManager,
     761                 :                                            StructuredCloneReadInfo& aInfo)
     762                 : {
     763                 : #ifdef DEBUG
     764                 :   {
     765                 :     PRInt32 type;
     766            1970 :     NS_ASSERTION(NS_SUCCEEDED(aStatement->GetTypeOfIndex(aDataIndex, &type)) &&
     767                 :                  type == mozIStorageStatement::VALUE_TYPE_BLOB,
     768                 :                  "Bad value type!");
     769                 :   }
     770                 : #endif
     771                 : 
     772                 :   const PRUint8* blobData;
     773                 :   PRUint32 blobDataLength;
     774                 :   nsresult rv = aStatement->GetSharedBlob(aDataIndex, &blobDataLength,
     775            1970 :                                           &blobData);
     776            1970 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     777                 : 
     778            1970 :   const char* compressed = reinterpret_cast<const char*>(blobData);
     779            1970 :   size_t compressedLength = size_t(blobDataLength);
     780                 : 
     781                 :   size_t uncompressedLength;
     782            1970 :   if (!snappy::GetUncompressedLength(compressed, compressedLength,
     783            1970 :                                      &uncompressedLength)) {
     784               0 :     NS_WARNING("Snappy can't determine uncompressed length!");
     785               0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     786                 :   }
     787                 : 
     788            5910 :   nsAutoArrayPtr<char> uncompressed(new char[uncompressedLength]);
     789                 : 
     790            1970 :   if (!snappy::RawUncompress(compressed, compressedLength,
     791            1970 :                              uncompressed.get())) {
     792               0 :     NS_WARNING("Snappy can't determine uncompressed length!");
     793               0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     794                 :   }
     795                 : 
     796            1970 :   JSAutoStructuredCloneBuffer& buffer = aInfo.mCloneBuffer;
     797            3940 :   if (!buffer.copy(reinterpret_cast<const uint64_t *>(uncompressed.get()),
     798            3940 :                    uncompressedLength)) {
     799               0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     800                 :   }
     801                 : 
     802                 :   bool isNull;
     803            1970 :   rv = aStatement->GetIsNull(aFileIdsIndex, &isNull);
     804            1970 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     805                 : 
     806            1970 :   if (isNull) {
     807            1970 :     return NS_OK;
     808                 :   }
     809                 : 
     810               0 :   nsString ids;
     811               0 :   rv = aStatement->GetString(aFileIdsIndex, ids);
     812               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     813                 : 
     814               0 :   nsAutoTArray<PRInt64, 10> array;
     815               0 :   rv = ConvertFileIdsToArray(ids, array);
     816               0 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     817                 : 
     818               0 :   for (PRUint32 i = 0; i < array.Length(); i++) {
     819               0 :     const PRInt64& id = array.ElementAt(i);
     820                 : 
     821               0 :     nsRefPtr<FileInfo> fileInfo = aFileManager->GetFileInfo(id);
     822               0 :     NS_ASSERTION(fileInfo, "Null file info!");
     823                 : 
     824               0 :     aInfo.mFileInfos.AppendElement(fileInfo);
     825                 :   }
     826                 : 
     827               0 :   return NS_OK;
     828                 : }
     829                 : 
     830                 : // static
     831                 : void
     832            6214 : IDBObjectStore::ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer)
     833                 : {
     834            6214 :   if (aBuffer.data()) {
     835              63 :     aBuffer.clear();
     836                 :   }
     837            6214 : }
     838                 : 
     839                 : // static
     840                 : bool
     841             623 : IDBObjectStore::DeserializeValue(JSContext* aCx,
     842                 :                                  StructuredCloneReadInfo& aCloneReadInfo,
     843                 :                                  jsval* aValue)
     844                 : {
     845             623 :   NS_ASSERTION(NS_IsMainThread(),
     846                 :                "Should only be deserializing on the main thread!");
     847             623 :   NS_ASSERTION(aCx, "A JSContext is required!");
     848                 : 
     849             623 :   JSAutoStructuredCloneBuffer& buffer = aCloneReadInfo.mCloneBuffer;
     850                 : 
     851             623 :   if (!buffer.data()) {
     852              13 :     *aValue = JSVAL_VOID;
     853              13 :     return true;
     854                 :   }
     855                 : 
     856            1220 :   JSAutoRequest ar(aCx);
     857                 : 
     858                 :   JSStructuredCloneCallbacks callbacks = {
     859                 :     IDBObjectStore::StructuredCloneReadCallback,
     860                 :     nsnull,
     861                 :     nsnull
     862             610 :   };
     863                 : 
     864             610 :   return buffer.read(aCx, aValue, &callbacks, &aCloneReadInfo);
     865                 : }
     866                 : 
     867                 : // static
     868                 : bool
     869            1837 : IDBObjectStore::SerializeValue(JSContext* aCx,
     870                 :                                StructuredCloneWriteInfo& aCloneWriteInfo,
     871                 :                                jsval aValue)
     872                 : {
     873            1837 :   NS_ASSERTION(NS_IsMainThread(),
     874                 :                "Should only be serializing on the main thread!");
     875            1837 :   NS_ASSERTION(aCx, "A JSContext is required!");
     876                 : 
     877            3674 :   JSAutoRequest ar(aCx);
     878                 : 
     879                 :   JSStructuredCloneCallbacks callbacks = {
     880                 :     nsnull,
     881                 :     StructuredCloneWriteCallback,
     882                 :     nsnull
     883            1837 :   };
     884                 : 
     885            1837 :   JSAutoStructuredCloneBuffer& buffer = aCloneWriteInfo.mCloneBuffer;
     886                 : 
     887            1837 :   return buffer.write(aCx, aValue, &callbacks, &aCloneWriteInfo);
     888                 : }
     889                 : 
     890                 : static inline PRUint32
     891               0 : SwapBytes(PRUint32 u)
     892                 : {
     893                 : #ifdef IS_BIG_ENDIAN
     894                 :   return ((u & 0x000000ffU) << 24) |                                          
     895                 :          ((u & 0x0000ff00U) << 8) |                                           
     896                 :          ((u & 0x00ff0000U) >> 8) |                                           
     897                 :          ((u & 0xff000000U) >> 24);
     898                 : #else
     899               0 :   return u;
     900                 : #endif
     901                 : }
     902                 : 
     903                 : static inline double
     904              16 : SwapBytes(PRUint64 u)
     905                 : {
     906                 : #ifdef IS_BIG_ENDIAN
     907                 :   return ((u & 0x00000000000000ffLLU) << 56) |
     908                 :          ((u & 0x000000000000ff00LLU) << 40) |
     909                 :          ((u & 0x0000000000ff0000LLU) << 24) |
     910                 :          ((u & 0x00000000ff000000LLU) << 8) |
     911                 :          ((u & 0x000000ff00000000LLU) >> 8) |
     912                 :          ((u & 0x0000ff0000000000LLU) >> 24) |
     913                 :          ((u & 0x00ff000000000000LLU) >> 40) |
     914                 :          ((u & 0xff00000000000000LLU) >> 56);
     915                 : #else
     916              16 :   return double(u);
     917                 : #endif
     918                 : }
     919                 : 
     920                 : static inline bool
     921               0 : StructuredCloneReadString(JSStructuredCloneReader* aReader,
     922                 :                           nsCString& aString)
     923                 : {
     924                 :   PRUint32 length;
     925               0 :   if (!JS_ReadBytes(aReader, &length, sizeof(PRUint32))) {
     926               0 :     NS_WARNING("Failed to read length!");
     927               0 :     return false;
     928                 :   }
     929               0 :   length = SwapBytes(length);
     930                 : 
     931               0 :   if (!EnsureStringLength(aString, length)) {
     932               0 :     NS_WARNING("Out of memory?");
     933               0 :     return false;
     934                 :   }
     935               0 :   char* buffer = aString.BeginWriting();
     936                 : 
     937               0 :   if (!JS_ReadBytes(aReader, buffer, length)) {
     938               0 :     NS_WARNING("Failed to read type!");
     939               0 :     return false;
     940                 :   }
     941                 : 
     942               0 :   return true;
     943                 : }
     944                 : 
     945                 : JSObject*
     946               0 : IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
     947                 :                                             JSStructuredCloneReader* aReader,
     948                 :                                             uint32_t aTag,
     949                 :                                             uint32_t aData,
     950                 :                                             void* aClosure)
     951                 : {
     952               0 :   if (aTag == SCTAG_DOM_BLOB || aTag == SCTAG_DOM_FILE) {
     953                 :     StructuredCloneReadInfo* cloneReadInfo =
     954               0 :       reinterpret_cast<StructuredCloneReadInfo*>(aClosure);
     955                 : 
     956               0 :     NS_ASSERTION(aData < cloneReadInfo->mFileInfos.Length(),
     957                 :                  "Bad blob index!");
     958                 : 
     959               0 :     nsRefPtr<FileInfo> fileInfo = cloneReadInfo->mFileInfos[aData];
     960               0 :     nsRefPtr<FileManager> fileManager = fileInfo->Manager();
     961               0 :     nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
     962               0 :     if (!directory) {
     963               0 :       return nsnull;
     964                 :     }
     965                 : 
     966                 :     nsCOMPtr<nsIFile> nativeFile =
     967               0 :       fileManager->GetFileForId(directory, fileInfo->Id());
     968               0 :     if (!nativeFile) {
     969               0 :       return nsnull;
     970                 :     }
     971                 : 
     972                 :     PRUint64 size;
     973               0 :     if (!JS_ReadBytes(aReader, &size, sizeof(PRUint64))) {
     974               0 :       NS_WARNING("Failed to read size!");
     975               0 :       return nsnull;
     976                 :     }
     977               0 :     size = SwapBytes(size);
     978                 : 
     979               0 :     nsCString type;
     980               0 :     if (!StructuredCloneReadString(aReader, type)) {
     981               0 :       return nsnull;
     982                 :     }
     983               0 :     NS_ConvertUTF8toUTF16 convType(type);
     984                 : 
     985               0 :     if (aTag == SCTAG_DOM_BLOB) {
     986                 :       nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(convType, size,
     987               0 :                                                     nativeFile, fileInfo);
     988                 : 
     989                 :       jsval wrappedBlob;
     990                 :       nsresult rv =
     991                 :         nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), blob,
     992               0 :                                    &NS_GET_IID(nsIDOMBlob), &wrappedBlob);
     993               0 :       if (NS_FAILED(rv)) {
     994               0 :         NS_WARNING("Failed to wrap native!");
     995               0 :         return nsnull;
     996                 :       }
     997                 : 
     998               0 :       return JSVAL_TO_OBJECT(wrappedBlob);
     999                 :     }
    1000                 : 
    1001               0 :     nsCString name;
    1002               0 :     if (!StructuredCloneReadString(aReader, name)) {
    1003               0 :       return nsnull;
    1004                 :     }
    1005               0 :     NS_ConvertUTF8toUTF16 convName(name);
    1006                 : 
    1007                 :     nsCOMPtr<nsIDOMFile> file = new nsDOMFileFile(convName, convType, size,
    1008               0 :                                                   nativeFile, fileInfo);
    1009                 : 
    1010                 :     jsval wrappedFile;
    1011                 :     nsresult rv =
    1012                 :       nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), file,
    1013               0 :                                  &NS_GET_IID(nsIDOMFile), &wrappedFile);
    1014               0 :     if (NS_FAILED(rv)) {
    1015               0 :       NS_WARNING("Failed to wrap native!");
    1016               0 :       return nsnull;
    1017                 :     }
    1018                 : 
    1019               0 :     return JSVAL_TO_OBJECT(wrappedFile);
    1020                 :   }
    1021                 : 
    1022                 :   const JSStructuredCloneCallbacks* runtimeCallbacks =
    1023               0 :     js::GetContextStructuredCloneCallbacks(aCx);
    1024                 : 
    1025               0 :   if (runtimeCallbacks) {
    1026               0 :     return runtimeCallbacks->read(aCx, aReader, aTag, aData, nsnull);
    1027                 :   }
    1028                 : 
    1029               0 :   return nsnull;
    1030                 : }
    1031                 : 
    1032                 : JSBool
    1033              16 : IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
    1034                 :                                              JSStructuredCloneWriter* aWriter,
    1035                 :                                              JSObject* aObj,
    1036                 :                                              void* aClosure)
    1037                 : {
    1038                 :   StructuredCloneWriteInfo* cloneWriteInfo =
    1039              16 :     reinterpret_cast<StructuredCloneWriteInfo*>(aClosure);
    1040                 : 
    1041              16 :   if (JS_GetClass(aObj) == &gDummyPropClass) {
    1042              16 :     NS_ASSERTION(cloneWriteInfo->mOffsetToKeyProp == 0,
    1043                 :                  "We should not have been here before!");
    1044              16 :     cloneWriteInfo->mOffsetToKeyProp = js_GetSCOffset(aWriter);
    1045                 : 
    1046              16 :     PRUint64 value = 0;
    1047              16 :     return JS_WriteBytes(aWriter, &value, sizeof(value));
    1048                 :   }
    1049                 : 
    1050               0 :   nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
    1051               0 :   nsContentUtils::XPConnect()->
    1052               0 :     GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative));
    1053                 : 
    1054               0 :   if (wrappedNative) {
    1055               0 :     nsISupports* supports = wrappedNative->Native();
    1056                 : 
    1057               0 :     nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
    1058               0 :     if (blob) {
    1059               0 :       nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob);
    1060                 : 
    1061                 :       PRUint64 size;
    1062               0 :       if (NS_FAILED(blob->GetSize(&size))) {
    1063               0 :         return false;
    1064                 :       }
    1065               0 :       size = SwapBytes(size);
    1066                 : 
    1067               0 :       nsString type;
    1068               0 :       if (NS_FAILED(blob->GetType(type))) {
    1069               0 :         return false;
    1070                 :       }
    1071               0 :       NS_ConvertUTF16toUTF8 convType(type);
    1072               0 :       PRUint32 convTypeLength = SwapBytes(convType.Length());
    1073                 : 
    1074               0 :       if (!JS_WriteUint32Pair(aWriter, file ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB,
    1075               0 :                               cloneWriteInfo->mBlobs.Length()) ||
    1076               0 :           !JS_WriteBytes(aWriter, &size, sizeof(PRUint64)) ||
    1077               0 :           !JS_WriteBytes(aWriter, &convTypeLength, sizeof(PRUint32)) ||
    1078               0 :           !JS_WriteBytes(aWriter, convType.get(), convType.Length())) {
    1079               0 :         return false;
    1080                 :       }
    1081                 : 
    1082               0 :       if (file) {
    1083               0 :         nsString name;
    1084               0 :         if (NS_FAILED(file->GetName(name))) {
    1085               0 :           return false;
    1086                 :         }
    1087               0 :         NS_ConvertUTF16toUTF8 convName(name);
    1088               0 :         PRUint32 convNameLength = SwapBytes(convName.Length());
    1089                 : 
    1090               0 :         if (!JS_WriteBytes(aWriter, &convNameLength, sizeof(PRUint32)) ||
    1091               0 :             !JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
    1092               0 :           return false;
    1093                 :         }
    1094                 :       }
    1095                 : 
    1096               0 :       cloneWriteInfo->mBlobs.AppendElement(blob);
    1097                 : 
    1098               0 :       return true;
    1099                 :     }
    1100                 :   }
    1101                 : 
    1102                 :   // try using the runtime callbacks
    1103                 :   const JSStructuredCloneCallbacks* runtimeCallbacks =
    1104               0 :     js::GetContextStructuredCloneCallbacks(aCx);
    1105               0 :   if (runtimeCallbacks) {
    1106               0 :     return runtimeCallbacks->write(aCx, aWriter, aObj, nsnull);
    1107                 :   }
    1108                 : 
    1109               0 :   return false;
    1110                 : }
    1111                 : 
    1112                 : nsresult
    1113               0 : IDBObjectStore::ConvertFileIdsToArray(const nsAString& aFileIds,
    1114                 :                                       nsTArray<PRInt64>& aResult)
    1115                 : {
    1116               0 :   nsCharSeparatedTokenizerTemplate<IgnoreWhitespace> tokenizer(aFileIds, ' ');
    1117                 : 
    1118               0 :   while (tokenizer.hasMoreTokens()) {
    1119               0 :     nsString token(tokenizer.nextToken());
    1120                 : 
    1121               0 :     NS_ASSERTION(!token.IsEmpty(), "Should be a valid id!");
    1122                 : 
    1123                 :     nsresult rv;
    1124               0 :     PRInt32 id = token.ToInteger(&rv);
    1125               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1126                 :     
    1127               0 :     PRInt64* element = aResult.AppendElement();
    1128               0 :     *element = id;
    1129                 :   }
    1130                 : 
    1131               0 :   return NS_OK;
    1132                 : }
    1133                 : 
    1134             667 : IDBObjectStore::IDBObjectStore()
    1135                 : : mId(LL_MININT),
    1136             667 :   mAutoIncrement(false)
    1137                 : {
    1138             667 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1139             667 : }
    1140                 : 
    1141            1334 : IDBObjectStore::~IDBObjectStore()
    1142                 : {
    1143             667 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1144             667 : }
    1145                 : 
    1146                 : nsresult
    1147            1956 : IDBObjectStore::GetAddInfo(JSContext* aCx,
    1148                 :                            jsval aValue,
    1149                 :                            jsval aKeyVal,
    1150                 :                            StructuredCloneWriteInfo& aCloneWriteInfo,
    1151                 :                            Key& aKey,
    1152                 :                            nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
    1153                 : {
    1154                 :   nsresult rv;
    1155                 : 
    1156                 :   // Return DATA_ERR if a key was passed in and this objectStore uses inline
    1157                 :   // keys.
    1158            1956 :   if (!JSVAL_IS_VOID(aKeyVal) && HasKeyPath()) {
    1159              53 :     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    1160                 :   }
    1161                 : 
    1162            3806 :   JSAutoRequest ar(aCx);
    1163                 : 
    1164            1903 :   if (!HasKeyPath()) {
    1165                 :     // Out-of-line keys must be passed in.
    1166            1561 :     rv = aKey.SetFromJSVal(aCx, aKeyVal);
    1167            1561 :     NS_ENSURE_SUCCESS(rv, rv);
    1168                 :   }
    1169             342 :   else if (!mAutoIncrement) {
    1170                 :     // Inline keys live on the object. Make sure that the value passed in is an
    1171                 :     // object.
    1172             260 :     if (UsesKeyPathArray()) {
    1173               0 :       rv = GetKeyFromValue(aCx, aValue, mKeyPathArray, aKey);
    1174                 :     }
    1175                 :     else {
    1176             260 :       rv = GetKeyFromValue(aCx, aValue, mKeyPath, aKey);
    1177                 :     }
    1178             260 :     NS_ENSURE_SUCCESS(rv, rv);
    1179                 :   }
    1180                 : 
    1181                 :   // Return DATA_ERR if no key was specified this isn't an autoIncrement
    1182                 :   // objectStore.
    1183            1877 :   if (aKey.IsUnset() && !mAutoIncrement) {
    1184              32 :     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    1185                 :   }
    1186                 : 
    1187                 :   // Figure out indexes and the index values to update here.
    1188            1845 :   PRUint32 count = mInfo->indexes.Length();
    1189            1845 :   aUpdateInfoArray.SetCapacity(count); // Pretty good estimate
    1190            2076 :   for (PRUint32 indexesIndex = 0; indexesIndex < count; indexesIndex++) {
    1191             231 :     const IndexInfo& indexInfo = mInfo->indexes[indexesIndex];
    1192                 : 
    1193                 :     rv = AppendIndexUpdateInfo(indexInfo.id, indexInfo.keyPath,
    1194                 :                                indexInfo.keyPathArray, indexInfo.unique,
    1195                 :                                indexInfo.multiEntry, aCx, aValue,
    1196             231 :                                aUpdateInfoArray);
    1197             231 :     NS_ENSURE_SUCCESS(rv, rv);
    1198                 :   }
    1199                 : 
    1200            3690 :   nsString targetObjectPropName;
    1201            1845 :   JSObject* targetObject = nsnull;
    1202                 : 
    1203            1845 :   rv = NS_OK;
    1204            1845 :   if (mAutoIncrement && HasKeyPath()) {
    1205              82 :     NS_ASSERTION(aKey.IsUnset(), "Shouldn't have gotten the key yet!");
    1206                 : 
    1207              82 :     if (JSVAL_IS_PRIMITIVE(aValue)) {
    1208               0 :       return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    1209                 :     }
    1210                 : 
    1211              82 :     KeyPathTokenizer tokenizer(mKeyPath, '.');
    1212              82 :     NS_ASSERTION(tokenizer.hasMoreTokens(),
    1213                 :                  "Shouldn't have empty keypath and autoincrement");
    1214                 : 
    1215              82 :     JSObject* obj = JSVAL_TO_OBJECT(aValue);
    1216             238 :     while (tokenizer.hasMoreTokens()) {
    1217             164 :       const nsDependentSubstring& token = tokenizer.nextToken();
    1218                 :   
    1219              82 :       NS_ASSERTION(!token.IsEmpty(), "Should be a valid keypath");
    1220                 :   
    1221              82 :       const jschar* keyPathChars = token.BeginReading();
    1222              82 :       const size_t keyPathLen = token.Length();
    1223                 :   
    1224                 :       JSBool hasProp;
    1225              82 :       if (!targetObject) {
    1226                 :         // We're still walking the chain of existing objects
    1227                 : 
    1228                 :         JSBool ok = JS_HasUCProperty(aCx, obj, keyPathChars, keyPathLen,
    1229              82 :                                      &hasProp);
    1230              82 :         NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1231                 : 
    1232              82 :         if (hasProp) {
    1233                 :           // Get if the property exists...
    1234                 :           jsval intermediate;
    1235                 :           JSBool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen,
    1236              66 :                                        &intermediate);
    1237              66 :           NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1238                 : 
    1239              66 :           if (tokenizer.hasMoreTokens()) {
    1240                 :             // ...and walk to it if there are more steps...
    1241               0 :             if (JSVAL_IS_PRIMITIVE(intermediate)) {
    1242               0 :               return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    1243                 :             }
    1244               0 :             obj = JSVAL_TO_OBJECT(intermediate);
    1245                 :           }
    1246                 :           else {
    1247                 :             // ...otherwise use it as key
    1248              66 :             aKey.SetFromJSVal(aCx, intermediate);
    1249              66 :             if (aKey.IsUnset()) {
    1250               8 :               return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    1251                 :             }
    1252                 :           }
    1253                 :         }
    1254                 :         else {
    1255                 :           // If the property doesn't exist, fall into below path of starting
    1256                 :           // to define properties
    1257              16 :           targetObject = obj;
    1258              16 :           targetObjectPropName = token;
    1259                 :         }
    1260                 :       }
    1261                 : 
    1262              74 :       if (targetObject) {
    1263                 :         // We have started inserting new objects or are about to just insert
    1264                 :         // the first one.
    1265              16 :         if (tokenizer.hasMoreTokens()) {
    1266                 :           // If we're not at the end, we need to add a dummy object to the chain.
    1267               0 :           JSObject* dummy = JS_NewObject(aCx, nsnull, nsnull, nsnull);
    1268               0 :           if (!dummy) {
    1269               0 :             rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1270                 :             break;
    1271                 :           }
    1272                 :   
    1273               0 :           if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
    1274                 :                                    token.Length(),
    1275                 :                                    OBJECT_TO_JSVAL(dummy), nsnull, nsnull,
    1276               0 :                                    JSPROP_ENUMERATE)) {
    1277               0 :             rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1278                 :             break;
    1279                 :           }
    1280                 :   
    1281               0 :           obj = dummy;
    1282                 :         }
    1283                 :         else {
    1284              16 :           JSObject* dummy = JS_NewObject(aCx, &gDummyPropClass, nsnull, nsnull);
    1285              16 :           if (!dummy) {
    1286               0 :             rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1287                 :             break;
    1288                 :           }
    1289                 :   
    1290              16 :           if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
    1291                 :                                    token.Length(), OBJECT_TO_JSVAL(dummy),
    1292              16 :                                    nsnull, nsnull, JSPROP_ENUMERATE)) {
    1293               0 :             rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1294                 :             break;
    1295                 :           }
    1296                 :         }
    1297                 :       }
    1298                 :     }
    1299                 :   }
    1300                 : 
    1301            1837 :   aCloneWriteInfo.mOffsetToKeyProp = 0;
    1302                 : 
    1303                 :   // We guard on rv being a success because we need to run the property
    1304                 :   // deletion code below even if we should not be serializing the value
    1305            3674 :   if (NS_SUCCEEDED(rv) && 
    1306            1837 :       !IDBObjectStore::SerializeValue(aCx, aCloneWriteInfo, aValue)) {
    1307               0 :     rv = NS_ERROR_DOM_DATA_CLONE_ERR;
    1308                 :   }
    1309                 : 
    1310            1837 :   if (targetObject) {
    1311                 :     // If this fails, we lose, and the web page sees a magical property
    1312                 :     // appear on the object :-(
    1313                 :     jsval succeeded;
    1314              16 :     if (!JS_DeleteUCProperty2(aCx, targetObject,
    1315                 :                               targetObjectPropName.get(),
    1316              16 :                               targetObjectPropName.Length(), &succeeded)) {
    1317               0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1318                 :     }
    1319              16 :     NS_ASSERTION(JSVAL_IS_BOOLEAN(succeeded), "Wtf?");
    1320              16 :     NS_ENSURE_TRUE(JSVAL_TO_BOOLEAN(succeeded),
    1321                 :                    NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1322                 :   }
    1323                 : 
    1324            1837 :   return rv;
    1325                 : }
    1326                 : 
    1327                 : nsresult
    1328            1959 : IDBObjectStore::AddOrPut(const jsval& aValue,
    1329                 :                          const jsval& aKey,
    1330                 :                          JSContext* aCx,
    1331                 :                          PRUint8 aOptionalArgCount,
    1332                 :                          nsIIDBRequest** _retval,
    1333                 :                          bool aOverwrite)
    1334                 : {
    1335            1959 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1336                 : 
    1337            1959 :   if (!mTransaction->IsOpen()) {
    1338               3 :     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
    1339                 :   }
    1340                 : 
    1341            1956 :   if (!IsWriteAllowed()) {
    1342               0 :     return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
    1343                 :   }
    1344                 : 
    1345            1956 :   jsval keyval = (aOptionalArgCount >= 1) ? aKey : JSVAL_VOID;
    1346                 : 
    1347            3912 :   StructuredCloneWriteInfo cloneWriteInfo;
    1348            3912 :   Key key;
    1349            3912 :   nsTArray<IndexUpdateInfo> updateInfo;
    1350                 : 
    1351                 :   nsresult rv = GetAddInfo(aCx, aValue, keyval, cloneWriteInfo, key,
    1352            1956 :                            updateInfo);
    1353            1956 :   if (NS_FAILED(rv)) {
    1354             119 :     return rv;
    1355                 :   }
    1356                 : 
    1357            3674 :   nsRefPtr<IDBRequest> request = GenerateRequest(this);
    1358            1837 :   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1359                 : 
    1360                 :   nsRefPtr<AddHelper> helper =
    1361                 :     new AddHelper(mTransaction, request, this, cloneWriteInfo, key, aOverwrite,
    1362            5511 :                   updateInfo);
    1363                 : 
    1364            1837 :   rv = helper->DispatchToTransactionPool();
    1365            1837 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1366                 : 
    1367            1837 :   request.forget(_retval);
    1368            1837 :   return NS_OK;
    1369                 : }
    1370                 : 
    1371            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore)
    1372                 : 
    1373             544 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore)
    1374             544 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTransaction,
    1375                 :                                                        nsIDOMEventTarget)
    1376                 : 
    1377             649 :   for (PRUint32 i = 0; i < tmp->mCreatedIndexes.Length(); i++) {
    1378             105 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCreatedIndexes[i]");
    1379             105 :     cb.NoteXPCOMChild(static_cast<nsIIDBIndex*>(tmp->mCreatedIndexes[i].get()));
    1380                 :   }
    1381             544 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1382                 : 
    1383             544 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBObjectStore)
    1384                 :   // Don't unlink mTransaction!
    1385                 : 
    1386             544 :   tmp->mCreatedIndexes.Clear();
    1387             544 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1388                 : 
    1389           20350 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBObjectStore)
    1390           10027 :   NS_INTERFACE_MAP_ENTRY(nsIIDBObjectStore)
    1391            6022 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBObjectStore)
    1392            5355 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
    1393            4674 : NS_INTERFACE_MAP_END
    1394                 : 
    1395           11744 : NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBObjectStore)
    1396           12411 : NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBObjectStore)
    1397                 : 
    1398                 : DOMCI_DATA(IDBObjectStore, IDBObjectStore)
    1399                 : 
    1400                 : NS_IMETHODIMP
    1401              28 : IDBObjectStore::GetName(nsAString& aName)
    1402                 : {
    1403              28 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1404                 : 
    1405              28 :   aName.Assign(mName);
    1406              28 :   return NS_OK;
    1407                 : }
    1408                 : 
    1409                 : NS_IMETHODIMP
    1410              20 : IDBObjectStore::GetKeyPath(JSContext* aCx,
    1411                 :                            jsval* aVal)
    1412                 : {
    1413              20 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1414                 : 
    1415              20 :   if (UsesKeyPathArray()) {
    1416               0 :     JSObject* array = JS_NewArrayObject(aCx, mKeyPathArray.Length(), nsnull);
    1417               0 :     if (!array) {
    1418               0 :       NS_WARNING("Failed to make array!");
    1419               0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1420                 :     }
    1421                 : 
    1422               0 :     for (PRUint32 i = 0; i < mKeyPathArray.Length(); ++i) {
    1423                 :       jsval val;
    1424               0 :       nsString tmp(mKeyPathArray[i]);
    1425               0 :       if (!xpc::StringToJsval(aCx, tmp, &val)) {
    1426               0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1427                 :       }
    1428                 : 
    1429               0 :       if (!JS_SetElement(aCx, array, i, &val)) {
    1430               0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1431                 :       }
    1432                 :     }
    1433                 : 
    1434               0 :     *aVal = OBJECT_TO_JSVAL(array);
    1435                 :   }
    1436                 :   else {
    1437              40 :     nsString tmp(mKeyPath);
    1438              20 :     if (!xpc::StringToJsval(aCx, tmp, aVal)) {
    1439               0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1440                 :     }
    1441                 :   }
    1442              20 :   return NS_OK;
    1443                 : }
    1444                 : 
    1445                 : NS_IMETHODIMP
    1446               1 : IDBObjectStore::GetTransaction(nsIIDBTransaction** aTransaction)
    1447                 : {
    1448               1 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1449                 : 
    1450               2 :   nsCOMPtr<nsIIDBTransaction> transaction(mTransaction);
    1451               1 :   transaction.forget(aTransaction);
    1452               1 :   return NS_OK;
    1453                 : }
    1454                 : 
    1455                 : NS_IMETHODIMP
    1456               0 : IDBObjectStore::GetAutoIncrement(bool* aAutoIncrement)
    1457                 : {
    1458               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1459                 : 
    1460               0 :   *aAutoIncrement = mAutoIncrement;
    1461               0 :   return NS_OK;
    1462                 : }
    1463                 : 
    1464                 : NS_IMETHODIMP
    1465             150 : IDBObjectStore::GetIndexNames(nsIDOMDOMStringList** aIndexNames)
    1466                 : {
    1467             150 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1468                 : 
    1469             300 :   nsRefPtr<nsDOMStringList> list(new nsDOMStringList());
    1470                 : 
    1471             150 :   PRUint32 count = mInfo->indexes.Length();
    1472             643 :   for (PRUint32 index = 0; index < count; index++) {
    1473             493 :     NS_ENSURE_TRUE(list->Add(mInfo->indexes[index].name),
    1474                 :                    NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1475                 :   }
    1476                 : 
    1477             150 :   list.forget(aIndexNames);
    1478             150 :   return NS_OK;
    1479                 : }
    1480                 : 
    1481                 : NS_IMETHODIMP
    1482             176 : IDBObjectStore::Get(const jsval& aKey,
    1483                 :                     JSContext* aCx,
    1484                 :                     nsIIDBRequest** _retval)
    1485                 : {
    1486             176 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1487                 : 
    1488             176 :   if (!mTransaction->IsOpen()) {
    1489               1 :     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
    1490                 :   }
    1491                 : 
    1492             350 :   nsRefPtr<IDBKeyRange> keyRange;
    1493             175 :   nsresult rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
    1494             175 :   NS_ENSURE_SUCCESS(rv, rv);
    1495                 : 
    1496             175 :   if (!keyRange) {
    1497                 :     // Must specify a key or keyRange for get().
    1498               2 :     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    1499                 :   }
    1500                 : 
    1501             346 :   nsRefPtr<IDBRequest> request = GenerateRequest(this);
    1502             173 :   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1503                 : 
    1504                 :   nsRefPtr<GetHelper> helper =
    1505             519 :     new GetHelper(mTransaction, request, this, keyRange);
    1506                 : 
    1507             173 :   rv = helper->DispatchToTransactionPool();
    1508             173 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1509                 : 
    1510             173 :   request.forget(_retval);
    1511             173 :   return NS_OK;
    1512                 : }
    1513                 : 
    1514                 : NS_IMETHODIMP
    1515              18 : IDBObjectStore::GetAll(const jsval& aKey,
    1516                 :                        PRUint32 aLimit,
    1517                 :                        JSContext* aCx,
    1518                 :                        PRUint8 aOptionalArgCount,
    1519                 :                        nsIIDBRequest** _retval)
    1520                 : {
    1521              18 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1522                 : 
    1523              18 :   if (!mTransaction->IsOpen()) {
    1524               1 :     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
    1525                 :   }
    1526                 : 
    1527                 :   nsresult rv;
    1528                 : 
    1529              34 :   nsRefPtr<IDBKeyRange> keyRange;
    1530              17 :   if (aOptionalArgCount) {
    1531              14 :     rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
    1532              14 :     NS_ENSURE_SUCCESS(rv, rv);
    1533                 :   }
    1534                 : 
    1535              17 :   if (aOptionalArgCount < 2 || aLimit == 0) {
    1536              14 :     aLimit = PR_UINT32_MAX;
    1537                 :   }
    1538                 : 
    1539              34 :   nsRefPtr<IDBRequest> request = GenerateRequest(this);
    1540              17 :   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1541                 : 
    1542                 :   nsRefPtr<GetAllHelper> helper =
    1543              51 :     new GetAllHelper(mTransaction, request, this, keyRange, aLimit);
    1544                 : 
    1545              17 :   rv = helper->DispatchToTransactionPool();
    1546              17 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1547                 : 
    1548              17 :   request.forget(_retval);
    1549              17 :   return NS_OK;
    1550                 : }
    1551                 : 
    1552                 : NS_IMETHODIMP
    1553            1827 : IDBObjectStore::Add(const jsval& aValue,
    1554                 :                     const jsval& aKey,
    1555                 :                     JSContext* aCx,
    1556                 :                     PRUint8 aOptionalArgCount,
    1557                 :                     nsIIDBRequest** _retval)
    1558                 : {
    1559            1827 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1560                 : 
    1561            1827 :   return AddOrPut(aValue, aKey, aCx, aOptionalArgCount, _retval, false);
    1562                 : }
    1563                 : 
    1564                 : NS_IMETHODIMP
    1565             132 : IDBObjectStore::Put(const jsval& aValue,
    1566                 :                     const jsval& aKey,
    1567                 :                     JSContext* aCx,
    1568                 :                     PRUint8 aOptionalArgCount,
    1569                 :                     nsIIDBRequest** _retval)
    1570                 : {
    1571             132 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1572                 : 
    1573             132 :   return AddOrPut(aValue, aKey, aCx, aOptionalArgCount, _retval, true);
    1574                 : }
    1575                 : 
    1576                 : NS_IMETHODIMP
    1577              30 : IDBObjectStore::Delete(const jsval& aKey,
    1578                 :                        JSContext* aCx,
    1579                 :                        nsIIDBRequest** _retval)
    1580                 : {
    1581              30 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1582                 : 
    1583              30 :   if (!mTransaction->IsOpen()) {
    1584               1 :     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
    1585                 :   }
    1586                 : 
    1587              29 :   if (!IsWriteAllowed()) {
    1588               0 :     return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
    1589                 :   }
    1590                 : 
    1591              58 :   nsRefPtr<IDBKeyRange> keyRange;
    1592              29 :   nsresult rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
    1593              29 :   NS_ENSURE_SUCCESS(rv, rv);
    1594                 : 
    1595              28 :   if (!keyRange) {
    1596                 :     // Must specify a key or keyRange for delete().
    1597               2 :     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    1598                 :   }
    1599                 : 
    1600              52 :   nsRefPtr<IDBRequest> request = GenerateRequest(this);
    1601              26 :   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1602                 : 
    1603                 :   nsRefPtr<DeleteHelper> helper =
    1604              78 :     new DeleteHelper(mTransaction, request, this, keyRange);
    1605                 : 
    1606              26 :   rv = helper->DispatchToTransactionPool();
    1607              26 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1608                 : 
    1609              26 :   request.forget(_retval);
    1610              26 :   return NS_OK;
    1611                 : }
    1612                 : 
    1613                 : NS_IMETHODIMP
    1614              11 : IDBObjectStore::Clear(nsIIDBRequest** _retval)
    1615                 : {
    1616              11 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1617                 : 
    1618              11 :   if (!mTransaction->IsOpen()) {
    1619               0 :     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
    1620                 :   }
    1621                 : 
    1622              11 :   if (!IsWriteAllowed()) {
    1623               1 :     return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
    1624                 :   }
    1625                 : 
    1626              20 :   nsRefPtr<IDBRequest> request = GenerateRequest(this);
    1627              10 :   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1628                 : 
    1629              30 :   nsRefPtr<ClearHelper> helper(new ClearHelper(mTransaction, request, this));
    1630                 : 
    1631              10 :   nsresult rv = helper->DispatchToTransactionPool();
    1632              10 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1633                 : 
    1634              10 :   request.forget(_retval);
    1635              10 :   return NS_OK;
    1636                 : }
    1637                 : 
    1638                 : NS_IMETHODIMP
    1639              48 : IDBObjectStore::OpenCursor(const jsval& aKey,
    1640                 :                            const nsAString& aDirection,
    1641                 :                            JSContext* aCx,
    1642                 :                            PRUint8 aOptionalArgCount,
    1643                 :                            nsIIDBRequest** _retval)
    1644                 : {
    1645              48 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    1646                 : 
    1647              48 :   if (!mTransaction->IsOpen()) {
    1648               1 :     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
    1649                 :   }
    1650                 : 
    1651                 :   nsresult rv;
    1652                 : 
    1653              47 :   IDBCursor::Direction direction = IDBCursor::NEXT;
    1654                 : 
    1655              94 :   nsRefPtr<IDBKeyRange> keyRange;
    1656              47 :   if (aOptionalArgCount) {
    1657              16 :     rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
    1658              16 :     NS_ENSURE_SUCCESS(rv, rv);
    1659                 : 
    1660              16 :     if (aOptionalArgCount >= 2) {
    1661               4 :       rv = IDBCursor::ParseDirection(aDirection, &direction);
    1662               4 :       NS_ENSURE_SUCCESS(rv, rv);
    1663                 :     }
    1664                 :   }
    1665                 : 
    1666              94 :   nsRefPtr<IDBRequest> request = GenerateRequest(this);
    1667              47 :   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1668                 : 
    1669                 :   nsRefPtr<OpenCursorHelper> helper =
    1670             141 :     new OpenCursorHelper(mTransaction, request, this, keyRange, direction);
    1671                 : 
    1672              47 :   rv = helper->DispatchToTransactionPool();
    1673              47 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1674                 : 
    1675              47 :   request.forget(_retval);
    1676              47 :   return NS_OK;
    1677                 : }
    1678                 : 
    1679                 : NS_IMETHODIMP
    1680              92 : IDBObjectStore::CreateIndex(const nsAString& aName,
    1681                 :                             const jsval& aKeyPath,
    1682                 :                             const jsval& aOptions,
    1683                 :                             JSContext* aCx,
    1684                 :                             nsIIDBIndex** _retval)
    1685                 : {
    1686              92 :   NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
    1687                 : 
    1688                 :   // Get KeyPath
    1689             184 :   nsString keyPath;
    1690             184 :   nsTArray<nsString> keyPathArray;
    1691                 : 
    1692                 :   // See if this is a JS array.
    1693              96 :   if (!JSVAL_IS_PRIMITIVE(aKeyPath) &&
    1694               4 :       JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(aKeyPath))) {
    1695                 : 
    1696               4 :     JSObject* obj = JSVAL_TO_OBJECT(aKeyPath);
    1697                 : 
    1698                 :     uint32_t length;
    1699               4 :     if (!JS_GetArrayLength(aCx, obj, &length)) {
    1700               0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1701                 :     }
    1702                 : 
    1703               4 :     if (!length) {
    1704               2 :       return NS_ERROR_DOM_SYNTAX_ERR;
    1705                 :     }
    1706                 : 
    1707               2 :     keyPathArray.SetCapacity(length);
    1708                 : 
    1709               4 :     for (uint32_t index = 0; index < length; index++) {
    1710                 :       jsval val;
    1711                 :       JSString* jsstr;
    1712               4 :       nsDependentJSString str;
    1713               4 :       if (!JS_GetElement(aCx, obj, index, &val) ||
    1714                 :           !(jsstr = JS_ValueToString(aCx, val)) ||
    1715               2 :           !str.init(aCx, jsstr)) {
    1716               0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1717                 :       }
    1718                 : 
    1719               2 :       if (!IsValidKeyPath(aCx, str)) {
    1720               0 :         return NS_ERROR_DOM_SYNTAX_ERR;
    1721                 :       }
    1722                 : 
    1723               4 :       keyPathArray.AppendElement(str);
    1724                 :     }
    1725                 : 
    1726               2 :     NS_ASSERTION(!keyPathArray.IsEmpty(), "This shouldn't have happened!");
    1727                 :   }
    1728                 :   else {
    1729                 :     JSString* jsstr;
    1730             176 :     nsDependentJSString str;
    1731             176 :     if (!(jsstr = JS_ValueToString(aCx, aKeyPath)) ||
    1732              88 :         !str.init(aCx, jsstr)) {
    1733               0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1734                 :     }
    1735                 : 
    1736              88 :     if (!IsValidKeyPath(aCx, str)) {
    1737               0 :       return NS_ERROR_DOM_SYNTAX_ERR;
    1738                 :     }
    1739                 : 
    1740             176 :     keyPath = str;
    1741                 :   }
    1742                 : 
    1743                 :   // Check name and current mode
    1744              90 :   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
    1745                 : 
    1746             268 :   if (!transaction ||
    1747              89 :       transaction != mTransaction ||
    1748              89 :       mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
    1749               1 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
    1750                 :   }
    1751                 : 
    1752              89 :   bool found = false;
    1753              89 :   PRUint32 indexCount = mInfo->indexes.Length();
    1754             163 :   for (PRUint32 index = 0; index < indexCount; index++) {
    1755              74 :     if (mInfo->indexes[index].name == aName) {
    1756               0 :       found = true;
    1757               0 :       break;
    1758                 :     }
    1759                 :   }
    1760                 : 
    1761              89 :   if (found) {
    1762               0 :     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
    1763                 :   }
    1764                 : 
    1765              89 :   NS_ASSERTION(mTransaction->IsOpen(), "Impossible!");
    1766                 : 
    1767             178 :   mozilla::dom::IDBIndexParameters params;
    1768                 : 
    1769                 :   // Get optional arguments.
    1770              89 :   if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
    1771              79 :     nsresult rv = params.Init(aCx, &aOptions);
    1772              79 :     NS_ENSURE_SUCCESS(rv, rv);
    1773                 :   }
    1774                 : 
    1775              87 :   if (params.multiEntry && !keyPathArray.IsEmpty()) {
    1776               2 :     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
    1777                 :   }
    1778                 : 
    1779              85 :   DatabaseInfo* databaseInfo = mTransaction->DBInfo();
    1780                 : 
    1781              85 :   IndexInfo* indexInfo = mInfo->indexes.AppendElement();
    1782              85 :   indexInfo->id = databaseInfo->nextIndexId++;
    1783              85 :   indexInfo->name = aName;
    1784              85 :   indexInfo->keyPath = keyPath;
    1785              85 :   indexInfo->keyPathArray.SwapElements(keyPathArray);
    1786              85 :   indexInfo->unique = params.unique;
    1787              85 :   indexInfo->multiEntry = params.multiEntry;
    1788                 : 
    1789                 :   // Don't leave this in the list if we fail below!
    1790             170 :   AutoRemoveIndex autoRemove(mInfo, aName);
    1791                 : 
    1792                 : #ifdef DEBUG
    1793             159 :   for (PRUint32 index = 0; index < mCreatedIndexes.Length(); index++) {
    1794              74 :     if (mCreatedIndexes[index]->Name() == aName) {
    1795               0 :       NS_ERROR("Already created this one!");
    1796                 :     }
    1797                 :   }
    1798                 : #endif
    1799                 : 
    1800             170 :   nsRefPtr<IDBIndex> index(IDBIndex::Create(this, indexInfo));
    1801                 : 
    1802              85 :   if (!mCreatedIndexes.AppendElement(index)) {
    1803               0 :     NS_WARNING("Out of memory!");
    1804               0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1805                 :   }
    1806                 : 
    1807                 :   nsRefPtr<CreateIndexHelper> helper =
    1808             255 :     new CreateIndexHelper(mTransaction, index);
    1809                 : 
    1810              85 :   nsresult rv = helper->DispatchToTransactionPool();
    1811              85 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1812                 : 
    1813              85 :   autoRemove.forget();
    1814                 : 
    1815              85 :   index.forget(_retval);
    1816              85 :   return NS_OK;
    1817                 : }
    1818                 : 
    1819                 : NS_IMETHODIMP
    1820              94 : IDBObjectStore::Index(const nsAString& aName,
    1821                 :                       nsIIDBIndex** _retval)
    1822                 : {
    1823              94 :   NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
    1824                 : 
    1825              94 :   if (!mTransaction->IsOpen()) {
    1826               1 :     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
    1827                 :   }
    1828                 : 
    1829              93 :   IndexInfo* indexInfo = nsnull;
    1830              93 :   PRUint32 indexCount = mInfo->indexes.Length();
    1831             135 :   for (PRUint32 index = 0; index < indexCount; index++) {
    1832             134 :     if (mInfo->indexes[index].name == aName) {
    1833              92 :       indexInfo = &(mInfo->indexes[index]);
    1834              92 :       break;
    1835                 :     }
    1836                 :   }
    1837                 : 
    1838              93 :   if (!indexInfo) {
    1839               1 :     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
    1840                 :   }
    1841                 : 
    1842             184 :   nsRefPtr<IDBIndex> retval;
    1843             108 :   for (PRUint32 i = 0; i < mCreatedIndexes.Length(); i++) {
    1844              64 :     nsRefPtr<IDBIndex>& index = mCreatedIndexes[i];
    1845              64 :     if (index->Name() == aName) {
    1846              48 :       retval = index;
    1847              48 :       break;
    1848                 :     }
    1849                 :   }
    1850                 : 
    1851              92 :   if (!retval) {
    1852              44 :     retval = IDBIndex::Create(this, indexInfo);
    1853              44 :     NS_ENSURE_TRUE(retval, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1854                 : 
    1855              44 :     if (!mCreatedIndexes.AppendElement(retval)) {
    1856               0 :       NS_WARNING("Out of memory!");
    1857               0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1858                 :     }
    1859                 :   }
    1860                 : 
    1861              92 :   retval.forget(_retval);
    1862              92 :   return NS_OK;
    1863                 : }
    1864                 : 
    1865                 : NS_IMETHODIMP
    1866              25 : IDBObjectStore::DeleteIndex(const nsAString& aName)
    1867                 : {
    1868              25 :   NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
    1869                 : 
    1870              25 :   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
    1871                 : 
    1872              73 :   if (!transaction ||
    1873              24 :       transaction != mTransaction ||
    1874              24 :       mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
    1875               1 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
    1876                 :   }
    1877                 : 
    1878              24 :   NS_ASSERTION(mTransaction->IsOpen(), "Impossible!");
    1879                 : 
    1880              24 :   PRUint32 index = 0;
    1881              44 :   for (; index < mInfo->indexes.Length(); index++) {
    1882              44 :     if (mInfo->indexes[index].name == aName) {
    1883              24 :       break;
    1884                 :     }
    1885                 :   }
    1886                 : 
    1887              24 :   if (index == mInfo->indexes.Length()) {
    1888               0 :     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
    1889                 :   }
    1890                 : 
    1891                 :   nsRefPtr<DeleteIndexHelper> helper =
    1892              72 :     new DeleteIndexHelper(mTransaction, aName, this);
    1893                 : 
    1894              24 :   nsresult rv = helper->DispatchToTransactionPool();
    1895              24 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1896                 : 
    1897              24 :   mInfo->indexes.RemoveElementAt(index);
    1898                 : 
    1899              44 :   for (PRUint32 i = 0; i < mCreatedIndexes.Length(); i++) {
    1900              44 :     if (mCreatedIndexes[i]->Name() == aName) {
    1901              24 :       mCreatedIndexes.RemoveElementAt(i);
    1902              24 :       break;
    1903                 :     }
    1904                 :   }
    1905                 : 
    1906              24 :   return NS_OK;
    1907                 : }
    1908                 : 
    1909                 : NS_IMETHODIMP
    1910              32 : IDBObjectStore::Count(const jsval& aKey,
    1911                 :                       JSContext* aCx,
    1912                 :                       PRUint8 aOptionalArgCount,
    1913                 :                       nsIIDBRequest** _retval)
    1914                 : {
    1915              32 :   if (!mTransaction->IsOpen()) {
    1916               0 :     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
    1917                 :   }
    1918                 : 
    1919                 :   nsresult rv;
    1920                 : 
    1921              64 :   nsRefPtr<IDBKeyRange> keyRange;
    1922              32 :   if (aOptionalArgCount) {
    1923              16 :     rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
    1924              16 :     NS_ENSURE_SUCCESS(rv, rv);
    1925                 :   }
    1926                 : 
    1927              64 :   nsRefPtr<IDBRequest> request = GenerateRequest(this);
    1928              32 :   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1929                 : 
    1930                 :   nsRefPtr<CountHelper> helper =
    1931              96 :     new CountHelper(mTransaction, request, this, keyRange);
    1932              32 :   rv = helper->DispatchToTransactionPool();
    1933              32 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1934                 : 
    1935              32 :   request.forget(_retval);
    1936              32 :   return NS_OK;
    1937                 : }
    1938                 : 
    1939                 : inline nsresult
    1940               0 : CopyData(nsIInputStream* aStream, quota_FILE* aFile)
    1941                 : {
    1942               0 :   do {
    1943                 :     char copyBuffer[FILE_COPY_BUFFER_SIZE];
    1944                 : 
    1945                 :     PRUint32 numRead;
    1946               0 :     nsresult rv = aStream->Read(copyBuffer, FILE_COPY_BUFFER_SIZE, &numRead);
    1947               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1948                 : 
    1949               0 :     if (numRead <= 0) {
    1950                 :       break;
    1951                 :     }
    1952                 : 
    1953               0 :     size_t numWrite = sqlite3_quota_fwrite(copyBuffer, 1, numRead, aFile);
    1954               0 :     NS_ENSURE_TRUE(numWrite == numRead, NS_ERROR_FAILURE);
    1955                 :   } while (true);
    1956                 : 
    1957                 :   // Flush and sync
    1958               0 :   NS_ENSURE_TRUE(sqlite3_quota_fflush(aFile, 1) == 0,
    1959                 :                  NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1960                 : 
    1961               0 :   return NS_OK;
    1962                 : }
    1963                 : 
    1964                 : nsresult
    1965            1837 : AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
    1966                 : {
    1967            1837 :   NS_PRECONDITION(aConnection, "Passed a null connection!");
    1968                 : 
    1969                 :   nsresult rv;
    1970            1837 :   bool keyUnset = mKey.IsUnset();
    1971            1837 :   PRInt64 osid = mObjectStore->Id();
    1972            1837 :   const nsString& keyPath = mObjectStore->KeyPath();
    1973                 : 
    1974                 :   // The "|| keyUnset" here is mostly a debugging tool. If a key isn't
    1975                 :   // specified we should never have a collision and so it shouldn't matter
    1976                 :   // if we allow overwrite or not. By not allowing overwrite we raise
    1977                 :   // detectable errors rather than corrupting data
    1978            1837 :   nsCOMPtr<mozIStorageStatement> stmt = !mOverwrite || keyUnset ?
    1979                 :     mTransaction->GetCachedStatement(
    1980                 :       "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
    1981            1787 :       "VALUES (:osid, :key_value, :data, :file_ids)") :
    1982                 :     mTransaction->GetCachedStatement(
    1983                 :       "INSERT OR REPLACE INTO object_data (object_store_id, key_value, data, file_ids) "
    1984            5461 :       "VALUES (:osid, :key_value, :data, :file_ids)");
    1985            1837 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1986                 : 
    1987            3674 :   mozStorageStatementScoper scoper(stmt);
    1988                 : 
    1989            1837 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
    1990            1837 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    1991                 : 
    1992            1837 :   NS_ASSERTION(!keyUnset || mObjectStore->IsAutoIncrement(),
    1993                 :                "Should have key unless autoincrement");
    1994                 : 
    1995            1837 :   PRInt64 autoIncrementNum = 0;
    1996                 : 
    1997            1837 :   if (mObjectStore->IsAutoIncrement()) {
    1998            1385 :     if (keyUnset) {
    1999            1307 :       autoIncrementNum = mObjectStore->Info()->nextAutoIncrementId;
    2000            1307 :       if (autoIncrementNum > (1LL << 53)) {
    2001               0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    2002                 :       }
    2003            1307 :       mKey.SetFromInteger(autoIncrementNum);
    2004                 :     }
    2005             156 :     else if (mKey.IsFloat() &&
    2006              78 :              mKey.ToFloat() >= mObjectStore->Info()->nextAutoIncrementId) {
    2007              55 :       autoIncrementNum = floor(mKey.ToFloat());
    2008                 :     }
    2009                 : 
    2010            1385 :     if (keyUnset && !keyPath.IsEmpty()) {
    2011                 :       // Special case where someone put an object into an autoIncrement'ing
    2012                 :       // objectStore with no key in its keyPath set. We needed to figure out
    2013                 :       // which row id we would get above before we could set that properly.
    2014                 : 
    2015                 :       // This is a duplicate of the js engine's byte munging here
    2016                 :       union {
    2017                 :         double d;
    2018                 :         PRUint64 u;
    2019                 :       } pun;
    2020                 :     
    2021              16 :       pun.d = SwapBytes(static_cast<PRUint64>(autoIncrementNum));
    2022                 : 
    2023              16 :       JSAutoStructuredCloneBuffer& buffer = mCloneWriteInfo.mCloneBuffer;
    2024              16 :       PRUint64 offsetToKeyProp = mCloneWriteInfo.mOffsetToKeyProp;
    2025                 : 
    2026              16 :       memcpy((char*)buffer.data() + offsetToKeyProp, &pun.u, sizeof(PRUint64));
    2027                 :     }
    2028                 :   }
    2029                 : 
    2030            1837 :   mKey.BindToStatement(stmt, NS_LITERAL_CSTRING("key_value"));
    2031                 : 
    2032                 :   // Compress the bytes before adding into the database.
    2033                 :   const char* uncompressed =
    2034            1837 :     reinterpret_cast<const char*>(mCloneWriteInfo.mCloneBuffer.data());
    2035            1837 :   size_t uncompressedLength = mCloneWriteInfo.mCloneBuffer.nbytes();
    2036                 : 
    2037            1837 :   size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
    2038                 :   // This will hold our compressed data until the end of the method. The
    2039                 :   // BindBlobByName function will copy it.
    2040            5511 :   nsAutoArrayPtr<char> compressed(new char[compressedLength]);
    2041                 : 
    2042                 :   snappy::RawCompress(uncompressed, uncompressedLength, compressed.get(),
    2043            1837 :                       &compressedLength);
    2044                 : 
    2045            1837 :   const PRUint8* dataBuffer = reinterpret_cast<const PRUint8*>(compressed.get());
    2046            1837 :   size_t dataBufferLength = compressedLength;
    2047                 : 
    2048            3674 :   rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"), dataBuffer,
    2049            1837 :                             dataBufferLength);
    2050            1837 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2051                 : 
    2052                 :   // Handle blobs
    2053            3674 :   nsRefPtr<FileManager> fileManager = mDatabase->Manager();
    2054            3674 :   nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
    2055            1837 :   NS_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2056                 : 
    2057            3674 :   nsAutoString fileIds;
    2058                 : 
    2059            1837 :   for (PRUint32 index = 0; index < mCloneWriteInfo.mBlobs.Length(); index++) {
    2060               0 :     nsCOMPtr<nsIDOMBlob>& domBlob = mCloneWriteInfo.mBlobs[index];
    2061                 : 
    2062               0 :     PRInt64 id = -1;
    2063                 : 
    2064                 :     // Check if it is a blob created from this db or the blob was already
    2065                 :     // stored in this db
    2066               0 :     nsRefPtr<FileInfo> fileInfo = domBlob->GetFileInfo(fileManager);
    2067               0 :     if (fileInfo) {
    2068               0 :       id = fileInfo->Id();
    2069                 :     }
    2070                 : 
    2071               0 :     if (id == -1) {
    2072               0 :       fileInfo = fileManager->GetNewFileInfo();
    2073               0 :       NS_ENSURE_TRUE(fileInfo, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2074                 : 
    2075               0 :       id = fileInfo->Id();
    2076                 : 
    2077               0 :       mTransaction->OnNewFileInfo(fileInfo);
    2078                 : 
    2079                 :       // Copy it
    2080               0 :       nsCOMPtr<nsIInputStream> inputStream;
    2081               0 :       rv = domBlob->GetInternalStream(getter_AddRefs(inputStream));
    2082               0 :       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2083                 : 
    2084               0 :       nsCOMPtr<nsIFile> nativeFile = fileManager->GetFileForId(directory, id);
    2085               0 :       NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2086                 : 
    2087               0 :       nsString nativeFilePath;
    2088               0 :       rv = nativeFile->GetPath(nativeFilePath);
    2089               0 :       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2090                 : 
    2091                 :       quota_FILE* file =
    2092               0 :         sqlite3_quota_fopen(NS_ConvertUTF16toUTF8(nativeFilePath).get(), "wb");
    2093               0 :       NS_ENSURE_TRUE(file, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2094                 : 
    2095               0 :       rv = CopyData(inputStream, file);
    2096                 : 
    2097               0 :       NS_ENSURE_TRUE(sqlite3_quota_fclose(file) == 0,
    2098                 :                      NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2099                 : 
    2100               0 :       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2101                 : 
    2102               0 :       domBlob->AddFileInfo(fileInfo);
    2103                 :     }
    2104                 : 
    2105               0 :     if (index) {
    2106               0 :       fileIds.Append(NS_LITERAL_STRING(" "));
    2107                 :     }
    2108               0 :     fileIds.AppendInt(id);
    2109                 :   }
    2110                 : 
    2111            1837 :   if (fileIds.IsEmpty()) {
    2112            1837 :     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("file_ids"));
    2113                 :   }
    2114                 :   else {
    2115               0 :     rv = stmt->BindStringByName(NS_LITERAL_CSTRING("file_ids"), fileIds);
    2116                 :   }
    2117            1837 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2118                 : 
    2119            1837 :   rv = stmt->Execute();
    2120            1837 :   if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
    2121              12 :     NS_ASSERTION(!keyUnset, "Generated key had a collision!?");
    2122              12 :     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
    2123                 :   }
    2124            1825 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2125                 : 
    2126                 :   PRInt64 objectDataId;
    2127            1825 :   rv = aConnection->GetLastInsertRowID(&objectDataId);
    2128            1825 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2129                 : 
    2130                 :   // Update our indexes if needed.
    2131            1825 :   if (mOverwrite || !mIndexUpdateInfo.IsEmpty()) {
    2132                 :     rv = IDBObjectStore::UpdateIndexes(mTransaction, osid, mKey, mOverwrite,
    2133             172 :                                        objectDataId, mIndexUpdateInfo);
    2134             172 :     if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
    2135               7 :       return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
    2136                 :     }
    2137             165 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2138                 :   }
    2139                 : 
    2140            1818 :   if (autoIncrementNum) {
    2141            1361 :     mObjectStore->Info()->nextAutoIncrementId = autoIncrementNum + 1;
    2142                 :   }
    2143                 : 
    2144            1818 :   return NS_OK;
    2145                 : }
    2146                 : 
    2147                 : nsresult
    2148            1813 : AddHelper::GetSuccessResult(JSContext* aCx,
    2149                 :                             jsval* aVal)
    2150                 : {
    2151            1813 :   NS_ASSERTION(!mKey.IsUnset(), "Badness!");
    2152                 : 
    2153            1813 :   mCloneWriteInfo.mCloneBuffer.clear();
    2154                 : 
    2155            1813 :   return mKey.ToJSVal(aCx, aVal);
    2156                 : }
    2157                 : 
    2158                 : nsresult
    2159             173 : GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
    2160                 : {
    2161             173 :   NS_ASSERTION(mKeyRange, "Must have a key range here!");
    2162                 : 
    2163             346 :   nsCString keyRangeClause;
    2164             173 :   mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause);
    2165                 : 
    2166             173 :   NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
    2167                 : 
    2168             173 :   nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
    2169                 :                                        "WHERE object_store_id = :osid") +
    2170             519 :                     keyRangeClause + NS_LITERAL_CSTRING(" LIMIT 1");
    2171                 : 
    2172             346 :   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
    2173             173 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2174                 : 
    2175             346 :   mozStorageStatementScoper scoper(stmt);
    2176                 : 
    2177             173 :   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStore->Id());
    2178             173 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2179                 : 
    2180             173 :   rv = mKeyRange->BindToStatement(stmt);
    2181             173 :   NS_ENSURE_SUCCESS(rv, rv);
    2182                 : 
    2183                 :   bool hasResult;
    2184             173 :   rv = stmt->ExecuteStep(&hasResult);
    2185             173 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2186                 : 
    2187             173 :   if (hasResult) {
    2188                 :     rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
    2189             162 :       mDatabase->Manager(), mCloneReadInfo);
    2190             162 :     NS_ENSURE_SUCCESS(rv, rv);
    2191                 :   }
    2192                 : 
    2193             173 :   return NS_OK;
    2194                 : }
    2195                 : 
    2196                 : nsresult
    2197             167 : GetHelper::GetSuccessResult(JSContext* aCx,
    2198                 :                             jsval* aVal)
    2199                 : {
    2200             167 :   bool result = IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, aVal);
    2201                 : 
    2202             167 :   mCloneReadInfo.mCloneBuffer.clear();
    2203                 : 
    2204             167 :   NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
    2205             167 :   return NS_OK;
    2206                 : }
    2207                 : 
    2208                 : nsresult
    2209              26 : DeleteHelper::DoDatabaseWork(mozIStorageConnection* /*aConnection */)
    2210                 : {
    2211              26 :   NS_ASSERTION(mKeyRange, "Must have a key range here!");
    2212                 : 
    2213              52 :   nsCString keyRangeClause;
    2214              26 :   mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause);
    2215                 : 
    2216              26 :   NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
    2217                 : 
    2218              26 :   nsCString query = NS_LITERAL_CSTRING("DELETE FROM object_data "
    2219                 :                                        "WHERE object_store_id = :osid") +
    2220              52 :                     keyRangeClause;
    2221                 : 
    2222              52 :   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
    2223              26 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2224                 : 
    2225              52 :   mozStorageStatementScoper scoper(stmt);
    2226                 : 
    2227              52 :   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
    2228              26 :                                       mObjectStore->Id());
    2229              26 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2230                 : 
    2231              26 :   rv = mKeyRange->BindToStatement(stmt);
    2232              26 :   NS_ENSURE_SUCCESS(rv, rv);
    2233                 : 
    2234              26 :   rv = stmt->Execute();
    2235              26 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2236                 : 
    2237              26 :   return NS_OK;
    2238                 : }
    2239                 : 
    2240                 : nsresult
    2241              26 : DeleteHelper::GetSuccessResult(JSContext* aCx,
    2242                 :                                jsval* aVal)
    2243                 : {
    2244              26 :   *aVal = JSVAL_VOID;
    2245              26 :   return NS_OK;
    2246                 : }
    2247                 : 
    2248                 : nsresult
    2249              10 : ClearHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
    2250                 : {
    2251              10 :   NS_PRECONDITION(aConnection, "Passed a null connection!");
    2252                 : 
    2253                 :   nsCOMPtr<mozIStorageStatement> stmt =
    2254                 :     mTransaction->GetCachedStatement(
    2255              10 :       NS_LITERAL_CSTRING("DELETE FROM object_data "
    2256              20 :                          "WHERE object_store_id = :osid"));
    2257              10 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2258                 : 
    2259              20 :   mozStorageStatementScoper scoper(stmt);
    2260                 : 
    2261              20 :   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
    2262              10 :                                       mObjectStore->Id());
    2263              10 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2264                 : 
    2265              10 :   rv = stmt->Execute();
    2266              10 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2267                 : 
    2268              10 :   return NS_OK;
    2269                 : }
    2270                 : 
    2271                 : nsresult
    2272              47 : OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
    2273                 : {
    2274              94 :   NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
    2275                 : 
    2276              94 :   nsCString keyRangeClause;
    2277              47 :   if (mKeyRange) {
    2278              10 :     mKeyRange->GetBindingClause(keyValue, keyRangeClause);
    2279                 :   }
    2280                 : 
    2281              94 :   nsCAutoString directionClause;
    2282              47 :   switch (mDirection) {
    2283                 :     case IDBCursor::NEXT:
    2284                 :     case IDBCursor::NEXT_UNIQUE:
    2285              44 :       directionClause.AssignLiteral(" ORDER BY key_value ASC");
    2286              44 :       break;
    2287                 : 
    2288                 :     case IDBCursor::PREV:
    2289                 :     case IDBCursor::PREV_UNIQUE:
    2290               3 :       directionClause.AssignLiteral(" ORDER BY key_value DESC");
    2291               3 :       break;
    2292                 : 
    2293                 :     default:
    2294               0 :       NS_NOTREACHED("Unknown direction type!");
    2295                 :   }
    2296                 : 
    2297              47 :   nsCString firstQuery = NS_LITERAL_CSTRING("SELECT key_value, data, file_ids "
    2298                 :                                             "FROM object_data "
    2299                 :                                             "WHERE object_store_id = :id") +
    2300              47 :                          keyRangeClause + directionClause +
    2301             188 :                          NS_LITERAL_CSTRING(" LIMIT 1");
    2302                 : 
    2303                 :   nsCOMPtr<mozIStorageStatement> stmt =
    2304              94 :     mTransaction->GetCachedStatement(firstQuery);
    2305              47 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2306                 : 
    2307              94 :   mozStorageStatementScoper scoper(stmt);
    2308                 : 
    2309              94 :   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
    2310              47 :                                       mObjectStore->Id());
    2311              47 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2312                 : 
    2313              47 :   if (mKeyRange) {
    2314              10 :     rv = mKeyRange->BindToStatement(stmt);
    2315              10 :     NS_ENSURE_SUCCESS(rv, rv);
    2316                 :   }
    2317                 : 
    2318                 :   bool hasResult;
    2319              47 :   rv = stmt->ExecuteStep(&hasResult);
    2320              47 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2321                 : 
    2322              47 :   if (!hasResult) {
    2323               9 :     mKey.Unset();
    2324               9 :     return NS_OK;
    2325                 :   }
    2326                 : 
    2327              38 :   rv = mKey.SetFromStatement(stmt, 0);
    2328              38 :   NS_ENSURE_SUCCESS(rv, rv);
    2329                 : 
    2330                 :   rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 1, 2,
    2331              38 :     mDatabase->Manager(), mCloneReadInfo);
    2332              38 :   NS_ENSURE_SUCCESS(rv, rv);
    2333                 : 
    2334                 :   // Now we need to make the query to get the next match.
    2335              38 :   keyRangeClause.Truncate();
    2336              76 :   nsCAutoString continueToKeyRangeClause;
    2337                 : 
    2338              76 :   NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
    2339              76 :   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
    2340                 : 
    2341              38 :   switch (mDirection) {
    2342                 :     case IDBCursor::NEXT:
    2343                 :     case IDBCursor::NEXT_UNIQUE:
    2344                 :       AppendConditionClause(keyValue, currentKey, false, false,
    2345              35 :                             keyRangeClause);
    2346                 :       AppendConditionClause(keyValue, currentKey, false, true,
    2347              35 :                             continueToKeyRangeClause);
    2348              35 :       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
    2349                 :         AppendConditionClause(keyValue, rangeKey, true,
    2350               5 :                               !mKeyRange->IsUpperOpen(), keyRangeClause);
    2351                 :         AppendConditionClause(keyValue, rangeKey, true,
    2352               5 :                               !mKeyRange->IsUpperOpen(),
    2353               5 :                               continueToKeyRangeClause);
    2354               5 :         mRangeKey = mKeyRange->Upper();
    2355                 :       }
    2356              35 :       break;
    2357                 : 
    2358                 :     case IDBCursor::PREV:
    2359                 :     case IDBCursor::PREV_UNIQUE:
    2360               3 :       AppendConditionClause(keyValue, currentKey, true, false, keyRangeClause);
    2361                 :       AppendConditionClause(keyValue, currentKey, true, true,
    2362               3 :                            continueToKeyRangeClause);
    2363               3 :       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
    2364                 :         AppendConditionClause(keyValue, rangeKey, false,
    2365               0 :                               !mKeyRange->IsLowerOpen(), keyRangeClause);
    2366                 :         AppendConditionClause(keyValue, rangeKey, false,
    2367               0 :                               !mKeyRange->IsLowerOpen(),
    2368               0 :                               continueToKeyRangeClause);
    2369               0 :         mRangeKey = mKeyRange->Lower();
    2370                 :       }
    2371               3 :       break;
    2372                 : 
    2373                 :     default:
    2374               0 :       NS_NOTREACHED("Unknown direction type!");
    2375                 :   }
    2376                 : 
    2377              76 :   NS_NAMED_LITERAL_CSTRING(queryStart, "SELECT key_value, data, file_ids "
    2378                 :                                        "FROM object_data "
    2379                 :                                        "WHERE object_store_id = :id");
    2380                 : 
    2381              38 :   mContinueQuery = queryStart + keyRangeClause + directionClause +
    2382              76 :                    NS_LITERAL_CSTRING(" LIMIT ");
    2383                 : 
    2384              38 :   mContinueToQuery = queryStart + continueToKeyRangeClause + directionClause +
    2385              76 :                      NS_LITERAL_CSTRING(" LIMIT ");
    2386                 : 
    2387              38 :   return NS_OK;
    2388                 : }
    2389                 : 
    2390                 : nsresult
    2391              47 : OpenCursorHelper::GetSuccessResult(JSContext* aCx,
    2392                 :                                    jsval* aVal)
    2393                 : {
    2394              47 :   if (mKey.IsUnset()) {
    2395               9 :     *aVal = JSVAL_VOID;
    2396               9 :     return NS_OK;
    2397                 :   }
    2398                 : 
    2399                 :   nsRefPtr<IDBCursor> cursor =
    2400                 :     IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection,
    2401                 :                       mRangeKey, mContinueQuery, mContinueToQuery, mKey,
    2402              76 :                       mCloneReadInfo);
    2403              38 :   NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2404                 : 
    2405              38 :   NS_ASSERTION(!mCloneReadInfo.mCloneBuffer.data(), "Should have swapped!");
    2406                 : 
    2407              38 :   return WrapNative(aCx, cursor, aVal);
    2408                 : }
    2409                 : 
    2410                 : class ThreadLocalJSRuntime
    2411                 : {
    2412                 :   JSRuntime* mRuntime;
    2413                 :   JSContext* mContext;
    2414                 :   JSObject* mGlobal;
    2415                 : 
    2416                 :   static JSClass sGlobalClass;
    2417                 :   static const unsigned sRuntimeHeapSize = 256 * 1024;  // should be enough for anyone
    2418                 : 
    2419               8 :   ThreadLocalJSRuntime()
    2420               8 :   : mRuntime(NULL), mContext(NULL), mGlobal(NULL)
    2421                 :   {
    2422               8 :       MOZ_COUNT_CTOR(ThreadLocalJSRuntime);
    2423               8 :   }
    2424                 : 
    2425               8 :   nsresult Init()
    2426                 :   {
    2427               8 :     mRuntime = JS_NewRuntime(sRuntimeHeapSize);
    2428               8 :     NS_ENSURE_TRUE(mRuntime, NS_ERROR_OUT_OF_MEMORY);
    2429                 : 
    2430               8 :     mContext = JS_NewContext(mRuntime, 0);
    2431               8 :     NS_ENSURE_TRUE(mContext, NS_ERROR_OUT_OF_MEMORY);
    2432                 : 
    2433              16 :     JSAutoRequest ar(mContext);
    2434                 : 
    2435               8 :     mGlobal = JS_NewCompartmentAndGlobalObject(mContext, &sGlobalClass, NULL);
    2436               8 :     NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY);
    2437                 : 
    2438               8 :     JS_SetGlobalObject(mContext, mGlobal);
    2439               8 :     return NS_OK;
    2440                 :   }
    2441                 : 
    2442                 :  public:
    2443               8 :   static ThreadLocalJSRuntime *Create()
    2444                 :   {
    2445               8 :     ThreadLocalJSRuntime *entry = new ThreadLocalJSRuntime();
    2446               8 :     NS_ENSURE_TRUE(entry, nsnull);
    2447                 : 
    2448               8 :     if (NS_FAILED(entry->Init())) {
    2449               0 :       delete entry;
    2450               0 :       return nsnull;
    2451                 :     }
    2452                 : 
    2453               8 :     return entry;
    2454                 :   }
    2455                 : 
    2456             171 :   JSContext *Context() const
    2457                 :   {
    2458             171 :     return mContext;
    2459                 :   }
    2460                 : 
    2461               8 :   ~ThreadLocalJSRuntime()
    2462                 :   {
    2463               8 :     MOZ_COUNT_DTOR(ThreadLocalJSRuntime);
    2464                 : 
    2465               8 :     if (mContext) {
    2466               8 :       JS_DestroyContext(mContext);
    2467                 :     }
    2468                 : 
    2469               8 :     if (mRuntime) {
    2470               8 :       JS_DestroyRuntime(mRuntime);
    2471                 :     }
    2472               8 :   }
    2473                 : };
    2474                 : 
    2475                 : JSClass ThreadLocalJSRuntime::sGlobalClass = {
    2476                 :   "IndexedDBTransactionThreadGlobal",
    2477                 :   JSCLASS_GLOBAL_FLAGS,
    2478                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
    2479                 :   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
    2480                 : };
    2481                 : 
    2482              85 : CreateIndexHelper::CreateIndexHelper(IDBTransaction* aTransaction,
    2483                 :                                      IDBIndex* aIndex)
    2484              85 :   : AsyncConnectionHelper(aTransaction, nsnull), mIndex(aIndex)
    2485                 : {
    2486              85 :   if (sTLSIndex == BAD_TLS_INDEX) {
    2487              22 :     PR_NewThreadPrivateIndex(&sTLSIndex, DestroyTLSEntry);
    2488                 :   }
    2489              85 : }
    2490                 : 
    2491                 : void
    2492               8 : CreateIndexHelper::DestroyTLSEntry(void* aPtr)
    2493                 : {
    2494               8 :   delete reinterpret_cast<ThreadLocalJSRuntime *>(aPtr);
    2495               8 : }
    2496                 : 
    2497                 : nsresult
    2498              85 : CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
    2499                 : {
    2500                 :   // Insert the data into the database.
    2501                 :   nsCOMPtr<mozIStorageStatement> stmt =
    2502                 :     mTransaction->GetCachedStatement(
    2503                 :     "INSERT INTO object_store_index (id, name, key_path, unique_index, "
    2504                 :       "multientry, object_store_id) "
    2505                 :     "VALUES (:id, :name, :key_path, :unique, :multientry, :osid)"
    2506             170 :   );
    2507              85 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2508                 : 
    2509             170 :   mozStorageStatementScoper scoper(stmt);
    2510                 : 
    2511             170 :   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
    2512              85 :                                       mIndex->Id());
    2513              85 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2514                 : 
    2515              85 :   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mIndex->Name());
    2516              85 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2517                 : 
    2518              85 :   if (mIndex->UsesKeyPathArray()) {
    2519                 :     // We use a comma in the beginning to indicate that it's an array of
    2520                 :     // key paths. This is to be able to tell a string-keypath from an
    2521                 :     // array-keypath which contains only one item.
    2522                 :     // It also makes serializing easier :-)
    2523               0 :     nsAutoString keyPath;
    2524               0 :     const nsTArray<nsString>& keyPaths = mIndex->KeyPathArray();
    2525               0 :     for (PRUint32 i = 0; i < keyPaths.Length(); ++i) {
    2526               0 :       keyPath.Append(NS_LITERAL_STRING(",") + keyPaths[i]);
    2527                 :     }
    2528               0 :     rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
    2529               0 :                                 keyPath);
    2530               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2531                 :   }
    2532                 :   else {
    2533             170 :     rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
    2534              85 :                                 mIndex->KeyPath());
    2535              85 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2536                 :   }
    2537                 : 
    2538             170 :   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("unique"),
    2539              85 :                              mIndex->IsUnique() ? 1 : 0);
    2540              85 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2541                 : 
    2542             170 :   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("multientry"),
    2543              85 :                              mIndex->IsMultiEntry() ? 1 : 0);
    2544              85 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2545                 : 
    2546             170 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
    2547              85 :                              mIndex->ObjectStore()->Id());
    2548              85 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2549                 : 
    2550              85 :   if (NS_FAILED(stmt->Execute())) {
    2551               0 :     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
    2552                 :   }
    2553                 : 
    2554                 : #ifdef DEBUG
    2555                 :   {
    2556                 :     PRInt64 id;
    2557              85 :     aConnection->GetLastInsertRowID(&id);
    2558              85 :     NS_ASSERTION(mIndex->Id() == id, "Bad index id!");
    2559                 :   }
    2560                 : #endif
    2561                 : 
    2562                 :   // Now we need to populate the index with data from the object store.
    2563              85 :   rv = InsertDataFromObjectStore(aConnection);
    2564              85 :   if (NS_FAILED(rv)) {
    2565               0 :     return rv;
    2566                 :   }
    2567                 : 
    2568              85 :   return NS_OK;
    2569                 : }
    2570                 : 
    2571                 : nsresult
    2572              85 : CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
    2573                 : {
    2574                 :   nsCOMPtr<mozIStorageStatement> stmt =
    2575                 :     mTransaction->GetCachedStatement(
    2576              85 :       NS_LITERAL_CSTRING("SELECT id, data, file_ids, key_value FROM object_data "
    2577             170 :                          "WHERE object_store_id = :osid"));
    2578              85 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2579                 : 
    2580             170 :   mozStorageStatementScoper scoper(stmt);
    2581                 : 
    2582             170 :   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
    2583              85 :                                       mIndex->ObjectStore()->Id());
    2584              85 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2585                 : 
    2586              85 :   NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2587                 : 
    2588                 :   bool hasResult;
    2589              85 :   rv = stmt->ExecuteStep(&hasResult);
    2590              85 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2591              85 :   if (!hasResult) {
    2592                 :     // Bail early if we have no data to avoid creating the below runtime
    2593              51 :     return NS_OK;
    2594                 :   }
    2595                 : 
    2596                 :   ThreadLocalJSRuntime* tlsEntry =
    2597              34 :     reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex));
    2598                 : 
    2599              34 :   if (!tlsEntry) {
    2600               8 :     tlsEntry = ThreadLocalJSRuntime::Create();
    2601               8 :     NS_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2602                 : 
    2603               8 :     PR_SetThreadPrivate(sTLSIndex, tlsEntry);
    2604                 :   }
    2605                 : 
    2606              34 :   JSContext* cx = tlsEntry->Context();
    2607              68 :   JSAutoRequest ar(cx);
    2608                 : 
    2609             274 :   do {
    2610             274 :     StructuredCloneReadInfo cloneReadInfo;
    2611                 :     rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 1, 2,
    2612             137 :       mDatabase->Manager(), cloneReadInfo);
    2613             137 :     NS_ENSURE_SUCCESS(rv, rv);
    2614                 : 
    2615             137 :     JSAutoStructuredCloneBuffer& buffer = cloneReadInfo.mCloneBuffer;
    2616                 : 
    2617                 :     JSStructuredCloneCallbacks callbacks = {
    2618                 :       IDBObjectStore::StructuredCloneReadCallback,
    2619                 :       nsnull,
    2620                 :       nsnull
    2621             137 :     };
    2622                 : 
    2623                 :     jsval clone;
    2624             137 :     if (!buffer.read(cx, &clone, &callbacks, &cloneReadInfo)) {
    2625               0 :       NS_WARNING("Failed to deserialize structured clone data!");
    2626               0 :       return NS_ERROR_DOM_DATA_CLONE_ERR;
    2627                 :     }
    2628                 : 
    2629             274 :     nsTArray<IndexUpdateInfo> updateInfo;
    2630                 :     rv = IDBObjectStore::AppendIndexUpdateInfo(mIndex->Id(),
    2631             137 :                                                mIndex->KeyPath(),
    2632             137 :                                                mIndex->KeyPathArray(),
    2633             137 :                                                mIndex->IsUnique(),
    2634             137 :                                                mIndex->IsMultiEntry(),
    2635                 :                                                tlsEntry->Context(),
    2636             548 :                                                clone, updateInfo);
    2637             137 :     NS_ENSURE_SUCCESS(rv, rv);
    2638                 : 
    2639             137 :     PRInt64 objectDataID = stmt->AsInt64(0);
    2640                 : 
    2641             274 :     Key key;
    2642             137 :     rv = key.SetFromStatement(stmt, 3);
    2643             137 :     NS_ENSURE_SUCCESS(rv, rv);
    2644                 : 
    2645                 :     rv = IDBObjectStore::UpdateIndexes(mTransaction, mIndex->Id(),
    2646             137 :                                        key, false, objectDataID, updateInfo);
    2647             137 :     NS_ENSURE_SUCCESS(rv, rv);
    2648                 : 
    2649             274 :   } while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult);
    2650              34 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2651                 : 
    2652              34 :   return NS_OK;
    2653                 : }
    2654                 : 
    2655                 : nsresult
    2656              24 : DeleteIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
    2657                 : {
    2658              24 :   NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
    2659                 : 
    2660                 :   nsCOMPtr<mozIStorageStatement> stmt =
    2661                 :     mTransaction->GetCachedStatement(
    2662                 :       "DELETE FROM object_store_index "
    2663                 :       "WHERE name = :name "
    2664              48 :     );
    2665              24 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2666                 : 
    2667              48 :   mozStorageStatementScoper scoper(stmt);
    2668                 : 
    2669              24 :   nsresult rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mName);
    2670              24 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2671                 : 
    2672              24 :   if (NS_FAILED(stmt->Execute())) {
    2673               0 :     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
    2674                 :   }
    2675                 : 
    2676              24 :   return NS_OK;
    2677                 : }
    2678                 : 
    2679                 : nsresult
    2680              17 : GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
    2681                 : {
    2682              34 :   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
    2683              34 :   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
    2684                 : 
    2685              34 :   nsCAutoString keyRangeClause;
    2686              17 :   if (mKeyRange) {
    2687              11 :     if (!mKeyRange->Lower().IsUnset()) {
    2688              11 :       keyRangeClause = NS_LITERAL_CSTRING(" AND key_value");
    2689              11 :       if (mKeyRange->IsLowerOpen()) {
    2690               1 :         keyRangeClause.AppendLiteral(" > :");
    2691                 :       }
    2692                 :       else {
    2693              10 :         keyRangeClause.AppendLiteral(" >= :");
    2694                 :       }
    2695              11 :       keyRangeClause.Append(lowerKeyName);
    2696                 :     }
    2697                 : 
    2698              11 :     if (!mKeyRange->Upper().IsUnset()) {
    2699              10 :       keyRangeClause += NS_LITERAL_CSTRING(" AND key_value");
    2700              10 :       if (mKeyRange->IsUpperOpen()) {
    2701               1 :         keyRangeClause.AppendLiteral(" < :");
    2702                 :       }
    2703                 :       else {
    2704               9 :         keyRangeClause.AppendLiteral(" <= :");
    2705                 :       }
    2706              10 :       keyRangeClause.Append(upperKeyName);
    2707                 :     }
    2708                 :   }
    2709                 : 
    2710              34 :   nsCAutoString limitClause;
    2711              17 :   if (mLimit != PR_UINT32_MAX) {
    2712               3 :     limitClause.AssignLiteral(" LIMIT ");
    2713               3 :     limitClause.AppendInt(mLimit);
    2714                 :   }
    2715                 : 
    2716              17 :   nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
    2717                 :                                        "WHERE object_store_id = :osid") +
    2718              17 :                     keyRangeClause +
    2719              51 :                     NS_LITERAL_CSTRING(" ORDER BY key_value ASC") +
    2720              34 :                     limitClause;
    2721                 : 
    2722              17 :   mCloneReadInfos.SetCapacity(50);
    2723                 : 
    2724              34 :   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
    2725              17 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2726                 : 
    2727              34 :   mozStorageStatementScoper scoper(stmt);
    2728                 : 
    2729              34 :   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
    2730              17 :                                       mObjectStore->Id());
    2731              17 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2732                 : 
    2733              17 :   if (mKeyRange) {
    2734              11 :     if (!mKeyRange->Lower().IsUnset()) {
    2735              11 :       rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
    2736              11 :       NS_ENSURE_SUCCESS(rv, rv);
    2737                 :     }
    2738              11 :     if (!mKeyRange->Upper().IsUnset()) {
    2739              10 :       rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
    2740              10 :       NS_ENSURE_SUCCESS(rv, rv);
    2741                 :     }
    2742                 :   }
    2743                 : 
    2744                 :   bool hasResult;
    2745             133 :   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
    2746              99 :     if (mCloneReadInfos.Capacity() == mCloneReadInfos.Length()) {
    2747               0 :       if (!mCloneReadInfos.SetCapacity(mCloneReadInfos.Capacity() * 2)) {
    2748               0 :         NS_ERROR("Out of memory!");
    2749               0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    2750                 :       }
    2751                 :     }
    2752                 : 
    2753              99 :     StructuredCloneReadInfo* readInfo = mCloneReadInfos.AppendElement();
    2754              99 :     NS_ASSERTION(readInfo, "Shouldn't fail if SetCapacity succeeded!");
    2755                 : 
    2756                 :     rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
    2757              99 :       mDatabase->Manager(), *readInfo);
    2758              99 :     NS_ENSURE_SUCCESS(rv, rv);
    2759                 :   }
    2760              17 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2761                 : 
    2762              17 :   return NS_OK;
    2763                 : }
    2764                 : 
    2765                 : nsresult
    2766              17 : GetAllHelper::GetSuccessResult(JSContext* aCx,
    2767                 :                                jsval* aVal)
    2768                 : {
    2769              17 :   NS_ASSERTION(mCloneReadInfos.Length() <= mLimit, "Too many results!");
    2770                 : 
    2771              17 :   nsresult rv = ConvertCloneReadInfosToArray(aCx, mCloneReadInfos, aVal);
    2772                 : 
    2773              17 :   for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
    2774               0 :     mCloneReadInfos[index].mCloneBuffer.clear();
    2775                 :   }
    2776                 : 
    2777              17 :   NS_ENSURE_SUCCESS(rv, rv);
    2778              17 :   return NS_OK;
    2779                 : }
    2780                 : 
    2781                 : nsresult
    2782              32 : CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
    2783                 : {
    2784              64 :   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
    2785              64 :   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
    2786                 : 
    2787              64 :   nsCAutoString keyRangeClause;
    2788              32 :   if (mKeyRange) {
    2789              15 :     if (!mKeyRange->Lower().IsUnset()) {
    2790              12 :       keyRangeClause = NS_LITERAL_CSTRING(" AND key_value");
    2791              12 :       if (mKeyRange->IsLowerOpen()) {
    2792               5 :         keyRangeClause.AppendLiteral(" > :");
    2793                 :       }
    2794                 :       else {
    2795               7 :         keyRangeClause.AppendLiteral(" >= :");
    2796                 :       }
    2797              12 :       keyRangeClause.Append(lowerKeyName);
    2798                 :     }
    2799                 : 
    2800              15 :     if (!mKeyRange->Upper().IsUnset()) {
    2801              12 :       keyRangeClause += NS_LITERAL_CSTRING(" AND key_value");
    2802              12 :       if (mKeyRange->IsUpperOpen()) {
    2803               5 :         keyRangeClause.AppendLiteral(" < :");
    2804                 :       }
    2805                 :       else {
    2806               7 :         keyRangeClause.AppendLiteral(" <= :");
    2807                 :       }
    2808              12 :       keyRangeClause.Append(upperKeyName);
    2809                 :     }
    2810                 :   }
    2811                 : 
    2812              32 :   nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM object_data "
    2813                 :                                        "WHERE object_store_id = :osid") +
    2814              64 :                     keyRangeClause;
    2815                 : 
    2816              64 :   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
    2817              32 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2818                 : 
    2819              64 :   mozStorageStatementScoper scoper(stmt);
    2820                 : 
    2821              64 :   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
    2822              32 :                                       mObjectStore->Id());
    2823              32 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2824                 : 
    2825              32 :   if (mKeyRange) {
    2826              15 :     if (!mKeyRange->Lower().IsUnset()) {
    2827              12 :       rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
    2828              12 :       NS_ENSURE_SUCCESS(rv, rv);
    2829                 :     }
    2830              15 :     if (!mKeyRange->Upper().IsUnset()) {
    2831              12 :       rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
    2832              12 :       NS_ENSURE_SUCCESS(rv, rv);
    2833                 :     }
    2834                 :   }
    2835                 : 
    2836                 :   bool hasResult;
    2837              32 :   rv = stmt->ExecuteStep(&hasResult);
    2838              32 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2839              32 :   NS_ENSURE_TRUE(hasResult, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    2840                 : 
    2841              32 :   mCount = stmt->AsInt64(0);
    2842              32 :   return NS_OK;
    2843                 : }
    2844                 : 
    2845                 : nsresult
    2846              32 : CountHelper::GetSuccessResult(JSContext* aCx,
    2847                 :                               jsval* aVal)
    2848                 : {
    2849              32 :   return JS_NewNumberValue(aCx, static_cast<double>(mCount), aVal);
    2850            4392 : }

Generated by: LCOV version 1.7