mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 15:23:51 +00:00
Bug 1118028 - Allow objectStores and indexes to be renamed. r=khuey
--HG-- extra : rebase_source : 4f2d1da2ddafbe786c3908eb46723b4d2f0c48cc
This commit is contained in:
parent
d73d8b0f4e
commit
e0e7ead1f0
@ -3987,7 +3987,7 @@ UpgradeIndexDataValuesFunction::OnFunctionCall(mozIStorageValueArray* aArguments
|
||||
rv = MakeCompressedIndexDataValues(oldIdv, newIdv, &newIdvLength);
|
||||
|
||||
std::pair<uint8_t*, int> data(newIdv.release(), newIdvLength);
|
||||
|
||||
|
||||
nsCOMPtr<nsIVariant> result = new storage::AdoptedBlobVariant(data);
|
||||
|
||||
result.forget(aResult);
|
||||
@ -6990,6 +6990,10 @@ private:
|
||||
virtual bool
|
||||
RecvDeleteObjectStore(const int64_t& aObjectStoreId) override;
|
||||
|
||||
virtual bool
|
||||
RecvRenameObjectStore(const int64_t& aObjectStoreId,
|
||||
const nsString& aName) override;
|
||||
|
||||
virtual bool
|
||||
RecvCreateIndex(const int64_t& aObjectStoreId,
|
||||
const IndexMetadata& aMetadata) override;
|
||||
@ -6998,6 +7002,11 @@ private:
|
||||
RecvDeleteIndex(const int64_t& aObjectStoreId,
|
||||
const int64_t& aIndexId) override;
|
||||
|
||||
virtual bool
|
||||
RecvRenameIndex(const int64_t& aObjectStoreId,
|
||||
const int64_t& aIndexId,
|
||||
const nsString& aName) override;
|
||||
|
||||
virtual PBackgroundIDBRequestParent*
|
||||
AllocPBackgroundIDBRequestParent(const RequestParams& aParams) override;
|
||||
|
||||
@ -7747,6 +7756,30 @@ private:
|
||||
DoDatabaseWork(DatabaseConnection* aConnection) override;
|
||||
};
|
||||
|
||||
class RenameObjectStoreOp final
|
||||
: public VersionChangeTransactionOp
|
||||
{
|
||||
friend class VersionChangeTransaction;
|
||||
|
||||
const RefPtr<FullObjectStoreMetadata> mMetadata;
|
||||
|
||||
private:
|
||||
// Only created by VersionChangeTransaction.
|
||||
RenameObjectStoreOp(VersionChangeTransaction* aTransaction,
|
||||
FullObjectStoreMetadata* const aMetadata)
|
||||
: VersionChangeTransactionOp(aTransaction)
|
||||
, mMetadata(aMetadata)
|
||||
{
|
||||
MOZ_ASSERT(aMetadata->mCommonMetadata.id());
|
||||
}
|
||||
|
||||
~RenameObjectStoreOp()
|
||||
{ }
|
||||
|
||||
virtual nsresult
|
||||
DoDatabaseWork(DatabaseConnection* aConnection) override;
|
||||
};
|
||||
|
||||
class CreateIndexOp final
|
||||
: public VersionChangeTransactionOp
|
||||
{
|
||||
@ -7923,6 +7956,33 @@ private:
|
||||
DoDatabaseWork(DatabaseConnection* aConnection) override;
|
||||
};
|
||||
|
||||
class RenameIndexOp final
|
||||
: public VersionChangeTransactionOp
|
||||
{
|
||||
friend class VersionChangeTransaction;
|
||||
|
||||
const RefPtr<FullIndexMetadata> mMetadata;
|
||||
const int64_t mObjectStoreId;
|
||||
|
||||
private:
|
||||
// Only created by VersionChangeTransaction.
|
||||
RenameIndexOp(VersionChangeTransaction* aTransaction,
|
||||
FullIndexMetadata* const aMetadata,
|
||||
int64_t aObjectStoreId)
|
||||
: VersionChangeTransactionOp(aTransaction)
|
||||
, mMetadata(aMetadata)
|
||||
, mObjectStoreId(aObjectStoreId)
|
||||
{
|
||||
MOZ_ASSERT(aMetadata->mCommonMetadata.id());
|
||||
}
|
||||
|
||||
~RenameIndexOp()
|
||||
{ }
|
||||
|
||||
virtual nsresult
|
||||
DoDatabaseWork(DatabaseConnection* aConnection) override;
|
||||
};
|
||||
|
||||
class NormalTransactionOp
|
||||
: public TransactionDatabaseOperationBase
|
||||
, public PBackgroundIDBRequestParent
|
||||
@ -15562,6 +15622,54 @@ VersionChangeTransaction::RecvDeleteObjectStore(const int64_t& aObjectStoreId)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VersionChangeTransaction::RecvRenameObjectStore(const int64_t& aObjectStoreId,
|
||||
const nsString& aName)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (NS_WARN_IF(!aObjectStoreId)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
||||
const RefPtr<FullDatabaseMetadata> dbMetadata = GetDatabase()->Metadata();
|
||||
MOZ_ASSERT(dbMetadata);
|
||||
MOZ_ASSERT(dbMetadata->mNextObjectStoreId > 0);
|
||||
|
||||
if (NS_WARN_IF(aObjectStoreId >= dbMetadata->mNextObjectStoreId)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<FullObjectStoreMetadata> foundMetadata =
|
||||
GetMetadataForObjectStoreId(aObjectStoreId);
|
||||
|
||||
if (NS_WARN_IF(!foundMetadata)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(mCommitOrAbortReceived)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
||||
foundMetadata->mCommonMetadata.name() = aName;
|
||||
|
||||
RefPtr<RenameObjectStoreOp> renameOp =
|
||||
new RenameObjectStoreOp(this, foundMetadata);
|
||||
|
||||
if (NS_WARN_IF(!renameOp->Init(this))) {
|
||||
renameOp->Cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
renameOp->DispatchToConnectionPool();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VersionChangeTransaction::RecvCreateIndex(const int64_t& aObjectStoreId,
|
||||
const IndexMetadata& aMetadata)
|
||||
@ -15717,6 +15825,74 @@ VersionChangeTransaction::RecvDeleteIndex(const int64_t& aObjectStoreId,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VersionChangeTransaction::RecvRenameIndex(const int64_t& aObjectStoreId,
|
||||
const int64_t& aIndexId,
|
||||
const nsString& aName)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (NS_WARN_IF(!aObjectStoreId)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!aIndexId)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
||||
const RefPtr<FullDatabaseMetadata> dbMetadata = GetDatabase()->Metadata();
|
||||
MOZ_ASSERT(dbMetadata);
|
||||
MOZ_ASSERT(dbMetadata->mNextObjectStoreId > 0);
|
||||
MOZ_ASSERT(dbMetadata->mNextIndexId > 0);
|
||||
|
||||
if (NS_WARN_IF(aObjectStoreId >= dbMetadata->mNextObjectStoreId)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(aIndexId >= dbMetadata->mNextIndexId)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<FullObjectStoreMetadata> foundObjectStoreMetadata =
|
||||
GetMetadataForObjectStoreId(aObjectStoreId);
|
||||
|
||||
if (NS_WARN_IF(!foundObjectStoreMetadata)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<FullIndexMetadata> foundIndexMetadata =
|
||||
GetMetadataForIndexId(foundObjectStoreMetadata, aIndexId);
|
||||
|
||||
if (NS_WARN_IF(!foundIndexMetadata)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(mCommitOrAbortReceived)) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
||||
foundIndexMetadata->mCommonMetadata.name() = aName;
|
||||
|
||||
RefPtr<RenameIndexOp> renameOp =
|
||||
new RenameIndexOp(this, foundIndexMetadata, aObjectStoreId);
|
||||
|
||||
if (NS_WARN_IF(!renameOp->Init(this))) {
|
||||
renameOp->Cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
renameOp->DispatchToConnectionPool();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PBackgroundIDBRequestParent*
|
||||
VersionChangeTransaction::AllocPBackgroundIDBRequestParent(
|
||||
const RequestParams& aParams)
|
||||
@ -23484,6 +23660,91 @@ DeleteObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
RenameObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
||||
{
|
||||
MOZ_ASSERT(aConnection);
|
||||
aConnection->AssertIsOnConnectionThread();
|
||||
|
||||
PROFILER_LABEL("IndexedDB",
|
||||
"RenameObjectStoreOp::DoDatabaseWork",
|
||||
js::ProfileEntry::Category::STORAGE);
|
||||
|
||||
if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Make sure that we're not renaming an object store with the same name as
|
||||
// another that already exists. This should be impossible because we should
|
||||
// have thrown an error long before now...
|
||||
DatabaseConnection::CachedStatement stmt;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT name "
|
||||
"FROM object_store "
|
||||
"WHERE name = :name "
|
||||
"AND id != :id;"),
|
||||
&stmt));
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
stmt->BindStringByName(NS_LITERAL_CSTRING("name"),
|
||||
mMetadata->mCommonMetadata.name()));
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
|
||||
mMetadata->mCommonMetadata.id()));
|
||||
|
||||
bool hasResult;
|
||||
MOZ_ALWAYS_SUCCEEDS(stmt->ExecuteStep(&hasResult));
|
||||
MOZ_ASSERT(!hasResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
DatabaseConnection::AutoSavepoint autoSave;
|
||||
nsresult rv = autoSave.Start(Transaction());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
DatabaseConnection::CachedStatement stmt;
|
||||
rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE object_store "
|
||||
"SET name = :name "
|
||||
"WHERE id = :id;"),
|
||||
&stmt);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"),
|
||||
mMetadata->mCommonMetadata.name());
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
|
||||
mMetadata->mCommonMetadata.id());
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->Execute();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = autoSave.Commit();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
CreateIndexOp::CreateIndexOp(VersionChangeTransaction* aTransaction,
|
||||
const int64_t aObjectStoreId,
|
||||
const IndexMetadata& aMetadata)
|
||||
@ -23792,7 +24053,7 @@ NormalJSRuntime::Init()
|
||||
}
|
||||
|
||||
// Not setting this will cause JS_CHECK_RECURSION to report false positives.
|
||||
JS_SetNativeStackQuota(mRuntime, 128 * sizeof(size_t) * 1024);
|
||||
JS_SetNativeStackQuota(mRuntime, 128 * sizeof(size_t) * 1024);
|
||||
|
||||
mContext = JS_NewContext(mRuntime, 0);
|
||||
if (NS_WARN_IF(!mContext)) {
|
||||
@ -24501,6 +24762,99 @@ DeleteIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
RenameIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
||||
{
|
||||
MOZ_ASSERT(aConnection);
|
||||
aConnection->AssertIsOnConnectionThread();
|
||||
|
||||
PROFILER_LABEL("IndexedDB",
|
||||
"RenameIndexOp::DoDatabaseWork",
|
||||
js::ProfileEntry::Category::STORAGE);
|
||||
|
||||
if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Make sure that we're not renaming an index with the same name as another
|
||||
// that already exists. This should be impossible because we should have
|
||||
// thrown an error long before now...
|
||||
DatabaseConnection::CachedStatement stmt;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT name "
|
||||
"FROM object_store_index "
|
||||
"WHERE object_store_id = :object_store_id "
|
||||
"AND name = :name "
|
||||
"AND id != :id;"),
|
||||
&stmt));
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
stmt->BindInt64ByName(NS_LITERAL_CSTRING("object_store_id"),
|
||||
mObjectStoreId));
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
stmt->BindStringByName(NS_LITERAL_CSTRING("name"),
|
||||
mMetadata->mCommonMetadata.name()));
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
|
||||
mMetadata->mCommonMetadata.id()));
|
||||
|
||||
bool hasResult;
|
||||
MOZ_ALWAYS_SUCCEEDS(stmt->ExecuteStep(&hasResult));
|
||||
MOZ_ASSERT(!hasResult);
|
||||
}
|
||||
#else
|
||||
Unused << mObjectStoreId;
|
||||
#endif
|
||||
|
||||
DatabaseConnection::AutoSavepoint autoSave;
|
||||
nsresult rv = autoSave.Start(Transaction());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
DatabaseConnection::CachedStatement stmt;
|
||||
rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
|
||||
"UPDATE object_store_index "
|
||||
"SET name = :name "
|
||||
"WHERE id = :id;"),
|
||||
&stmt);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"),
|
||||
mMetadata->mCommonMetadata.name());
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
|
||||
mMetadata->mCommonMetadata.id());
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->Execute();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = autoSave.Commit();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
NormalTransactionOp::ObjectStoreHasIndexes(NormalTransactionOp* aOp,
|
||||
|
@ -1349,5 +1349,85 @@ Observer::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
IDBDatabase::RenameObjectStore(int64_t aObjectStoreId, const nsAString& aName)
|
||||
{
|
||||
MOZ_ASSERT(mSpec);
|
||||
|
||||
nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores();
|
||||
|
||||
ObjectStoreSpec* foundObjectStoreSpec = nullptr;
|
||||
// Find the matched object store spec and check if 'aName' is already used by
|
||||
// another object store.
|
||||
for (uint32_t objCount = objectStores.Length(), objIndex = 0;
|
||||
objIndex < objCount;
|
||||
objIndex++) {
|
||||
const ObjectStoreSpec& objSpec = objectStores[objIndex];
|
||||
if (objSpec.metadata().id() == aObjectStoreId) {
|
||||
MOZ_ASSERT(!foundObjectStoreSpec);
|
||||
foundObjectStoreSpec = &objectStores[objIndex];
|
||||
continue;
|
||||
}
|
||||
if (aName == objSpec.metadata().name()) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(foundObjectStoreSpec);
|
||||
|
||||
// Update the name of the matched object store.
|
||||
foundObjectStoreSpec->metadata().name() = nsString(aName);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
IDBDatabase::RenameIndex(int64_t aObjectStoreId,
|
||||
int64_t aIndexId,
|
||||
const nsAString& aName)
|
||||
{
|
||||
MOZ_ASSERT(mSpec);
|
||||
|
||||
nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores();
|
||||
|
||||
ObjectStoreSpec* foundObjectStoreSpec = nullptr;
|
||||
// Find the matched index metadata and check if 'aName' is already used by
|
||||
// another index.
|
||||
for (uint32_t objCount = objectStores.Length(), objIndex = 0;
|
||||
objIndex < objCount;
|
||||
objIndex++) {
|
||||
const ObjectStoreSpec& objSpec = objectStores[objIndex];
|
||||
if (objSpec.metadata().id() == aObjectStoreId) {
|
||||
foundObjectStoreSpec = &objectStores[objIndex];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(foundObjectStoreSpec);
|
||||
|
||||
nsTArray<IndexMetadata>& indexes = foundObjectStoreSpec->indexes();
|
||||
IndexMetadata* foundIndexMetadata = nullptr;
|
||||
for (uint32_t idxCount = indexes.Length(), idxIndex = 0;
|
||||
idxIndex < idxCount;
|
||||
idxIndex++) {
|
||||
const IndexMetadata& metadata = indexes[idxIndex];
|
||||
if (metadata.id() == aIndexId) {
|
||||
MOZ_ASSERT(!foundIndexMetadata);
|
||||
foundIndexMetadata = &indexes[idxIndex];
|
||||
continue;
|
||||
}
|
||||
if (aName == metadata.name()) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(foundIndexMetadata);
|
||||
|
||||
// Update the name of the matched object store.
|
||||
foundIndexMetadata->name() = nsString(aName);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -56,6 +56,9 @@ class IDBDatabase final
|
||||
class Observer;
|
||||
friend class Observer;
|
||||
|
||||
friend class IDBObjectStore;
|
||||
friend class IDBIndex;
|
||||
|
||||
// The factory must be kept alive when IndexedDB is used in multiple
|
||||
// processes. If it dies then the entire actor tree will be destroyed with it
|
||||
// and the world will explode.
|
||||
@ -327,6 +330,14 @@ private:
|
||||
const nsAString& aFilename,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber);
|
||||
|
||||
// Only accessed by IDBObjectStore.
|
||||
nsresult
|
||||
RenameObjectStore(int64_t aObjectStoreId, const nsAString& aName);
|
||||
|
||||
// Only accessed by IDBIndex.
|
||||
nsresult
|
||||
RenameIndex(int64_t aObjectStoreId, int64_t aIndexId, const nsAString& aName);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -149,6 +149,63 @@ IDBIndex::Name() const
|
||||
return mMetadata->name();
|
||||
}
|
||||
|
||||
void
|
||||
IDBIndex::SetName(const nsAString& aName, ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
IDBTransaction* transaction = mObjectStore->Transaction();
|
||||
|
||||
if (transaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
|
||||
mDeletedMetadata) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!transaction->IsOpen()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aName == mMetadata->name()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache logging string of this index before renaming.
|
||||
const LoggingString loggingOldIndex(this);
|
||||
|
||||
const int64_t indexId = Id();
|
||||
|
||||
nsresult rv =
|
||||
transaction->Database()->RenameIndex(mObjectStore->Id(),
|
||||
indexId,
|
||||
aName);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't do this in the macro because we always need to increment the serial
|
||||
// number to keep in sync with the parent.
|
||||
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
|
||||
|
||||
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
||||
"database(%s).transaction(%s).objectStore(%s).index(%s)."
|
||||
"rename(%s)",
|
||||
"IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.rename()",
|
||||
IDB_LOG_ID_STRING(),
|
||||
transaction->LoggingSerialNumber(),
|
||||
requestSerialNumber,
|
||||
IDB_LOG_STRINGIFY(transaction->Database()),
|
||||
IDB_LOG_STRINGIFY(transaction),
|
||||
IDB_LOG_STRINGIFY(mObjectStore),
|
||||
loggingOldIndex.get(),
|
||||
IDB_LOG_STRINGIFY(this));
|
||||
|
||||
transaction->RenameIndex(mObjectStore, indexId, aName);
|
||||
}
|
||||
|
||||
bool
|
||||
IDBIndex::Unique() const
|
||||
{
|
||||
|
@ -106,6 +106,9 @@ public:
|
||||
aName = Name();
|
||||
}
|
||||
|
||||
void
|
||||
SetName(const nsAString& aName, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
GetKeyPath(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aResult,
|
||||
|
@ -2265,6 +2265,59 @@ IDBObjectStore::Name() const
|
||||
return mSpec->metadata().name();
|
||||
}
|
||||
|
||||
void
|
||||
IDBObjectStore::SetName(const nsAString& aName, ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
|
||||
mDeletedSpec) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
IDBTransaction* transaction = IDBTransaction::GetCurrent();
|
||||
if (!transaction || transaction != mTransaction) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(transaction->IsOpen());
|
||||
|
||||
if (aName == mSpec->metadata().name()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache logging string of this object store before renaming.
|
||||
const LoggingString loggingOldObjectStore(this);
|
||||
|
||||
nsresult rv =
|
||||
transaction->Database()->RenameObjectStore(mSpec->metadata().id(),
|
||||
aName);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't do this in the macro because we always need to increment the serial
|
||||
// number to keep in sync with the parent.
|
||||
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
|
||||
|
||||
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
||||
"database(%s).transaction(%s).objectStore(%s).rename(%s)",
|
||||
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.rename()",
|
||||
IDB_LOG_ID_STRING(),
|
||||
mTransaction->LoggingSerialNumber(),
|
||||
requestSerialNumber,
|
||||
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
||||
IDB_LOG_STRINGIFY(mTransaction),
|
||||
loggingOldObjectStore.get(),
|
||||
IDB_LOG_STRINGIFY(this));
|
||||
|
||||
transaction->RenameObjectStore(mSpec->metadata().id(), aName);
|
||||
}
|
||||
|
||||
bool
|
||||
IDBObjectStore::AutoIncrement() const
|
||||
{
|
||||
|
@ -151,6 +151,9 @@ public:
|
||||
aName = Name();
|
||||
}
|
||||
|
||||
void
|
||||
SetName(const nsAString& aName, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
GetKeyPath(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
|
||||
ErrorResult& aRv);
|
||||
|
@ -566,6 +566,20 @@ IDBTransaction::DeleteObjectStore(int64_t aObjectStoreId)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IDBTransaction::RenameObjectStore(int64_t aObjectStoreId,
|
||||
const nsAString& aName)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aObjectStoreId);
|
||||
MOZ_ASSERT(VERSION_CHANGE == mMode);
|
||||
MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor);
|
||||
MOZ_ASSERT(IsOpen());
|
||||
|
||||
MOZ_ALWAYS_TRUE(mBackgroundActor.mVersionChangeBackgroundActor->
|
||||
SendRenameObjectStore(aObjectStoreId, nsString(aName)));
|
||||
}
|
||||
|
||||
void
|
||||
IDBTransaction::CreateIndex(IDBObjectStore* aObjectStore,
|
||||
const indexedDB::IndexMetadata& aMetadata)
|
||||
@ -596,6 +610,24 @@ IDBTransaction::DeleteIndex(IDBObjectStore* aObjectStore,
|
||||
SendDeleteIndex(aObjectStore->Id(), aIndexId));
|
||||
}
|
||||
|
||||
void
|
||||
IDBTransaction::RenameIndex(IDBObjectStore* aObjectStore,
|
||||
int64_t aIndexId,
|
||||
const nsAString& aName)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aObjectStore);
|
||||
MOZ_ASSERT(aIndexId);
|
||||
MOZ_ASSERT(VERSION_CHANGE == mMode);
|
||||
MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor);
|
||||
MOZ_ASSERT(IsOpen());
|
||||
|
||||
MOZ_ALWAYS_TRUE(mBackgroundActor.mVersionChangeBackgroundActor->
|
||||
SendRenameIndex(aObjectStore->Id(),
|
||||
aIndexId,
|
||||
nsString(aName)));
|
||||
}
|
||||
|
||||
void
|
||||
IDBTransaction::AbortInternal(nsresult aAbortCode,
|
||||
already_AddRefed<DOMError> aError)
|
||||
|
@ -245,12 +245,18 @@ public:
|
||||
void
|
||||
DeleteObjectStore(int64_t aObjectStoreId);
|
||||
|
||||
void
|
||||
RenameObjectStore(int64_t aObjectStoreId, const nsAString& aName);
|
||||
|
||||
void
|
||||
CreateIndex(IDBObjectStore* aObjectStore, const indexedDB::IndexMetadata& aMetadata);
|
||||
|
||||
void
|
||||
DeleteIndex(IDBObjectStore* aObjectStore, int64_t aIndexId);
|
||||
|
||||
void
|
||||
RenameIndex(IDBObjectStore* aObjectStore, int64_t aIndexId, const nsAString& aName);
|
||||
|
||||
void
|
||||
Abort(IDBRequest* aRequest);
|
||||
|
||||
|
@ -30,11 +30,16 @@ parent:
|
||||
|
||||
async CreateObjectStore(ObjectStoreMetadata metadata);
|
||||
async DeleteObjectStore(int64_t objectStoreId);
|
||||
async RenameObjectStore(int64_t objectStoreId,
|
||||
nsString name);
|
||||
|
||||
async CreateIndex(int64_t objectStoreId,
|
||||
IndexMetadata metadata);
|
||||
async DeleteIndex(int64_t objectStoreId,
|
||||
int64_t indexId);
|
||||
async RenameIndex(int64_t objectStoreId,
|
||||
int64_t indexId,
|
||||
nsString name);
|
||||
|
||||
async PBackgroundIDBCursor(OpenCursorParams params);
|
||||
|
||||
|
@ -82,7 +82,11 @@ support-files =
|
||||
unit/test_readonly_transactions.js
|
||||
unit/test_readwriteflush_disabled.js
|
||||
unit/test_remove_index.js
|
||||
unit/test_rename_index.js
|
||||
unit/test_rename_index_errors.js
|
||||
unit/test_remove_objectStore.js
|
||||
unit/test_rename_objectStore.js
|
||||
unit/test_rename_objectStore_errors.js
|
||||
unit/test_request_readyState.js
|
||||
unit/test_setVersion.js
|
||||
unit/test_setVersion_abort.js
|
||||
@ -317,8 +321,16 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
[test_remove_index.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
[test_rename_index.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
[test_rename_index_errors.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
[test_remove_objectStore.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || (buildapp == 'mulet') # Bug 931116 # TC: Bug 1144079 - Re-enable Mulet mochitests and reftests taskcluster-specific disables.
|
||||
[test_rename_objectStore.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
[test_rename_objectStore_errors.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
[test_request_readyState.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
[test_sandbox.html]
|
||||
|
19
dom/indexedDB/test/test_rename_index.html
Normal file
19
dom/indexedDB/test/test_rename_index.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7" src="unit/test_rename_index.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
19
dom/indexedDB/test/test_rename_index_errors.html
Normal file
19
dom/indexedDB/test/test_rename_index_errors.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7" src="unit/test_rename_index_errors.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
19
dom/indexedDB/test/test_rename_objectStore.html
Normal file
19
dom/indexedDB/test/test_rename_objectStore.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7" src="unit/test_rename_objectStore.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
19
dom/indexedDB/test/test_rename_objectStore_errors.html
Normal file
19
dom/indexedDB/test/test_rename_objectStore_errors.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7" src="unit/test_rename_objectStore_errors.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
193
dom/indexedDB/test/unit/test_rename_index.js
Normal file
193
dom/indexedDB/test/unit/test_rename_index.js
Normal file
@ -0,0 +1,193 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
const name = this.window ? window.location.pathname : "Splendid Test";
|
||||
const storeName = "test store";
|
||||
const indexName_ToBeDeleted = "test index to be deleted";
|
||||
const indexName_v0 = "test index v0";
|
||||
const indexName_v1 = "test index v1";
|
||||
const indexName_v2 = "test index v2";
|
||||
const indexName_v3 = indexName_ToBeDeleted;
|
||||
const indexName_v4 = "test index v4";
|
||||
|
||||
info("Rename in v1.");
|
||||
let request = indexedDB.open(name, 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
let db = event.target.result;
|
||||
let txn = event.target.transaction;
|
||||
|
||||
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
|
||||
|
||||
let objectStore = db.createObjectStore(storeName, { keyPath: "foo" });
|
||||
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
|
||||
is(db.objectStoreNames.item(0), objectStore.name, "Correct object store name");
|
||||
|
||||
// create index to be deleted later in v3.
|
||||
objectStore.createIndex(indexName_ToBeDeleted, "foo");
|
||||
ok(objectStore.index(indexName_ToBeDeleted), "Index created.");
|
||||
|
||||
// create target index to be renamed.
|
||||
let index = objectStore.createIndex(indexName_v0, "bar");
|
||||
ok(objectStore.index(indexName_v0), "Index created.");
|
||||
is(index.name, indexName_v0, "Correct index name");
|
||||
index.name = indexName_v1;
|
||||
is(index.name, indexName_v1, "Renamed index successfully");
|
||||
|
||||
txn.oncomplete = continueToNextStepSync;
|
||||
yield undefined;
|
||||
request.onsuccess = continueToNextStep;
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
info("Verify renaming done in v1 and run renaming in v2.");
|
||||
request = indexedDB.open(name, 2);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = event.target.transaction;
|
||||
|
||||
objectStore = txn.objectStore(storeName);
|
||||
|
||||
// indexName_v0 created in v1 shall not be available.
|
||||
try {
|
||||
index = objectStore.index(indexName_v0);
|
||||
ok(false, "NotFoundError shall be thrown.");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "got a database exception");
|
||||
is(e.name, "NotFoundError", "correct error");
|
||||
}
|
||||
|
||||
// rename to "v2".
|
||||
index = objectStore.index(indexName_v1);
|
||||
is(index.name, indexName_v1, "Correct index name")
|
||||
index.name = indexName_v2;
|
||||
is(index.name, indexName_v2, "Renamed index successfully");
|
||||
|
||||
txn.oncomplete = continueToNextStepSync;
|
||||
yield undefined;
|
||||
request.onsuccess = continueToNextStep;
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
info("Verify renaming done in v2.");
|
||||
request = indexedDB.open(name, 2);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = db.transaction(storeName);
|
||||
|
||||
objectStore = txn.objectStore(storeName);
|
||||
index = objectStore.index(indexName_v2);
|
||||
is(index.name, indexName_v2, "Correct index name");
|
||||
|
||||
db.close();
|
||||
|
||||
info("Rename in v3.");
|
||||
request = indexedDB.open(name, 3);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = event.target.transaction;
|
||||
|
||||
objectStore = txn.objectStore(storeName);
|
||||
ok(objectStore.index(indexName_ToBeDeleted), "index is valid.");
|
||||
objectStore.deleteIndex(indexName_ToBeDeleted);
|
||||
try {
|
||||
objectStore.index(indexName_ToBeDeleted);
|
||||
ok(false, "NotFoundError shall be thrown if the index name is deleted.");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "got a database exception");
|
||||
is(e.name, "NotFoundError", "correct error");
|
||||
}
|
||||
|
||||
info("Rename with the name of the deleted index.");
|
||||
index = objectStore.index(indexName_v2);
|
||||
index.name = indexName_v3;
|
||||
is(index.name, indexName_v3, "Renamed index successfully");
|
||||
|
||||
txn.oncomplete = continueToNextStepSync;
|
||||
yield undefined;
|
||||
request.onsuccess = continueToNextStep;
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
info("Verify renaming done in v3.");
|
||||
request = indexedDB.open(name, 3);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = db.transaction(storeName);
|
||||
|
||||
objectStore = txn.objectStore(storeName);
|
||||
index = objectStore.index(indexName_v3);
|
||||
is(index.name, indexName_v3, "Correct index name");
|
||||
|
||||
db.close();
|
||||
|
||||
info("Abort the version change transaction while renaming index.");
|
||||
request = indexedDB.open(name, 4);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = event.target.transaction;
|
||||
|
||||
objectStore = txn.objectStore(storeName);
|
||||
index = objectStore.index(indexName_v3);
|
||||
index.name = indexName_v4;
|
||||
is(index.name, indexName_v4, "Renamed successfully");
|
||||
let putRequest = objectStore.put({ foo: "fooValue", bar: "barValue" });
|
||||
putRequest.onsuccess = continueToNextStepSync;
|
||||
yield undefined;
|
||||
|
||||
// Aborting the transaction.
|
||||
request.onerror = expectedErrorHandler("AbortError");
|
||||
txn.abort();
|
||||
yield undefined;
|
||||
|
||||
// Verify if the name of the index handle is reverted.
|
||||
is(index.name, indexName_v3, "The name is reverted after aborted.");
|
||||
|
||||
info("Verify if the objectstore name is unchanged.");
|
||||
request = indexedDB.open(name, 3);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = db.transaction(storeName);
|
||||
|
||||
objectStore = txn.objectStore(storeName);
|
||||
index = objectStore.index(indexName_v3);
|
||||
is(index.name, indexName_v3, "Correct index name");
|
||||
|
||||
db.close();
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
129
dom/indexedDB/test/unit/test_rename_index_errors.js
Normal file
129
dom/indexedDB/test/unit/test_rename_index_errors.js
Normal file
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
const name = this.window ? window.location.pathname : "Splendid Test";
|
||||
const storeName = "test store";
|
||||
const indexName1 = "test index 1";
|
||||
const indexName2 = "test index 2";
|
||||
|
||||
info("Setup test indexes.");
|
||||
let request = indexedDB.open(name, 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
let db = event.target.result;
|
||||
let txn = event.target.transaction;
|
||||
|
||||
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
|
||||
|
||||
let objectStore = db.createObjectStore(storeName, { keyPath: "foo" });
|
||||
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
|
||||
is(db.objectStoreNames.item(0), objectStore.name, "Correct name");
|
||||
|
||||
let index1 = objectStore.createIndex(indexName1, "bar");
|
||||
is(objectStore.index(indexName1).name, index1.name, "Correct index name");
|
||||
is(index1.name, indexName1, "Correct index name");
|
||||
let index2 = objectStore.createIndex(indexName2, "baz");
|
||||
is(objectStore.index(indexName2).name, index2.name, "Correct index name");
|
||||
is(index2.name, indexName2, "Correct index name");
|
||||
|
||||
txn.oncomplete = continueToNextStepSync;
|
||||
yield undefined;
|
||||
request.onsuccess = continueToNextStep;
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
info("Verify IDB Errors in version 2.");
|
||||
request = indexedDB.open(name, 2);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = event.target.transaction;
|
||||
|
||||
objectStore = txn.objectStore(storeName);
|
||||
index1 = objectStore.index(indexName1);
|
||||
index2 = objectStore.index(indexName2);
|
||||
is(index1.name, indexName1, "Correct index name");
|
||||
is(index2.name, indexName2, "Correct index name");
|
||||
|
||||
// Rename with the name already adopted by the other index.
|
||||
try {
|
||||
index1.name = indexName2;
|
||||
ok(false, "ConstraintError shall be thrown if the index name already exists.");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "got a database exception");
|
||||
is(e.name, "ConstraintError", "correct error");
|
||||
}
|
||||
|
||||
// Rename with identical name.
|
||||
try {
|
||||
index1.name = indexName1;
|
||||
ok(true, "It shall be fine to set the same name.");
|
||||
} catch (e) {
|
||||
ok(false, "Got a database exception: " + e.name);
|
||||
}
|
||||
|
||||
objectStore.deleteIndex(indexName2);
|
||||
|
||||
// Rename after deleted.
|
||||
try {
|
||||
index2.name = indexName2;
|
||||
ok(false, "InvalidStateError shall be thrown if deleted.");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "got a database exception");
|
||||
is(e.name, "InvalidStateError", "correct error");
|
||||
}
|
||||
|
||||
txn.oncomplete = continueToNextStepSync;
|
||||
yield undefined;
|
||||
request.onsuccess = continueToNextStep;
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
// Rename when the transaction is inactive.
|
||||
try {
|
||||
index1.name = indexName1;
|
||||
ok(false, "TransactionInactiveError shall be thrown if the transaction is inactive.");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "got a database exception");
|
||||
is(e.name, "TransactionInactiveError", "correct error");
|
||||
}
|
||||
|
||||
info("Rename when the transaction is not an upgrade one.");
|
||||
request = indexedDB.open(name, 2);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = db.transaction(storeName);
|
||||
objectStore = txn.objectStore(storeName);
|
||||
index1 = objectStore.index(indexName1);
|
||||
|
||||
try {
|
||||
index1.name = indexName1;
|
||||
ok(false, "InvalidStateError shall be thrown if it's not an upgrade transaction.");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "got a database exception");
|
||||
is(e.name, "InvalidStateError", "correct error");
|
||||
}
|
||||
|
||||
txn.oncomplete = continueToNextStepSync;
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
171
dom/indexedDB/test/unit/test_rename_objectStore.js
Normal file
171
dom/indexedDB/test/unit/test_rename_objectStore.js
Normal file
@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
const name = this.window ? window.location.pathname : "Splendid Test";
|
||||
const storeName_ToBeDeleted = "test store to be deleted";
|
||||
const storeName_v0 = "test store v0";
|
||||
const storeName_v1 = "test store v1";
|
||||
const storeName_v2 = "test store v2";
|
||||
const storeName_v3 = storeName_ToBeDeleted;
|
||||
const storeName_v4 = "test store v4";
|
||||
|
||||
info("Rename in v1.");
|
||||
let request = indexedDB.open(name, 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
let db = event.target.result;
|
||||
let txn = event.target.transaction;
|
||||
|
||||
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
|
||||
|
||||
// create objectstore to be deleted later in v3.
|
||||
db.createObjectStore(storeName_ToBeDeleted, { keyPath: "foo" });
|
||||
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
|
||||
ok(db.objectStoreNames.contains(storeName_ToBeDeleted), "Correct name");
|
||||
|
||||
// create target objectstore to be renamed.
|
||||
let objectStore = db.createObjectStore(storeName_v0, { keyPath: "bar" });
|
||||
is(db.objectStoreNames.length, 2, "Correct objectStoreNames list");
|
||||
ok(db.objectStoreNames.contains(objectStore.name), "Correct name");
|
||||
|
||||
objectStore.name = storeName_v1;
|
||||
is(objectStore.name, storeName_v1, "Renamed successfully");
|
||||
|
||||
txn.oncomplete = continueToNextStepSync;
|
||||
yield undefined;
|
||||
request.onsuccess = continueToNextStep;
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
info("Verify renaming done in v1 and run renaming in v2.");
|
||||
request = indexedDB.open(name, 2);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = event.target.transaction;
|
||||
|
||||
is(db.objectStoreNames.length, 2, "Correct objectStoreNames list");
|
||||
ok(db.objectStoreNames.contains(storeName_v1), "Correct name");
|
||||
ok(db.objectStoreNames.contains(storeName_ToBeDeleted), "Correct name");
|
||||
|
||||
objectStore = txn.objectStore(storeName_v1);
|
||||
objectStore.name = storeName_v2;
|
||||
is(objectStore.name, storeName_v2, "Renamed successfully");
|
||||
|
||||
txn.oncomplete = continueToNextStepSync;
|
||||
yield undefined;
|
||||
request.onsuccess = continueToNextStep;
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
info("Verify renaming done in v2.");
|
||||
request = indexedDB.open(name, 2);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
|
||||
is(db.objectStoreNames.length, 2, "Correct objectStoreNames list");
|
||||
ok(db.objectStoreNames.contains(storeName_v2), "Correct name");
|
||||
ok(db.objectStoreNames.contains(storeName_ToBeDeleted), "Correct name");
|
||||
|
||||
db.close();
|
||||
|
||||
info("Rename in v3.");
|
||||
request = indexedDB.open(name, 3);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = event.target.transaction;
|
||||
|
||||
is(db.objectStoreNames.length, 2, "Correct objectStoreNames list");
|
||||
ok(db.objectStoreNames.contains(storeName_v2), "Correct name");
|
||||
ok(db.objectStoreNames.contains(storeName_ToBeDeleted), "Correct name");
|
||||
db.deleteObjectStore(storeName_ToBeDeleted);
|
||||
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
|
||||
ok(db.objectStoreNames.contains(storeName_v2) &&
|
||||
!db.objectStoreNames.contains(storeName_ToBeDeleted), "Deleted correctly");
|
||||
|
||||
objectStore = txn.objectStore(storeName_v2);
|
||||
objectStore.name = storeName_v3;
|
||||
is(objectStore.name, storeName_v3, "Renamed successfully");
|
||||
|
||||
txn.oncomplete = continueToNextStepSync;
|
||||
yield undefined;
|
||||
request.onsuccess = continueToNextStep;
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
info("Verify renaming done in v3.");
|
||||
request = indexedDB.open(name, 3);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
|
||||
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
|
||||
ok(db.objectStoreNames.contains(storeName_v3), "Correct name");
|
||||
|
||||
db.close();
|
||||
|
||||
info("Abort the version change transaction while renaming objectstore.");
|
||||
request = indexedDB.open(name, 4);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = event.target.transaction;
|
||||
|
||||
objectStore = txn.objectStore(storeName_v3);
|
||||
objectStore.name = storeName_v4;
|
||||
is(objectStore.name, storeName_v4, "Renamed successfully");
|
||||
let putRequest = objectStore.put({ bar: "barValue" });
|
||||
putRequest.onsuccess = continueToNextStepSync;
|
||||
yield undefined;
|
||||
|
||||
// Aborting the transaction.
|
||||
request.onerror = expectedErrorHandler("AbortError");
|
||||
txn.abort();
|
||||
yield undefined;
|
||||
|
||||
// Verify if the name of the objectStore handle is reverted.
|
||||
is(objectStore.name, storeName_v3, "The name is reverted after aborted.");
|
||||
|
||||
info("Verify if the objectstore name is unchanged.");
|
||||
request = indexedDB.open(name, 3);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
|
||||
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
|
||||
ok(db.objectStoreNames.contains(storeName_v3), "Correct name");
|
||||
|
||||
db.close();
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
127
dom/indexedDB/test/unit/test_rename_objectStore_errors.js
Normal file
127
dom/indexedDB/test/unit/test_rename_objectStore_errors.js
Normal file
@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
const name = this.window ? window.location.pathname : "Splendid Test";
|
||||
const storeName1 = "test store 1";
|
||||
const storeName2 = "test store 2";
|
||||
|
||||
info("Setup test object stores.");
|
||||
let request = indexedDB.open(name, 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
let event = yield undefined;
|
||||
|
||||
let db = event.target.result;
|
||||
let txn = event.target.transaction;
|
||||
|
||||
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
|
||||
|
||||
let objectStore1 = db.createObjectStore(storeName1, { keyPath: "foo" });
|
||||
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
|
||||
is(db.objectStoreNames.item(0), objectStore1.name, "Correct name");
|
||||
is(objectStore1.name, storeName1, "Correct name");
|
||||
|
||||
let objectStore2 = db.createObjectStore(storeName2, { keyPath: "bar" });
|
||||
is(db.objectStoreNames.length, 2, "Correct objectStoreNames list");
|
||||
is(db.objectStoreNames.item(1), objectStore2.name, "Correct name");
|
||||
is(objectStore2.name, storeName2, "Correct name");
|
||||
|
||||
txn.oncomplete = continueToNextStepSync;
|
||||
yield undefined;
|
||||
request.onsuccess = continueToNextStep;
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
info("Verify IDB Errors in version 2.");
|
||||
request = indexedDB.open(name, 2);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = continueToNextStep;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = event.target.transaction;
|
||||
|
||||
is(db.objectStoreNames.length, 2, "Correct objectStoreNames list");
|
||||
|
||||
objectStore1 = txn.objectStore(storeName1);
|
||||
objectStore2 = txn.objectStore(storeName2);
|
||||
is(objectStore1.name, storeName1, "Correct name");
|
||||
is(objectStore2.name, storeName2, "Correct name");
|
||||
|
||||
// Rename with the name already adopted by the other object store.
|
||||
try {
|
||||
objectStore1.name = storeName2;
|
||||
ok(false, "ConstraintError shall be thrown if the store name already exists.");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "got a database exception");
|
||||
is(e.name, "ConstraintError", "correct error");
|
||||
}
|
||||
|
||||
// Rename with the identical name.
|
||||
try {
|
||||
objectStore1.name = storeName1;
|
||||
ok(true, "It shall be fine to set the same name.");
|
||||
} catch (e) {
|
||||
ok(false, "Got a database exception: " + e.name);
|
||||
}
|
||||
|
||||
db.deleteObjectStore(storeName2);
|
||||
|
||||
// Rename after deleted.
|
||||
try {
|
||||
objectStore2.name = storeName2;
|
||||
ok(false, "InvalidStateError shall be thrown if deleted.");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "got a database exception");
|
||||
is(e.name, "InvalidStateError", "correct error");
|
||||
}
|
||||
|
||||
txn.oncomplete = continueToNextStepSync;
|
||||
yield undefined;
|
||||
request.onsuccess = continueToNextStep;
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
info("Rename when the transaction is inactive.");
|
||||
try {
|
||||
objectStore1.name = storeName1;
|
||||
ok(false, "TransactionInactiveError shall be thrown if the transaction is inactive.");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "got a database exception");
|
||||
is(e.name, "TransactionInactiveError", "correct error");
|
||||
}
|
||||
|
||||
info("Rename when the transaction is not an upgrade one.");
|
||||
request = indexedDB.open(name, 2);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield undefined;
|
||||
|
||||
db = event.target.result;
|
||||
txn = db.transaction(storeName1);
|
||||
objectStore1 = txn.objectStore(storeName1);
|
||||
|
||||
try {
|
||||
objectStore1.name = storeName1;
|
||||
ok(false, "InvalidStateError shall be thrown if it's not an upgrade transaction.");
|
||||
} catch (e) {
|
||||
ok(e instanceof DOMException, "got a database exception");
|
||||
is(e.name, "InvalidStateError", "correct error");
|
||||
}
|
||||
|
||||
txn.oncomplete = continueToNextStepSync;
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
@ -65,7 +65,11 @@ skip-if = toolkit == 'android' # bug 864843
|
||||
[test_put_get_values_autoIncrement.js]
|
||||
[test_readonly_transactions.js]
|
||||
[test_remove_index.js]
|
||||
[test_rename_index.js]
|
||||
[test_rename_index_errors.js]
|
||||
[test_remove_objectStore.js]
|
||||
[test_rename_objectStore.js]
|
||||
[test_rename_objectStore_errors.js]
|
||||
[test_request_readyState.js]
|
||||
[test_sandbox.js]
|
||||
[test_setVersion.js]
|
||||
|
@ -20,7 +20,9 @@ dictionary IDBIndexParameters {
|
||||
|
||||
[Exposed=(Window,Worker,System)]
|
||||
interface IDBIndex {
|
||||
readonly attribute DOMString name;
|
||||
[SetterThrows]
|
||||
attribute DOMString name;
|
||||
|
||||
readonly attribute IDBObjectStore objectStore;
|
||||
|
||||
[Throws]
|
||||
|
@ -14,7 +14,8 @@ dictionary IDBObjectStoreParameters {
|
||||
|
||||
[Exposed=(Window,Worker,System)]
|
||||
interface IDBObjectStore {
|
||||
readonly attribute DOMString name;
|
||||
[SetterThrows]
|
||||
attribute DOMString name;
|
||||
|
||||
[Throws]
|
||||
readonly attribute any keyPath;
|
||||
|
@ -88,7 +88,7 @@ interface IDBDatabase : EventTarget {
|
||||
};
|
||||
|
||||
interface IDBObjectStore {
|
||||
readonly attribute DOMString name;
|
||||
attribute DOMString name;
|
||||
readonly attribute any keyPath;
|
||||
readonly attribute DOMStringList indexNames;
|
||||
readonly attribute IDBTransaction transaction;
|
||||
@ -106,7 +106,7 @@ interface IDBObjectStore {
|
||||
};
|
||||
|
||||
interface IDBIndex {
|
||||
readonly attribute DOMString name;
|
||||
attribute DOMString name;
|
||||
readonly attribute IDBObjectStore objectStore;
|
||||
readonly attribute any keyPath;
|
||||
readonly attribute boolean multiEntry;
|
||||
|
Loading…
Reference in New Issue
Block a user