LCOV - code coverage report
Current view: directory - dom/indexedDB - IDBDatabase.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 356 287 80.6 %
Date: 2012-06-02 Functions: 49 43 87.8 %

       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 "IDBDatabase.h"
      41                 : 
      42                 : #include "mozilla/Mutex.h"
      43                 : #include "mozilla/storage.h"
      44                 : #include "nsDOMClassInfo.h"
      45                 : #include "nsDOMLists.h"
      46                 : #include "nsEventDispatcher.h"
      47                 : #include "nsJSUtils.h"
      48                 : #include "nsProxyRelease.h"
      49                 : #include "nsThreadUtils.h"
      50                 : 
      51                 : #include "AsyncConnectionHelper.h"
      52                 : #include "CheckQuotaHelper.h"
      53                 : #include "DatabaseInfo.h"
      54                 : #include "IDBEvents.h"
      55                 : #include "IDBIndex.h"
      56                 : #include "IDBObjectStore.h"
      57                 : #include "IDBTransaction.h"
      58                 : #include "IDBFactory.h"
      59                 : #include "IndexedDatabaseManager.h"
      60                 : #include "TransactionThreadPool.h"
      61                 : #include "DictionaryHelpers.h"
      62                 : #include "nsDOMEventTargetHelper.h"
      63                 : 
      64                 : USING_INDEXEDDB_NAMESPACE
      65                 : 
      66                 : namespace {
      67                 : 
      68                 : class CreateObjectStoreHelper : public AsyncConnectionHelper
      69             804 : {
      70                 : public:
      71             201 :   CreateObjectStoreHelper(IDBTransaction* aTransaction,
      72                 :                           IDBObjectStore* aObjectStore)
      73             201 :   : AsyncConnectionHelper(aTransaction, nsnull), mObjectStore(aObjectStore)
      74             201 :   { }
      75                 : 
      76                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
      77                 : 
      78             200 :   nsresult OnSuccess()
      79                 :   {
      80             200 :     return NS_OK;
      81                 :   }
      82                 : 
      83               1 :   void OnError()
      84                 :   {
      85               1 :     NS_ASSERTION(mTransaction->IsAborted(), "How else can this fail?!");
      86               1 :   }
      87                 : 
      88             201 :   void ReleaseMainThreadObjects()
      89                 :   {
      90             201 :     mObjectStore = nsnull;
      91             201 :     AsyncConnectionHelper::ReleaseMainThreadObjects();
      92             201 :   }
      93                 : 
      94                 : private:
      95                 :   nsRefPtr<IDBObjectStore> mObjectStore;
      96                 : };
      97                 : 
      98                 : class DeleteObjectStoreHelper : public AsyncConnectionHelper
      99             492 : {
     100                 : public:
     101             123 :   DeleteObjectStoreHelper(IDBTransaction* aTransaction,
     102                 :                           PRInt64 aObjectStoreId)
     103             123 :   : AsyncConnectionHelper(aTransaction, nsnull), mObjectStoreId(aObjectStoreId)
     104             123 :   { }
     105                 : 
     106                 :   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
     107                 : 
     108             123 :   nsresult OnSuccess()
     109                 :   {
     110             123 :     return NS_OK;
     111                 :   }
     112                 : 
     113               0 :   void OnError()
     114                 :   {
     115               0 :     NS_ASSERTION(mTransaction->IsAborted(), "How else can this fail?!");
     116               0 :   }
     117                 : 
     118                 : private:
     119                 :   // In-params.
     120                 :   PRInt64 mObjectStoreId;
     121                 : };
     122                 : 
     123                 : NS_STACK_CLASS
     124                 : class AutoRemoveObjectStore
     125                 : {
     126                 : public:
     127             201 :   AutoRemoveObjectStore(DatabaseInfo* aInfo, const nsAString& aName)
     128             201 :   : mInfo(aInfo), mName(aName)
     129             201 :   { }
     130                 : 
     131             201 :   ~AutoRemoveObjectStore()
     132             201 :   {
     133             201 :     if (mInfo) {
     134               0 :       mInfo->RemoveObjectStore(mName);
     135                 :     }
     136             201 :   }
     137                 : 
     138             201 :   void forget()
     139                 :   {
     140             201 :     mInfo = nsnull;
     141             201 :   }
     142                 : 
     143                 : private:
     144                 :   DatabaseInfo* mInfo;
     145                 :   nsString mName;
     146                 : };
     147                 : 
     148                 : } // anonymous namespace
     149                 : 
     150                 : // static
     151                 : already_AddRefed<IDBDatabase>
     152              75 : IDBDatabase::Create(IDBWrapperCache* aOwnerCache,
     153                 :                     already_AddRefed<DatabaseInfo> aDatabaseInfo,
     154                 :                     const nsACString& aASCIIOrigin,
     155                 :                     FileManager* aFileManager)
     156                 : {
     157              75 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     158              75 :   NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!");
     159                 : 
     160             150 :   nsRefPtr<DatabaseInfo> databaseInfo(aDatabaseInfo);
     161              75 :   NS_ASSERTION(databaseInfo, "Null pointer!");
     162                 : 
     163             150 :   nsRefPtr<IDBDatabase> db(new IDBDatabase());
     164                 : 
     165              75 :   db->BindToOwner(aOwnerCache);
     166              75 :   if (!db->SetScriptOwner(aOwnerCache->GetScriptOwner())) {
     167               0 :     return nsnull;
     168                 :   }
     169                 : 
     170              75 :   db->mDatabaseId = databaseInfo->id;
     171              75 :   db->mName = databaseInfo->name;
     172              75 :   db->mFilePath = databaseInfo->filePath;
     173              75 :   databaseInfo.swap(db->mDatabaseInfo);
     174              75 :   db->mASCIIOrigin = aASCIIOrigin;
     175              75 :   db->mFileManager = aFileManager;
     176                 : 
     177              75 :   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
     178              75 :   NS_ASSERTION(mgr, "This should never be null!");
     179                 : 
     180              75 :   if (!mgr->RegisterDatabase(db)) {
     181                 :     // Either out of memory or shutting down.
     182               0 :     return nsnull;
     183                 :   }
     184                 : 
     185              75 :   return db.forget();
     186                 : }
     187                 : 
     188              75 : IDBDatabase::IDBDatabase()
     189                 : : mDatabaseId(0),
     190                 :   mInvalidated(0),
     191                 :   mRegistered(false),
     192                 :   mClosed(false),
     193              75 :   mRunningVersionChange(false)
     194                 : {
     195              75 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     196              75 : }
     197                 : 
     198             225 : IDBDatabase::~IDBDatabase()
     199                 : {
     200              75 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     201                 : 
     202              75 :   if (mRegistered) {
     203              75 :     CloseInternal(true);
     204                 : 
     205              75 :     IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
     206              75 :     if (mgr) {
     207              12 :       mgr->UnregisterDatabase(this);
     208                 :     }
     209                 :   }
     210                 : 
     211              75 :   nsContentUtils::ReleaseWrapper(static_cast<nsIDOMEventTarget*>(this), this);
     212             300 : }
     213                 : 
     214                 : void
     215               0 : IDBDatabase::Invalidate()
     216                 : {
     217               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     218                 : 
     219                 :   // Make sure we're closed too.
     220               0 :   Close();
     221                 : 
     222                 :   // When the IndexedDatabaseManager needs to invalidate databases, all it has
     223                 :   // is an origin, so we call back into the manager to cancel any prompts for
     224                 :   // our owner.
     225               0 :   IndexedDatabaseManager::CancelPromptsForWindow(GetOwner());
     226                 : 
     227               0 :   mInvalidated = true;
     228               0 : }
     229                 : 
     230                 : bool
     231           12101 : IDBDatabase::IsInvalidated()
     232                 : {
     233           12101 :   return !!mInvalidated;
     234                 : }
     235                 : 
     236                 : void
     237             162 : IDBDatabase::CloseInternal(bool aIsDead)
     238                 : {
     239             162 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     240                 : 
     241             162 :   if (!mClosed) {
     242                 :     // If we're getting called from Unlink, avoid cloning the DatabaseInfo.
     243                 :     {
     244             150 :       nsRefPtr<DatabaseInfo> previousInfo;
     245              75 :       mDatabaseInfo.swap(previousInfo);
     246                 : 
     247              75 :       if (!aIsDead) {
     248              52 :         nsRefPtr<DatabaseInfo> clonedInfo = previousInfo->Clone();
     249                 : 
     250              26 :         clonedInfo.swap(mDatabaseInfo);
     251                 :       }
     252                 :     }
     253                 : 
     254              75 :     IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
     255              75 :     if (mgr) {
     256              31 :       mgr->OnDatabaseClosed(this);
     257                 :     }
     258              75 :     mClosed = true;
     259                 :   }
     260             162 : }
     261                 : 
     262                 : bool
     263             114 : IDBDatabase::IsClosed()
     264                 : {
     265             114 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     266             114 :   return mClosed;
     267                 : }
     268                 : 
     269                 : void
     270              71 : IDBDatabase::EnterSetVersionTransaction()
     271                 : {
     272              71 :   NS_ASSERTION(!mRunningVersionChange, "How did that happen?");
     273              71 :   mRunningVersionChange = true;
     274              71 : }
     275                 : 
     276                 : void
     277              71 : IDBDatabase::ExitSetVersionTransaction()
     278                 : {
     279              71 :   NS_ASSERTION(mRunningVersionChange, "How did that happen?");
     280              71 :   mRunningVersionChange = false;
     281              71 : }
     282                 : 
     283                 : void
     284              61 : IDBDatabase::OnUnlink()
     285                 : {
     286              61 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     287              61 :   NS_ASSERTION(!GetOwner() && !GetScriptOwner(),
     288                 :                "Should have been cleared already!");
     289                 : 
     290                 :   // We've been unlinked, at the very least we should be able to prevent further
     291                 :   // transactions from starting and unblock any other SetVersion callers.
     292              61 :   CloseInternal(true);
     293                 : 
     294                 :   // No reason for the IndexedDatabaseManager to track us any longer.
     295              61 :   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
     296              61 :   if (mgr) {
     297               0 :     mgr->UnregisterDatabase(this);
     298                 : 
     299                 :     // Don't try to unregister again in the destructor.
     300               0 :     mRegistered = false;
     301                 :   }
     302              61 : }
     303                 : 
     304            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(IDBDatabase)
     305                 : 
     306              62 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
     307              62 :   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(abort)
     308              62 :   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
     309              62 :   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(versionchange)
     310              62 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     311                 : 
     312              61 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
     313              61 :   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(abort)
     314              61 :   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
     315              61 :   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(versionchange)
     316                 : 
     317                 :   // Do some cleanup.
     318              61 :   tmp->OnUnlink();
     319              61 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     320                 : 
     321           18608 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBDatabase)
     322            9329 :   NS_INTERFACE_MAP_ENTRY(nsIIDBDatabase)
     323            8210 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBDatabase)
     324            8135 : NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
     325                 : 
     326           16404 : NS_IMPL_ADDREF_INHERITED(IDBDatabase, IDBWrapperCache)
     327           16404 : NS_IMPL_RELEASE_INHERITED(IDBDatabase, IDBWrapperCache)
     328                 : 
     329                 : DOMCI_DATA(IDBDatabase, IDBDatabase)
     330                 : 
     331               1 : NS_IMPL_EVENT_HANDLER(IDBDatabase, abort);
     332              13 : NS_IMPL_EVENT_HANDLER(IDBDatabase, error);
     333               1 : NS_IMPL_EVENT_HANDLER(IDBDatabase, versionchange);
     334                 : 
     335                 : NS_IMETHODIMP
     336               9 : IDBDatabase::GetName(nsAString& aName)
     337                 : {
     338               9 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     339               9 :   aName.Assign(mName);
     340               9 :   return NS_OK;
     341                 : }
     342                 : 
     343                 : NS_IMETHODIMP
     344              24 : IDBDatabase::GetVersion(PRUint64* aVersion)
     345                 : {
     346              24 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     347                 : 
     348              24 :   DatabaseInfo* info = Info();
     349              24 :   *aVersion = info->version;
     350                 : 
     351              24 :   return NS_OK;
     352                 : }
     353                 : 
     354                 : NS_IMETHODIMP
     355             219 : IDBDatabase::GetObjectStoreNames(nsIDOMDOMStringList** aObjectStores)
     356                 : {
     357             219 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     358                 : 
     359             219 :   DatabaseInfo* info = Info();
     360                 : 
     361             438 :   nsAutoTArray<nsString, 10> objectStoreNames;
     362             219 :   if (!info->GetObjectStoreNames(objectStoreNames)) {
     363               0 :     NS_WARNING("Couldn't get names!");
     364               0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     365                 :   }
     366                 : 
     367             438 :   nsRefPtr<nsDOMStringList> list(new nsDOMStringList());
     368             219 :   PRUint32 count = objectStoreNames.Length();
     369             904 :   for (PRUint32 index = 0; index < count; index++) {
     370             685 :     NS_ENSURE_TRUE(list->Add(objectStoreNames[index]),
     371                 :                    NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     372                 :   }
     373                 : 
     374             219 :   list.forget(aObjectStores);
     375             219 :   return NS_OK;
     376                 : }
     377                 : 
     378                 : NS_IMETHODIMP
     379             202 : IDBDatabase::CreateObjectStore(const nsAString& aName,
     380                 :                                const jsval& aOptions,
     381                 :                                JSContext* aCx,
     382                 :                                nsIIDBObjectStore** _retval)
     383                 : {
     384             202 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     385                 : 
     386             202 :   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
     387                 : 
     388             404 :   if (!transaction ||
     389             202 :       transaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
     390               0 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
     391                 :   }
     392                 : 
     393             202 :   DatabaseInfo* databaseInfo = transaction->DBInfo();
     394                 : 
     395             404 :   mozilla::dom::IDBObjectStoreParameters params;
     396             404 :   nsString keyPath;
     397             202 :   keyPath.SetIsVoid(true);
     398             404 :   nsTArray<nsString> keyPathArray;
     399                 : 
     400             202 :   if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
     401             185 :     nsresult rv = params.Init(aCx, &aOptions);
     402             185 :     NS_ENSURE_SUCCESS(rv, rv);
     403                 : 
     404                 :     // Get keyPath
     405             184 :     jsval val = params.keyPath;
     406             184 :     if (!JSVAL_IS_VOID(val) && !JSVAL_IS_NULL(val)) {
     407             125 :       if (!JSVAL_IS_PRIMITIVE(val) &&
     408               0 :           JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(val))) {
     409                 :     
     410               0 :         JSObject* obj = JSVAL_TO_OBJECT(val);
     411                 :     
     412                 :         uint32_t length;
     413               0 :         if (!JS_GetArrayLength(aCx, obj, &length)) {
     414               0 :           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     415                 :         }
     416                 :     
     417               0 :         if (!length) {
     418               0 :           return NS_ERROR_DOM_SYNTAX_ERR;
     419                 :         }
     420                 :     
     421               0 :         keyPathArray.SetCapacity(length);
     422                 :     
     423               0 :         for (uint32_t index = 0; index < length; index++) {
     424                 :           jsval val;
     425                 :           JSString* jsstr;
     426               0 :           nsDependentJSString str;
     427               0 :           if (!JS_GetElement(aCx, obj, index, &val) ||
     428                 :               !(jsstr = JS_ValueToString(aCx, val)) ||
     429               0 :               !str.init(aCx, jsstr)) {
     430               0 :             return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     431                 :           }
     432                 :     
     433               0 :           if (!IDBObjectStore::IsValidKeyPath(aCx, str)) {
     434               0 :             return NS_ERROR_DOM_SYNTAX_ERR;
     435                 :           }
     436                 :     
     437               0 :           keyPathArray.AppendElement(str);
     438                 :         }
     439                 :     
     440               0 :         NS_ASSERTION(!keyPathArray.IsEmpty(), "This shouldn't have happened!");
     441                 :       }
     442                 :       else {
     443                 :         JSString* jsstr;
     444             250 :         nsDependentJSString str;
     445             250 :         if (!(jsstr = JS_ValueToString(aCx, val)) ||
     446             125 :             !str.init(aCx, jsstr)) {
     447               0 :           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     448                 :         }
     449                 :     
     450             125 :         if (!IDBObjectStore::IsValidKeyPath(aCx, str)) {
     451               0 :           return NS_ERROR_DOM_SYNTAX_ERR;
     452                 :         }
     453                 :     
     454             250 :         keyPath = str;
     455                 :       }
     456                 :     }
     457                 :   }
     458                 : 
     459             201 :   if (databaseInfo->ContainsStoreName(aName)) {
     460               0 :     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
     461                 :   }
     462                 : 
     463             428 :   if (params.autoIncrement &&
     464             227 :       ((!keyPath.IsVoid() && keyPath.IsEmpty()) || !keyPathArray.IsEmpty())) {
     465               0 :     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
     466                 :   }
     467                 : 
     468             402 :   nsRefPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo());
     469                 : 
     470             201 :   newInfo->name = aName;
     471             201 :   newInfo->id = databaseInfo->nextObjectStoreId++;
     472             201 :   newInfo->keyPath = keyPath;
     473             201 :   newInfo->keyPathArray = keyPathArray;
     474             201 :   newInfo->nextAutoIncrementId = params.autoIncrement ? 1 : 0;
     475             201 :   newInfo->comittedAutoIncrementId = newInfo->nextAutoIncrementId;
     476                 : 
     477             201 :   if (!databaseInfo->PutObjectStore(newInfo)) {
     478               0 :     NS_WARNING("Put failed!");
     479               0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     480                 :   }
     481                 : 
     482                 :   // Don't leave this in the hash if we fail below!
     483             402 :   AutoRemoveObjectStore autoRemove(databaseInfo, aName);
     484                 : 
     485                 :   nsRefPtr<IDBObjectStore> objectStore =
     486             402 :     transaction->GetOrCreateObjectStore(aName, newInfo);
     487             201 :   NS_ENSURE_TRUE(objectStore, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     488                 : 
     489                 :   nsRefPtr<CreateObjectStoreHelper> helper =
     490             603 :     new CreateObjectStoreHelper(transaction, objectStore);
     491                 : 
     492             201 :   nsresult rv = helper->DispatchToTransactionPool();
     493             201 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     494                 : 
     495             201 :   autoRemove.forget();
     496                 : 
     497             201 :   objectStore.forget(_retval);
     498             201 :   return NS_OK;
     499                 : }
     500                 : 
     501                 : NS_IMETHODIMP
     502             123 : IDBDatabase::DeleteObjectStore(const nsAString& aName)
     503                 : {
     504             123 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     505                 : 
     506             123 :   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
     507                 : 
     508             246 :   if (!transaction ||
     509             123 :       transaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
     510               0 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
     511                 :   }
     512                 : 
     513             123 :   DatabaseInfo* info = transaction->DBInfo();
     514             123 :   ObjectStoreInfo* objectStoreInfo = info->GetObjectStore(aName);
     515             123 :   if (!objectStoreInfo) {
     516               0 :     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
     517                 :   }
     518                 : 
     519                 :   nsRefPtr<DeleteObjectStoreHelper> helper =
     520             246 :     new DeleteObjectStoreHelper(transaction, objectStoreInfo->id);
     521             123 :   nsresult rv = helper->DispatchToTransactionPool();
     522             123 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     523                 : 
     524             123 :   transaction->RemoveObjectStore(aName);
     525                 : 
     526             123 :   return NS_OK;
     527                 : }
     528                 : 
     529                 : NS_IMETHODIMP
     530             471 : IDBDatabase::Transaction(const jsval& aStoreNames,
     531                 :                          const nsAString& aMode,
     532                 :                          JSContext* aCx,
     533                 :                          PRUint8 aOptionalArgCount,
     534                 :                          nsIIDBTransaction** _retval)
     535                 : {
     536             471 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     537                 : 
     538             471 :   if (IndexedDatabaseManager::IsShuttingDown()) {
     539               0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     540                 :   }
     541                 : 
     542             471 :   if (mClosed) {
     543               0 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
     544                 :   }
     545                 : 
     546             471 :   if (mRunningVersionChange) {
     547               2 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
     548                 :   }
     549                 : 
     550             469 :   IDBTransaction::Mode transactionMode = IDBTransaction::READ_ONLY;
     551             469 :   if (aOptionalArgCount) {
     552             298 :     if (aMode.EqualsLiteral("readwrite")) {
     553             297 :       transactionMode = IDBTransaction::READ_WRITE;
     554                 :     }
     555               1 :     else if (!aMode.EqualsLiteral("readonly")) {
     556               0 :       return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
     557                 :     }
     558                 :   }
     559                 : 
     560                 :   nsresult rv;
     561             938 :   nsTArray<nsString> storesToOpen;
     562                 : 
     563             469 :   if (!JSVAL_IS_PRIMITIVE(aStoreNames)) {
     564             253 :     JSObject* obj = JSVAL_TO_OBJECT(aStoreNames);
     565                 : 
     566                 :     // See if this is a JS array.
     567             253 :     if (JS_IsArrayObject(aCx, obj)) {
     568                 :       uint32_t length;
     569             251 :       if (!JS_GetArrayLength(aCx, obj, &length)) {
     570               0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     571                 :       }
     572                 : 
     573             251 :       if (!length) {
     574               0 :         return NS_ERROR_DOM_INVALID_ACCESS_ERR;
     575                 :       }
     576                 : 
     577             251 :       storesToOpen.SetCapacity(length);
     578                 : 
     579             602 :       for (uint32_t index = 0; index < length; index++) {
     580                 :         jsval val;
     581                 :         JSString* jsstr;
     582             702 :         nsDependentJSString str;
     583             702 :         if (!JS_GetElement(aCx, obj, index, &val) ||
     584                 :             !(jsstr = JS_ValueToString(aCx, val)) ||
     585             351 :             !str.init(aCx, jsstr)) {
     586               0 :           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     587                 :         }
     588                 : 
     589             702 :         storesToOpen.AppendElement(str);
     590                 :       }
     591                 : 
     592             251 :       NS_ASSERTION(!storesToOpen.IsEmpty(),
     593                 :                    "Must have something here or else code below will "
     594                 :                    "misbehave!");
     595                 :     }
     596                 :     else {
     597                 :       // Perhaps some kind of wrapped object?
     598               2 :       nsIXPConnect* xpc = nsContentUtils::XPConnect();
     599               2 :       NS_ASSERTION(xpc, "This should never be null!");
     600                 : 
     601               4 :       nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
     602               2 :       rv = xpc->GetWrappedNativeOfJSObject(aCx, obj, getter_AddRefs(wrapper));
     603               2 :       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     604                 : 
     605               2 :       if (wrapper) {
     606               2 :         nsISupports* wrappedObject = wrapper->Native();
     607               2 :         NS_ENSURE_TRUE(wrappedObject, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     608                 : 
     609                 :         // We only accept DOMStringList.
     610               4 :         nsCOMPtr<nsIDOMDOMStringList> list = do_QueryInterface(wrappedObject);
     611               2 :         if (list) {
     612                 :           PRUint32 length;
     613               2 :           rv = list->GetLength(&length);
     614               2 :           NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     615                 : 
     616               2 :           if (!length) {
     617               0 :             return NS_ERROR_DOM_INVALID_ACCESS_ERR;
     618                 :           }
     619                 : 
     620               2 :           storesToOpen.SetCapacity(length);
     621                 : 
     622               4 :           for (PRUint32 index = 0; index < length; index++) {
     623               2 :             nsString* item = storesToOpen.AppendElement();
     624               2 :             NS_ASSERTION(item, "This should never fail!");
     625                 : 
     626               2 :             rv = list->Item(index, *item);
     627               2 :             NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     628                 :           }
     629                 : 
     630               2 :           NS_ASSERTION(!storesToOpen.IsEmpty(),
     631                 :                        "Must have something here or else code below will "
     632                 :                        "misbehave!");
     633                 :         }
     634                 :       }
     635                 :     }
     636                 :   }
     637                 : 
     638                 :   // If our list is empty here then the argument must have been an object that
     639                 :   // we don't support or a primitive. Either way we convert to a string.
     640             469 :   if (storesToOpen.IsEmpty()) {
     641                 :     JSString* jsstr;
     642             432 :     nsDependentJSString str;
     643             432 :     if (!(jsstr = JS_ValueToString(aCx, aStoreNames)) ||
     644             216 :         !str.init(aCx, jsstr)) {
     645               0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     646                 :     }
     647                 : 
     648             432 :     storesToOpen.AppendElement(str);
     649                 :   }
     650                 : 
     651                 :   // Now check to make sure the object store names we collected actually exist.
     652             469 :   DatabaseInfo* info = Info();
     653            1038 :   for (PRUint32 index = 0; index < storesToOpen.Length(); index++) {
     654             569 :     if (!info->ContainsStoreName(storesToOpen[index])) {
     655               0 :       return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
     656                 :     }
     657                 :   }
     658                 : 
     659                 :   nsRefPtr<IDBTransaction> transaction =
     660             938 :     IDBTransaction::Create(this, storesToOpen, transactionMode, false);
     661             469 :   NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     662                 : 
     663             469 :   transaction.forget(_retval);
     664             469 :   return NS_OK;
     665                 : }
     666                 : 
     667                 : NS_IMETHODIMP
     668              26 : IDBDatabase::Close()
     669                 : {
     670              26 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     671                 : 
     672              26 :   CloseInternal(false);
     673                 : 
     674              26 :   NS_ASSERTION(mClosed, "Should have set the closed flag!");
     675              26 :   return NS_OK;
     676                 : }
     677                 : 
     678                 : nsresult
     679              44 : IDBDatabase::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
     680                 : {
     681              44 :   NS_ENSURE_TRUE(aVisitor.mDOMEvent, NS_ERROR_UNEXPECTED);
     682                 : 
     683              44 :   if (!GetOwner()) {
     684              44 :     return NS_OK;
     685                 :   }
     686                 : 
     687               0 :   if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
     688               0 :     nsString type;
     689               0 :     nsresult rv = aVisitor.mDOMEvent->GetType(type);
     690               0 :     NS_ENSURE_SUCCESS(rv, rv);
     691                 : 
     692               0 :     if (type.EqualsLiteral(ERROR_EVT_STR)) {
     693                 :       nsRefPtr<nsDOMEvent> duplicateEvent =
     694               0 :         CreateGenericEvent(type, eDoesNotBubble, eNotCancelable);
     695               0 :       NS_ENSURE_STATE(duplicateEvent);
     696                 : 
     697               0 :       nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(GetOwner()));
     698               0 :       NS_ASSERTION(target, "How can this happen?!");
     699                 : 
     700                 :       bool dummy;
     701               0 :       rv = target->DispatchEvent(duplicateEvent, &dummy);
     702               0 :       NS_ENSURE_SUCCESS(rv, rv);
     703                 :     }
     704                 :   }
     705                 : 
     706               0 :   return NS_OK;
     707                 : }
     708                 : 
     709                 : nsresult
     710             201 : CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
     711                 : {
     712                 :   nsCOMPtr<mozIStorageStatement> stmt =
     713             201 :     mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
     714                 :     "INSERT INTO object_store (id, auto_increment, name, key_path) "
     715                 :     "VALUES (:id, :auto_increment, :name, :key_path)"
     716             402 :   ));
     717             201 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     718                 : 
     719             402 :   mozStorageStatementScoper scoper(stmt);
     720                 : 
     721             402 :   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
     722             201 :                                        mObjectStore->Id());
     723             201 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     724                 : 
     725             402 :   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("auto_increment"),
     726             201 :                              mObjectStore->IsAutoIncrement() ? 1 : 0);
     727             201 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     728                 : 
     729             201 :   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mObjectStore->Name());
     730             201 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     731                 : 
     732             201 :   if (mObjectStore->UsesKeyPathArray()) {
     733                 :     // We use a comma in the beginning to indicate that it's an array of
     734                 :     // key paths. This is to be able to tell a string-keypath from an
     735                 :     // array-keypath which contains only one item.
     736                 :     // It also makes serializing easier :-)
     737               0 :     nsAutoString keyPath;
     738               0 :     const nsTArray<nsString>& keyPaths = mObjectStore->KeyPathArray();
     739               0 :     for (PRUint32 i = 0; i < keyPaths.Length(); ++i) {
     740               0 :       keyPath.Append(NS_LITERAL_STRING(",") + keyPaths[i]);
     741                 :     }
     742               0 :     rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
     743               0 :                                 keyPath);
     744               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     745                 :   }
     746             201 :   else if (mObjectStore->HasKeyPath()) {
     747             250 :     rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
     748             125 :                                 mObjectStore->KeyPath());
     749             125 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     750                 :   }
     751                 :   else {
     752              76 :     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("key_path"));
     753              76 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     754                 :   }
     755                 : 
     756                 : 
     757             201 :   rv = stmt->Execute();
     758             201 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     759                 : 
     760             201 :   return NS_OK;
     761                 : }
     762                 : 
     763                 : nsresult
     764             123 : DeleteObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
     765                 : {
     766                 :   nsCOMPtr<mozIStorageStatement> stmt =
     767             123 :     mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
     768                 :     "DELETE FROM object_store "
     769                 :     "WHERE id = :id "
     770             246 :   ));
     771             123 :   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     772                 : 
     773             246 :   mozStorageStatementScoper scoper(stmt);
     774                 : 
     775             123 :   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mObjectStoreId);
     776             123 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     777                 : 
     778             123 :   rv = stmt->Execute();
     779             123 :   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     780                 : 
     781             123 :   return NS_OK;
     782            4392 : }

Generated by: LCOV version 1.7