mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
6cfd64d931
- Bug 1195173 - Test asyncopen2 security checks for stylesheets (r=bz,ehsan) (358ae850a4) - Bug 1223644 - Clean up the nsSVGClipPathFrame reference loop detection code. r=longsonr (65042c3148) - Bug 1157064 - font-display descriptor parsing. r=dbaron (18f63d9244) - Bug 1242523 - Guard against GetWidget getting called with a null shell. r=snorp (55de891c6c) - Bug 1247679, part 3 - Replace NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK with JS_MEMBER. r=smaug (09435e582c) - Bug 1247515 - Check nsScriptErrorWithStack's mStack member for null before tracing; r=mccr8 (0cb1e09aa9) - Bug 1178803. Fix the handling of the 'length' key in IDB keypaths when operating on a string. r=bent (69f15272a8) - Bug 1201037 - coalesce network-events on Windows, r=mcmanus (5f48aab5c3) - Bug 1131626, fix autoscroll tests to work in e10s, r=felipe (c47adbaa10) - Bug 1231529 - Increase the timeout of browser_bug295977_autoscroll_overflow.js (691d27224d) - Bug 416611 - Changed BookmarkHTMLUtils.jsm to import bookmark tags from HTML document. r=mak (49a0accc13) - Bug 1130858 - Recipient autocomplete suggestion overrides ANY manual address input if quickly entered/pasted and confirmed with Enter/Tab before autocomplete suggestions disappear. r=mak (308196e116) - Bug 1197361. Optimize page thumbnails based on screen size. r=ttaubert (29dca20366) - Bug 555087 - Add check for exception when passing undefined parameter. r=adw (3588477c56) - Bug 1203803: Force cleanup for specific states only; r=khuey a=CLOSED TREE (2f9f78ad72) - Bug 1203803 - Remove forced cleanup from FactoryOp::ActorDestroy() since it cause more harm than good; r=khuey (76a00e58cb) - Bug 1195149 - Upgrade the check to a MOZ_RELEASE_ASSERT. r=janv (071d1fc267) - Bug 1185223 - crash at [@ mozilla::dom::quota::QuotaObject::Release() ]; r=khuey (d460972a45) - Bug 1229376 - Downgrade lastVacuumSize > 0 assertion to an NS_ASSERTION so we don't have to star it all over the place, rs=khuey (81d715ab71) - Bug 1239666 - part 1, get rid of the default parameter. r=waldo (639fb79ec3) - Bug 1239666 - part 2, dom/indexedDB change. r=khuey (6faaf25df4) - Bug 1239666 - part 3, devtools test case changes. r=sphink (c010d06a77) - Bug 1248309 - Fix caret size not updated when only zoom level is changed. r=roc (91cc5b35df) - Bug 1245649: Turn on no-trailing-spaces. r=Gijs (7f87c967af) - Bug 1245649: Enable no-negated-in-lhs, no-native-reassign, no-func-assign and no-labels. r=MattN (5f801e4a4c) - Bug 1197966 - Fix typo when releasing content-side probes in PerformanceStats-content.js. r=felipe (9241324efd) - Bug 1219144 - Performance alerts are now labelled with isJankVisible; r=avih,froydnj (c1549a24f5) - Bug 1219144 - Using the nsRefreshDriver's jank indication for performance monitoring;f?froydnj r=froydnj (735c6fba9c) - Bug 1211783 - Add KeyframeEffect interface to dom/webidl/KeyframeEffect.webidl. r=smaug,birtles (fca332fea0) - Bug 795681 - Print out failures in mozunit runner. r=gps (ce418e5ea8) - Bug 801679 - Handle expected failures and skipped tests in mozunit runner. r=gps (396ca02893) - Bug 1247833 - Display the class name in mozunit output. r=gps (0b5724f41c) - Bug 1245022 - Kill stlport's Makefile.in. r=mshal (225f662efc) - Bug 1194603 - Remove INTERNAL_TOOLS; r=mshal (e8e90ec1c3) - Bug 1247743 - Expose non-pinning JS_Atomize[UC]String JSAPI functions; r=terrence (66aa23066d) - Bug 1230071 - Enable warnings-as-errors in js/src. r=Waldo (a0c8acf6ad) - Bug 1007136 - Ensure malloc/free always match when using JSAutoByteString; r=bz (81dfcf036a) - Bug 1246850 - check the NotifyIpInterfaceChange() return code, r=mcmanus (bc224f287c) - Bug 739029 - null check a thread allocation in notifyaddrlistener r=bagder (ce0ddfc44c)
902 lines
24 KiB
C++
902 lines
24 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "IDBCursor.h"
|
|
|
|
#include "IDBDatabase.h"
|
|
#include "IDBIndex.h"
|
|
#include "IDBObjectStore.h"
|
|
#include "IDBRequest.h"
|
|
#include "IDBTransaction.h"
|
|
#include "IndexedDatabaseInlines.h"
|
|
#include "mozilla/ErrorResult.h"
|
|
#include "mozilla/dom/UnionTypes.h"
|
|
#include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
|
|
#include "nsString.h"
|
|
#include "ProfilerHelpers.h"
|
|
#include "ReportInternalError.h"
|
|
|
|
// Include this last to avoid path problems on Windows.
|
|
#include "ActorsChild.h"
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
|
|
using namespace indexedDB;
|
|
|
|
IDBCursor::IDBCursor(Type aType,
|
|
BackgroundCursorChild* aBackgroundActor,
|
|
const Key& aKey)
|
|
: mBackgroundActor(aBackgroundActor)
|
|
, mRequest(aBackgroundActor->GetRequest())
|
|
, mSourceObjectStore(aBackgroundActor->GetObjectStore())
|
|
, mSourceIndex(aBackgroundActor->GetIndex())
|
|
, mTransaction(mRequest->GetTransaction())
|
|
, mScriptOwner(mTransaction->Database()->GetScriptOwner())
|
|
, mCachedKey(JS::UndefinedValue())
|
|
, mCachedPrimaryKey(JS::UndefinedValue())
|
|
, mCachedValue(JS::UndefinedValue())
|
|
, mKey(aKey)
|
|
, mType(aType)
|
|
, mDirection(aBackgroundActor->GetDirection())
|
|
, mHaveCachedKey(false)
|
|
, mHaveCachedPrimaryKey(false)
|
|
, mHaveCachedValue(false)
|
|
, mRooted(false)
|
|
, mContinueCalled(false)
|
|
, mHaveValue(true)
|
|
{
|
|
MOZ_ASSERT(aBackgroundActor);
|
|
aBackgroundActor->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
MOZ_ASSERT_IF(aType == Type_ObjectStore || aType == Type_ObjectStoreKey,
|
|
mSourceObjectStore);
|
|
MOZ_ASSERT_IF(aType == Type_Index || aType == Type_IndexKey, mSourceIndex);
|
|
MOZ_ASSERT(mTransaction);
|
|
MOZ_ASSERT(!aKey.IsUnset());
|
|
MOZ_ASSERT(mScriptOwner);
|
|
|
|
if (mScriptOwner) {
|
|
mozilla::HoldJSObjects(this);
|
|
mRooted = true;
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_INTL_API
|
|
bool
|
|
IDBCursor::IsLocaleAware() const
|
|
{
|
|
return mSourceIndex && !mSourceIndex->Locale().IsEmpty();
|
|
}
|
|
#endif
|
|
|
|
IDBCursor::~IDBCursor()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
DropJSObjects();
|
|
|
|
if (mBackgroundActor) {
|
|
mBackgroundActor->SendDeleteMeInternal();
|
|
MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
|
|
}
|
|
}
|
|
|
|
// static
|
|
already_AddRefed<IDBCursor>
|
|
IDBCursor::Create(BackgroundCursorChild* aBackgroundActor,
|
|
const Key& aKey,
|
|
StructuredCloneReadInfo&& aCloneInfo)
|
|
{
|
|
MOZ_ASSERT(aBackgroundActor);
|
|
aBackgroundActor->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(aBackgroundActor->GetObjectStore());
|
|
MOZ_ASSERT(!aBackgroundActor->GetIndex());
|
|
MOZ_ASSERT(!aKey.IsUnset());
|
|
|
|
RefPtr<IDBCursor> cursor =
|
|
new IDBCursor(Type_ObjectStore, aBackgroundActor, aKey);
|
|
|
|
cursor->mCloneInfo = Move(aCloneInfo);
|
|
|
|
return cursor.forget();
|
|
}
|
|
|
|
// static
|
|
already_AddRefed<IDBCursor>
|
|
IDBCursor::Create(BackgroundCursorChild* aBackgroundActor,
|
|
const Key& aKey)
|
|
{
|
|
MOZ_ASSERT(aBackgroundActor);
|
|
aBackgroundActor->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(aBackgroundActor->GetObjectStore());
|
|
MOZ_ASSERT(!aBackgroundActor->GetIndex());
|
|
MOZ_ASSERT(!aKey.IsUnset());
|
|
|
|
RefPtr<IDBCursor> cursor =
|
|
new IDBCursor(Type_ObjectStoreKey, aBackgroundActor, aKey);
|
|
|
|
return cursor.forget();
|
|
}
|
|
|
|
// static
|
|
already_AddRefed<IDBCursor>
|
|
IDBCursor::Create(BackgroundCursorChild* aBackgroundActor,
|
|
const Key& aKey,
|
|
const Key& aSortKey,
|
|
const Key& aPrimaryKey,
|
|
StructuredCloneReadInfo&& aCloneInfo)
|
|
{
|
|
MOZ_ASSERT(aBackgroundActor);
|
|
aBackgroundActor->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(aBackgroundActor->GetIndex());
|
|
MOZ_ASSERT(!aBackgroundActor->GetObjectStore());
|
|
MOZ_ASSERT(!aKey.IsUnset());
|
|
MOZ_ASSERT(!aPrimaryKey.IsUnset());
|
|
|
|
RefPtr<IDBCursor> cursor =
|
|
new IDBCursor(Type_Index, aBackgroundActor, aKey);
|
|
|
|
cursor->mSortKey = Move(aSortKey);
|
|
cursor->mPrimaryKey = Move(aPrimaryKey);
|
|
cursor->mCloneInfo = Move(aCloneInfo);
|
|
|
|
return cursor.forget();
|
|
}
|
|
|
|
// static
|
|
already_AddRefed<IDBCursor>
|
|
IDBCursor::Create(BackgroundCursorChild* aBackgroundActor,
|
|
const Key& aKey,
|
|
const Key& aSortKey,
|
|
const Key& aPrimaryKey)
|
|
{
|
|
MOZ_ASSERT(aBackgroundActor);
|
|
aBackgroundActor->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(aBackgroundActor->GetIndex());
|
|
MOZ_ASSERT(!aBackgroundActor->GetObjectStore());
|
|
MOZ_ASSERT(!aKey.IsUnset());
|
|
MOZ_ASSERT(!aPrimaryKey.IsUnset());
|
|
|
|
RefPtr<IDBCursor> cursor =
|
|
new IDBCursor(Type_IndexKey, aBackgroundActor, aKey);
|
|
|
|
cursor->mSortKey = Move(aSortKey);
|
|
cursor->mPrimaryKey = Move(aPrimaryKey);
|
|
|
|
return cursor.forget();
|
|
}
|
|
|
|
// static
|
|
auto
|
|
IDBCursor::ConvertDirection(IDBCursorDirection aDirection) -> Direction
|
|
{
|
|
switch (aDirection) {
|
|
case mozilla::dom::IDBCursorDirection::Next:
|
|
return NEXT;
|
|
|
|
case mozilla::dom::IDBCursorDirection::Nextunique:
|
|
return NEXT_UNIQUE;
|
|
|
|
case mozilla::dom::IDBCursorDirection::Prev:
|
|
return PREV;
|
|
|
|
case mozilla::dom::IDBCursorDirection::Prevunique:
|
|
return PREV_UNIQUE;
|
|
|
|
default:
|
|
MOZ_CRASH("Unknown direction!");
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
IDBCursor::AssertIsOnOwningThread() const
|
|
{
|
|
MOZ_ASSERT(mTransaction);
|
|
mTransaction->AssertIsOnOwningThread();
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
void
|
|
IDBCursor::DropJSObjects()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
Reset();
|
|
|
|
if (!mRooted) {
|
|
return;
|
|
}
|
|
|
|
mScriptOwner = nullptr;
|
|
mRooted = false;
|
|
|
|
mozilla::DropJSObjects(this);
|
|
}
|
|
|
|
bool
|
|
IDBCursor::IsSourceDeleted() const
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mTransaction);
|
|
MOZ_ASSERT(mTransaction->IsOpen());
|
|
|
|
IDBObjectStore* sourceObjectStore;
|
|
if (mType == Type_Index || mType == Type_IndexKey) {
|
|
MOZ_ASSERT(mSourceIndex);
|
|
|
|
if (mSourceIndex->IsDeleted()) {
|
|
return true;
|
|
}
|
|
|
|
sourceObjectStore = mSourceIndex->ObjectStore();
|
|
MOZ_ASSERT(sourceObjectStore);
|
|
} else {
|
|
MOZ_ASSERT(mSourceObjectStore);
|
|
sourceObjectStore = mSourceObjectStore;
|
|
}
|
|
|
|
return sourceObjectStore->IsDeleted();
|
|
}
|
|
|
|
void
|
|
IDBCursor::Reset()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
mCachedKey.setUndefined();
|
|
mCachedPrimaryKey.setUndefined();
|
|
mCachedValue.setUndefined();
|
|
IDBObjectStore::ClearCloneReadInfo(mCloneInfo);
|
|
|
|
mHaveCachedKey = false;
|
|
mHaveCachedPrimaryKey = false;
|
|
mHaveCachedValue = false;
|
|
mHaveValue = false;
|
|
mContinueCalled = false;
|
|
}
|
|
|
|
nsPIDOMWindow*
|
|
IDBCursor::GetParentObject() const
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mTransaction);
|
|
|
|
return mTransaction->GetParentObject();
|
|
}
|
|
|
|
IDBCursorDirection
|
|
IDBCursor::GetDirection() const
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
switch (mDirection) {
|
|
case NEXT:
|
|
return IDBCursorDirection::Next;
|
|
|
|
case NEXT_UNIQUE:
|
|
return IDBCursorDirection::Nextunique;
|
|
|
|
case PREV:
|
|
return IDBCursorDirection::Prev;
|
|
|
|
case PREV_UNIQUE:
|
|
return IDBCursorDirection::Prevunique;
|
|
|
|
default:
|
|
MOZ_CRASH("Bad direction!");
|
|
}
|
|
}
|
|
|
|
void
|
|
IDBCursor::GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
switch (mType) {
|
|
case Type_ObjectStore:
|
|
case Type_ObjectStoreKey:
|
|
MOZ_ASSERT(mSourceObjectStore);
|
|
aSource.SetAsIDBObjectStore() = mSourceObjectStore;
|
|
return;
|
|
|
|
case Type_Index:
|
|
case Type_IndexKey:
|
|
MOZ_ASSERT(mSourceIndex);
|
|
aSource.SetAsIDBIndex() = mSourceIndex;
|
|
return;
|
|
|
|
default:
|
|
MOZ_ASSERT_UNREACHABLE("Bad type!");
|
|
}
|
|
}
|
|
|
|
void
|
|
IDBCursor::GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
|
|
ErrorResult& aRv)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(!mKey.IsUnset() || !mHaveValue);
|
|
|
|
if (!mHaveValue) {
|
|
aResult.setUndefined();
|
|
return;
|
|
}
|
|
|
|
if (!mHaveCachedKey) {
|
|
if (!mRooted) {
|
|
mozilla::HoldJSObjects(this);
|
|
mRooted = true;
|
|
}
|
|
|
|
aRv = mKey.ToJSVal(aCx, mCachedKey);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return;
|
|
}
|
|
|
|
mHaveCachedKey = true;
|
|
}
|
|
|
|
JS::ExposeValueToActiveJS(mCachedKey);
|
|
aResult.set(mCachedKey);
|
|
}
|
|
|
|
void
|
|
IDBCursor::GetPrimaryKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
|
|
ErrorResult& aRv)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
if (!mHaveValue) {
|
|
aResult.setUndefined();
|
|
return;
|
|
}
|
|
|
|
if (!mHaveCachedPrimaryKey) {
|
|
if (!mRooted) {
|
|
mozilla::HoldJSObjects(this);
|
|
mRooted = true;
|
|
}
|
|
|
|
const Key& key =
|
|
(mType == Type_ObjectStore || mType == Type_ObjectStoreKey) ?
|
|
mKey :
|
|
mPrimaryKey;
|
|
|
|
MOZ_ASSERT(!key.IsUnset());
|
|
|
|
aRv = key.ToJSVal(aCx, mCachedPrimaryKey);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return;
|
|
}
|
|
|
|
mHaveCachedPrimaryKey = true;
|
|
}
|
|
|
|
JS::ExposeValueToActiveJS(mCachedPrimaryKey);
|
|
aResult.set(mCachedPrimaryKey);
|
|
}
|
|
|
|
void
|
|
IDBCursor::GetValue(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
|
|
ErrorResult& aRv)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mType == Type_ObjectStore || mType == Type_Index);
|
|
|
|
if (!mHaveValue) {
|
|
aResult.setUndefined();
|
|
return;
|
|
}
|
|
|
|
if (!mHaveCachedValue) {
|
|
if (!mRooted) {
|
|
mozilla::HoldJSObjects(this);
|
|
mRooted = true;
|
|
}
|
|
|
|
JS::Rooted<JS::Value> val(aCx);
|
|
if (NS_WARN_IF(!IDBObjectStore::DeserializeValue(aCx, mCloneInfo, &val))) {
|
|
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
|
return;
|
|
}
|
|
|
|
IDBObjectStore::ClearCloneReadInfo(mCloneInfo);
|
|
|
|
mCachedValue = val;
|
|
mHaveCachedValue = true;
|
|
}
|
|
|
|
JS::ExposeValueToActiveJS(mCachedValue);
|
|
aResult.set(mCachedValue);
|
|
}
|
|
|
|
void
|
|
IDBCursor::Continue(JSContext* aCx,
|
|
JS::Handle<JS::Value> aKey,
|
|
ErrorResult &aRv)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
if (!mTransaction->IsOpen()) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
return;
|
|
}
|
|
|
|
if (IsSourceDeleted() || !mHaveValue || mContinueCalled) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
return;
|
|
}
|
|
|
|
Key key;
|
|
aRv = key.SetFromJSVal(aCx, aKey);
|
|
if (aRv.Failed()) {
|
|
return;
|
|
}
|
|
|
|
#ifdef ENABLE_INTL_API
|
|
if (IsLocaleAware() && !key.IsUnset()) {
|
|
Key tmp;
|
|
aRv = key.ToLocaleBasedKey(tmp, mSourceIndex->Locale());
|
|
if (aRv.Failed()) {
|
|
return;
|
|
}
|
|
key = tmp;
|
|
}
|
|
|
|
const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
|
|
#else
|
|
const Key& sortKey = mKey;
|
|
#endif
|
|
|
|
if (!key.IsUnset()) {
|
|
switch (mDirection) {
|
|
case NEXT:
|
|
case NEXT_UNIQUE:
|
|
if (key <= sortKey) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case PREV:
|
|
case PREV_UNIQUE:
|
|
if (key >= sortKey) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
MOZ_CRASH("Unknown direction type!");
|
|
}
|
|
}
|
|
|
|
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
|
|
mRequest->SetLoggingSerialNumber(requestSerialNumber);
|
|
|
|
if (mType == Type_ObjectStore || mType == Type_ObjectStoreKey) {
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
"cursor(%s).continue(%s)",
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.continue()",
|
|
IDB_LOG_ID_STRING(),
|
|
mTransaction->LoggingSerialNumber(),
|
|
requestSerialNumber,
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
IDB_LOG_STRINGIFY(mSourceObjectStore),
|
|
IDB_LOG_STRINGIFY(mDirection),
|
|
IDB_LOG_STRINGIFY(key));
|
|
} else {
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
"index(%s).cursor(%s).continue(%s)",
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.continue()",
|
|
IDB_LOG_ID_STRING(),
|
|
mTransaction->LoggingSerialNumber(),
|
|
requestSerialNumber,
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()),
|
|
IDB_LOG_STRINGIFY(mSourceIndex),
|
|
IDB_LOG_STRINGIFY(mDirection),
|
|
IDB_LOG_STRINGIFY(key));
|
|
}
|
|
|
|
mBackgroundActor->SendContinueInternal(ContinueParams(key), mKey);
|
|
|
|
mContinueCalled = true;
|
|
}
|
|
|
|
void
|
|
IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
if (!aCount) {
|
|
aRv.ThrowTypeError<MSG_INVALID_ADVANCE_COUNT>();
|
|
return;
|
|
}
|
|
|
|
if (!mTransaction->IsOpen()) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
return;
|
|
}
|
|
|
|
|
|
if (IsSourceDeleted() || !mHaveValue || mContinueCalled) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
return;
|
|
}
|
|
|
|
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
|
|
mRequest->SetLoggingSerialNumber(requestSerialNumber);
|
|
|
|
if (mType == Type_ObjectStore || mType == Type_ObjectStoreKey) {
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
"cursor(%s).advance(%ld)",
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.advance()",
|
|
IDB_LOG_ID_STRING(),
|
|
mTransaction->LoggingSerialNumber(),
|
|
requestSerialNumber,
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
IDB_LOG_STRINGIFY(mSourceObjectStore),
|
|
IDB_LOG_STRINGIFY(mDirection),
|
|
aCount);
|
|
} else {
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
"index(%s).cursor(%s).advance(%ld)",
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.advance()",
|
|
IDB_LOG_ID_STRING(),
|
|
mTransaction->LoggingSerialNumber(),
|
|
requestSerialNumber,
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()),
|
|
IDB_LOG_STRINGIFY(mSourceIndex),
|
|
IDB_LOG_STRINGIFY(mDirection),
|
|
aCount);
|
|
}
|
|
|
|
mBackgroundActor->SendContinueInternal(AdvanceParams(aCount), mKey);
|
|
|
|
mContinueCalled = true;
|
|
}
|
|
|
|
already_AddRefed<IDBRequest>
|
|
IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
|
ErrorResult& aRv)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
if (!mTransaction->IsOpen()) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
return nullptr;
|
|
}
|
|
|
|
if (!mTransaction->IsWriteAllowed()) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
|
|
return nullptr;
|
|
}
|
|
|
|
if (IsSourceDeleted() ||
|
|
!mHaveValue ||
|
|
mType == Type_ObjectStoreKey ||
|
|
mType == Type_IndexKey) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
return nullptr;
|
|
}
|
|
|
|
MOZ_ASSERT(mType == Type_ObjectStore || mType == Type_Index);
|
|
MOZ_ASSERT(!mKey.IsUnset());
|
|
MOZ_ASSERT_IF(mType == Type_Index, !mPrimaryKey.IsUnset());
|
|
|
|
mBackgroundActor->InvalidateCachedResponses();
|
|
|
|
IDBObjectStore* objectStore;
|
|
if (mType == Type_ObjectStore) {
|
|
objectStore = mSourceObjectStore;
|
|
} else {
|
|
objectStore = mSourceIndex->ObjectStore();
|
|
}
|
|
|
|
MOZ_ASSERT(objectStore);
|
|
|
|
const Key& primaryKey = (mType == Type_ObjectStore) ? mKey : mPrimaryKey;
|
|
|
|
RefPtr<IDBRequest> request;
|
|
|
|
if (objectStore->HasValidKeyPath()) {
|
|
// Make sure the object given has the correct keyPath value set on it.
|
|
const KeyPath& keyPath = objectStore->GetKeyPath();
|
|
Key key;
|
|
|
|
aRv = keyPath.ExtractKey(aCx, aValue, key);
|
|
if (aRv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (key != primaryKey) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
|
|
return nullptr;
|
|
}
|
|
|
|
request = objectStore->AddOrPut(aCx,
|
|
aValue,
|
|
/* aKey */ JS::UndefinedHandleValue,
|
|
/* aOverwrite */ true,
|
|
/* aFromCursor */ true,
|
|
aRv);
|
|
if (aRv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
else {
|
|
JS::Rooted<JS::Value> keyVal(aCx);
|
|
aRv = primaryKey.ToJSVal(aCx, &keyVal);
|
|
if (aRv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
|
|
request = objectStore->AddOrPut(aCx,
|
|
aValue,
|
|
keyVal,
|
|
/* aOverwrite */ true,
|
|
/* aFromCursor */ true,
|
|
aRv);
|
|
if (aRv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
request->SetSource(this);
|
|
|
|
if (mType == Type_ObjectStore) {
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
"cursor(%s).update(%s)",
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.update()",
|
|
IDB_LOG_ID_STRING(),
|
|
mTransaction->LoggingSerialNumber(),
|
|
request->LoggingSerialNumber(),
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
IDB_LOG_STRINGIFY(objectStore),
|
|
IDB_LOG_STRINGIFY(mDirection),
|
|
IDB_LOG_STRINGIFY(objectStore, primaryKey));
|
|
} else {
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
"index(%s).cursor(%s).update(%s)",
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.update()",
|
|
IDB_LOG_ID_STRING(),
|
|
mTransaction->LoggingSerialNumber(),
|
|
request->LoggingSerialNumber(),
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
IDB_LOG_STRINGIFY(objectStore),
|
|
IDB_LOG_STRINGIFY(mSourceIndex),
|
|
IDB_LOG_STRINGIFY(mDirection),
|
|
IDB_LOG_STRINGIFY(objectStore, primaryKey));
|
|
}
|
|
|
|
return request.forget();
|
|
}
|
|
|
|
already_AddRefed<IDBRequest>
|
|
IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
if (!mTransaction->IsOpen()) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
return nullptr;
|
|
}
|
|
|
|
if (!mTransaction->IsWriteAllowed()) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
|
|
return nullptr;
|
|
}
|
|
|
|
if (IsSourceDeleted() ||
|
|
!mHaveValue ||
|
|
mType == Type_ObjectStoreKey ||
|
|
mType == Type_IndexKey ||
|
|
mContinueCalled) {
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
return nullptr;
|
|
}
|
|
|
|
MOZ_ASSERT(mType == Type_ObjectStore || mType == Type_Index);
|
|
MOZ_ASSERT(!mKey.IsUnset());
|
|
|
|
mBackgroundActor->InvalidateCachedResponses();
|
|
|
|
IDBObjectStore* objectStore;
|
|
if (mType == Type_ObjectStore) {
|
|
objectStore = mSourceObjectStore;
|
|
} else {
|
|
objectStore = mSourceIndex->ObjectStore();
|
|
}
|
|
|
|
MOZ_ASSERT(objectStore);
|
|
|
|
const Key& primaryKey = (mType == Type_ObjectStore) ? mKey : mPrimaryKey;
|
|
|
|
JS::Rooted<JS::Value> key(aCx);
|
|
aRv = primaryKey.ToJSVal(aCx, &key);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<IDBRequest> request =
|
|
objectStore->DeleteInternal(aCx, key, /* aFromCursor */ true, aRv);
|
|
if (aRv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
|
|
request->SetSource(this);
|
|
|
|
if (mType == Type_ObjectStore) {
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
"cursor(%s).delete(%s)",
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.delete()",
|
|
IDB_LOG_ID_STRING(),
|
|
mTransaction->LoggingSerialNumber(),
|
|
request->LoggingSerialNumber(),
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
IDB_LOG_STRINGIFY(objectStore),
|
|
IDB_LOG_STRINGIFY(mDirection),
|
|
IDB_LOG_STRINGIFY(objectStore, primaryKey));
|
|
} else {
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
"index(%s).cursor(%s).delete(%s)",
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.delete()",
|
|
IDB_LOG_ID_STRING(),
|
|
mTransaction->LoggingSerialNumber(),
|
|
request->LoggingSerialNumber(),
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
IDB_LOG_STRINGIFY(objectStore),
|
|
IDB_LOG_STRINGIFY(mSourceIndex),
|
|
IDB_LOG_STRINGIFY(mDirection),
|
|
IDB_LOG_STRINGIFY(objectStore, primaryKey));
|
|
}
|
|
|
|
return request.forget();
|
|
}
|
|
|
|
void
|
|
IDBCursor::Reset(Key&& aKey, StructuredCloneReadInfo&& aValue)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mType == Type_ObjectStore);
|
|
|
|
Reset();
|
|
|
|
mKey = Move(aKey);
|
|
mCloneInfo = Move(aValue);
|
|
|
|
mHaveValue = !mKey.IsUnset();
|
|
}
|
|
|
|
void
|
|
IDBCursor::Reset(Key&& aKey)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mType == Type_ObjectStoreKey);
|
|
|
|
Reset();
|
|
|
|
mKey = Move(aKey);
|
|
|
|
mHaveValue = !mKey.IsUnset();
|
|
}
|
|
|
|
void
|
|
IDBCursor::Reset(Key&& aKey,
|
|
Key&& aSortKey,
|
|
Key&& aPrimaryKey,
|
|
StructuredCloneReadInfo&& aValue)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mType == Type_Index);
|
|
|
|
Reset();
|
|
|
|
mKey = Move(aKey);
|
|
mSortKey = Move(aSortKey);
|
|
mPrimaryKey = Move(aPrimaryKey);
|
|
mCloneInfo = Move(aValue);
|
|
|
|
mHaveValue = !mKey.IsUnset();
|
|
}
|
|
|
|
void
|
|
IDBCursor::Reset(Key&& aKey,
|
|
Key&& aSortKey,
|
|
Key&& aPrimaryKey)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mType == Type_IndexKey);
|
|
|
|
Reset();
|
|
|
|
mKey = Move(aKey);
|
|
mSortKey = Move(aSortKey);
|
|
mPrimaryKey = Move(aPrimaryKey);
|
|
|
|
mHaveValue = !mKey.IsUnset();
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBCursor)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBCursor)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceObjectStore)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceIndex)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
|
|
MOZ_ASSERT_IF(!tmp->mHaveCachedKey, tmp->mCachedKey.isUndefined());
|
|
MOZ_ASSERT_IF(!tmp->mHaveCachedPrimaryKey,
|
|
tmp->mCachedPrimaryKey.isUndefined());
|
|
MOZ_ASSERT_IF(!tmp->mHaveCachedValue, tmp->mCachedValue.isUndefined());
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptOwner)
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKey)
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedPrimaryKey)
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedValue)
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor)
|
|
// Don't unlink mRequest, mSourceObjectStore, or mSourceIndex!
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
|
tmp->DropJSObjects();
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
JSObject*
|
|
IDBCursor::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
switch (mType) {
|
|
case Type_ObjectStore:
|
|
case Type_Index:
|
|
return IDBCursorWithValueBinding::Wrap(aCx, this, aGivenProto);
|
|
|
|
case Type_ObjectStoreKey:
|
|
case Type_IndexKey:
|
|
return IDBCursorBinding::Wrap(aCx, this, aGivenProto);
|
|
|
|
default:
|
|
MOZ_CRASH("Bad type!");
|
|
}
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|