Back out fb4d12d2a2da, bug 701772, due to leaks.

This commit is contained in:
Jonas Sicking 2011-12-16 13:09:42 -08:00
parent 817fccb725
commit 488e12717c
23 changed files with 1233 additions and 1173 deletions

View File

@ -71,13 +71,14 @@ CloneObjectStoreInfo(const nsAString& aKey,
{
ObjectStoreInfoHash* hash = static_cast<ObjectStoreInfoHash*>(aUserArg);
nsRefPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo(*aData));
nsAutoPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo(*aData));
if (!hash->Put(aKey, newInfo)) {
NS_WARNING("Out of memory?");
return PL_DHASH_STOP;
}
newInfo.forget();
return PL_DHASH_NEXT;
}
@ -91,23 +92,12 @@ DatabaseInfo::~DatabaseInfo()
}
}
ObjectStoreInfo::ObjectStoreInfo(ObjectStoreInfo& aOther)
: name(aOther.name),
id(aOther.id),
keyPath(aOther.keyPath),
indexes(aOther.indexes),
nextAutoIncrementId(aOther.nextAutoIncrementId),
comittedAutoIncrementId(aOther.comittedAutoIncrementId)
{
// Doesn't copy the refcount
MOZ_COUNT_CTOR(ObjectStoreInfo);
}
#ifdef NS_BUILD_REFCNT_LOGGING
IndexInfo::IndexInfo()
: id(LL_MININT),
unique(false),
autoIncrement(false),
multiEntry(false)
{
MOZ_COUNT_CTOR(IndexInfo);
@ -118,6 +108,7 @@ IndexInfo::IndexInfo(const IndexInfo& aOther)
name(aOther.name),
keyPath(aOther.keyPath),
unique(aOther.unique),
autoIncrement(aOther.autoIncrement),
multiEntry(aOther.multiEntry)
{
MOZ_COUNT_CTOR(IndexInfo);
@ -130,8 +121,19 @@ IndexInfo::~IndexInfo()
ObjectStoreInfo::ObjectStoreInfo()
: id(0),
nextAutoIncrementId(0),
comittedAutoIncrementId(0)
autoIncrement(false),
databaseId(0)
{
MOZ_COUNT_CTOR(ObjectStoreInfo);
}
ObjectStoreInfo::ObjectStoreInfo(ObjectStoreInfo& aOther)
: name(aOther.name),
id(aOther.id),
keyPath(aOther.keyPath),
autoIncrement(aOther.autoIncrement),
databaseId(aOther.databaseId),
indexes(aOther.indexes)
{
MOZ_COUNT_CTOR(ObjectStoreInfo);
}
@ -204,6 +206,11 @@ DatabaseInfo::Remove(nsIAtom* aId)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
DatabaseInfo* info = nsnull;
DebugOnly<bool> got = Get(aId, &info);
NS_ASSERTION(got && info, "Don't know anything about this one!");
if (gDatabaseHash) {
gDatabaseHash->Remove(aId);
@ -214,31 +221,6 @@ DatabaseInfo::Remove(nsIAtom* aId)
}
}
PLDHashOperator
EnumerateDatabasesRemoveOrigin(nsISupports* aId,
DatabaseInfo*& aDatabaseInfo,
void* aUserArg)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
const nsACString* origin = static_cast<const nsACString*>(aUserArg);
return aDatabaseInfo->origin.Equals(*origin) ?
PL_DHASH_REMOVE :
PL_DHASH_NEXT;
}
// static
void
DatabaseInfo::RemoveAllForOrigin(const nsACString& aOrigin)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (gDatabaseHash) {
gDatabaseHash->Enumerate(EnumerateDatabasesRemoveOrigin,
const_cast<nsACString*>(&aOrigin));
}
}
bool
DatabaseInfo::GetObjectStoreNames(nsTArray<nsString>& aNames)
{
@ -259,16 +241,17 @@ DatabaseInfo::ContainsStoreName(const nsAString& aName)
return objectStoreHash && objectStoreHash->Get(aName, nsnull);
}
ObjectStoreInfo*
DatabaseInfo::GetObjectStore(const nsAString& aName)
bool
DatabaseInfo::GetObjectStore(const nsAString& aName,
ObjectStoreInfo** aInfo)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (objectStoreHash) {
return objectStoreHash->GetWeak(aName);
return objectStoreHash->Get(aName, aInfo);
}
return nsnull;
return false;
}
bool
@ -298,7 +281,7 @@ void
DatabaseInfo::RemoveObjectStore(const nsAString& aName)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(GetObjectStore(aName), "Don't know about this one!");
NS_ASSERTION(GetObjectStore(aName, nsnull), "Don't know about this one!");
if (objectStoreHash) {
objectStoreHash->Remove(aName);

View File

@ -46,14 +46,14 @@
#include "Key.h"
#include "IDBObjectStore.h"
#include "nsRefPtrHashtable.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
BEGIN_INDEXEDDB_NAMESPACE
struct ObjectStoreInfo;
typedef nsRefPtrHashtable<nsStringHashKey, ObjectStoreInfo>
typedef nsClassHashtable<nsStringHashKey, ObjectStoreInfo>
ObjectStoreInfoHash;
class IDBDatabase;
@ -77,15 +77,14 @@ private:
static bool Put(DatabaseInfo* aInfo);
public:
static void Remove(nsIAtom* aId);
static void RemoveAllForOrigin(const nsACString& aOrigin);
public:
bool GetObjectStoreNames(nsTArray<nsString>& aNames);
bool ContainsStoreName(const nsAString& aName);
ObjectStoreInfo* GetObjectStore(const nsAString& aName);
bool GetObjectStore(const nsAString& aName,
ObjectStoreInfo** aInfo);
bool PutObjectStore(ObjectStoreInfo* aInfo);
@ -94,9 +93,8 @@ public:
already_AddRefed<DatabaseInfo> Clone();
nsString name;
nsCString origin;
PRUint64 version;
nsCOMPtr<nsIAtom> id;
nsIAtom* id;
nsString filePath;
PRInt64 nextObjectStoreId;
PRInt64 nextIndexId;
@ -115,13 +113,14 @@ struct IndexInfo
~IndexInfo();
#else
IndexInfo()
: id(LL_MININT), unique(false), multiEntry(false) { }
: id(LL_MININT), unique(false), autoIncrement(false) { }
#endif
PRInt64 id;
nsString name;
nsString keyPath;
bool unique;
bool autoIncrement;
bool multiEntry;
};
@ -129,39 +128,19 @@ struct ObjectStoreInfo
{
#ifdef NS_BUILD_REFCNT_LOGGING
ObjectStoreInfo();
#else
ObjectStoreInfo()
: id(0), nextAutoIncrementId(0), comittedAutoIncrementId(0) { }
#endif
ObjectStoreInfo(ObjectStoreInfo& aOther);
private:
#ifdef NS_BUILD_REFCNT_LOGGING
~ObjectStoreInfo();
#else
~ObjectStoreInfo() {}
ObjectStoreInfo()
: id(0), autoIncrement(false), databaseId(0) { }
#endif
public:
// Constant members, can be gotten on any thread
nsString name;
PRInt64 id;
nsString keyPath;
// Main-thread only members. This must *not* be touced on the database thread
bool autoIncrement;
nsIAtom* databaseId;
nsTArray<IndexInfo> indexes;
// Database-thread members. After the ObjectStoreInfo has been initialized,
// these can *only* be touced on the database thread.
PRInt64 nextAutoIncrementId;
PRInt64 comittedAutoIncrementId;
// This is threadsafe since the ObjectStoreInfos are created on the database
// thread but then only used from the main thread. Ideal would be if we
// could transfer ownership from the database thread to the main thread, but
// we don't have that ability yet.
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ObjectStoreInfo)
};
struct IndexUpdateInfo

View File

@ -124,24 +124,24 @@ NS_STACK_CLASS
class AutoRemoveObjectStore
{
public:
AutoRemoveObjectStore(DatabaseInfo* aInfo, const nsAString& aName)
: mInfo(aInfo), mName(aName)
AutoRemoveObjectStore(IDBDatabase* aDatabase, const nsAString& aName)
: mDatabase(aDatabase), mName(aName)
{ }
~AutoRemoveObjectStore()
{
if (mInfo) {
mInfo->RemoveObjectStore(mName);
if (mDatabase) {
mDatabase->Info()->RemoveObjectStore(mName);
}
}
void forget()
{
mInfo = nsnull;
mDatabase = nsnull;
}
private:
DatabaseInfo* mInfo;
IDBDatabase* mDatabase;
nsString mName;
};
@ -384,7 +384,7 @@ IDBDatabase::CreateObjectStore(const nsAString& aName,
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
}
DatabaseInfo* databaseInfo = transaction->DBInfo();
DatabaseInfo* databaseInfo = Info();
nsString keyPath;
keyPath.SetIsVoid(true);
@ -446,24 +446,25 @@ IDBDatabase::CreateObjectStore(const nsAString& aName,
}
}
nsRefPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo());
nsAutoPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo());
newInfo->name = aName;
newInfo->id = databaseInfo->nextObjectStoreId++;
newInfo->keyPath = keyPath;
newInfo->nextAutoIncrementId = autoIncrement ? 1 : 0;
newInfo->comittedAutoIncrementId = newInfo->nextAutoIncrementId;
newInfo->autoIncrement = autoIncrement;
newInfo->databaseId = mDatabaseId;
if (!databaseInfo->PutObjectStore(newInfo)) {
if (!Info()->PutObjectStore(newInfo)) {
NS_WARNING("Put failed!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
ObjectStoreInfo* objectStoreInfo = newInfo.forget();
// Don't leave this in the hash if we fail below!
AutoRemoveObjectStore autoRemove(databaseInfo, aName);
AutoRemoveObjectStore autoRemove(this, aName);
nsRefPtr<IDBObjectStore> objectStore =
transaction->GetOrCreateObjectStore(aName, newInfo);
transaction->GetOrCreateObjectStore(aName, objectStoreInfo);
NS_ENSURE_TRUE(objectStore, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsRefPtr<CreateObjectStoreHelper> helper =
@ -490,9 +491,9 @@ IDBDatabase::DeleteObjectStore(const nsAString& aName)
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
}
DatabaseInfo* info = transaction->DBInfo();
ObjectStoreInfo* objectStoreInfo = info->GetObjectStore(aName);
if (!objectStoreInfo) {
DatabaseInfo* info = Info();
ObjectStoreInfo* objectStoreInfo;
if (!info->GetObjectStore(aName, &objectStoreInfo)) {
return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
}
@ -501,7 +502,9 @@ IDBDatabase::DeleteObjectStore(const nsAString& aName)
nsresult rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
transaction->RemoveObjectStore(aName);
info->RemoveObjectStore(aName);
transaction->ReleaseCachedObjectStore(aName);
return NS_OK;
}

View File

@ -226,8 +226,9 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
bool hasResult;
while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
nsRefPtr<ObjectStoreInfo>* element =
nsAutoPtr<ObjectStoreInfo>* element =
aObjectStores.AppendElement(new ObjectStoreInfo());
NS_ENSURE_TRUE(element, NS_ERROR_OUT_OF_MEMORY);
ObjectStoreInfo* info = element->get();
@ -249,8 +250,8 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
NS_ENSURE_SUCCESS(rv, rv);
}
info->nextAutoIncrementId = stmt->AsInt64(3);
info->comittedAutoIncrementId = info->nextAutoIncrementId;
info->autoIncrement = !!stmt->AsInt32(3);
info->databaseId = aDatabaseId;
ObjectStoreInfoMap* mapEntry = infoMap.AppendElement();
NS_ENSURE_TRUE(mapEntry, NS_ERROR_OUT_OF_MEMORY);
@ -262,7 +263,8 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
// Load index information
rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT object_store_id, id, name, key_path, unique_index, multientry "
"SELECT object_store_id, id, name, key_path, unique_index, multientry, "
"object_store_autoincrement "
"FROM object_store_index"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
@ -296,6 +298,7 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
indexInfo->unique = !!stmt->AsInt32(4);
indexInfo->multiEntry = !!stmt->AsInt32(5);
indexInfo->autoIncrement = !!stmt->AsInt32(6);
}
NS_ENSURE_SUCCESS(rv, rv);
@ -324,28 +327,35 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
// static
nsresult
IDBFactory::SetDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
PRUint64 aVersion,
ObjectStoreInfoArray& aObjectStores)
IDBFactory::UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
PRUint64 aVersion,
ObjectStoreInfoArray& aObjectStores)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aDatabaseInfo, "Null pointer!");
ObjectStoreInfoArray objectStores;
objectStores.SwapElements(aObjectStores);
#ifdef DEBUG
{
nsTArray<nsString> existingNames;
aDatabaseInfo->GetObjectStoreNames(existingNames);
NS_ASSERTION(existingNames.IsEmpty(), "Should be an empty DatabaseInfo");
if (!objectStores.SwapElements(aObjectStores)) {
NS_WARNING("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
}
nsAutoTArray<nsString, 10> existingNames;
if (!aDatabaseInfo->GetObjectStoreNames(existingNames)) {
NS_WARNING("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
}
// Remove all the old ones.
for (PRUint32 index = 0; index < existingNames.Length(); index++) {
aDatabaseInfo->RemoveObjectStore(existingNames[index]);
}
#endif
aDatabaseInfo->version = aVersion;
for (PRUint32 index = 0; index < objectStores.Length(); index++) {
nsRefPtr<ObjectStoreInfo>& info = objectStores[index];
nsAutoPtr<ObjectStoreInfo>& info = objectStores[index];
NS_ASSERTION(info->databaseId == aDatabaseInfo->id, "Huh?!");
if (!aDatabaseInfo->PutObjectStore(info)) {
NS_WARNING("Out of memory!");

View File

@ -59,7 +59,7 @@ struct ObjectStoreInfo;
class IDBFactory : public nsIIDBFactory
{
typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
typedef nsTArray<nsAutoPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIIDBFACTORY
@ -90,9 +90,9 @@ public:
ObjectStoreInfoArray& aObjectStores);
static nsresult
SetDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
PRUint64 aVersion,
ObjectStoreInfoArray& aObjectStores);
UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
PRUint64 aVersion,
ObjectStoreInfoArray& aObjectStores);
private:
IDBFactory();

View File

@ -321,13 +321,15 @@ IDBIndex::Create(IDBObjectStore* aObjectStore,
index->mKeyPath = aIndexInfo->keyPath;
index->mUnique = aIndexInfo->unique;
index->mMultiEntry = aIndexInfo->multiEntry;
index->mAutoIncrement = aIndexInfo->autoIncrement;
return index.forget();
}
IDBIndex::IDBIndex()
: mId(LL_MININT),
mUnique(false)
mUnique(false),
mAutoIncrement(false)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
}
@ -691,12 +693,26 @@ GetKeyHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
{
NS_ASSERTION(mKeyRange, "Must have a key range here!");
nsCString keyColumn;
nsCString indexTable;
if (mIndex->IsUnique()) {
indexTable.AssignLiteral("unique_index_data");
if (mIndex->IsAutoIncrement()) {
keyColumn.AssignLiteral("ai_object_data_id");
if (mIndex->IsUnique()) {
indexTable.AssignLiteral("ai_unique_index_data");
}
else {
indexTable.AssignLiteral("ai_index_data");
}
}
else {
indexTable.AssignLiteral("index_data");
keyColumn.AssignLiteral("object_data_key");
if (mIndex->IsUnique()) {
indexTable.AssignLiteral("unique_index_data");
}
else {
indexTable.AssignLiteral("index_data");
}
}
nsCString keyRangeClause;
@ -704,10 +720,12 @@ GetKeyHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
nsCString query = NS_LITERAL_CSTRING("SELECT object_data_key FROM ") +
indexTable +
NS_LITERAL_CSTRING(" WHERE index_id = :index_id") +
keyRangeClause +
NS_NAMED_LITERAL_CSTRING(indexId, "index_id");
nsCString query = NS_LITERAL_CSTRING("SELECT ") + keyColumn +
NS_LITERAL_CSTRING(" FROM ") + indexTable +
NS_LITERAL_CSTRING(" WHERE ") + indexId +
NS_LITERAL_CSTRING(" = :") + indexId + keyRangeClause +
NS_LITERAL_CSTRING(" LIMIT 1");
nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
@ -715,8 +733,7 @@ GetKeyHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
mIndex->Id());
nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = mKeyRange->BindToStatement(stmt);
@ -746,12 +763,29 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
{
NS_ASSERTION(mKeyRange, "Must have a key range here!");
nsCString indexTable;
if (mIndex->IsUnique()) {
indexTable.AssignLiteral("unique_index_data");
nsCString objectTable;
nsCString joinTable;
nsCString objectColumn;
if (mIndex->IsAutoIncrement()) {
objectTable.AssignLiteral("ai_object_data");
objectColumn.AssignLiteral("ai_object_data_id");
if (mIndex->IsUnique()) {
joinTable.AssignLiteral("ai_unique_index_data");
}
else {
joinTable.AssignLiteral("ai_index_data");
}
}
else {
indexTable.AssignLiteral("index_data");
objectTable.AssignLiteral("object_data");
objectColumn.AssignLiteral("object_data_id");
if (mIndex->IsUnique()) {
joinTable.AssignLiteral("unique_index_data");
}
else {
joinTable.AssignLiteral("index_data");
}
}
nsCString keyRangeClause;
@ -759,12 +793,15 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
"INNER JOIN ") + indexTable +
NS_LITERAL_CSTRING(" AS index_table ON object_data.id = ") +
NS_LITERAL_CSTRING("index_table.object_data_id WHERE "
"index_id = :index_id") +
keyRangeClause +
NS_NAMED_LITERAL_CSTRING(indexId, "index_id");
nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM ") + objectTable +
NS_LITERAL_CSTRING(" INNER JOIN ") + joinTable +
NS_LITERAL_CSTRING(" ON ") + objectTable +
NS_LITERAL_CSTRING(".id = ") + joinTable +
NS_LITERAL_CSTRING(".") + objectColumn +
NS_LITERAL_CSTRING(" WHERE ") + indexId +
NS_LITERAL_CSTRING(" = :") + indexId + keyRangeClause +
NS_LITERAL_CSTRING(" LIMIT 1");
nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
@ -772,8 +809,7 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
mIndex->Id());
nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = mKeyRange->BindToStatement(stmt);
@ -807,12 +843,26 @@ GetHelper::GetSuccessResult(JSContext* aCx,
nsresult
GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
{
nsCString keyColumn;
nsCString tableName;
if (mIndex->IsUnique()) {
tableName.AssignLiteral("unique_index_data");
if (mIndex->IsAutoIncrement()) {
keyColumn.AssignLiteral("ai_object_data_id");
if (mIndex->IsUnique()) {
tableName.AssignLiteral("ai_unique_index_data");
}
else {
tableName.AssignLiteral("ai_index_data");
}
}
else {
tableName.AssignLiteral("index_data");
keyColumn.AssignLiteral("object_data_key");
if (mIndex->IsUnique()) {
tableName.AssignLiteral("unique_index_data");
}
else {
tableName.AssignLiteral("index_data");
}
}
nsCString keyRangeClause;
@ -826,18 +876,20 @@ GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
limitClause.AppendInt(mLimit);
}
nsCString query = NS_LITERAL_CSTRING("SELECT object_data_key FROM ") +
tableName +
NS_LITERAL_CSTRING(" WHERE index_id = :index_id") +
keyRangeClause + limitClause;
NS_NAMED_LITERAL_CSTRING(indexId, "index_id");
nsCString query = NS_LITERAL_CSTRING("SELECT ") + keyColumn +
NS_LITERAL_CSTRING(" FROM ") + tableName +
NS_LITERAL_CSTRING(" WHERE ") + indexId +
NS_LITERAL_CSTRING(" = :") + indexId + keyRangeClause +
limitClause;
nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
mIndex->Id());
nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (mKeyRange) {
@ -915,14 +967,33 @@ GetAllKeysHelper::GetSuccessResult(JSContext* aCx,
nsresult
GetAllHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
{
nsCString indexTable;
if (mIndex->IsUnique()) {
indexTable.AssignLiteral("unique_index_data");
nsCString dataTableName;
nsCString objectDataId;
nsCString indexTableName;
if (mIndex->IsAutoIncrement()) {
dataTableName.AssignLiteral("ai_object_data");
objectDataId.AssignLiteral("ai_object_data_id");
if (mIndex->IsUnique()) {
indexTableName.AssignLiteral("ai_unique_index_data");
}
else {
indexTableName.AssignLiteral("ai_index_data");
}
}
else {
indexTable.AssignLiteral("index_data");
dataTableName.AssignLiteral("object_data");
objectDataId.AssignLiteral("object_data_id");
if (mIndex->IsUnique()) {
indexTableName.AssignLiteral("unique_index_data");
}
else {
indexTableName.AssignLiteral("index_data");
}
}
NS_NAMED_LITERAL_CSTRING(indexId, "index_id");
nsCString keyRangeClause;
if (mKeyRange) {
mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("value"), keyRangeClause);
@ -934,20 +1005,21 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
limitClause.AppendInt(mLimit);
}
nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
"INNER JOIN ") + indexTable +
NS_LITERAL_CSTRING(" AS index_table ON object_data.id = "
"index_table.object_data_id "
"WHERE index_id = :index_id") +
keyRangeClause + limitClause;
nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM ") + dataTableName +
NS_LITERAL_CSTRING(" INNER JOIN ") + indexTableName +
NS_LITERAL_CSTRING(" ON ") + dataTableName +
NS_LITERAL_CSTRING(".id = ") + indexTableName +
NS_LITERAL_CSTRING(".") + objectDataId +
NS_LITERAL_CSTRING(" WHERE ") + indexId +
NS_LITERAL_CSTRING(" = :") + indexId + keyRangeClause +
limitClause;
nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
mIndex->Id());
nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (mKeyRange) {
@ -997,13 +1069,31 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_ASSERTION(aConnection, "Passed a null connection!");
nsCString table;
if (mIndex->IsUnique()) {
table.AssignLiteral("unique_index_data");
nsCString keyColumn;
if (mIndex->IsAutoIncrement()) {
keyColumn.AssignLiteral("ai_object_data_id");
if (mIndex->IsUnique()) {
table.AssignLiteral("ai_unique_index_data");
}
else {
table.AssignLiteral("ai_index_data");
}
}
else {
table.AssignLiteral("index_data");
keyColumn.AssignLiteral("object_data_key");
if (mIndex->IsUnique()) {
table.AssignLiteral("unique_index_data");
}
else {
table.AssignLiteral("index_data");
}
}
NS_NAMED_LITERAL_CSTRING(id, "id");
NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
NS_NAMED_LITERAL_CSTRING(value, "value");
nsCString keyRangeClause;
@ -1011,27 +1101,30 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mKeyRange->GetBindingClause(value, keyRangeClause);
}
nsCAutoString directionClause(" ORDER BY value ");
nsCAutoString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + value;
switch (mDirection) {
case nsIIDBCursor::NEXT:
case nsIIDBCursor::NEXT_NO_DUPLICATE:
directionClause += NS_LITERAL_CSTRING("ASC, object_data_key ASC");
directionClause += NS_LITERAL_CSTRING(" ASC, ") + keyColumn +
NS_LITERAL_CSTRING(" ASC");
break;
case nsIIDBCursor::PREV:
directionClause += NS_LITERAL_CSTRING("DESC, object_data_key DESC");
directionClause += NS_LITERAL_CSTRING(" DESC, ") + keyColumn +
NS_LITERAL_CSTRING(" DESC");
break;
case nsIIDBCursor::PREV_NO_DUPLICATE:
directionClause += NS_LITERAL_CSTRING("DESC, object_data_key ASC");
directionClause += NS_LITERAL_CSTRING(" DESC, ") + keyColumn +
NS_LITERAL_CSTRING(" ASC");
break;
default:
NS_NOTREACHED("Unknown direction!");
}
nsCString firstQuery = NS_LITERAL_CSTRING("SELECT value, object_data_key "
"FROM ") + table +
NS_LITERAL_CSTRING(" WHERE index_id = :index_id") +
nsCString firstQuery = NS_LITERAL_CSTRING("SELECT value, ") + keyColumn +
NS_LITERAL_CSTRING(" FROM ") + table +
NS_LITERAL_CSTRING(" WHERE index_id = :") + id +
keyRangeClause + directionClause +
NS_LITERAL_CSTRING(" LIMIT 1");
@ -1041,8 +1134,7 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
mIndex->Id());
nsresult rv = stmt->BindInt64ByName(id, mIndex->Id());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (mKeyRange) {
@ -1066,11 +1158,13 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_ENSURE_SUCCESS(rv, rv);
// Now we need to make the query to get the next match.
nsCAutoString queryStart = NS_LITERAL_CSTRING("SELECT value, object_data_key"
" FROM ") + table +
NS_LITERAL_CSTRING(" WHERE index_id = :id");
nsCAutoString queryStart = NS_LITERAL_CSTRING("SELECT value, ") + keyColumn +
NS_LITERAL_CSTRING(" FROM ") + table +
NS_LITERAL_CSTRING(" WHERE index_id = :") + id;
NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
NS_NAMED_LITERAL_CSTRING(objectKey, "object_key");
switch (mDirection) {
case nsIIDBCursor::NEXT:
@ -1079,18 +1173,14 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
queryStart);
mRangeKey = mKeyRange->Upper();
}
mContinueQuery =
queryStart +
NS_LITERAL_CSTRING(" AND value >= :current_key AND "
"( value > :current_key OR "
" object_data_key > :object_key )") +
directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
mContinueToQuery =
queryStart +
NS_LITERAL_CSTRING(" AND value >= :current_key ") +
directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND value >= :") +
currentKey + NS_LITERAL_CSTRING(" AND ( value > :") +
currentKey + NS_LITERAL_CSTRING(" OR ") + keyColumn +
NS_LITERAL_CSTRING(" > :") + objectKey +
NS_LITERAL_CSTRING(" )") + directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND value >= :") +
currentKey + NS_LITERAL_CSTRING(" LIMIT ");
break;
case nsIIDBCursor::NEXT_NO_DUPLICATE:
@ -1099,14 +1189,12 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
queryStart);
mRangeKey = mKeyRange->Upper();
}
mContinueQuery =
queryStart + NS_LITERAL_CSTRING(" AND value > :current_key") +
directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
mContinueToQuery =
queryStart + NS_LITERAL_CSTRING(" AND value >= :current_key") +
directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND value > :") +
currentKey + directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND value >= :") +
currentKey + directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
break;
case nsIIDBCursor::PREV:
@ -1116,18 +1204,14 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mRangeKey = mKeyRange->Lower();
}
mContinueQuery =
queryStart +
NS_LITERAL_CSTRING(" AND value <= :current_key AND "
"( value < :current_key OR "
" object_data_key < :object_key )") +
directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
mContinueToQuery =
queryStart +
NS_LITERAL_CSTRING(" AND value <= :current_key ") +
directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND value <= :") +
currentKey + NS_LITERAL_CSTRING(" AND ( value < :") +
currentKey + NS_LITERAL_CSTRING(" OR ") + keyColumn +
NS_LITERAL_CSTRING(" < :") + objectKey +
NS_LITERAL_CSTRING(" ) ") + directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND value <= :") +
currentKey + NS_LITERAL_CSTRING(" LIMIT ");
break;
case nsIIDBCursor::PREV_NO_DUPLICATE:
@ -1136,16 +1220,12 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
queryStart);
mRangeKey = mKeyRange->Lower();
}
mContinueQuery =
queryStart +
NS_LITERAL_CSTRING(" AND value < :current_key") +
directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
mContinueToQuery =
queryStart +
NS_LITERAL_CSTRING(" AND value <= :current_key") +
directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND value < :") +
currentKey + directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND value <= :") +
currentKey + directionClause +
NS_LITERAL_CSTRING(" LIMIT ");
break;
default:
@ -1178,52 +1258,81 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_ASSERTION(aConnection, "Passed a null connection!");
nsCString indexTable;
if (mIndex->IsUnique()) {
indexTable.AssignLiteral("unique_index_data");
nsCString objectTable;
nsCString objectDataIdColumn;
nsCString keyValueColumn;
if (mIndex->IsAutoIncrement()) {
objectTable.AssignLiteral("ai_object_data");
objectDataIdColumn.AssignLiteral("ai_object_data_id");
keyValueColumn.AssignLiteral("ai_object_data_id");
if (mIndex->IsUnique()) {
indexTable.AssignLiteral("ai_unique_index_data");
}
else {
indexTable.AssignLiteral("ai_index_data");
}
}
else {
indexTable.AssignLiteral("index_data");
objectTable.AssignLiteral("object_data");
objectDataIdColumn.AssignLiteral("object_data_id");
keyValueColumn.AssignLiteral("object_data_key");
if (mIndex->IsUnique()) {
indexTable.AssignLiteral("unique_index_data");
}
else {
indexTable.AssignLiteral("index_data");
}
}
NS_NAMED_LITERAL_CSTRING(value, "index_table.value");
nsCString value = indexTable + NS_LITERAL_CSTRING(".value");
nsCString keyValue = indexTable + NS_LITERAL_CSTRING(".") + keyValueColumn;
nsCString keyRangeClause;
if (mKeyRange) {
mKeyRange->GetBindingClause(value, keyRangeClause);
}
nsCAutoString directionClause(" ORDER BY index_table.value ");
nsCAutoString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + value;
switch (mDirection) {
case nsIIDBCursor::NEXT:
case nsIIDBCursor::NEXT_NO_DUPLICATE:
directionClause +=
NS_LITERAL_CSTRING("ASC, index_table.object_data_key ASC");
directionClause += NS_LITERAL_CSTRING(" ASC, ") + keyValue +
NS_LITERAL_CSTRING(" ASC");
break;
case nsIIDBCursor::PREV:
directionClause +=
NS_LITERAL_CSTRING("DESC, index_table.object_data_key DESC");
directionClause += NS_LITERAL_CSTRING(" DESC, ") + keyValue +
NS_LITERAL_CSTRING(" DESC");
break;
case nsIIDBCursor::PREV_NO_DUPLICATE:
directionClause +=
NS_LITERAL_CSTRING("DESC, index_table.object_data_key ASC");
directionClause += NS_LITERAL_CSTRING(" DESC, ") + keyValue +
NS_LITERAL_CSTRING(" ASC");
break;
default:
NS_NOTREACHED("Unknown direction!");
}
nsCString firstQuery =
NS_LITERAL_CSTRING("SELECT index_table.value, "
"index_table.object_data_key, object_data.data, "
"object_data.file_ids FROM ") +
indexTable +
NS_LITERAL_CSTRING(" AS index_table INNER JOIN object_data ON "
"index_table.object_data_id = object_data.id "
"WHERE index_table.index_id = :id") +
keyRangeClause + directionClause +
NS_LITERAL_CSTRING(" LIMIT 1");
NS_NAMED_LITERAL_CSTRING(id, "id");
NS_NAMED_LITERAL_CSTRING(dot, ".");
NS_NAMED_LITERAL_CSTRING(commaspace, ", ");
nsCString data = objectTable + NS_LITERAL_CSTRING(".data");
nsCString fileIds = objectTable + NS_LITERAL_CSTRING(".file_ids");
nsCString firstQuery = NS_LITERAL_CSTRING("SELECT ") + value + commaspace +
keyValue + commaspace + data + commaspace + fileIds +
NS_LITERAL_CSTRING(" FROM ") + indexTable +
NS_LITERAL_CSTRING(" INNER JOIN ") + objectTable +
NS_LITERAL_CSTRING(" ON ") + indexTable + dot +
objectDataIdColumn + NS_LITERAL_CSTRING(" = ") +
objectTable + dot + id +
NS_LITERAL_CSTRING(" WHERE ") + indexTable +
NS_LITERAL_CSTRING(".index_id = :") + id +
keyRangeClause + directionClause +
NS_LITERAL_CSTRING(" LIMIT 1");
nsCOMPtr<mozIStorageStatement> stmt =
mTransaction->GetCachedStatement(firstQuery);
@ -1231,7 +1340,7 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndex->Id());
nsresult rv = stmt->BindInt64ByName(id, mIndex->Id());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (mKeyRange) {
@ -1259,17 +1368,29 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_ENSURE_SUCCESS(rv, rv);
// Now we need to make the query to get the next match.
nsCAutoString queryStart =
NS_LITERAL_CSTRING("SELECT index_table.value, "
"index_table.object_data_key, object_data.data, "
"object_data.file_ids FROM ") +
indexTable +
NS_LITERAL_CSTRING(" AS index_table INNER JOIN object_data ON "
"index_table.object_data_id = object_data.id "
"WHERE index_table.index_id = :id");
nsCAutoString queryStart = NS_LITERAL_CSTRING("SELECT ") + value +
commaspace + keyValue + commaspace + data +
commaspace + fileIds +
NS_LITERAL_CSTRING(" FROM ") + indexTable +
NS_LITERAL_CSTRING(" INNER JOIN ") + objectTable +
NS_LITERAL_CSTRING(" ON ") + indexTable + dot +
objectDataIdColumn + NS_LITERAL_CSTRING(" = ") +
objectTable + dot + id +
NS_LITERAL_CSTRING(" WHERE ") + indexTable +
NS_LITERAL_CSTRING(".index_id = :") + id;
NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
NS_NAMED_LITERAL_CSTRING(objectKey, "object_key");
NS_NAMED_LITERAL_CSTRING(andStr, " AND ");
NS_NAMED_LITERAL_CSTRING(orStr, " OR ");
NS_NAMED_LITERAL_CSTRING(ge, " >= :");
NS_NAMED_LITERAL_CSTRING(gt, " > :");
NS_NAMED_LITERAL_CSTRING(le, " <= :");
NS_NAMED_LITERAL_CSTRING(lt, " < :");
NS_NAMED_LITERAL_CSTRING(openparen, " ( ");
NS_NAMED_LITERAL_CSTRING(closeparen, " ) ");
NS_NAMED_LITERAL_CSTRING(limit, " LIMIT ");
switch (mDirection) {
@ -1279,16 +1400,11 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
queryStart);
mRangeKey = mKeyRange->Upper();
}
mContinueQuery =
queryStart +
NS_LITERAL_CSTRING(" AND index_table.value >= :current_key AND "
"( index_table.value > :current_key OR "
" index_table.object_data_key > :object_key ) ") +
directionClause + limit;
mContinueToQuery =
queryStart +
NS_LITERAL_CSTRING(" AND index_table.value >= :current_key") +
directionClause + limit;
mContinueQuery = queryStart + andStr + value + ge + currentKey + andStr +
openparen + value + gt + currentKey + orStr + keyValue +
gt + objectKey + closeparen + directionClause + limit;
mContinueToQuery = queryStart + andStr + value + ge + currentKey +
directionClause + limit;
break;
case nsIIDBCursor::NEXT_NO_DUPLICATE:
@ -1297,14 +1413,10 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
queryStart);
mRangeKey = mKeyRange->Upper();
}
mContinueQuery =
queryStart +
NS_LITERAL_CSTRING(" AND index_table.value > :current_key") +
directionClause + limit;
mContinueToQuery =
queryStart +
NS_LITERAL_CSTRING(" AND index_table.value >= :current_key") +
directionClause + limit;
mContinueQuery = queryStart + andStr + value + gt + currentKey +
directionClause + limit;
mContinueToQuery = queryStart + andStr + value + ge + currentKey +
directionClause + limit;
break;
case nsIIDBCursor::PREV:
@ -1313,16 +1425,11 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
queryStart);
mRangeKey = mKeyRange->Lower();
}
mContinueQuery =
queryStart +
NS_LITERAL_CSTRING(" AND index_table.value <= :current_key AND "
"( index_table.value < :current_key OR "
" index_table.object_data_key < :object_key ) ") +
directionClause + limit;
mContinueToQuery =
queryStart +
NS_LITERAL_CSTRING(" AND index_table.value <= :current_key") +
directionClause + limit;
mContinueQuery = queryStart + andStr + value + le + currentKey + andStr +
openparen + value + lt + currentKey + orStr + keyValue +
lt + objectKey + closeparen + directionClause + limit;
mContinueToQuery = queryStart + andStr + value + le + currentKey +
directionClause + limit;
break;
case nsIIDBCursor::PREV_NO_DUPLICATE:
@ -1331,14 +1438,10 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
queryStart);
mRangeKey = mKeyRange->Lower();
}
mContinueQuery =
queryStart +
NS_LITERAL_CSTRING(" AND index_table.value < :current_key") +
directionClause + limit;
mContinueToQuery =
queryStart +
NS_LITERAL_CSTRING(" AND index_table.value <= :current_key") +
directionClause + limit;
mContinueQuery = queryStart + andStr + value + lt + currentKey +
directionClause +limit;
mContinueToQuery = queryStart + andStr + value + le + currentKey +
directionClause + limit;
break;
default:
@ -1372,11 +1475,22 @@ nsresult
CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
nsCString table;
if (mIndex->IsUnique()) {
table.AssignLiteral("unique_index_data");
if (mIndex->IsAutoIncrement()) {
if (mIndex->IsUnique()) {
table.AssignLiteral("ai_unique_index_data");
}
else {
table.AssignLiteral("ai_index_data");
}
}
else {
table.AssignLiteral("index_data");
if (mIndex->IsUnique()) {
table.AssignLiteral("unique_index_data");
}
else {
table.AssignLiteral("index_data");
}
}
NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
@ -1395,8 +1509,10 @@ CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
}
}
NS_NAMED_LITERAL_CSTRING(id, "id");
nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM ") + table +
NS_LITERAL_CSTRING(" WHERE index_id = :id") +
NS_LITERAL_CSTRING(" WHERE index_id = :") + id +
keyRangeClause;
nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
@ -1404,7 +1520,7 @@ CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndex->Id());
nsresult rv = stmt->BindInt64ByName(id, mIndex->Id());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (mKeyRange) {

View File

@ -92,6 +92,11 @@ public:
return mMultiEntry;
}
bool IsAutoIncrement() const
{
return mAutoIncrement;
}
const nsString& KeyPath() const
{
return mKeyPath;
@ -111,6 +116,7 @@ private:
nsString mKeyPath;
bool mUnique;
bool mMultiEntry;
bool mAutoIncrement;
};
END_INDEXEDDB_NAMESPACE

File diff suppressed because it is too large Load Diff

View File

@ -72,8 +72,7 @@ public:
static already_AddRefed<IDBObjectStore>
Create(IDBTransaction* aTransaction,
ObjectStoreInfo* aInfo,
nsIAtom* aDatabaseId);
const ObjectStoreInfo* aInfo);
static bool
IsValidKeyPath(JSContext* aCx, const nsAString& aKeyPath);
@ -91,6 +90,7 @@ public:
UpdateIndexes(IDBTransaction* aTransaction,
PRInt64 aObjectStoreId,
const Key& aObjectStoreKey,
bool aAutoIncrement,
bool aOverwrite,
PRInt64 aObjectDataId,
const nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
@ -167,10 +167,8 @@ public:
return mTransaction;
}
ObjectStoreInfo* Info()
{
return mInfo;
}
nsresult ModifyValueForNewKey(StructuredCloneWriteInfo& aCloneWriteInfo,
Key& aKey);
protected:
IDBObjectStore();
@ -201,7 +199,6 @@ private:
nsString mKeyPath;
bool mAutoIncrement;
nsCOMPtr<nsIAtom> mDatabaseId;
nsRefPtr<ObjectStoreInfo> mInfo;
PRUint32 mStructuredCloneVersion;
nsTArray<nsRefPtr<IDBIndex> > mCreatedIndexes;

View File

@ -121,8 +121,6 @@ IDBTransaction::Create(IDBDatabase* aDatabase,
transaction->mDatabase = aDatabase;
transaction->mMode = aMode;
transaction->mDatabaseInfo = aDatabase->Info();
if (!transaction->mObjectStoreNames.AppendElements(aObjectStoreNames)) {
NS_ERROR("Out of memory!");
@ -213,13 +211,8 @@ IDBTransaction::OnRequestFinished()
}
void
IDBTransaction::RemoveObjectStore(const nsAString& aName)
IDBTransaction::ReleaseCachedObjectStore(const nsAString& aName)
{
NS_ASSERTION(mMode == nsIIDBTransaction::VERSION_CHANGE,
"Only remove object stores on VERSION_CHANGE transactions");
mDatabaseInfo->RemoveObjectStore(aName);
for (PRUint32 i = 0; i < mCreatedObjectStores.Length(); i++) {
if (mCreatedObjectStores[i]->Name() == aName) {
mCreatedObjectStores.RemoveElementAt(i);
@ -244,8 +237,7 @@ IDBTransaction::CommitOrRollback()
TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
NS_ENSURE_STATE(pool);
nsRefPtr<CommitHelper> helper(new CommitHelper(this, mListener,
mCreatedObjectStores));
nsRefPtr<CommitHelper> helper(new CommitHelper(this, mListener));
mCachedStatements.Enumerate(DoomCachedStatements, helper);
NS_ASSERTION(!mCachedStatements.Count(), "Statements left!");
@ -371,6 +363,119 @@ IDBTransaction::GetOrCreateConnection(mozIStorageConnection** aResult)
return NS_OK;
}
already_AddRefed<mozIStorageStatement>
IDBTransaction::AddStatement(bool aCreate,
bool aOverwrite,
bool aAutoIncrement)
{
#ifdef DEBUG
if (!aCreate) {
NS_ASSERTION(aOverwrite, "Bad param combo!");
}
#endif
if (aAutoIncrement) {
if (aCreate) {
if (aOverwrite) {
return GetCachedStatement(
"INSERT OR FAIL INTO ai_object_data (object_store_id, id, data, "
"file_ids) "
"VALUES (:osid, :key_value, :data, :file_ids)"
);
}
return GetCachedStatement(
"INSERT INTO ai_object_data (object_store_id, data, file_ids) "
"VALUES (:osid, :data, :file_ids)"
);
}
return GetCachedStatement(
"UPDATE ai_object_data "
"SET data = :data, file_ids = :file_ids "
"WHERE object_store_id = :osid "
"AND id = :key_value"
);
}
if (aCreate) {
if (aOverwrite) {
return GetCachedStatement(
"INSERT OR FAIL INTO object_data (object_store_id, key_value, data, "
"file_ids) "
"VALUES (:osid, :key_value, :data, :file_ids)"
);
}
return GetCachedStatement(
"INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
"VALUES (:osid, :key_value, :data, :file_ids)"
);
}
return GetCachedStatement(
"UPDATE object_data "
"SET data = :data, file_ids = :file_ids "
"WHERE object_store_id = :osid "
"AND key_value = :key_value"
);
}
already_AddRefed<mozIStorageStatement>
IDBTransaction::IndexDataInsertStatement(bool aAutoIncrement,
bool aUnique)
{
if (aAutoIncrement) {
if (aUnique) {
return GetCachedStatement(
"INSERT INTO ai_unique_index_data "
"(index_id, ai_object_data_id, value) "
"VALUES (:index_id, :object_data_id, :value)"
);
}
return GetCachedStatement(
"INSERT OR IGNORE INTO ai_index_data "
"(index_id, ai_object_data_id, value) "
"VALUES (:index_id, :object_data_id, :value)"
);
}
if (aUnique) {
return GetCachedStatement(
"INSERT INTO unique_index_data "
"(index_id, object_data_id, object_data_key, value) "
"VALUES (:index_id, :object_data_id, :object_data_key, :value)"
);
}
return GetCachedStatement(
"INSERT OR IGNORE INTO index_data ("
"index_id, object_data_id, object_data_key, value) "
"VALUES (:index_id, :object_data_id, :object_data_key, :value)"
);
}
already_AddRefed<mozIStorageStatement>
IDBTransaction::IndexDataDeleteStatement(bool aAutoIncrement,
bool aUnique)
{
if (aAutoIncrement) {
if (aUnique) {
return GetCachedStatement(
"DELETE FROM ai_unique_index_data "
"WHERE ai_object_data_id = :object_data_id"
);
}
return GetCachedStatement(
"DELETE FROM ai_index_data "
"WHERE ai_object_data_id = :object_data_id"
);
}
if (aUnique) {
return GetCachedStatement(
"DELETE FROM unique_index_data "
"WHERE object_data_id = :object_data_id"
);
}
return GetCachedStatement(
"DELETE FROM index_data "
"WHERE object_data_id = :object_data_id"
);
}
already_AddRefed<mozIStorageStatement>
IDBTransaction::GetCachedStatement(const nsACString& aQuery)
{
@ -452,9 +557,13 @@ IDBTransaction::GetOrCreateObjectStore(const nsAString& aName,
}
}
retval = IDBObjectStore::Create(this, aObjectStoreInfo, mDatabaseInfo->id);
retval = IDBObjectStore::Create(this, aObjectStoreInfo);
NS_ENSURE_TRUE(retval, nsnull);
mCreatedObjectStores.AppendElement(retval);
if (!mCreatedObjectStores.AppendElement(retval)) {
NS_WARNING("Out of memory!");
return nsnull;
}
return retval.forget();
}
@ -549,7 +658,12 @@ IDBTransaction::GetObjectStoreNames(nsIDOMDOMStringList** aObjectStores)
nsTArray<nsString>* arrayOfNames;
if (mMode == IDBTransaction::VERSION_CHANGE) {
mDatabaseInfo->GetObjectStoreNames(stackArray);
DatabaseInfo* info = mDatabase->Info();
if (!info->GetObjectStoreNames(stackArray)) {
NS_ERROR("Out of memory!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
arrayOfNames = &stackArray;
}
@ -581,7 +695,7 @@ IDBTransaction::ObjectStore(const nsAString& aName,
if (mMode == nsIIDBTransaction::VERSION_CHANGE ||
mObjectStoreNames.Contains(aName)) {
info = mDatabaseInfo->GetObjectStore(aName);
mDatabase->Info()->GetObjectStore(aName, &info);
}
if (!info) {
@ -733,23 +847,15 @@ IDBTransaction::AfterProcessNextEvent(nsIThreadInternal* aThread,
return NS_OK;
}
CommitHelper::CommitHelper(
IDBTransaction* aTransaction,
IDBTransactionListener* aListener,
const nsTArray<nsRefPtr<IDBObjectStore> >& aUpdatedObjectStores)
CommitHelper::CommitHelper(IDBTransaction* aTransaction,
IDBTransactionListener* aListener)
: mTransaction(aTransaction),
mListener(aListener),
mAborted(!!aTransaction->mAborted)
mAborted(!!aTransaction->mAborted),
mHaveMetadata(false)
{
mConnection.swap(aTransaction->mConnection);
mUpdateFileRefcountFunction.swap(aTransaction->mUpdateFileRefcountFunction);
for (PRUint32 i = 0; i < aUpdatedObjectStores.Length(); i++) {
ObjectStoreInfo* info = aUpdatedObjectStores[i]->Info();
if (info->comittedAutoIncrementId != info->nextAutoIncrementId) {
mAutoIncrementObjectStores.AppendElement(aUpdatedObjectStores[i]);
}
}
}
CommitHelper::~CommitHelper()
@ -776,11 +882,19 @@ CommitHelper::Run()
nsCOMPtr<nsIDOMEvent> event;
if (mAborted) {
if (mTransaction->Mode() == nsIIDBTransaction::VERSION_CHANGE) {
// This will make the database take a snapshot of it's DatabaseInfo
mTransaction->Database()->Close();
// Then remove the info from the hash as it contains invalid data.
DatabaseInfo::Remove(mTransaction->Database()->Id());
if (mHaveMetadata) {
NS_ASSERTION(mTransaction->Mode() == nsIIDBTransaction::VERSION_CHANGE,
"Bad transaction type!");
DatabaseInfo* dbInfo = mTransaction->Database()->Info();
if (NS_FAILED(IDBFactory::UpdateDatabaseMetadata(dbInfo, mOldVersion,
mOldObjectStores))) {
NS_WARNING("Failed to update database metadata!");
}
else {
NS_ASSERTION(mOldObjectStores.IsEmpty(), "Should have swapped!");
}
}
event = CreateGenericEvent(NS_LITERAL_STRING(ABORT_EVT_STR),
@ -824,17 +938,12 @@ CommitHelper::Run()
mAborted = true;
}
if (!mAborted && NS_FAILED(WriteAutoIncrementCounts())) {
mAborted = true;
}
if (!mAborted) {
NS_NAMED_LITERAL_CSTRING(release, "COMMIT TRANSACTION");
if (NS_SUCCEEDED(mConnection->ExecuteSimpleSQL(release))) {
if (mUpdateFileRefcountFunction) {
mUpdateFileRefcountFunction->UpdateFileInfos();
}
CommitAutoIncrementCounts();
}
else {
mAborted = true;
@ -842,11 +951,23 @@ CommitHelper::Run()
}
if (mAborted) {
RevertAutoIncrementCounts();
NS_NAMED_LITERAL_CSTRING(rollback, "ROLLBACK TRANSACTION");
if (NS_FAILED(mConnection->ExecuteSimpleSQL(rollback))) {
NS_WARNING("Failed to rollback transaction!");
}
if (mTransaction->Mode() == nsIIDBTransaction::VERSION_CHANGE) {
nsresult rv =
IDBFactory::LoadDatabaseInformation(mConnection,
mTransaction->Database()->Id(),
&mOldVersion, mOldObjectStores);
if (NS_SUCCEEDED(rv)) {
mHaveMetadata = true;
}
else {
NS_WARNING("Failed to get database information!");
}
}
}
}
@ -870,55 +991,6 @@ CommitHelper::Run()
return NS_OK;
}
nsresult
CommitHelper::WriteAutoIncrementCounts()
{
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv;
for (PRUint32 i = 0; i < mAutoIncrementObjectStores.Length(); i++) {
ObjectStoreInfo* info = mAutoIncrementObjectStores[i]->Info();
if (!stmt) {
rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE object_store SET auto_increment = :ai "
"WHERE id = :osid;"), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
}
else {
stmt->Reset();
}
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), info->id);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("ai"),
info->nextAutoIncrementId);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
void
CommitHelper::CommitAutoIncrementCounts()
{
for (PRUint32 i = 0; i < mAutoIncrementObjectStores.Length(); i++) {
ObjectStoreInfo* info = mAutoIncrementObjectStores[i]->Info();
info->comittedAutoIncrementId = info->nextAutoIncrementId;
}
}
void
CommitHelper::RevertAutoIncrementCounts()
{
for (PRUint32 i = 0; i < mAutoIncrementObjectStores.Length(); i++) {
ObjectStoreInfo* info = mAutoIncrementObjectStores[i]->Info();
info->nextAutoIncrementId = info->comittedAutoIncrementId;
}
}
nsresult
UpdateRefcountFunction::Init()
{

View File

@ -107,7 +107,7 @@ public:
void OnNewRequest();
void OnRequestFinished();
void RemoveObjectStore(const nsAString& aName);
void ReleaseCachedObjectStore(const nsAString& aName);
void SetTransactionListener(IDBTransactionListener* aListener);
@ -118,6 +118,19 @@ public:
// Only meant to be called on mStorageThread!
nsresult GetOrCreateConnection(mozIStorageConnection** aConnection);
already_AddRefed<mozIStorageStatement>
AddStatement(bool aCreate,
bool aOverwrite,
bool aAutoIncrement);
already_AddRefed<mozIStorageStatement>
IndexDataInsertStatement(bool aAutoIncrement,
bool aUnique);
already_AddRefed<mozIStorageStatement>
IndexDataDeleteStatement(bool aAutoIncrement,
bool aUnique);
already_AddRefed<mozIStorageStatement>
GetCachedStatement(const nsACString& aQuery);
@ -125,7 +138,9 @@ public:
already_AddRefed<mozIStorageStatement>
GetCachedStatement(const char (&aQuery)[N])
{
return GetCachedStatement(NS_LITERAL_CSTRING(aQuery));
nsCString query;
query.AssignLiteral(aQuery);
return GetCachedStatement(query);
}
bool IsOpen() const;
@ -152,11 +167,6 @@ public:
return mDatabase;
}
DatabaseInfo* DBInfo() const
{
return mDatabaseInfo;
}
already_AddRefed<IDBObjectStore>
GetOrCreateObjectStore(const nsAString& aName,
ObjectStoreInfo* aObjectStoreInfo);
@ -172,7 +182,6 @@ private:
nsresult CommitOrRollback();
nsRefPtr<IDBDatabase> mDatabase;
nsRefPtr<DatabaseInfo> mDatabaseInfo;
nsTArray<nsString> mObjectStoreNames;
PRUint16 mReadyState;
PRUint16 mMode;
@ -215,8 +224,7 @@ public:
NS_DECL_NSIRUNNABLE
CommitHelper(IDBTransaction* aTransaction,
IDBTransactionListener* aListener,
const nsTArray<nsRefPtr<IDBObjectStore> >& mUpdatedObjectStores);
IDBTransactionListener* aListener);
~CommitHelper();
template<class T>
@ -233,23 +241,17 @@ public:
}
private:
// Writes new autoincrement counts to database
nsresult WriteAutoIncrementCounts();
// Updates counts after a successful commit
void CommitAutoIncrementCounts();
// Reverts counts when a transaction is aborted
void RevertAutoIncrementCounts();
nsRefPtr<IDBTransaction> mTransaction;
nsRefPtr<IDBTransactionListener> mListener;
nsCOMPtr<mozIStorageConnection> mConnection;
nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction;
nsAutoTArray<nsCOMPtr<nsISupports>, 10> mDoomedObjects;
nsAutoTArray<nsRefPtr<IDBObjectStore>, 10> mAutoIncrementObjectStores;
PRUint64 mOldVersion;
nsTArray<nsAutoPtr<ObjectStoreInfo> > mOldObjectStores;
bool mAborted;
bool mHaveMetadata;
};
class UpdateRefcountFunction : public mozIStorageFunction

View File

@ -38,7 +38,6 @@
* ***** END LICENSE BLOCK ***** */
#include "IndexedDatabaseManager.h"
#include "DatabaseInfo.h"
#include "nsIFile.h"
#include "nsIObserverService.h"
@ -80,6 +79,9 @@
// Preference that users can set to override DEFAULT_QUOTA_MB
#define PREF_INDEXEDDB_QUOTA "dom.indexedDB.warningQuota"
// A bad TLS index number.
#define BAD_TLS_INDEX (PRUintn)-1
USING_INDEXEDDB_NAMESPACE
using namespace mozilla::services;
using mozilla::Preferences;
@ -1181,8 +1183,6 @@ IndexedDatabaseManager::ClearDatabasesForURI(nsIURI* aURI)
for (PRUint32 index = 0; index < liveDatabases.Length(); index++) {
liveDatabases[index]->Invalidate();
}
DatabaseInfo::RemoveAllForOrigin(origin);
// After everything has been invalidated the helper should be dispatched to
// the end of the event queue.

View File

@ -238,10 +238,12 @@ public:
if (IsString()) {
rv = aStatement->BindStringByName(aParamName, ToString());
}
else {
NS_ASSERTION(IsInteger(), "Bad key!");
else if (IsInteger()) {
rv = aStatement->BindInt64ByName(aParamName, ToInteger());
}
else {
NS_NOTREACHED("Bad key!");
}
return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}

View File

@ -60,7 +60,7 @@ namespace {
PR_STATIC_ASSERT(JS_STRUCTURED_CLONE_VERSION == 1);
// Major schema version. Bump for almost everything.
const PRUint32 kMajorSchemaVersion = 11;
const PRUint32 kMajorSchemaVersion = 10;
// Minor schema version. Should almost always be 0 (maybe bump on release
// branches if we have to).
@ -169,6 +169,38 @@ CreateFileTables(mozIStorageConnection* aDBConn)
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TRIGGER ai_object_data_insert_trigger "
"AFTER INSERT ON ai_object_data "
"FOR EACH ROW "
"WHEN NEW.file_ids IS NOT NULL "
"BEGIN "
"SELECT update_refcount(NULL, NEW.file_ids); "
"END;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TRIGGER ai_object_data_update_trigger "
"AFTER UPDATE OF file_ids ON ai_object_data "
"FOR EACH ROW "
"WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
"BEGIN "
"SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
"END;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TRIGGER ai_object_data_delete_trigger "
"AFTER DELETE ON ai_object_data "
"FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
"BEGIN "
"SELECT update_refcount(OLD.file_ids, NULL); "
"END;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TRIGGER file_update_trigger "
"AFTER UPDATE ON file "
@ -225,15 +257,31 @@ CreateTables(mozIStorageConnection* aDBConn)
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `ai_object_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE ai_object_data ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"object_store_id INTEGER NOT NULL, "
"data BLOB NOT NULL, "
"file_ids TEXT, "
"UNIQUE (object_store_id, id), "
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `index`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE object_store_index ("
"id INTEGER PRIMARY KEY, "
"id INTEGER, "
"object_store_id INTEGER NOT NULL, "
"name TEXT NOT NULL, "
"key_path TEXT NOT NULL, "
"unique_index INTEGER NOT NULL, "
"multientry INTEGER NOT NULL, "
"multientry INTEGER NOT NULL DEFAULT 0, "
"object_store_autoincrement INTERGER NOT NULL, "
"PRIMARY KEY (id), "
"UNIQUE (object_store_id, name), "
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
"CASCADE"
@ -288,6 +336,53 @@ CreateTables(mozIStorageConnection* aDBConn)
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `ai_index_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE ai_index_data ("
"index_id INTEGER NOT NULL, "
"value NOT NULL, "
"ai_object_data_id INTEGER NOT NULL, "
"PRIMARY KEY (index_id, value, ai_object_data_id), "
"FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
"CASCADE, "
"FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
// Need this to make cascading deletes from ai_object_data and object_store
// fast.
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE INDEX ai_index_data_ai_object_data_id_index "
"ON ai_index_data (ai_object_data_id);"
));
NS_ENSURE_SUCCESS(rv, rv);
// Table `ai_unique_index_data`
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE ai_unique_index_data ("
"index_id INTEGER NOT NULL, "
"value NOT NULL, "
"ai_object_data_id INTEGER NOT NULL, "
"UNIQUE (index_id, value), "
"PRIMARY KEY (index_id, value, ai_object_data_id), "
"FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
"CASCADE, "
"FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
// Need this to make cascading deletes from ai_object_data and object_store
// fast.
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE INDEX ai_unique_index_data_ai_object_data_id_index "
"ON ai_unique_index_data (ai_object_data_id);"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = CreateFileTables(aDBConn);
NS_ENSURE_SUCCESS(rv, rv);
@ -963,121 +1058,6 @@ UpgradeSchemaFrom9_0To10_0(mozIStorageConnection* aConnection)
return NS_OK;
}
nsresult
UpgradeSchemaFrom10_0To11_0(mozIStorageConnection* aConnection)
{
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TEMPORARY TABLE temp_upgrade ("
"id, "
"object_store_id, "
"name, "
"key_path, "
"unique_index, "
"multientry"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"INSERT INTO temp_upgrade "
"SELECT id, object_store_id, name, key_path, "
"unique_index, multientry "
"FROM object_store_index;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE object_store_index;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE object_store_index ("
"id INTEGER PRIMARY KEY, "
"object_store_id INTEGER NOT NULL, "
"name TEXT NOT NULL, "
"key_path TEXT NOT NULL, "
"unique_index INTEGER NOT NULL, "
"multientry INTEGER NOT NULL, "
"UNIQUE (object_store_id, name), "
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
"CASCADE"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"INSERT INTO object_store_index "
"SELECT id, object_store_id, name, key_path, "
"unique_index, multientry "
"FROM temp_upgrade;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE temp_upgrade;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
"SELECT object_store_id, id, data, file_ids "
"FROM ai_object_data;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"INSERT INTO index_data (index_id, value, object_data_key, object_data_id) "
"SELECT ai_index_data.index_id, ai_index_data.value, ai_index_data.ai_object_data_id, object_data.id "
"FROM ai_index_data "
"INNER JOIN object_store_index ON "
"object_store_index.id = ai_index_data.index_id "
"INNER JOIN object_data ON "
"object_data.object_store_id = object_store_index.object_store_id AND "
"object_data.key_value = ai_index_data.ai_object_data_id;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"INSERT INTO unique_index_data (index_id, value, object_data_key, object_data_id) "
"SELECT ai_unique_index_data.index_id, ai_unique_index_data.value, ai_unique_index_data.ai_object_data_id, object_data.id "
"FROM ai_unique_index_data "
"INNER JOIN object_store_index ON "
"object_store_index.id = ai_unique_index_data.index_id "
"INNER JOIN object_data ON "
"object_data.object_store_id = object_store_index.object_store_id AND "
"object_data.key_value = ai_unique_index_data.ai_object_data_id;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"UPDATE object_store "
"SET auto_increment = (SELECT max(id) FROM ai_object_data) + 1 "
"WHERE auto_increment;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE ai_unique_index_data;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE ai_index_data;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE ai_object_data;"
));
NS_ENSURE_SUCCESS(rv, rv);
rv = aConnection->SetSchemaVersion(MakeSchemaVersion(11, 0));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
class VersionChangeEventsRunnable;
class SetVersionHelper : public AsyncConnectionHelper,
@ -1383,7 +1363,7 @@ OpenDatabaseHelper::DoDatabaseWork()
}
for (PRUint32 i = 0; i < mObjectStores.Length(); i++) {
nsRefPtr<ObjectStoreInfo>& objectStoreInfo = mObjectStores[i];
nsAutoPtr<ObjectStoreInfo>& objectStoreInfo = mObjectStores[i];
for (PRUint32 j = 0; j < objectStoreInfo->indexes.Length(); j++) {
IndexInfo& indexInfo = objectStoreInfo->indexes[j];
mLastIndexId = NS_MAX(indexInfo.id, mLastIndexId);
@ -1529,7 +1509,7 @@ OpenDatabaseHelper::CreateDatabaseConnection(
}
else {
// This logic needs to change next time we change the schema!
PR_STATIC_ASSERT(kSQLiteSchemaVersion == PRInt32((11 << 4) + 0));
PR_STATIC_ASSERT(kSQLiteSchemaVersion == PRInt32((10 << 4) + 0));
while (schemaVersion != kSQLiteSchemaVersion) {
if (schemaVersion == 4) {
@ -1551,9 +1531,6 @@ OpenDatabaseHelper::CreateDatabaseConnection(
else if (schemaVersion == MakeSchemaVersion(9, 0)) {
rv = UpgradeSchemaFrom9_0To10_0(connection);
}
else if (schemaVersion == MakeSchemaVersion(10, 0)) {
rv = UpgradeSchemaFrom10_0To11_0(connection);
}
else {
NS_WARNING("Unable to open IndexedDB database, no upgrade path is "
"available!");
@ -1704,8 +1681,6 @@ OpenDatabaseHelper::Run()
// Destroy the database now (we should have the only ref).
mDatabase = nsnull;
DatabaseInfo::Remove(mDatabaseId);
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never fail!");
@ -1774,14 +1749,18 @@ OpenDatabaseHelper::EnsureSuccessResult()
PRUint32 objectStoreCount = mObjectStores.Length();
for (PRUint32 index = 0; index < objectStoreCount; index++) {
nsRefPtr<ObjectStoreInfo>& info = mObjectStores[index];
nsAutoPtr<ObjectStoreInfo>& info = mObjectStores[index];
NS_ASSERTION(info->databaseId == mDatabaseId, "Huh?!");
ObjectStoreInfo* otherInfo = dbInfo->GetObjectStore(info->name);
NS_ASSERTION(otherInfo, "ObjectStore not known!");
ObjectStoreInfo* otherInfo;
NS_ASSERTION(dbInfo->GetObjectStore(info->name, &otherInfo),
"ObjectStore not known!");
NS_ASSERTION(info->name == otherInfo->name &&
info->id == otherInfo->id &&
info->keyPath == otherInfo->keyPath,
info->keyPath == otherInfo->keyPath &&
info->autoIncrement == otherInfo->autoIncrement &&
info->databaseId == otherInfo->databaseId,
"Metadata mismatch!");
NS_ASSERTION(dbInfo->ContainsStoreName(info->name),
"Object store names out of date!");
@ -1800,6 +1779,8 @@ OpenDatabaseHelper::EnsureSuccessResult()
"Bad index keyPath!");
NS_ASSERTION(indexInfo.unique == otherIndexInfo.unique,
"Bad index unique value!");
NS_ASSERTION(indexInfo.autoIncrement == otherIndexInfo.autoIncrement,
"Bad index autoIncrement value!");
}
}
}
@ -1810,7 +1791,6 @@ OpenDatabaseHelper::EnsureSuccessResult()
nsRefPtr<DatabaseInfo> newInfo(new DatabaseInfo());
newInfo->name = mName;
newInfo->origin = mASCIIOrigin;
newInfo->id = mDatabaseId;
newInfo->filePath = mDatabaseFilePath;
@ -1821,8 +1801,8 @@ OpenDatabaseHelper::EnsureSuccessResult()
newInfo.swap(dbInfo);
nsresult rv = IDBFactory::SetDatabaseMetadata(dbInfo, mCurrentVersion,
mObjectStores);
nsresult rv = IDBFactory::UpdateDatabaseMetadata(dbInfo, mCurrentVersion,
mObjectStores);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
NS_ASSERTION(mObjectStores.IsEmpty(), "Should have swapped!");

View File

@ -62,7 +62,7 @@ public:
mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion),
mForDeletion(aForDeletion), mDatabaseId(nsnull), mCurrentVersion(0),
mLastObjectStoreId(0), mLastIndexId(0), mState(eCreated),
mResultCode(NS_OK), mLoadDBMetadata(false)
mResultCode(NS_OK)
{
NS_ASSERTION(!aForDeletion || !aRequestedVersion,
"Can't be for deletion and request a version!");
@ -132,7 +132,7 @@ private:
nsCOMPtr<nsIAtom> mDatabaseId;
// Out-params.
nsTArray<nsRefPtr<ObjectStoreInfo> > mObjectStores;
nsTArray<nsAutoPtr<ObjectStoreInfo> > mObjectStores;
PRUint64 mCurrentVersion;
nsString mDatabaseFilePath;
PRInt64 mLastObjectStoreId;
@ -153,9 +153,6 @@ private:
nsresult mResultCode;
nsRefPtr<FileManager> mFileManager;
nsRefPtr<DatabaseInfo> mDBInfo;
bool mLoadDBMetadata;
};
END_INDEXEDDB_NAMESPACE

View File

@ -50,7 +50,7 @@ interface nsIDOMDOMStringList;
* http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-nsIIDBObjectStore
* for more information.
*/
[scriptable, builtinclass, uuid(e93c5ca4-89da-4eb4-b839-271ba4f65a27)]
[scriptable, builtinclass, uuid(adc6a1e2-9fd7-4d28-a7f9-9c653313124b)]
interface nsIIDBObjectStore : nsISupports
{
readonly attribute DOMString name;
@ -61,8 +61,6 @@ interface nsIIDBObjectStore : nsISupports
readonly attribute nsIIDBTransaction transaction;
readonly attribute boolean autoIncrement;
// Success fires IDBTransactionEvent, result == value for key
[implicit_jscontext]
nsIIDBRequest

View File

@ -57,7 +57,6 @@ TEST_FILES = \
test_add_twice_failure.html \
test_advance.html \
test_autoIncrement_indexes.html \
test_autoIncrement.html \
test_bfcache.html \
test_clear.html \
test_cmp.html \

View File

@ -88,13 +88,15 @@
event = yield;
is(event.type, "abort", "Got a transaction abort event");
is(db.version, 1, "Correct version");
is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
//todo(db.version, 1, "Correct version");
is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
event = yield;
is(event.type, "error", "Got request error event");
is(event.target.errorCode, IDBDatabaseException.ABORT_ERR, "Right error code");
db.close();
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;

View File

@ -47,11 +47,6 @@ function continueToNextStep()
});
}
function continueToNextStepSync()
{
testGenerator.next();
}
function errorHandler(event)
{
ok(false, "indexedDB error, code " + event.target.errorCode);
@ -80,7 +75,6 @@ ExpectError.prototype = {
is(event.type, "error", "Got an error event");
is(this._code, event.target.errorCode, "Expected error was thrown.");
event.preventDefault();
event.stopPropagation();
grabEventAndContinueHandler(event);
}
};

View File

@ -82,8 +82,6 @@
let expected = expectedResult(method, keypath, explicit, autoincrement, existing);
let valueJSON = JSON.stringify(value);
ok(true, "making call" + test);
// Make function call for throwing functions
@ -96,16 +94,13 @@
ok(true, "did throw" + test);
ok(ex instanceof IDBDatabaseException, "Got a IDBDatabaseException" + test);
is(ex.code, IDBDatabaseException.DATA_ERR, "expect a DATA_ERR" + test);
is(JSON.stringify(value), valueJSON, "call didn't modify value" + test);
}
continue;
}
// Make non-throwing function call
let req = store[method].apply(store, args);
is(JSON.stringify(value), valueJSON, "call didn't modify value" + test);
req.onsuccess = req.onerror = grabEventAndContinueHandler;
req.onsuccess = req.onerror = grabEventAndContinueHandler
let e = yield;
// Figure out what key we used
@ -128,7 +123,16 @@
}
is(e.type, "success", "write should succeed" + test);
is(e.target.result, key, "write should return correct key" + test);
if (autoincrement && speccedNoKey) {
todo_is(e.target.result, key, "(fix ai) write should return correct key" + test);
key = e.target.result;
if (keypath) {
value.id = key;
}
}
else {
is(e.target.result, key, "write should return correct key" + test);
}
store.get(key).onsuccess = grabEventAndContinueHandler;
e = yield;

View File

@ -1,384 +0,0 @@
<!--
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">
function genCheck(key, value, test, options) {
return function(event) {
is(event.target.result, key, "correct returned key in " + test);
if (options && options.store) {
is(event.target.source, options.store, "correct store in " + test);
}
if (options && options.trans) {
is(event.target.transaction, options.trans, "correct transaction in " + test);
}
event.target.source.get(key).onsuccess = function(event) {
is(JSON.stringify(event.target.result), JSON.stringify(value),
"correct stored value in " + test);
continueToNextStepSync();
}
}
}
function testSteps()
{
const dbname = window.location.pathname;
const RW = IDBTransaction.READ_WRITE
let c1 = 1;
let c2 = 1;
let openRequest = mozIndexedDB.open(dbname, 1);
openRequest.onerror = errorHandler;
openRequest.onupgradeneeded = grabEventAndContinueHandler;
openRequest.onsuccess = unexpectedSuccessHandler;
let event = yield;
let db = event.target.result;
let trans = event.target.transaction;
// Create test stores
let store1 = db.createObjectStore("store1", { autoIncrement: true });
let store2 = db.createObjectStore("store2", { autoIncrement: true, keyPath: "id" });
let store3 = db.createObjectStore("store3", { autoIncrement: false });
is(store1.autoIncrement, true, "store1 .autoIncrement");
is(store2.autoIncrement, true, "store2 .autoIncrement");
is(store3.autoIncrement, false, "store3 .autoIncrement");
store1.createIndex("unique1", "unique", { unique: true });
store2.createIndex("unique1", "unique", { unique: true });
// Test simple inserts
let test = " for test simple insert"
store1.add({ foo: "value1" }).onsuccess =
genCheck(c1++, { foo: "value1" }, "first" + test);
store1.add({ foo: "value2" }).onsuccess =
genCheck(c1++, { foo: "value2" }, "second" + test);
yield;
yield;
store2.put({ bar: "value1" }).onsuccess =
genCheck(c2, { bar: "value1", id: c2 }, "first in store2" + test,
{ store: store2 });
c2++;
store1.put({ foo: "value3" }).onsuccess =
genCheck(c1++, { foo: "value3" }, "third" + test,
{ store: store1 });
yield;
yield;
store2.get(IDBKeyRange.lowerBound(c2)).onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target.result, undefined, "no such value" + test);
// Close version_change transaction
openRequest.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target, openRequest, "succeeded to open" + test);
is(event.type, "success", "succeeded to open" + test);
// Test inserting explicit keys
test = " for test explicit keys";
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 1 }, 100).onsuccess =
genCheck(100, { explicit: 1 }, "first" + test);
c1 = 101;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 2 }).onsuccess =
genCheck(c1++, { explicit: 2 }, "second" + test);
yield; yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 3 }, 200).onsuccess =
genCheck(200, { explicit: 3 }, "third" + test);
c1 = 201;
trans.objectStore("store1").add({ explicit: 4 }).onsuccess =
genCheck(c1++, { explicit: 4 }, "fourth" + test);
yield; yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 5 }, 150).onsuccess =
genCheck(150, { explicit: 5 }, "fifth" + test);
yield;
trans.objectStore("store1").add({ explicit: 6 }).onsuccess =
genCheck(c1++, { explicit: 6 }, "sixth" + test);
yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 7 }, "key").onsuccess =
genCheck("key", { explicit: 7 }, "seventh" + test);
yield;
trans.objectStore("store1").add({ explicit: 8 }).onsuccess =
genCheck(c1++, { explicit: 8 }, "eighth" + test);
yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 9 }, -100000).onsuccess =
genCheck(-100000, { explicit: 9 }, "ninth" + test);
yield;
trans.objectStore("store1").add({ explicit: 10 }).onsuccess =
genCheck(c1++, { explicit: 10 }, "tenth" + test);
yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit2: 1, id: 300 }).onsuccess =
genCheck(300, { explicit2: 1, id: 300 }, "first store2" + test);
c2 = 301;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit2: 2 }).onsuccess =
genCheck(c2, { explicit2: 2, id: c2 }, "second store2" + test);
c2++;
yield; yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit2: 3, id: 400 }).onsuccess =
genCheck(400, { explicit2: 3, id: 400 }, "third store2" + test);
c2 = 401;
trans.objectStore("store2").add({ explicit2: 4 }).onsuccess =
genCheck(c2, { explicit2: 4, id: c2 }, "fourth store2" + test);
c2++;
yield; yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit: 5, id: 150 }).onsuccess =
genCheck(150, { explicit: 5, id: 150 }, "fifth store2" + test);
yield;
trans.objectStore("store2").add({ explicit: 6 }).onsuccess =
genCheck(c2, { explicit: 6, id: c2 }, "sixth store2" + test);
c2++;
yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit: 7, id: "key" }).onsuccess =
genCheck("key", { explicit: 7, id: "key" }, "seventh store2" + test);
yield;
trans.objectStore("store2").add({ explicit: 8 }).onsuccess =
genCheck(c2, { explicit: 8, id: c2 }, "eighth store2" + test);
c2++;
yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit: 9, id: -100000 }).onsuccess =
genCheck(-100000, { explicit: 9, id: -100000 }, "ninth store2" + test);
yield;
trans.objectStore("store2").add({ explicit: 10 }).onsuccess =
genCheck(c2, { explicit: 10, id: c2 }, "tenth store2" + test);
c2++;
yield;
// Test separate transactions doesn't generate overlapping numbers
test = " for test non-overlapping counts";
trans = db.transaction("store1", RW);
trans2 = db.transaction("store1", RW);
trans2.objectStore("store1").put({ over: 2 }).onsuccess =
genCheck(c1 + 1, { over: 2 }, "first" + test,
{ trans: trans2 });
trans.objectStore("store1").put({ over: 1 }).onsuccess =
genCheck(c1, { over: 1 }, "second" + test,
{ trans: trans });
c1 += 2;
yield; yield;
trans = db.transaction("store2", RW);
trans2 = db.transaction("store2", RW);
trans2.objectStore("store2").put({ over: 2 }).onsuccess =
genCheck(c2 + 1, { over: 2, id: c2 + 1 }, "third" + test,
{ trans: trans2 });
trans.objectStore("store2").put({ over: 1 }).onsuccess =
genCheck(c2, { over: 1, id: c2 }, "fourth" + test,
{ trans: trans });
c2 += 2;
yield; yield;
// Test that error inserts doesn't increase generator
test = " for test error inserts";
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ unique: 1 }, -1);
trans.objectStore("store2").add({ unique: 1, id: "unique" });
trans.objectStore("store1").add({ error: 1, unique: 1 }).onerror =
new ExpectError(IDBDatabaseException.CONSTRAINT_ERR);
trans.objectStore("store1").add({ error: 2 }).onsuccess =
genCheck(c1++, { error: 2 }, "first" + test);
yield; yield;
trans.objectStore("store2").add({ error: 3, unique: 1 }).onerror =
new ExpectError(IDBDatabaseException.CONSTRAINT_ERR);
trans.objectStore("store2").add({ error: 4 }).onsuccess =
genCheck(c2, { error: 4, id: c2 }, "second" + test);
c2++;
yield; yield;
trans.objectStore("store1").add({ error: 5, unique: 1 }, 100000).onerror =
new ExpectError(IDBDatabaseException.CONSTRAINT_ERR);
trans.objectStore("store1").add({ error: 6 }).onsuccess =
genCheck(c1++, { error: 6 }, "third" + test);
yield; yield;
trans.objectStore("store2").add({ error: 7, unique: 1, id: 100000 }).onerror =
new ExpectError(IDBDatabaseException.CONSTRAINT_ERR);
trans.objectStore("store2").add({ error: 8 }).onsuccess =
genCheck(c2, { error: 8, id: c2 }, "fourth" + test);
c2++;
yield; yield;
// Test that aborts doesn't increase generator
test = " for test aborted transaction";
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ abort: 1 }).onsuccess =
genCheck(c1, { abort: 1 }, "first" + test);
trans.objectStore("store2").put({ abort: 2 }).onsuccess =
genCheck(c2, { abort: 2, id: c2 }, "second" + test);
yield; yield;
trans.objectStore("store1").add({ abort: 3 }, 500).onsuccess =
genCheck(500, { abort: 3 }, "third" + test);
trans.objectStore("store2").put({ abort: 4, id: 600 }).onsuccess =
genCheck(600, { abort: 4, id: 600 }, "fourth" + test);
yield; yield;
trans.objectStore("store1").add({ abort: 5 }).onsuccess =
genCheck(501, { abort: 5 }, "fifth" + test);
trans.objectStore("store2").put({ abort: 6 }).onsuccess =
genCheck(601, { abort: 6, id: 601 }, "sixth" + test);
yield; yield;
trans.abort();
trans.onabort = grabEventAndContinueHandler;
event = yield
is(event.type, "abort", "transaction aborted");
is(event.target, trans, "correct transaction aborted");
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ abort: 1 }).onsuccess =
genCheck(c1++, { abort: 1 }, "re-first" + test);
trans.objectStore("store2").put({ abort: 2 }).onsuccess =
genCheck(c2, { abort: 2, id: c2 }, "re-second" + test);
c2++;
yield; yield;
// Test that delete doesn't decrease generator
test = " for test delete items"
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ delete: 1 }).onsuccess =
genCheck(c1++, { delete: 1 }, "first" + test);
trans.objectStore("store2").put({ delete: 2 }).onsuccess =
genCheck(c2, { delete: 2, id: c2 }, "second" + test);
c2++;
yield; yield;
trans.objectStore("store1").delete(c1 - 1).onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").delete(c2 - 1).onsuccess =
grabEventAndContinueHandler;
yield; yield;
trans.objectStore("store1").add({ delete: 3 }).onsuccess =
genCheck(c1++, { delete: 3 }, "first" + test);
trans.objectStore("store2").put({ delete: 4 }).onsuccess =
genCheck(c2, { delete: 4, id: c2 }, "second" + test);
c2++;
yield; yield;
trans.objectStore("store1").delete(c1 - 1).onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").delete(c2 - 1).onsuccess =
grabEventAndContinueHandler;
yield; yield;
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ delete: 5 }).onsuccess =
genCheck(c1++, { delete: 5 }, "first" + test);
trans.objectStore("store2").put({ delete: 6 }).onsuccess =
genCheck(c2, { delete: 6, id: c2 }, "second" + test);
c2++;
yield; yield;
// Test that clears doesn't decrease generator
test = " for test clear stores";
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ clear: 1 }).onsuccess =
genCheck(c1++, { clear: 1 }, "first" + test);
trans.objectStore("store2").put({ clear: 2 }).onsuccess =
genCheck(c2, { clear: 2, id: c2 }, "second" + test);
c2++;
yield; yield;
trans.objectStore("store1").clear().onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").clear().onsuccess =
grabEventAndContinueHandler;
yield; yield;
trans.objectStore("store1").add({ clear: 3 }).onsuccess =
genCheck(c1++, { clear: 3 }, "third" + test);
trans.objectStore("store2").put({ clear: 4 }).onsuccess =
genCheck(c2, { clear: 4, id: c2 }, "forth" + test);
c2++;
yield; yield;
trans.objectStore("store1").clear().onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").clear().onsuccess =
grabEventAndContinueHandler;
yield; yield;
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ clear: 5 }).onsuccess =
genCheck(c1++, { clear: 5 }, "fifth" + test);
trans.objectStore("store2").put({ clear: 6 }).onsuccess =
genCheck(c2, { clear: 6, id: c2 }, "sixth" + test);
c2++;
yield; yield;
// Test that close/reopen doesn't decrease generator
test = " for test clear stores";
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").clear().onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").clear().onsuccess =
grabEventAndContinueHandler;
yield; yield;
db.close();
SpecialPowers.gc();
openRequest = mozIndexedDB.open(dbname, 2);
openRequest.onerror = errorHandler;
openRequest.onupgradeneeded = grabEventAndContinueHandler;
openRequest.onsuccess = unexpectedSuccessHandler;
event = yield;
db = event.target.result;
trans = event.target.transaction;
trans.objectStore("store1").add({ reopen: 1 }).onsuccess =
genCheck(c1++, { reopen: 1 }, "first" + test);
trans.objectStore("store2").put({ reopen: 2 }).onsuccess =
genCheck(c2, { reopen: 2, id: c2 }, "second" + test);
c2++;
yield; yield;
openRequest.onsuccess = grabEventAndContinueHandler;
yield;
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>

View File

@ -31,7 +31,8 @@
objectStore.add(data).onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target.result, 1, "Added entry");
let key = event.target.result;
ok(key, "Added entry");
request.onsuccess = grabEventAndContinueHandler;
event = yield;
@ -44,17 +45,17 @@
first.get("foo").onsuccess = grabEventAndContinueHandler;
event = yield;
is (event.target.result.id, 1, "Entry in first");
is (event.target.result.id, key, "Entry in first");
second.get("foo").onsuccess = grabEventAndContinueHandler;
event = yield;
is (event.target.result.id, 1, "Entry in second");
is (event.target.result.id, key, "Entry in second");
third.get("foo").onsuccess = grabEventAndContinueHandler;
event = yield;
is (event.target.result.id, 1, "Entry in third");
is (event.target.result.id, key, "Entry in third");
finishTest();
yield;

View File

@ -21,7 +21,7 @@ function testSteps()
let request = mozIndexedDB.open(name, 1, description);
request.onerror = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
request.onsuccess = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
@ -43,28 +43,13 @@ function testSteps()
is(event.type, "abort", "Got transaction abort event");
is(event.target, transaction, "Right target");
is(db.version, 1, "Correct version");
is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
todo(db.version, 1, "Correct version");
is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
event = yield;
is(event.type, "error", "Got request error event");
is(event.target, request, "Right target");
request = mozIndexedDB.open(name, 1, description);
request.onerror = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db2 = event.target.result;
isnot(db, db2, "Should give a different db instance");
is(db2.version, 1, "Correct version");
is(db2.objectStoreNames.length, 0, "Correct objectStoreNames length");
request.onsuccess = grabEventAndContinueHandler;
yield;
finishTest();
yield;
}