Bumping manifests a=b2g-bump
[gecko.git] / dom / indexedDB / IDBDatabase.cpp
blob5664d0d9d35a9e7626634be5c2b56cc907f10c2c
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "base/basictypes.h"
9 #include "IDBDatabase.h"
11 #include "mozilla/EventDispatcher.h"
12 #include "mozilla/Mutex.h"
13 #include "mozilla/storage.h"
14 #include "mozilla/dom/nsIContentParent.h"
15 #include "mozilla/dom/DOMStringList.h"
16 #include "mozilla/dom/DOMStringListBinding.h"
17 #include "mozilla/dom/quota/Client.h"
18 #include "mozilla/dom/quota/QuotaManager.h"
19 #include "nsJSUtils.h"
20 #include "nsProxyRelease.h"
21 #include "nsThreadUtils.h"
23 #include "AsyncConnectionHelper.h"
24 #include "DatabaseInfo.h"
25 #include "IDBEvents.h"
26 #include "IDBFactory.h"
27 #include "IDBIndex.h"
28 #include "IDBMutableFile.h"
29 #include "IDBObjectStore.h"
30 #include "IDBTransaction.h"
31 #include "IDBFactory.h"
32 #include "ProfilerHelpers.h"
33 #include "ReportInternalError.h"
34 #include "TransactionThreadPool.h"
36 #include "ipc/IndexedDBChild.h"
37 #include "ipc/IndexedDBParent.h"
39 #include "mozilla/dom/IDBDatabaseBinding.h"
41 USING_INDEXEDDB_NAMESPACE
42 using mozilla::dom::nsIContentParent;
43 using mozilla::dom::quota::AssertIsOnIOThread;
44 using mozilla::dom::quota::Client;
45 using mozilla::dom::quota::QuotaManager;
46 using mozilla::ErrorResult;
47 using namespace mozilla;
48 using namespace mozilla::dom;
50 namespace {
52 class NoRequestDatabaseHelper : public AsyncConnectionHelper
54 public:
55 NoRequestDatabaseHelper(IDBTransaction* aTransaction)
56 : AsyncConnectionHelper(aTransaction, nullptr)
58 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
59 NS_ASSERTION(aTransaction, "Null transaction!");
62 virtual ChildProcessSendResult
63 SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
65 virtual nsresult
66 UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
67 MOZ_OVERRIDE;
69 virtual nsresult OnSuccess() MOZ_OVERRIDE;
71 virtual void OnError() MOZ_OVERRIDE;
74 class CreateObjectStoreHelper : public NoRequestDatabaseHelper
76 public:
77 CreateObjectStoreHelper(IDBTransaction* aTransaction,
78 IDBObjectStore* aObjectStore)
79 : NoRequestDatabaseHelper(aTransaction), mObjectStore(aObjectStore)
80 { }
82 virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
83 MOZ_OVERRIDE;
85 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
87 private:
88 nsRefPtr<IDBObjectStore> mObjectStore;
91 class DeleteObjectStoreHelper : public NoRequestDatabaseHelper
93 public:
94 DeleteObjectStoreHelper(IDBTransaction* aTransaction,
95 int64_t aObjectStoreId)
96 : NoRequestDatabaseHelper(aTransaction), mObjectStoreId(aObjectStoreId)
97 { }
99 virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
100 MOZ_OVERRIDE;
102 private:
103 // In-params.
104 int64_t mObjectStoreId;
107 class CreateFileHelper : public AsyncConnectionHelper
109 public:
110 CreateFileHelper(IDBDatabase* aDatabase,
111 IDBRequest* aRequest,
112 const nsAString& aName,
113 const nsAString& aType)
114 : AsyncConnectionHelper(aDatabase, aRequest),
115 mName(aName), mType(aType)
118 ~CreateFileHelper()
121 nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
122 nsresult GetSuccessResult(JSContext* aCx,
123 JS::MutableHandle<JS::Value> aVal);
124 void ReleaseMainThreadObjects()
126 mFileInfo = nullptr;
127 AsyncConnectionHelper::ReleaseMainThreadObjects();
130 virtual ChildProcessSendResult SendResponseToChildProcess(
131 nsresult aResultCode)
132 MOZ_OVERRIDE
134 return Success_NotSent;
137 virtual nsresult UnpackResponseFromParentProcess(
138 const ResponseValue& aResponseValue)
139 MOZ_OVERRIDE
141 MOZ_CRASH("Should never get here!");
144 private:
145 // In-params.
146 nsString mName;
147 nsString mType;
149 // Out-params.
150 nsRefPtr<FileInfo> mFileInfo;
153 class MOZ_STACK_CLASS AutoRemoveObjectStore
155 public:
156 AutoRemoveObjectStore(DatabaseInfo* aInfo, const nsAString& aName)
157 : mInfo(aInfo), mName(aName)
160 ~AutoRemoveObjectStore()
162 if (mInfo) {
163 mInfo->RemoveObjectStore(mName);
167 void forget()
169 mInfo = nullptr;
172 private:
173 DatabaseInfo* mInfo;
174 nsString mName;
177 } // anonymous namespace
179 // static
180 already_AddRefed<IDBDatabase>
181 IDBDatabase::Create(IDBWrapperCache* aOwnerCache,
182 IDBFactory* aFactory,
183 already_AddRefed<DatabaseInfo> aDatabaseInfo,
184 const nsACString& aASCIIOrigin,
185 FileManager* aFileManager,
186 mozilla::dom::nsIContentParent* aContentParent)
188 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
189 NS_ASSERTION(aFactory, "Null pointer!");
190 NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!");
192 nsRefPtr<DatabaseInfo> databaseInfo(aDatabaseInfo);
193 NS_ASSERTION(databaseInfo, "Null pointer!");
195 nsRefPtr<IDBDatabase> db(new IDBDatabase(aOwnerCache));
197 db->SetScriptOwner(aOwnerCache->GetScriptOwner());
198 db->mFactory = aFactory;
199 db->mDatabaseId = databaseInfo->id;
200 db->mName = databaseInfo->name;
201 db->mFilePath = databaseInfo->filePath;
202 db->mPersistenceType = databaseInfo->persistenceType;
203 db->mGroup = databaseInfo->group;
204 databaseInfo.swap(db->mDatabaseInfo);
205 db->mASCIIOrigin = aASCIIOrigin;
206 db->mFileManager = aFileManager;
207 db->mContentParent = aContentParent;
209 QuotaManager* quotaManager = QuotaManager::Get();
210 NS_ASSERTION(quotaManager, "This should never be null!");
212 db->mQuotaClient = quotaManager->GetClient(Client::IDB);
213 NS_ASSERTION(db->mQuotaClient, "This shouldn't fail!");
215 if (!quotaManager->RegisterStorage(db)) {
216 // Either out of memory or shutting down.
217 return nullptr;
220 db->mRegistered = true;
222 return db.forget();
225 // static
226 IDBDatabase*
227 IDBDatabase::FromStorage(nsIOfflineStorage* aStorage)
229 return aStorage->GetClient()->GetType() == Client::IDB ?
230 static_cast<IDBDatabase*>(aStorage) : nullptr;
233 IDBDatabase::IDBDatabase(IDBWrapperCache* aOwnerCache)
234 : IDBWrapperCache(aOwnerCache),
235 mActorChild(nullptr),
236 mActorParent(nullptr),
237 mContentParent(nullptr),
238 mInvalidated(false),
239 mRegistered(false),
240 mClosed(false),
241 mRunningVersionChange(false)
243 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
246 IDBDatabase::~IDBDatabase()
248 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
251 void
252 IDBDatabase::LastRelease()
254 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
256 NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
257 if (mActorChild) {
258 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
259 mActorChild->Send__delete__(mActorChild);
260 NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
263 if (mRegistered) {
264 CloseInternal(true);
266 QuotaManager* quotaManager = QuotaManager::Get();
267 if (quotaManager) {
268 quotaManager->UnregisterStorage(this);
270 mRegistered = false;
274 NS_IMETHODIMP_(void)
275 IDBDatabase::Invalidate()
277 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
279 InvalidateInternal(/* aIsDead */ false);
282 void
283 IDBDatabase::InvalidateInternal(bool aIsDead)
285 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
287 if (IsInvalidated()) {
288 return;
291 mInvalidated = true;
293 // Make sure we're closed too.
294 Close();
296 // When the IndexedDatabaseManager needs to invalidate databases, all it has
297 // is an origin, so we call into the quota manager here to cancel any prompts
298 // for our owner.
299 nsPIDOMWindow* owner = GetOwner();
300 if (owner) {
301 QuotaManager::CancelPromptsForWindow(owner);
304 // We want to forcefully remove in the child when the parent has invalidated
305 // us in IPC mode because the database might no longer exist.
306 // We don't want to forcefully remove in the parent when a child dies since
307 // other child processes may be using the referenced DatabaseInfo.
308 if (!aIsDead) {
309 DatabaseInfo::Remove(mDatabaseId);
312 // And let the child process know as well.
313 if (mActorParent) {
314 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
315 mActorParent->Invalidate();
319 void
320 IDBDatabase::DisconnectFromActorParent()
322 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
323 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
325 // Make sure we're closed too.
326 Close();
328 // Kill any outstanding prompts.
329 nsPIDOMWindow* owner = GetOwner();
330 if (owner) {
331 QuotaManager::CancelPromptsForWindow(owner);
335 void
336 IDBDatabase::CloseInternal(bool aIsDead)
338 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
340 if (!mClosed) {
341 mClosed = true;
343 // If we're getting called from Unlink, avoid cloning the DatabaseInfo.
345 nsRefPtr<DatabaseInfo> previousInfo;
346 mDatabaseInfo.swap(previousInfo);
348 if (!aIsDead) {
349 mDatabaseInfo = previousInfo->Clone();
353 QuotaManager* quotaManager = QuotaManager::Get();
354 if (quotaManager) {
355 quotaManager->OnStorageClosed(this);
358 // And let the parent process know as well.
359 if (mActorChild && !IsInvalidated()) {
360 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
361 mActorChild->SendClose(aIsDead);
366 NS_IMETHODIMP_(bool)
367 IDBDatabase::IsClosed()
369 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
370 return mClosed;
373 void
374 IDBDatabase::EnterSetVersionTransaction()
376 NS_ASSERTION(!mRunningVersionChange, "How did that happen?");
378 mPreviousDatabaseInfo = mDatabaseInfo->Clone();
380 mRunningVersionChange = true;
383 void
384 IDBDatabase::ExitSetVersionTransaction()
386 NS_ASSERTION(mRunningVersionChange, "How did that happen?");
388 mPreviousDatabaseInfo = nullptr;
390 mRunningVersionChange = false;
393 void
394 IDBDatabase::RevertToPreviousState()
396 mDatabaseInfo = mPreviousDatabaseInfo;
397 mPreviousDatabaseInfo = nullptr;
400 void
401 IDBDatabase::OnUnlink()
403 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
405 // We've been unlinked, at the very least we should be able to prevent further
406 // transactions from starting and unblock any other SetVersion callers.
407 CloseInternal(true);
409 // No reason for the QuotaManager to track us any longer.
410 QuotaManager* quotaManager = QuotaManager::Get();
411 if (mRegistered && quotaManager) {
412 quotaManager->UnregisterStorage(this);
414 // Don't try to unregister again in the destructor.
415 mRegistered = false;
419 already_AddRefed<IDBObjectStore>
420 IDBDatabase::CreateObjectStoreInternal(IDBTransaction* aTransaction,
421 const ObjectStoreInfoGuts& aInfo,
422 ErrorResult& aRv)
424 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
425 NS_ASSERTION(aTransaction, "Null transaction!");
427 DatabaseInfo* databaseInfo = aTransaction->DBInfo();
429 nsRefPtr<ObjectStoreInfo> newInfo = new ObjectStoreInfo();
430 *static_cast<ObjectStoreInfoGuts*>(newInfo.get()) = aInfo;
432 newInfo->nextAutoIncrementId = aInfo.autoIncrement ? 1 : 0;
433 newInfo->comittedAutoIncrementId = newInfo->nextAutoIncrementId;
435 if (!databaseInfo->PutObjectStore(newInfo)) {
436 IDB_WARNING("Put failed!");
437 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
438 return nullptr;
441 // Don't leave this in the hash if we fail below!
442 AutoRemoveObjectStore autoRemove(databaseInfo, newInfo->name);
444 nsRefPtr<IDBObjectStore> objectStore =
445 aTransaction->GetOrCreateObjectStore(newInfo->name, newInfo, true);
446 if (!objectStore) {
447 IDB_WARNING("Failed to get objectStore!");
448 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
449 return nullptr;
452 if (IndexedDatabaseManager::IsMainProcess()) {
453 nsRefPtr<CreateObjectStoreHelper> helper =
454 new CreateObjectStoreHelper(aTransaction, objectStore);
456 nsresult rv = helper->DispatchToTransactionPool();
457 if (NS_FAILED(rv)) {
458 IDB_WARNING("Failed to dispatch!");
459 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
460 return nullptr;
464 autoRemove.forget();
466 IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
467 "database(%s).transaction(%s).createObjectStore(%s)",
468 "MT IDBDatabase.createObjectStore()",
469 IDB_PROFILER_STRING(this),
470 IDB_PROFILER_STRING(aTransaction),
471 IDB_PROFILER_STRING(objectStore));
473 return objectStore.forget();
476 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBDatabase)
478 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
479 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFactory)
480 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
482 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
483 // Don't unlink mFactory!
485 // Do some cleanup.
486 tmp->OnUnlink();
487 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
489 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBDatabase)
490 NS_INTERFACE_MAP_ENTRY(nsIOfflineStorage)
491 NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
493 NS_IMPL_ADDREF_INHERITED(IDBDatabase, IDBWrapperCache)
494 NS_IMPL_RELEASE_INHERITED(IDBDatabase, IDBWrapperCache)
496 JSObject*
497 IDBDatabase::WrapObject(JSContext* aCx)
499 return IDBDatabaseBinding::Wrap(aCx, this);
502 uint64_t
503 IDBDatabase::Version() const
505 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
506 DatabaseInfo* info = Info();
507 return info->version;
510 already_AddRefed<DOMStringList>
511 IDBDatabase::GetObjectStoreNames(ErrorResult& aRv) const
513 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
515 DatabaseInfo* info = Info();
517 nsRefPtr<DOMStringList> list(new DOMStringList());
518 if (!info->GetObjectStoreNames(list->StringArray())) {
519 IDB_WARNING("Couldn't get names!");
520 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
521 return nullptr;
524 return list.forget();
527 already_AddRefed<IDBObjectStore>
528 IDBDatabase::CreateObjectStore(
529 JSContext* aCx, const nsAString& aName,
530 const IDBObjectStoreParameters& aOptionalParameters,
531 ErrorResult& aRv)
533 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
535 IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
537 if (!transaction ||
538 transaction->Database() != this ||
539 transaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
540 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
541 return nullptr;
544 DatabaseInfo* databaseInfo = transaction->DBInfo();
546 KeyPath keyPath(0);
547 if (NS_FAILED(KeyPath::Parse(aCx, aOptionalParameters.mKeyPath, &keyPath))) {
548 aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
549 return nullptr;
552 if (databaseInfo->ContainsStoreName(aName)) {
553 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR);
554 return nullptr;
557 if (!keyPath.IsAllowedForObjectStore(aOptionalParameters.mAutoIncrement)) {
558 aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
559 return nullptr;
562 ObjectStoreInfoGuts guts;
564 guts.name = aName;
565 guts.id = databaseInfo->nextObjectStoreId++;
566 guts.keyPath = keyPath;
567 guts.autoIncrement = aOptionalParameters.mAutoIncrement;
569 return CreateObjectStoreInternal(transaction, guts, aRv);
572 void
573 IDBDatabase::DeleteObjectStore(const nsAString& aName, ErrorResult& aRv)
575 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
577 IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
579 if (!transaction ||
580 transaction->Database() != this ||
581 transaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
582 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
583 return;
586 DatabaseInfo* info = transaction->DBInfo();
587 ObjectStoreInfo* objectStoreInfo = info->GetObjectStore(aName);
588 if (!objectStoreInfo) {
589 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
590 return;
593 if (IndexedDatabaseManager::IsMainProcess()) {
594 nsRefPtr<DeleteObjectStoreHelper> helper =
595 new DeleteObjectStoreHelper(transaction, objectStoreInfo->id);
597 nsresult rv = helper->DispatchToTransactionPool();
598 if (NS_FAILED(rv)) {
599 IDB_WARNING("Failed to dispatch!");
600 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
601 return;
604 else {
605 IndexedDBTransactionChild* actor = transaction->GetActorChild();
606 NS_ASSERTION(actor, "Must have an actor here!");
608 actor->SendDeleteObjectStore(nsString(aName));
611 transaction->RemoveObjectStore(aName);
613 IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
614 "database(%s).transaction(%s).deleteObjectStore(\"%s\")",
615 "MT IDBDatabase.deleteObjectStore()",
616 IDB_PROFILER_STRING(this),
617 IDB_PROFILER_STRING(transaction),
618 NS_ConvertUTF16toUTF8(aName).get());
621 already_AddRefed<indexedDB::IDBTransaction>
622 IDBDatabase::Transaction(const Sequence<nsString>& aStoreNames,
623 IDBTransactionMode aMode, ErrorResult& aRv)
625 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
627 if (QuotaManager::IsShuttingDown()) {
628 IDB_REPORT_INTERNAL_ERR();
629 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
630 return nullptr;
633 if (mClosed) {
634 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
635 return nullptr;
638 if (mRunningVersionChange) {
639 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
640 return nullptr;
643 if (aStoreNames.IsEmpty()) {
644 aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
645 return nullptr;
648 IDBTransaction::Mode transactionMode = IDBTransaction::READ_ONLY;
649 switch (aMode) {
650 case IDBTransactionMode::Readonly:
651 transactionMode = IDBTransaction::READ_ONLY;
652 break;
653 case IDBTransactionMode::Readwrite:
654 transactionMode = IDBTransaction::READ_WRITE;
655 break;
656 case IDBTransactionMode::Versionchange:
657 transactionMode = IDBTransaction::VERSION_CHANGE;
658 break;
659 default:
660 MOZ_CRASH("Unknown mode!");
663 // Now check to make sure the object store names we collected actually exist.
664 DatabaseInfo* info = Info();
665 for (uint32_t index = 0; index < aStoreNames.Length(); index++) {
666 if (!info->ContainsStoreName(aStoreNames[index])) {
667 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
668 return nullptr;
672 nsRefPtr<IDBTransaction> transaction =
673 IDBTransaction::Create(this, aStoreNames, transactionMode, false);
674 if (!transaction) {
675 IDB_WARNING("Failed to create the transaction!");
676 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
677 return nullptr;
680 IDB_PROFILER_MARK("IndexedDB Transaction %llu: database(%s).transaction(%s)",
681 "IDBTransaction[%llu] MT Started",
682 transaction->GetSerialNumber(), IDB_PROFILER_STRING(this),
683 IDB_PROFILER_STRING(transaction));
685 return transaction.forget();
688 already_AddRefed<IDBRequest>
689 IDBDatabase::CreateMutableFile(const nsAString& aName,
690 const Optional<nsAString>& aType,
691 ErrorResult& aRv)
693 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
695 if (!IndexedDatabaseManager::IsMainProcess()) {
696 IDB_WARNING("Not supported yet!");
697 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
698 return nullptr;
701 if (QuotaManager::IsShuttingDown()) {
702 IDB_REPORT_INTERNAL_ERR();
703 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
704 return nullptr;
707 if (mClosed) {
708 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
709 return nullptr;
712 nsRefPtr<IDBRequest> request = IDBRequest::Create(this, nullptr);
714 nsRefPtr<CreateFileHelper> helper =
715 new CreateFileHelper(this, request, aName,
716 aType.WasPassed() ? aType.Value() : EmptyString());
718 QuotaManager* quotaManager = QuotaManager::Get();
719 NS_ASSERTION(quotaManager, "We should definitely have a manager here");
721 nsresult rv = helper->Dispatch(quotaManager->IOThread());
722 if (NS_FAILED(rv)) {
723 IDB_WARNING("Failed to dispatch!");
724 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
725 return nullptr;
728 return request.forget();
731 NS_IMETHODIMP
732 IDBDatabase::Close()
734 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
736 CloseInternal(false);
738 NS_ASSERTION(mClosed, "Should have set the closed flag!");
740 return NS_OK;
743 NS_IMETHODIMP_(const nsACString&)
744 IDBDatabase::Id()
746 return mDatabaseId;
749 NS_IMETHODIMP_(mozilla::dom::quota::Client*)
750 IDBDatabase::GetClient()
752 return mQuotaClient;
755 NS_IMETHODIMP_(bool)
756 IDBDatabase::IsOwned(nsPIDOMWindow* aOwner)
758 return GetOwner() == aOwner;
761 NS_IMETHODIMP_(const nsACString&)
762 IDBDatabase::Origin()
764 return mASCIIOrigin;
767 nsresult
768 IDBDatabase::PostHandleEvent(EventChainPostVisitor& aVisitor)
770 return IndexedDatabaseManager::FireWindowOnError(GetOwner(), aVisitor);
773 AsyncConnectionHelper::ChildProcessSendResult
774 NoRequestDatabaseHelper::SendResponseToChildProcess(nsresult aResultCode)
776 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
777 return Success_NotSent;
780 nsresult
781 NoRequestDatabaseHelper::UnpackResponseFromParentProcess(
782 const ResponseValue& aResponseValue)
784 MOZ_CRASH("Should never get here!");
787 nsresult
788 NoRequestDatabaseHelper::OnSuccess()
790 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
791 return NS_OK;
794 void
795 NoRequestDatabaseHelper::OnError()
797 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
798 mTransaction->Abort(GetResultCode());
801 nsresult
802 CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
804 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
805 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
807 PROFILER_LABEL("CreateObjectStoreHelper", "DoDatabaseWork",
808 js::ProfileEntry::Category::STORAGE);
810 if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
811 NS_WARNING("Refusing to create additional objectStore because disk space "
812 "is low!");
813 return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
816 nsCOMPtr<mozIStorageStatement> stmt =
817 mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
818 "INSERT INTO object_store (id, auto_increment, name, key_path) "
819 "VALUES (:id, :auto_increment, :name, :key_path)"
821 IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
823 mozStorageStatementScoper scoper(stmt);
825 nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
826 mObjectStore->Id());
827 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
829 rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("auto_increment"),
830 mObjectStore->IsAutoIncrement() ? 1 : 0);
831 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
833 rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mObjectStore->Name());
834 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
836 const KeyPath& keyPath = mObjectStore->GetKeyPath();
837 if (keyPath.IsValid()) {
838 nsAutoString keyPathSerialization;
839 keyPath.SerializeToString(keyPathSerialization);
840 rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
841 keyPathSerialization);
842 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
844 else {
845 rv = stmt->BindNullByName(NS_LITERAL_CSTRING("key_path"));
846 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
849 rv = stmt->Execute();
850 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
852 return NS_OK;
855 void
856 CreateObjectStoreHelper::ReleaseMainThreadObjects()
858 mObjectStore = nullptr;
859 NoRequestDatabaseHelper::ReleaseMainThreadObjects();
862 nsresult
863 DeleteObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
865 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
866 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
868 PROFILER_LABEL("DeleteObjectStoreHelper", "DoDatabaseWork",
869 js::ProfileEntry::Category::STORAGE);
871 nsCOMPtr<mozIStorageStatement> stmt =
872 mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
873 "DELETE FROM object_store "
874 "WHERE id = :id "
876 IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
878 mozStorageStatementScoper scoper(stmt);
880 nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mObjectStoreId);
881 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
883 rv = stmt->Execute();
884 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
886 return NS_OK;
889 nsresult
890 CreateFileHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
892 AssertIsOnIOThread();
893 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
895 PROFILER_LABEL("CreateFileHelper", "DoDatabaseWork",
896 js::ProfileEntry::Category::STORAGE);
898 if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
899 NS_WARNING("Refusing to create file because disk space is low!");
900 return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
903 FileManager* fileManager = mDatabase->Manager();
905 mFileInfo = fileManager->GetNewFileInfo();
906 IDB_ENSURE_TRUE(mFileInfo, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
908 const int64_t& fileId = mFileInfo->Id();
910 nsCOMPtr<nsIFile> directory = fileManager->EnsureJournalDirectory();
911 NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
913 nsCOMPtr<nsIFile> file = fileManager->GetFileForId(directory, fileId);
914 NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
916 nsresult rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
917 NS_ENSURE_SUCCESS(rv, rv);
919 directory = fileManager->GetDirectory();
920 IDB_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
922 file = fileManager->GetFileForId(directory, fileId);
923 IDB_ENSURE_TRUE(file, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
925 rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
926 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
928 return NS_OK;
931 nsresult
932 CreateFileHelper::GetSuccessResult(JSContext* aCx,
933 JS::MutableHandle<JS::Value> aVal)
935 nsRefPtr<IDBMutableFile> mutableFile =
936 IDBMutableFile::Create(mName, mType, mDatabase, mFileInfo.forget());
937 IDB_ENSURE_TRUE(mutableFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
939 return WrapNative(aCx, NS_ISUPPORTS_CAST(EventTarget*, mutableFile), aVal);