123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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 "IDBKeyRange.h"
- #include "Key.h"
- #include "mozilla/ErrorResult.h"
- #include "mozilla/dom/BindingUtils.h"
- #include "mozilla/dom/IDBKeyRangeBinding.h"
- #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
- namespace mozilla {
- namespace dom {
- using namespace mozilla::dom::indexedDB;
- namespace {
- nsresult
- GetKeyFromJSVal(JSContext* aCx,
- JS::Handle<JS::Value> aVal,
- Key& aKey)
- {
- nsresult rv = aKey.SetFromJSVal(aCx, aVal, /* aCallGetters */ true);
- if (NS_FAILED(rv)) {
- MOZ_ASSERT(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB);
- return rv;
- }
- if (aKey.IsUnset()) {
- return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
- }
- return NS_OK;
- }
- } // namespace
- IDBKeyRange::IDBKeyRange(nsISupports* aGlobal,
- bool aLowerOpen,
- bool aUpperOpen,
- bool aIsOnly)
- : mGlobal(aGlobal)
- , mCachedLowerVal(JS::UndefinedValue())
- , mCachedUpperVal(JS::UndefinedValue())
- , mLowerOpen(aLowerOpen)
- , mUpperOpen(aUpperOpen)
- , mIsOnly(aIsOnly)
- , mHaveCachedLowerVal(false)
- , mHaveCachedUpperVal(false)
- , mRooted(false)
- {
- #ifdef DEBUG
- mOwningThread = PR_GetCurrentThread();
- #endif
- AssertIsOnOwningThread();
- }
- IDBKeyRange::~IDBKeyRange()
- {
- DropJSObjects();
- }
- IDBLocaleAwareKeyRange::IDBLocaleAwareKeyRange(nsISupports* aGlobal,
- bool aLowerOpen,
- bool aUpperOpen,
- bool aIsOnly)
- : IDBKeyRange(aGlobal, aLowerOpen, aUpperOpen, aIsOnly)
- {
- #ifdef DEBUG
- mOwningThread = PR_GetCurrentThread();
- #endif
- AssertIsOnOwningThread();
- }
- IDBLocaleAwareKeyRange::~IDBLocaleAwareKeyRange()
- {
- DropJSObjects();
- }
- #ifdef DEBUG
- void
- IDBKeyRange::AssertIsOnOwningThread() const
- {
- MOZ_ASSERT(mOwningThread);
- MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
- }
- #endif // DEBUG
- // static
- nsresult
- IDBKeyRange::FromJSVal(JSContext* aCx,
- JS::Handle<JS::Value> aVal,
- IDBKeyRange** aKeyRange)
- {
- MOZ_ASSERT_IF(!aCx, aVal.isUndefined());
- RefPtr<IDBKeyRange> keyRange;
- if (aVal.isNullOrUndefined()) {
- // undefined and null returns no IDBKeyRange.
- keyRange.forget(aKeyRange);
- return NS_OK;
- }
- JS::Rooted<JSObject*> obj(aCx, aVal.isObject() ? &aVal.toObject() : nullptr);
- bool isValidKey = aVal.isPrimitive();
- if (!isValidKey) {
- js::ESClass cls;
- if (!js::GetBuiltinClass(aCx, obj, &cls)) {
- return NS_ERROR_UNEXPECTED;
- }
- isValidKey = cls == js::ESClass::Array || cls == js::ESClass::Date;
- }
- if (isValidKey) {
- // A valid key returns an 'only' IDBKeyRange.
- keyRange = new IDBKeyRange(nullptr, false, false, true);
- nsresult rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower());
- if (NS_FAILED(rv)) {
- return rv;
- }
- }
- else {
- MOZ_ASSERT(aVal.isObject());
- // An object is not permitted unless it's another IDBKeyRange.
- if (NS_FAILED(UNWRAP_OBJECT(IDBKeyRange, obj, keyRange))) {
- return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
- }
- }
- keyRange.forget(aKeyRange);
- return NS_OK;
- }
- // static
- already_AddRefed<IDBKeyRange>
- IDBKeyRange::FromSerialized(const SerializedKeyRange& aKeyRange)
- {
- RefPtr<IDBKeyRange> keyRange =
- new IDBKeyRange(nullptr, aKeyRange.lowerOpen(), aKeyRange.upperOpen(),
- aKeyRange.isOnly());
- keyRange->Lower() = aKeyRange.lower();
- if (!keyRange->IsOnly()) {
- keyRange->Upper() = aKeyRange.upper();
- }
- return keyRange.forget();
- }
- void
- IDBKeyRange::ToSerialized(SerializedKeyRange& aKeyRange) const
- {
- aKeyRange.lowerOpen() = LowerOpen();
- aKeyRange.upperOpen() = UpperOpen();
- aKeyRange.isOnly() = IsOnly();
- aKeyRange.lower() = Lower();
- if (!IsOnly()) {
- aKeyRange.upper() = Upper();
- }
- }
- void
- IDBKeyRange::GetBindingClause(const nsACString& aKeyColumnName,
- nsACString& _retval) const
- {
- NS_NAMED_LITERAL_CSTRING(andStr, " AND ");
- NS_NAMED_LITERAL_CSTRING(spacecolon, " :");
- NS_NAMED_LITERAL_CSTRING(lowerKey, "lower_key");
- if (IsOnly()) {
- // Both keys are set and they're equal.
- _retval = andStr + aKeyColumnName + NS_LITERAL_CSTRING(" =") +
- spacecolon + lowerKey;
- return;
- }
- nsAutoCString clause;
- if (!Lower().IsUnset()) {
- // Lower key is set.
- clause.Append(andStr + aKeyColumnName);
- clause.AppendLiteral(" >");
- if (!LowerOpen()) {
- clause.Append('=');
- }
- clause.Append(spacecolon + lowerKey);
- }
- if (!Upper().IsUnset()) {
- // Upper key is set.
- clause.Append(andStr + aKeyColumnName);
- clause.AppendLiteral(" <");
- if (!UpperOpen()) {
- clause.Append('=');
- }
- clause.Append(spacecolon + NS_LITERAL_CSTRING("upper_key"));
- }
- _retval = clause;
- }
- nsresult
- IDBKeyRange::BindToStatement(mozIStorageStatement* aStatement) const
- {
- MOZ_ASSERT(aStatement);
- NS_NAMED_LITERAL_CSTRING(lowerKey, "lower_key");
- if (IsOnly()) {
- return Lower().BindToStatement(aStatement, lowerKey);
- }
- nsresult rv;
- if (!Lower().IsUnset()) {
- rv = Lower().BindToStatement(aStatement, lowerKey);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- }
- if (!Upper().IsUnset()) {
- rv = Upper().BindToStatement(aStatement, NS_LITERAL_CSTRING("upper_key"));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- }
- return NS_OK;
- }
- NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
- NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedLowerVal)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedUpperVal)
- NS_IMPL_CYCLE_COLLECTION_TRACE_END
- NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBKeyRange)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
- tmp->DropJSObjects();
- NS_IMPL_CYCLE_COLLECTION_UNLINK_END
- NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBKeyRange)
- NS_INTERFACE_MAP_ENTRY(nsISupports)
- NS_INTERFACE_MAP_END
- NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBKeyRange)
- NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBKeyRange)
- NS_IMPL_ISUPPORTS_INHERITED0(IDBLocaleAwareKeyRange, IDBKeyRange)
- void
- IDBKeyRange::DropJSObjects()
- {
- if (!mRooted) {
- return;
- }
- mCachedLowerVal.setUndefined();
- mCachedUpperVal.setUndefined();
- mHaveCachedLowerVal = false;
- mHaveCachedUpperVal = false;
- mRooted = false;
- mozilla::DropJSObjects(this);
- }
- bool
- IDBKeyRange::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
- {
- return IDBKeyRangeBinding::Wrap(aCx, this, aGivenProto, aReflector);
- }
- bool
- IDBLocaleAwareKeyRange::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
- {
- return IDBLocaleAwareKeyRangeBinding::Wrap(aCx, this, aGivenProto, aReflector);
- }
- void
- IDBKeyRange::GetLower(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
- ErrorResult& aRv)
- {
- AssertIsOnOwningThread();
- if (!mHaveCachedLowerVal) {
- if (!mRooted) {
- mozilla::HoldJSObjects(this);
- mRooted = true;
- }
- aRv = Lower().ToJSVal(aCx, mCachedLowerVal);
- if (aRv.Failed()) {
- return;
- }
- mHaveCachedLowerVal = true;
- }
- aResult.set(mCachedLowerVal);
- }
- void
- IDBKeyRange::GetUpper(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
- ErrorResult& aRv)
- {
- AssertIsOnOwningThread();
- if (!mHaveCachedUpperVal) {
- if (!mRooted) {
- mozilla::HoldJSObjects(this);
- mRooted = true;
- }
- aRv = Upper().ToJSVal(aCx, mCachedUpperVal);
- if (aRv.Failed()) {
- return;
- }
- mHaveCachedUpperVal = true;
- }
- aResult.set(mCachedUpperVal);
- }
- bool
- IDBKeyRange::Includes(JSContext* aCx,
- JS::Handle<JS::Value> aValue,
- ErrorResult& aRv) const
- {
- Key key;
- aRv = GetKeyFromJSVal(aCx, aValue, key);
- if (aRv.Failed()) {
- return false;
- }
- MOZ_ASSERT(!(Lower().IsUnset() && Upper().IsUnset()));
- MOZ_ASSERT_IF(IsOnly(),
- !Lower().IsUnset() && !LowerOpen() &&
- Lower() == Upper() && LowerOpen() == UpperOpen());
- if (!Lower().IsUnset()) {
- switch (Key::CompareKeys(Lower(), key)) {
- case 1:
- return false;
- case 0:
- // Identical keys.
- return !LowerOpen();
- case -1:
- if (IsOnly()) {
- return false;
- }
- break;
- default:
- MOZ_CRASH();
- }
- }
- if (!Upper().IsUnset()) {
- switch (Key::CompareKeys(key, Upper())) {
- case 1:
- return false;
- case 0:
- // Identical keys.
- return !UpperOpen();
- case -1:
- break;
- }
- }
- return true;
- }
- // static
- already_AddRefed<IDBKeyRange>
- IDBKeyRange::Only(const GlobalObject& aGlobal,
- JS::Handle<JS::Value> aValue,
- ErrorResult& aRv)
- {
- RefPtr<IDBKeyRange> keyRange =
- new IDBKeyRange(aGlobal.GetAsSupports(), false, false, true);
- aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Lower());
- if (aRv.Failed()) {
- return nullptr;
- }
- return keyRange.forget();
- }
- // static
- already_AddRefed<IDBKeyRange>
- IDBKeyRange::LowerBound(const GlobalObject& aGlobal,
- JS::Handle<JS::Value> aValue,
- bool aOpen,
- ErrorResult& aRv)
- {
- RefPtr<IDBKeyRange> keyRange =
- new IDBKeyRange(aGlobal.GetAsSupports(), aOpen, true, false);
- aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Lower());
- if (aRv.Failed()) {
- return nullptr;
- }
- return keyRange.forget();
- }
- // static
- already_AddRefed<IDBKeyRange>
- IDBKeyRange::UpperBound(const GlobalObject& aGlobal,
- JS::Handle<JS::Value> aValue,
- bool aOpen,
- ErrorResult& aRv)
- {
- RefPtr<IDBKeyRange> keyRange =
- new IDBKeyRange(aGlobal.GetAsSupports(), true, aOpen, false);
- aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Upper());
- if (aRv.Failed()) {
- return nullptr;
- }
- return keyRange.forget();
- }
- // static
- already_AddRefed<IDBKeyRange>
- IDBKeyRange::Bound(const GlobalObject& aGlobal,
- JS::Handle<JS::Value> aLower,
- JS::Handle<JS::Value> aUpper,
- bool aLowerOpen,
- bool aUpperOpen,
- ErrorResult& aRv)
- {
- RefPtr<IDBKeyRange> keyRange =
- new IDBKeyRange(aGlobal.GetAsSupports(), aLowerOpen, aUpperOpen, false);
- aRv = GetKeyFromJSVal(aGlobal.Context(), aLower, keyRange->Lower());
- if (aRv.Failed()) {
- return nullptr;
- }
- aRv = GetKeyFromJSVal(aGlobal.Context(), aUpper, keyRange->Upper());
- if (aRv.Failed()) {
- return nullptr;
- }
- if (keyRange->Lower() > keyRange->Upper() ||
- (keyRange->Lower() == keyRange->Upper() && (aLowerOpen || aUpperOpen))) {
- aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
- return nullptr;
- }
- return keyRange.forget();
- }
- // static
- already_AddRefed<IDBLocaleAwareKeyRange>
- IDBLocaleAwareKeyRange::Bound(const GlobalObject& aGlobal,
- JS::Handle<JS::Value> aLower,
- JS::Handle<JS::Value> aUpper,
- bool aLowerOpen,
- bool aUpperOpen,
- ErrorResult& aRv)
- {
- RefPtr<IDBLocaleAwareKeyRange> keyRange =
- new IDBLocaleAwareKeyRange(aGlobal.GetAsSupports(), aLowerOpen, aUpperOpen, false);
- aRv = GetKeyFromJSVal(aGlobal.Context(), aLower, keyRange->Lower());
- if (aRv.Failed()) {
- return nullptr;
- }
- aRv = GetKeyFromJSVal(aGlobal.Context(), aUpper, keyRange->Upper());
- if (aRv.Failed()) {
- return nullptr;
- }
- if (keyRange->Lower() == keyRange->Upper() && (aLowerOpen || aUpperOpen)) {
- aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
- return nullptr;
- }
- return keyRange.forget();
- }
- } // namespace dom
- } // namespace mozilla
|