From c2a8c167f7b8605896b65a14782e8ce1feb39153 Mon Sep 17 00:00:00 2001 From: Jonas Sicking Date: Fri, 16 Dec 2011 12:29:15 -0800 Subject: [PATCH] Bug 701772: Manage autoIncrement for objectStores ourselves in order to simplify the code, make ai-keys unique per objectStore and not per database, and allow ai-objectStores to contain non-integer keys. r=bent --- dom/indexedDB/DatabaseInfo.cpp | 73 +- dom/indexedDB/DatabaseInfo.h | 47 +- dom/indexedDB/IDBDatabase.cpp | 37 +- dom/indexedDB/IDBFactory.cpp | 40 +- dom/indexedDB/IDBFactory.h | 8 +- dom/indexedDB/IDBIndex.cpp | 458 +++++------ dom/indexedDB/IDBIndex.h | 6 - dom/indexedDB/IDBObjectStore.cpp | 720 +++++------------- dom/indexedDB/IDBObjectStore.h | 11 +- dom/indexedDB/IDBTransaction.cpp | 244 +++--- dom/indexedDB/IDBTransaction.h | 42 +- dom/indexedDB/IndexedDatabaseManager.cpp | 6 +- dom/indexedDB/Key.h | 6 +- dom/indexedDB/OpenDatabaseHelper.cpp | 244 +++--- dom/indexedDB/OpenDatabaseHelper.h | 7 +- dom/indexedDB/nsIIDBObjectStore.idl | 4 +- dom/indexedDB/test/Makefile.in | 1 + ...rror_events_abort_transactions_iframe.html | 6 +- dom/indexedDB/test/helpers.js | 6 + dom/indexedDB/test/test_add_put.html | 18 +- dom/indexedDB/test/test_autoIncrement.html | 384 ++++++++++ .../test/test_autoIncrement_indexes.html | 9 +- dom/indexedDB/test/test_setVersion_abort.html | 21 +- 23 files changed, 1169 insertions(+), 1229 deletions(-) create mode 100644 dom/indexedDB/test/test_autoIncrement.html diff --git a/dom/indexedDB/DatabaseInfo.cpp b/dom/indexedDB/DatabaseInfo.cpp index 91958ff6ccda..1d35d9a8f4b4 100644 --- a/dom/indexedDB/DatabaseInfo.cpp +++ b/dom/indexedDB/DatabaseInfo.cpp @@ -71,14 +71,13 @@ CloneObjectStoreInfo(const nsAString& aKey, { ObjectStoreInfoHash* hash = static_cast(aUserArg); - nsAutoPtr newInfo(new ObjectStoreInfo(*aData)); + nsRefPtr newInfo(new ObjectStoreInfo(*aData)); if (!hash->Put(aKey, newInfo)) { NS_WARNING("Out of memory?"); return PL_DHASH_STOP; } - newInfo.forget(); return PL_DHASH_NEXT; } @@ -92,12 +91,23 @@ 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); @@ -108,7 +118,6 @@ IndexInfo::IndexInfo(const IndexInfo& aOther) name(aOther.name), keyPath(aOther.keyPath), unique(aOther.unique), - autoIncrement(aOther.autoIncrement), multiEntry(aOther.multiEntry) { MOZ_COUNT_CTOR(IndexInfo); @@ -121,19 +130,8 @@ IndexInfo::~IndexInfo() ObjectStoreInfo::ObjectStoreInfo() : id(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) + nextAutoIncrementId(0), + comittedAutoIncrementId(0) { MOZ_COUNT_CTOR(ObjectStoreInfo); } @@ -206,11 +204,6 @@ DatabaseInfo::Remove(nsIAtom* aId) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - DatabaseInfo* info = nsnull; - - DebugOnly got = Get(aId, &info); - NS_ASSERTION(got && info, "Don't know anything about this one!"); - if (gDatabaseHash) { gDatabaseHash->Remove(aId); @@ -221,6 +214,31 @@ DatabaseInfo::Remove(nsIAtom* aId) } } +PLDHashOperator +EnumerateDatabasesRemoveOrigin(nsISupports* aId, + DatabaseInfo*& aDatabaseInfo, + void* aUserArg) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + const nsACString* origin = static_cast(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(&aOrigin)); + } +} + bool DatabaseInfo::GetObjectStoreNames(nsTArray& aNames) { @@ -241,17 +259,16 @@ DatabaseInfo::ContainsStoreName(const nsAString& aName) return objectStoreHash && objectStoreHash->Get(aName, nsnull); } -bool -DatabaseInfo::GetObjectStore(const nsAString& aName, - ObjectStoreInfo** aInfo) +ObjectStoreInfo* +DatabaseInfo::GetObjectStore(const nsAString& aName) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); if (objectStoreHash) { - return objectStoreHash->Get(aName, aInfo); + return objectStoreHash->GetWeak(aName); } - return false; + return nsnull; } bool @@ -281,7 +298,7 @@ void DatabaseInfo::RemoveObjectStore(const nsAString& aName) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(GetObjectStore(aName, nsnull), "Don't know about this one!"); + NS_ASSERTION(GetObjectStore(aName), "Don't know about this one!"); if (objectStoreHash) { objectStoreHash->Remove(aName); diff --git a/dom/indexedDB/DatabaseInfo.h b/dom/indexedDB/DatabaseInfo.h index bb9cd9449b61..1c03c545945c 100644 --- a/dom/indexedDB/DatabaseInfo.h +++ b/dom/indexedDB/DatabaseInfo.h @@ -46,14 +46,14 @@ #include "Key.h" #include "IDBObjectStore.h" -#include "nsClassHashtable.h" +#include "nsRefPtrHashtable.h" #include "nsHashKeys.h" BEGIN_INDEXEDDB_NAMESPACE struct ObjectStoreInfo; -typedef nsClassHashtable +typedef nsRefPtrHashtable ObjectStoreInfoHash; class IDBDatabase; @@ -77,14 +77,15 @@ private: static bool Put(DatabaseInfo* aInfo); +public: static void Remove(nsIAtom* aId); -public: + static void RemoveAllForOrigin(const nsACString& aOrigin); + bool GetObjectStoreNames(nsTArray& aNames); bool ContainsStoreName(const nsAString& aName); - bool GetObjectStore(const nsAString& aName, - ObjectStoreInfo** aInfo); + ObjectStoreInfo* GetObjectStore(const nsAString& aName); bool PutObjectStore(ObjectStoreInfo* aInfo); @@ -93,8 +94,9 @@ public: already_AddRefed Clone(); nsString name; + nsCString origin; PRUint64 version; - nsIAtom* id; + nsCOMPtr id; nsString filePath; PRInt64 nextObjectStoreId; PRInt64 nextIndexId; @@ -113,14 +115,13 @@ struct IndexInfo ~IndexInfo(); #else IndexInfo() - : id(LL_MININT), unique(false), autoIncrement(false) { } + : id(LL_MININT), unique(false), multiEntry(false) { } #endif PRInt64 id; nsString name; nsString keyPath; bool unique; - bool autoIncrement; bool multiEntry; }; @@ -128,19 +129,39 @@ struct ObjectStoreInfo { #ifdef NS_BUILD_REFCNT_LOGGING ObjectStoreInfo(); - ObjectStoreInfo(ObjectStoreInfo& aOther); - ~ObjectStoreInfo(); #else ObjectStoreInfo() - : id(0), autoIncrement(false), databaseId(0) { } + : id(0), nextAutoIncrementId(0), comittedAutoIncrementId(0) { } #endif + ObjectStoreInfo(ObjectStoreInfo& aOther); + +private: +#ifdef NS_BUILD_REFCNT_LOGGING + ~ObjectStoreInfo(); +#else + ~ObjectStoreInfo() {} +#endif +public: + + // Constant members, can be gotten on any thread nsString name; PRInt64 id; nsString keyPath; - bool autoIncrement; - nsIAtom* databaseId; + + // Main-thread only members. This must *not* be touced on the database thread nsTArray 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 diff --git a/dom/indexedDB/IDBDatabase.cpp b/dom/indexedDB/IDBDatabase.cpp index beb65297cb18..235648d60e94 100644 --- a/dom/indexedDB/IDBDatabase.cpp +++ b/dom/indexedDB/IDBDatabase.cpp @@ -124,24 +124,24 @@ NS_STACK_CLASS class AutoRemoveObjectStore { public: - AutoRemoveObjectStore(IDBDatabase* aDatabase, const nsAString& aName) - : mDatabase(aDatabase), mName(aName) + AutoRemoveObjectStore(DatabaseInfo* aInfo, const nsAString& aName) + : mInfo(aInfo), mName(aName) { } ~AutoRemoveObjectStore() { - if (mDatabase) { - mDatabase->Info()->RemoveObjectStore(mName); + if (mInfo) { + mInfo->RemoveObjectStore(mName); } } void forget() { - mDatabase = nsnull; + mInfo = nsnull; } private: - IDBDatabase* mDatabase; + DatabaseInfo* mInfo; nsString mName; }; @@ -384,7 +384,7 @@ IDBDatabase::CreateObjectStore(const nsAString& aName, return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; } - DatabaseInfo* databaseInfo = Info(); + DatabaseInfo* databaseInfo = transaction->DBInfo(); nsString keyPath; keyPath.SetIsVoid(true); @@ -446,25 +446,24 @@ IDBDatabase::CreateObjectStore(const nsAString& aName, } } - nsAutoPtr newInfo(new ObjectStoreInfo()); + nsRefPtr newInfo(new ObjectStoreInfo()); newInfo->name = aName; newInfo->id = databaseInfo->nextObjectStoreId++; newInfo->keyPath = keyPath; - newInfo->autoIncrement = autoIncrement; - newInfo->databaseId = mDatabaseId; + newInfo->nextAutoIncrementId = autoIncrement ? 1 : 0; + newInfo->comittedAutoIncrementId = newInfo->nextAutoIncrementId; - if (!Info()->PutObjectStore(newInfo)) { + if (!databaseInfo->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(this, aName); + AutoRemoveObjectStore autoRemove(databaseInfo, aName); nsRefPtr objectStore = - transaction->GetOrCreateObjectStore(aName, objectStoreInfo); + transaction->GetOrCreateObjectStore(aName, newInfo); NS_ENSURE_TRUE(objectStore, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); nsRefPtr helper = @@ -491,9 +490,9 @@ IDBDatabase::DeleteObjectStore(const nsAString& aName) return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; } - DatabaseInfo* info = Info(); - ObjectStoreInfo* objectStoreInfo; - if (!info->GetObjectStore(aName, &objectStoreInfo)) { + DatabaseInfo* info = transaction->DBInfo(); + ObjectStoreInfo* objectStoreInfo = info->GetObjectStore(aName); + if (!objectStoreInfo) { return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR; } @@ -502,9 +501,7 @@ IDBDatabase::DeleteObjectStore(const nsAString& aName) nsresult rv = helper->DispatchToTransactionPool(); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - info->RemoveObjectStore(aName); - - transaction->ReleaseCachedObjectStore(aName); + transaction->RemoveObjectStore(aName); return NS_OK; } diff --git a/dom/indexedDB/IDBFactory.cpp b/dom/indexedDB/IDBFactory.cpp index 5511deb9b373..248fe16515d3 100644 --- a/dom/indexedDB/IDBFactory.cpp +++ b/dom/indexedDB/IDBFactory.cpp @@ -226,9 +226,8 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection, bool hasResult; while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) { - nsAutoPtr* element = + nsRefPtr* element = aObjectStores.AppendElement(new ObjectStoreInfo()); - NS_ENSURE_TRUE(element, NS_ERROR_OUT_OF_MEMORY); ObjectStoreInfo* info = element->get(); @@ -250,8 +249,8 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection, NS_ENSURE_SUCCESS(rv, rv); } - info->autoIncrement = !!stmt->AsInt32(3); - info->databaseId = aDatabaseId; + info->nextAutoIncrementId = stmt->AsInt64(3); + info->comittedAutoIncrementId = info->nextAutoIncrementId; ObjectStoreInfoMap* mapEntry = infoMap.AppendElement(); NS_ENSURE_TRUE(mapEntry, NS_ERROR_OUT_OF_MEMORY); @@ -263,8 +262,7 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection, // Load index information rv = aConnection->CreateStatement(NS_LITERAL_CSTRING( - "SELECT object_store_id, id, name, key_path, unique_index, multientry, " - "object_store_autoincrement " + "SELECT object_store_id, id, name, key_path, unique_index, multientry " "FROM object_store_index" ), getter_AddRefs(stmt)); NS_ENSURE_SUCCESS(rv, rv); @@ -298,7 +296,6 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection, indexInfo->unique = !!stmt->AsInt32(4); indexInfo->multiEntry = !!stmt->AsInt32(5); - indexInfo->autoIncrement = !!stmt->AsInt32(6); } NS_ENSURE_SUCCESS(rv, rv); @@ -327,35 +324,28 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection, // static nsresult -IDBFactory::UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo, - PRUint64 aVersion, - ObjectStoreInfoArray& aObjectStores) +IDBFactory::SetDatabaseMetadata(DatabaseInfo* aDatabaseInfo, + PRUint64 aVersion, + ObjectStoreInfoArray& aObjectStores) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(aDatabaseInfo, "Null pointer!"); ObjectStoreInfoArray objectStores; - if (!objectStores.SwapElements(aObjectStores)) { - NS_WARNING("Out of memory!"); - return NS_ERROR_OUT_OF_MEMORY; - } + objectStores.SwapElements(aObjectStores); - nsAutoTArray 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]); +#ifdef DEBUG + { + nsTArray existingNames; + aDatabaseInfo->GetObjectStoreNames(existingNames); + NS_ASSERTION(existingNames.IsEmpty(), "Should be an empty DatabaseInfo"); } +#endif aDatabaseInfo->version = aVersion; for (PRUint32 index = 0; index < objectStores.Length(); index++) { - nsAutoPtr& info = objectStores[index]; - NS_ASSERTION(info->databaseId == aDatabaseInfo->id, "Huh?!"); + nsRefPtr& info = objectStores[index]; if (!aDatabaseInfo->PutObjectStore(info)) { NS_WARNING("Out of memory!"); diff --git a/dom/indexedDB/IDBFactory.h b/dom/indexedDB/IDBFactory.h index e0e13d6372e7..8a1871fe180c 100644 --- a/dom/indexedDB/IDBFactory.h +++ b/dom/indexedDB/IDBFactory.h @@ -59,7 +59,7 @@ struct ObjectStoreInfo; class IDBFactory : public nsIIDBFactory { - typedef nsTArray > ObjectStoreInfoArray; + typedef nsTArray > ObjectStoreInfoArray; public: NS_DECL_ISUPPORTS NS_DECL_NSIIDBFACTORY @@ -90,9 +90,9 @@ public: ObjectStoreInfoArray& aObjectStores); static nsresult - UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo, - PRUint64 aVersion, - ObjectStoreInfoArray& aObjectStores); + SetDatabaseMetadata(DatabaseInfo* aDatabaseInfo, + PRUint64 aVersion, + ObjectStoreInfoArray& aObjectStores); private: IDBFactory(); diff --git a/dom/indexedDB/IDBIndex.cpp b/dom/indexedDB/IDBIndex.cpp index afeb1ee4e62e..ed33e718eaef 100644 --- a/dom/indexedDB/IDBIndex.cpp +++ b/dom/indexedDB/IDBIndex.cpp @@ -321,15 +321,13 @@ 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), - mAutoIncrement(false) + mUnique(false) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); } @@ -693,26 +691,12 @@ GetKeyHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) { NS_ASSERTION(mKeyRange, "Must have a key range here!"); - nsCString keyColumn; nsCString indexTable; - - if (mIndex->IsAutoIncrement()) { - keyColumn.AssignLiteral("ai_object_data_id"); - if (mIndex->IsUnique()) { - indexTable.AssignLiteral("ai_unique_index_data"); - } - else { - indexTable.AssignLiteral("ai_index_data"); - } + if (mIndex->IsUnique()) { + indexTable.AssignLiteral("unique_index_data"); } else { - keyColumn.AssignLiteral("object_data_key"); - if (mIndex->IsUnique()) { - indexTable.AssignLiteral("unique_index_data"); - } - else { - indexTable.AssignLiteral("index_data"); - } + indexTable.AssignLiteral("index_data"); } nsCString keyRangeClause; @@ -720,12 +704,10 @@ GetKeyHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!"); - 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 + + nsCString query = NS_LITERAL_CSTRING("SELECT object_data_key FROM ") + + indexTable + + NS_LITERAL_CSTRING(" WHERE index_id = :index_id") + + keyRangeClause + NS_LITERAL_CSTRING(" LIMIT 1"); nsCOMPtr stmt = mTransaction->GetCachedStatement(query); @@ -733,7 +715,8 @@ GetKeyHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) mozStorageStatementScoper scoper(stmt); - nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id()); + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), + mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); rv = mKeyRange->BindToStatement(stmt); @@ -763,29 +746,12 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) { NS_ASSERTION(mKeyRange, "Must have a key range here!"); - 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"); - } + nsCString indexTable; + if (mIndex->IsUnique()) { + indexTable.AssignLiteral("unique_index_data"); } else { - objectTable.AssignLiteral("object_data"); - objectColumn.AssignLiteral("object_data_id"); - if (mIndex->IsUnique()) { - joinTable.AssignLiteral("unique_index_data"); - } - else { - joinTable.AssignLiteral("index_data"); - } + indexTable.AssignLiteral("index_data"); } nsCString keyRangeClause; @@ -793,15 +759,12 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!"); - 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 + + 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_LITERAL_CSTRING(" LIMIT 1"); nsCOMPtr stmt = mTransaction->GetCachedStatement(query); @@ -809,7 +772,8 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) mozStorageStatementScoper scoper(stmt); - nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id()); + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), + mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); rv = mKeyRange->BindToStatement(stmt); @@ -843,26 +807,12 @@ GetHelper::GetSuccessResult(JSContext* aCx, nsresult GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) { - nsCString keyColumn; nsCString tableName; - - if (mIndex->IsAutoIncrement()) { - keyColumn.AssignLiteral("ai_object_data_id"); - if (mIndex->IsUnique()) { - tableName.AssignLiteral("ai_unique_index_data"); - } - else { - tableName.AssignLiteral("ai_index_data"); - } + if (mIndex->IsUnique()) { + tableName.AssignLiteral("unique_index_data"); } else { - keyColumn.AssignLiteral("object_data_key"); - if (mIndex->IsUnique()) { - tableName.AssignLiteral("unique_index_data"); - } - else { - tableName.AssignLiteral("index_data"); - } + tableName.AssignLiteral("index_data"); } nsCString keyRangeClause; @@ -876,20 +826,18 @@ GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) limitClause.AppendInt(mLimit); } - 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; + nsCString query = NS_LITERAL_CSTRING("SELECT object_data_key FROM ") + + tableName + + NS_LITERAL_CSTRING(" WHERE index_id = :index_id") + + keyRangeClause + limitClause; nsCOMPtr stmt = mTransaction->GetCachedStatement(query); NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); mozStorageStatementScoper scoper(stmt); - nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id()); + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), + mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (mKeyRange) { @@ -967,33 +915,14 @@ GetAllKeysHelper::GetSuccessResult(JSContext* aCx, nsresult GetAllHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) { - 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"); - } + nsCString indexTable; + if (mIndex->IsUnique()) { + indexTable.AssignLiteral("unique_index_data"); } else { - dataTableName.AssignLiteral("object_data"); - objectDataId.AssignLiteral("object_data_id"); - if (mIndex->IsUnique()) { - indexTableName.AssignLiteral("unique_index_data"); - } - else { - indexTableName.AssignLiteral("index_data"); - } + indexTable.AssignLiteral("index_data"); } - NS_NAMED_LITERAL_CSTRING(indexId, "index_id"); - nsCString keyRangeClause; if (mKeyRange) { mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("value"), keyRangeClause); @@ -1005,21 +934,20 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) limitClause.AppendInt(mLimit); } - 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; + 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; nsCOMPtr stmt = mTransaction->GetCachedStatement(query); NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); mozStorageStatementScoper scoper(stmt); - nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id()); + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), + mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (mKeyRange) { @@ -1069,31 +997,13 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) NS_ASSERTION(aConnection, "Passed a null connection!"); nsCString table; - 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"); - } + if (mIndex->IsUnique()) { + table.AssignLiteral("unique_index_data"); } else { - keyColumn.AssignLiteral("object_data_key"); - if (mIndex->IsUnique()) { - table.AssignLiteral("unique_index_data"); - } - else { - table.AssignLiteral("index_data"); - } + 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; @@ -1101,30 +1011,27 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) mKeyRange->GetBindingClause(value, keyRangeClause); } - nsCAutoString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + value; + nsCAutoString directionClause(" ORDER BY value "); switch (mDirection) { case nsIIDBCursor::NEXT: case nsIIDBCursor::NEXT_NO_DUPLICATE: - directionClause += NS_LITERAL_CSTRING(" ASC, ") + keyColumn + - NS_LITERAL_CSTRING(" ASC"); + directionClause += NS_LITERAL_CSTRING("ASC, object_data_key ASC"); break; case nsIIDBCursor::PREV: - directionClause += NS_LITERAL_CSTRING(" DESC, ") + keyColumn + - NS_LITERAL_CSTRING(" DESC"); + directionClause += NS_LITERAL_CSTRING("DESC, object_data_key DESC"); break; case nsIIDBCursor::PREV_NO_DUPLICATE: - directionClause += NS_LITERAL_CSTRING(" DESC, ") + keyColumn + - NS_LITERAL_CSTRING(" ASC"); + directionClause += NS_LITERAL_CSTRING("DESC, object_data_key ASC"); break; default: NS_NOTREACHED("Unknown direction!"); } - nsCString firstQuery = NS_LITERAL_CSTRING("SELECT value, ") + keyColumn + - NS_LITERAL_CSTRING(" FROM ") + table + - NS_LITERAL_CSTRING(" WHERE index_id = :") + id + + nsCString firstQuery = NS_LITERAL_CSTRING("SELECT value, object_data_key " + "FROM ") + table + + NS_LITERAL_CSTRING(" WHERE index_id = :index_id") + keyRangeClause + directionClause + NS_LITERAL_CSTRING(" LIMIT 1"); @@ -1134,7 +1041,8 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) mozStorageStatementScoper scoper(stmt); - nsresult rv = stmt->BindInt64ByName(id, mIndex->Id()); + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), + mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (mKeyRange) { @@ -1158,13 +1066,11 @@ 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, ") + keyColumn + - NS_LITERAL_CSTRING(" FROM ") + table + - NS_LITERAL_CSTRING(" WHERE index_id = :") + id; + nsCAutoString queryStart = NS_LITERAL_CSTRING("SELECT value, object_data_key" + " 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: @@ -1173,14 +1079,18 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) queryStart); mRangeKey = mKeyRange->Upper(); } - 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 "); + 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 "); break; case nsIIDBCursor::NEXT_NO_DUPLICATE: @@ -1189,12 +1099,14 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) queryStart); mRangeKey = mKeyRange->Upper(); } - 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 "); + 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 "); break; case nsIIDBCursor::PREV: @@ -1204,14 +1116,18 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) mRangeKey = mKeyRange->Lower(); } - 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 "); + 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 "); break; case nsIIDBCursor::PREV_NO_DUPLICATE: @@ -1220,12 +1136,16 @@ OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) queryStart); mRangeKey = mKeyRange->Lower(); } - 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 "); + 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 "); break; default: @@ -1258,81 +1178,52 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) NS_ASSERTION(aConnection, "Passed a null connection!"); nsCString indexTable; - 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"); - } + if (mIndex->IsUnique()) { + indexTable.AssignLiteral("unique_index_data"); } else { - 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"); - } + indexTable.AssignLiteral("index_data"); } - nsCString value = indexTable + NS_LITERAL_CSTRING(".value"); - nsCString keyValue = indexTable + NS_LITERAL_CSTRING(".") + keyValueColumn; + NS_NAMED_LITERAL_CSTRING(value, "index_table.value"); nsCString keyRangeClause; if (mKeyRange) { mKeyRange->GetBindingClause(value, keyRangeClause); } - nsCAutoString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + value; + nsCAutoString directionClause(" ORDER BY index_table.value "); switch (mDirection) { case nsIIDBCursor::NEXT: case nsIIDBCursor::NEXT_NO_DUPLICATE: - directionClause += NS_LITERAL_CSTRING(" ASC, ") + keyValue + - NS_LITERAL_CSTRING(" ASC"); + directionClause += + NS_LITERAL_CSTRING("ASC, index_table.object_data_key ASC"); break; case nsIIDBCursor::PREV: - directionClause += NS_LITERAL_CSTRING(" DESC, ") + keyValue + - NS_LITERAL_CSTRING(" DESC"); + directionClause += + NS_LITERAL_CSTRING("DESC, index_table.object_data_key DESC"); break; case nsIIDBCursor::PREV_NO_DUPLICATE: - directionClause += NS_LITERAL_CSTRING(" DESC, ") + keyValue + - NS_LITERAL_CSTRING(" ASC"); + directionClause += + NS_LITERAL_CSTRING("DESC, index_table.object_data_key ASC"); break; default: NS_NOTREACHED("Unknown direction!"); } - 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"); + 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"); nsCOMPtr stmt = mTransaction->GetCachedStatement(firstQuery); @@ -1340,7 +1231,7 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) mozStorageStatementScoper scoper(stmt); - nsresult rv = stmt->BindInt64ByName(id, mIndex->Id()); + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (mKeyRange) { @@ -1368,29 +1259,17 @@ 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 ") + 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; + 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"); - 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) { @@ -1400,11 +1279,16 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) queryStart); mRangeKey = mKeyRange->Upper(); } - 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; + 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; break; case nsIIDBCursor::NEXT_NO_DUPLICATE: @@ -1413,10 +1297,14 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) queryStart); mRangeKey = mKeyRange->Upper(); } - mContinueQuery = queryStart + andStr + value + gt + currentKey + - directionClause + limit; - mContinueToQuery = queryStart + andStr + value + ge + currentKey + - directionClause + limit; + 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; break; case nsIIDBCursor::PREV: @@ -1425,11 +1313,16 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) queryStart); mRangeKey = mKeyRange->Lower(); } - 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; + 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; break; case nsIIDBCursor::PREV_NO_DUPLICATE: @@ -1438,10 +1331,14 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) queryStart); mRangeKey = mKeyRange->Lower(); } - mContinueQuery = queryStart + andStr + value + lt + currentKey + - directionClause +limit; - mContinueToQuery = queryStart + andStr + value + le + currentKey + - directionClause + limit; + 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; break; default: @@ -1475,22 +1372,11 @@ nsresult CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { nsCString table; - - if (mIndex->IsAutoIncrement()) { - if (mIndex->IsUnique()) { - table.AssignLiteral("ai_unique_index_data"); - } - else { - table.AssignLiteral("ai_index_data"); - } + if (mIndex->IsUnique()) { + table.AssignLiteral("unique_index_data"); } else { - if (mIndex->IsUnique()) { - table.AssignLiteral("unique_index_data"); - } - else { - table.AssignLiteral("index_data"); - } + table.AssignLiteral("index_data"); } NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key"); @@ -1509,10 +1395,8 @@ 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 stmt = mTransaction->GetCachedStatement(query); @@ -1520,7 +1404,7 @@ CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection) mozStorageStatementScoper scoper(stmt); - nsresult rv = stmt->BindInt64ByName(id, mIndex->Id()); + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndex->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (mKeyRange) { diff --git a/dom/indexedDB/IDBIndex.h b/dom/indexedDB/IDBIndex.h index 643ae942de0c..4ed9c378afee 100644 --- a/dom/indexedDB/IDBIndex.h +++ b/dom/indexedDB/IDBIndex.h @@ -92,11 +92,6 @@ public: return mMultiEntry; } - bool IsAutoIncrement() const - { - return mAutoIncrement; - } - const nsString& KeyPath() const { return mKeyPath; @@ -116,7 +111,6 @@ private: nsString mKeyPath; bool mUnique; bool mMultiEntry; - bool mAutoIncrement; }; END_INDEXEDDB_NAMESPACE diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 6475376ed069..6cff1d9f865d 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -382,23 +382,18 @@ NS_STACK_CLASS class AutoRemoveIndex { public: - AutoRemoveIndex(IDBDatabase* aDatabase, - const nsAString& aObjectStoreName, + AutoRemoveIndex(ObjectStoreInfo* aObjectStoreInfo, const nsAString& aIndexName) - : mDatabase(aDatabase), mObjectStoreName(aObjectStoreName), - mIndexName(aIndexName) + : mObjectStoreInfo(aObjectStoreInfo), mIndexName(aIndexName) { } ~AutoRemoveIndex() { - if (mDatabase) { - ObjectStoreInfo* info; - if (mDatabase->Info()->GetObjectStore(mObjectStoreName, &info)) { - for (PRUint32 index = 0; index < info->indexes.Length(); index++) { - if (info->indexes[index].name == mIndexName) { - info->indexes.RemoveElementAt(index); - break; - } + if (mObjectStoreInfo) { + for (PRUint32 i = 0; i < mObjectStoreInfo->indexes.Length(); i++) { + if (mObjectStoreInfo->indexes[i].name == mIndexName) { + mObjectStoreInfo->indexes.RemoveElementAt(i); + break; } } } @@ -406,12 +401,11 @@ public: void forget() { - mDatabase = nsnull; + mObjectStoreInfo = nsnull; } private: - IDBDatabase* mDatabase; - nsString mObjectStoreName; + ObjectStoreInfo* mObjectStoreInfo; nsString mIndexName; }; @@ -503,7 +497,8 @@ JSClass gDummyPropClass = { // static already_AddRefed IDBObjectStore::Create(IDBTransaction* aTransaction, - const ObjectStoreInfo* aStoreInfo) + ObjectStoreInfo* aStoreInfo, + nsIAtom* aDatabaseId) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); @@ -516,8 +511,9 @@ IDBObjectStore::Create(IDBTransaction* aTransaction, objectStore->mName = aStoreInfo->name; objectStore->mId = aStoreInfo->id; objectStore->mKeyPath = aStoreInfo->keyPath; - objectStore->mAutoIncrement = aStoreInfo->autoIncrement; - objectStore->mDatabaseId = aStoreInfo->databaseId; + objectStore->mAutoIncrement = !!aStoreInfo->nextAutoIncrementId; + objectStore->mDatabaseId = aDatabaseId; + objectStore->mInfo = aStoreInfo; return objectStore.forget(); } @@ -625,71 +621,25 @@ nsresult IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction, PRInt64 aObjectStoreId, const Key& aObjectStoreKey, - bool aAutoIncrement, bool aOverwrite, PRInt64 aObjectDataId, const nsTArray& aUpdateInfoArray) { - NS_ASSERTION(!aAutoIncrement || aObjectDataId != LL_MININT, - "Bad objectData id!"); - nsCOMPtr stmt; nsresult rv; - if (aObjectDataId == LL_MININT) { - stmt = aTransaction->GetCachedStatement( - "SELECT id " - "FROM object_data " - "WHERE object_store_id = :osid " - "AND key_value = :key_value" - ); - NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE); - - mozStorageStatementScoper scoper(stmt); - - rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), aObjectStoreId); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ASSERTION(!aObjectStoreKey.IsUnset(), "This shouldn't happen!"); - - rv = aObjectStoreKey.BindToStatement(stmt, NS_LITERAL_CSTRING("key_value")); - NS_ENSURE_SUCCESS(rv, rv); - - bool hasResult; - rv = stmt->ExecuteStep(&hasResult); - NS_ENSURE_SUCCESS(rv, rv); - - if (!hasResult) { - NS_ERROR("This is bad, we just added this value! Where'd it go?!"); - return NS_ERROR_FAILURE; - } - - aObjectDataId = stmt->AsInt64(0); - } - NS_ASSERTION(aObjectDataId != LL_MININT, "Bad objectData id!"); - NS_NAMED_LITERAL_CSTRING(indexId, "index_id"); NS_NAMED_LITERAL_CSTRING(objectDataId, "object_data_id"); - NS_NAMED_LITERAL_CSTRING(objectDataKey, "object_data_key"); - NS_NAMED_LITERAL_CSTRING(value, "value"); if (aOverwrite) { - stmt = aTransaction->IndexDataDeleteStatement(aAutoIncrement, false); - NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE); + stmt = aTransaction->GetCachedStatement( + "DELETE FROM unique_index_data " + "WHERE object_data_id = :object_data_id; " + "DELETE FROM index_data " + "WHERE object_data_id = :object_data_id"); - mozStorageStatementScoper scoper2(stmt); - - rv = stmt->BindInt64ByName(objectDataId, aObjectDataId); - NS_ENSURE_SUCCESS(rv, rv); - - rv = stmt->Execute(); - NS_ENSURE_SUCCESS(rv, rv); - - stmt = aTransaction->IndexDataDeleteStatement(aAutoIncrement, true); - NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE); - - mozStorageStatementScoper scoper3(stmt); + mozStorageStatementScoper scoper(stmt); rv = stmt->BindInt64ByName(objectDataId, aObjectDataId); NS_ENSURE_SUCCESS(rv, rv); @@ -703,24 +653,33 @@ IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction, const IndexUpdateInfo& updateInfo = aUpdateInfoArray[i]; // Insert new values. - stmt = aTransaction->IndexDataInsertStatement(aAutoIncrement, - updateInfo.indexUnique); + + stmt = updateInfo.indexUnique ? + aTransaction->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)") : + aTransaction->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)"); + NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE); mozStorageStatementScoper scoper4(stmt); - rv = stmt->BindInt64ByName(indexId, updateInfo.indexId); + rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), + updateInfo.indexId); NS_ENSURE_SUCCESS(rv, rv); rv = stmt->BindInt64ByName(objectDataId, aObjectDataId); NS_ENSURE_SUCCESS(rv, rv); - if (!aAutoIncrement) { - rv = aObjectStoreKey.BindToStatement(stmt, objectDataKey); - NS_ENSURE_SUCCESS(rv, rv); - } + rv = aObjectStoreKey.BindToStatement(stmt, + NS_LITERAL_CSTRING("object_data_key")); + NS_ENSURE_SUCCESS(rv, rv); - rv = updateInfo.value.BindToStatement(stmt, value); + rv = updateInfo.value.BindToStatement(stmt, NS_LITERAL_CSTRING("value")); NS_ENSURE_SUCCESS(rv, rv); rv = stmt->Execute(); @@ -1129,28 +1088,6 @@ IDBObjectStore::ConvertFileIdsToArray(const nsAString& aFileIds, return NS_OK; } -nsresult -IDBObjectStore::ModifyValueForNewKey(StructuredCloneWriteInfo& aCloneWriteInfo, - Key& aKey) -{ - NS_ASSERTION(IsAutoIncrement() && aKey.IsInteger(), "Don't call me!"); - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread"); - - // This is a duplicate of the js engine's byte munging here - union { - jsdouble d; - PRUint64 u; - } pun; - - pun.d = SwapBytes(static_cast(aKey.ToInteger())); - - JSAutoStructuredCloneBuffer& buffer = aCloneWriteInfo.mCloneBuffer; - PRUint64 offsetToKeyProp = aCloneWriteInfo.mOffsetToKeyProp; - - memcpy((char*)buffer.data() + offsetToKeyProp, &pun.u, sizeof(PRUint64)); - return NS_OK; -} - IDBObjectStore::IDBObjectStore() : mId(LL_MININT), mAutoIncrement(false) @@ -1200,15 +1137,10 @@ IDBObjectStore::GetAddInfo(JSContext* aCx, } // Figure out indexes and the index values to update here. - ObjectStoreInfo* info; - if (!mTransaction->Database()->Info()->GetObjectStore(mName, &info)) { - NS_ERROR("This should never fail!"); - } - - PRUint32 count = info->indexes.Length(); + PRUint32 count = mInfo->indexes.Length(); aUpdateInfoArray.SetCapacity(count); // Pretty good estimate for (PRUint32 indexesIndex = 0; indexesIndex < count; indexesIndex++) { - const IndexInfo& indexInfo = info->indexes[indexesIndex]; + const IndexInfo& indexInfo = mInfo->indexes[indexesIndex]; rv = AppendIndexUpdateInfo(indexInfo.id, indexInfo.keyPath, indexInfo.unique, indexInfo.multiEntry, @@ -1373,11 +1305,6 @@ IDBObjectStore::AddOrPut(const jsval& aValue, return rv; } - // Put requires a key, unless this is an autoIncrementing objectStore. - if (aOverwrite && !mAutoIncrement && key.IsUnset()) { - return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; - } - nsRefPtr request = GenerateRequest(this); NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); @@ -1453,21 +1380,25 @@ IDBObjectStore::GetTransaction(nsIIDBTransaction** aTransaction) return NS_OK; } +NS_IMETHODIMP +IDBObjectStore::GetAutoIncrement(bool* aAutoIncrement) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + *aAutoIncrement = mAutoIncrement; + return NS_OK; +} + NS_IMETHODIMP IDBObjectStore::GetIndexNames(nsIDOMDOMStringList** aIndexNames) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - ObjectStoreInfo* info; - if (!mTransaction->Database()->Info()->GetObjectStore(mName, &info)) { - NS_ERROR("This should never fail!"); - } - nsRefPtr list(new nsDOMStringList()); - PRUint32 count = info->indexes.Length(); + PRUint32 count = mInfo->indexes.Length(); for (PRUint32 index = 0; index < count; index++) { - NS_ENSURE_TRUE(list->Add(info->indexes[index].name), + NS_ENSURE_TRUE(list->Add(mInfo->indexes[index].name), NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); } @@ -1699,15 +1630,10 @@ IDBObjectStore::CreateIndex(const nsAString& aName, return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; } - ObjectStoreInfo* info; - if (!mTransaction->Database()->Info()->GetObjectStore(mName, &info)) { - NS_ERROR("This should never fail!"); - } - bool found = false; - PRUint32 indexCount = info->indexes.Length(); + PRUint32 indexCount = mInfo->indexes.Length(); for (PRUint32 index = 0; index < indexCount; index++) { - if (info->indexes[index].name == aName) { + if (mInfo->indexes[index].name == aName) { found = true; break; } @@ -1757,23 +1683,17 @@ IDBObjectStore::CreateIndex(const nsAString& aName, multiEntry = !!boolVal; } - DatabaseInfo* databaseInfo = mTransaction->Database()->Info(); - - IndexInfo* indexInfo = info->indexes.AppendElement(); - if (!indexInfo) { - NS_WARNING("Out of memory!"); - return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; - } + DatabaseInfo* databaseInfo = mTransaction->DBInfo(); + IndexInfo* indexInfo = mInfo->indexes.AppendElement(); indexInfo->id = databaseInfo->nextIndexId++; indexInfo->name = aName; indexInfo->keyPath = aKeyPath; indexInfo->unique = unique; indexInfo->multiEntry = multiEntry; - indexInfo->autoIncrement = mAutoIncrement; // Don't leave this in the list if we fail below! - AutoRemoveIndex autoRemove(mTransaction->Database(), mName, aName); + AutoRemoveIndex autoRemove(mInfo, aName); #ifdef DEBUG for (PRUint32 index = 0; index < mCreatedIndexes.Length(); index++) { @@ -1812,16 +1732,11 @@ IDBObjectStore::Index(const nsAString& aName, return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR; } - ObjectStoreInfo* info; - if (!mTransaction->Database()->Info()->GetObjectStore(mName, &info)) { - NS_ERROR("This should never fail!"); - } - IndexInfo* indexInfo = nsnull; - PRUint32 indexCount = info->indexes.Length(); + PRUint32 indexCount = mInfo->indexes.Length(); for (PRUint32 index = 0; index < indexCount; index++) { - if (info->indexes[index].name == aName) { - indexInfo = &(info->indexes[index]); + if (mInfo->indexes[index].name == aName) { + indexInfo = &(mInfo->indexes[index]); break; } } @@ -1868,19 +1783,14 @@ IDBObjectStore::DeleteIndex(const nsAString& aName) NS_ASSERTION(mTransaction->IsOpen(), "Impossible!"); - ObjectStoreInfo* info; - if (!mTransaction->Database()->Info()->GetObjectStore(mName, &info)) { - NS_ERROR("This should never fail!"); - } - PRUint32 index = 0; - for (; index < info->indexes.Length(); index++) { - if (info->indexes[index].name == aName) { + for (; index < mInfo->indexes.Length(); index++) { + if (mInfo->indexes[index].name == aName) { break; } } - if (index == info->indexes.Length()) { + if (index == mInfo->indexes.Length()) { return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR; } @@ -1890,7 +1800,7 @@ IDBObjectStore::DeleteIndex(const nsAString& aName) nsresult rv = helper->DispatchToTransactionPool(); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - info->indexes.RemoveElementAt(index); + mInfo->indexes.RemoveElementAt(index); for (PRUint32 i = 0; i < mCreatedIndexes.Length(); i++) { if (mCreatedIndexes[i]->Name() == aName) { @@ -1963,67 +1873,90 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) NS_PRECONDITION(aConnection, "Passed a null connection!"); nsresult rv; - bool mayOverwrite = mOverwrite; - bool unsetKey = mKey.IsUnset(); - - bool autoIncrement = mObjectStore->IsAutoIncrement(); + bool keyUnset = mKey.IsUnset(); PRInt64 osid = mObjectStore->Id(); const nsString& keyPath = mObjectStore->KeyPath(); - if (unsetKey) { - NS_ASSERTION(autoIncrement, "Must have a key for non-autoIncrement!"); + // The "|| keyUnset" here is mostly a debugging tool. If a key isn't + // specified we should never have a collision and so it shouldn't matter + // if we allow overwrite or not. By not allowing overwrite we raise + // detectable errors rather than corrupting data + nsCOMPtr stmt = !mOverwrite || keyUnset ? + mTransaction->GetCachedStatement( + "INSERT INTO object_data (object_store_id, key_value, data, file_ids) " + "VALUES (:osid, :key_value, :data, :file_ids)") : + mTransaction->GetCachedStatement( + "INSERT OR REPLACE INTO object_data (object_store_id, key_value, data, file_ids) " + "VALUES (:osid, :key_value, :data, :file_ids)"); + NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - // Will need to add first and then set the key later. - mayOverwrite = false; - } + mozStorageStatementScoper scoper(stmt); - if (autoIncrement && !unsetKey) { - mayOverwrite = true; - } + rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - nsCOMPtr stmt; - if (!mOverwrite && !unsetKey) { - // Make sure the key doesn't exist already - NS_NAMED_LITERAL_CSTRING(id, "id"); - NS_NAMED_LITERAL_CSTRING(osidStr, "osid"); + NS_ASSERTION(!keyUnset || mObjectStore->IsAutoIncrement(), + "Should have key unless autoincrement"); - nsCString table; - nsCString value; + PRInt64 autoIncrementNum = 0; - if (autoIncrement) { - table.AssignLiteral("ai_object_data"); - value = id; + if (mObjectStore->IsAutoIncrement()) { + if (keyUnset) { + autoIncrementNum = mObjectStore->Info()->nextAutoIncrementId; + if (autoIncrementNum > (1LL << 53)) { + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; + } + mKey.SetFromInteger(autoIncrementNum); } - else { - table.AssignLiteral("object_data"); - value.AssignLiteral("key_value"); + else if (mKey.IsInteger() && + mKey.ToInteger() >= mObjectStore->Info()->nextAutoIncrementId) { + // XXX Once we support floats, we should use floor(mKey.ToFloat()) here + autoIncrementNum = mKey.ToInteger(); } - nsCString query = NS_LITERAL_CSTRING("SELECT data FROM ") + table + - NS_LITERAL_CSTRING(" WHERE ") + value + - NS_LITERAL_CSTRING(" = :") + id + - NS_LITERAL_CSTRING(" AND object_store_id = :") + osidStr; + if (keyUnset && !keyPath.IsEmpty()) { + // Special case where someone put an object into an autoIncrement'ing + // objectStore with no key in its keyPath set. We needed to figure out + // which row id we would get above before we could set that properly. - stmt = mTransaction->GetCachedStatement(query); - NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + // This is a duplicate of the js engine's byte munging here + union { + jsdouble d; + PRUint64 u; + } pun; + + pun.d = SwapBytes(static_cast(mKey.ToInteger())); - mozStorageStatementScoper scoper(stmt); + JSAutoStructuredCloneBuffer& buffer = mCloneWriteInfo.mCloneBuffer; + PRUint64 offsetToKeyProp = mCloneWriteInfo.mOffsetToKeyProp; - rv = stmt->BindInt64ByName(osidStr, osid); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - rv = mKey.BindToStatement(stmt, NS_LITERAL_CSTRING("id")); - NS_ENSURE_SUCCESS(rv, rv); - - bool hasResult; - rv = stmt->ExecuteStep(&hasResult); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - if (hasResult) { - return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; + memcpy((char*)buffer.data() + offsetToKeyProp, &pun.u, sizeof(PRUint64)); } } + mKey.BindToStatement(stmt, NS_LITERAL_CSTRING("key_value")); + + // Compress the bytes before adding into the database. + const char* uncompressed = + reinterpret_cast(mCloneWriteInfo.mCloneBuffer.data()); + size_t uncompressedLength = mCloneWriteInfo.mCloneBuffer.nbytes(); + + size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength); + // This will hold our compressed data until the end of the method. The + // BindBlobByName function will copy it. + nsAutoArrayPtr compressed(new char[compressedLength]); + + snappy::RawCompress(uncompressed, uncompressedLength, compressed.get(), + &compressedLength); + + const PRUint8* dataBuffer = reinterpret_cast(compressed.get()); + size_t dataBufferLength = compressedLength; + + rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"), dataBuffer, + dataBufferLength); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + // Handle blobs nsRefPtr fileManager = mDatabase->Manager(); nsCOMPtr directory = fileManager->GetDirectory(); NS_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); @@ -2082,60 +2015,6 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) fileIds.AppendInt(id); } - // Now we add it to the database (or update, depending on our variables). - stmt = mTransaction->AddStatement(true, mayOverwrite, autoIncrement); - NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - mozStorageStatementScoper scoper(stmt); - - NS_NAMED_LITERAL_CSTRING(keyValue, "key_value"); - - rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - if (!autoIncrement || mayOverwrite) { - NS_ASSERTION(!mKey.IsUnset(), "This shouldn't happen!"); - - rv = mKey.BindToStatement(stmt, keyValue); - NS_ENSURE_SUCCESS(rv, rv); - } - - NS_NAMED_LITERAL_CSTRING(data, "data"); - - // This will hold our compressed data until the end of the method. The - // BindBlobByName function will copy it. - nsAutoArrayPtr compressed; - - // This points to the compressed buffer. - const PRUint8* dataBuffer = nsnull; - size_t dataBufferLength = 0; - - // If we're going to modify the buffer later to add a key property on an - // autoIncrement objectStore then we will wait to compress our data until we - // have the appropriate key value. - if (autoIncrement && !mOverwrite && !keyPath.IsEmpty() && unsetKey) { - rv = stmt->BindInt32ByName(data, 0); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - } - else { - // Compress the bytes before adding into the database. - const char* uncompressed = - reinterpret_cast(mCloneWriteInfo.mCloneBuffer.data()); - size_t uncompressedLength = mCloneWriteInfo.mCloneBuffer.nbytes(); - - size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength); - compressed = new char[compressedLength]; - - snappy::RawCompress(uncompressed, uncompressedLength, compressed.get(), - &compressedLength); - - dataBuffer = reinterpret_cast(compressed.get()); - dataBufferLength = compressedLength; - - rv = stmt->BindBlobByName(data, dataBuffer, dataBufferLength); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - } - if (fileIds.IsEmpty()) { rv = stmt->BindNullByName(NS_LITERAL_CSTRING("file_ids")); } else { @@ -2144,124 +2023,19 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); rv = stmt->Execute(); - if (NS_FAILED(rv)) { - if (mayOverwrite && rv == NS_ERROR_STORAGE_CONSTRAINT) { - scoper.Abandon(); - - rv = stmt->Reset(); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - stmt = mTransaction->AddStatement(false, true, autoIncrement); - NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - mozStorageStatementScoper scoper2(stmt); - - rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - NS_ASSERTION(!mKey.IsUnset(), "This shouldn't happen!"); - - rv = mKey.BindToStatement(stmt, keyValue); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ASSERTION(dataBuffer && dataBufferLength, "These should be set!"); - - rv = stmt->BindBlobByName(data, dataBuffer, dataBufferLength); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - if (fileIds.IsEmpty()) { - rv = stmt->BindNullByName(NS_LITERAL_CSTRING("file_ids")); - } else { - rv = stmt->BindStringByName(NS_LITERAL_CSTRING("file_ids"), fileIds); - } - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - rv = stmt->Execute(); - } - - if (NS_FAILED(rv)) { - return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; - } + if (rv == NS_ERROR_STORAGE_CONSTRAINT) { + NS_ASSERTION(!keyUnset, "Generated key had a collision!?"); + return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; } + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - // If we are supposed to generate a key, get the new id. - if (autoIncrement && !mayOverwrite) { -#ifdef DEBUG - PRInt64 oldKey = unsetKey ? 0 : mKey.ToInteger(); -#endif - - PRInt64 newIntKey; - rv = aConnection->GetLastInsertRowID(&newIntKey); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - rv = mKey.SetFromInteger(newIntKey); - NS_ENSURE_SUCCESS(rv, rv); - -#ifdef DEBUG - NS_ASSERTION(mKey.IsInteger(), "Bad key value!"); - if (!unsetKey) { - NS_ASSERTION(mKey.ToInteger() == oldKey, "Something went haywire!"); - } -#endif - - if (!keyPath.IsEmpty() && unsetKey) { - // Special case where someone put an object into an autoIncrement'ing - // objectStore with no key in its keyPath set. We needed to figure out - // which row id we would get above before we could set that properly. - rv = mObjectStore->ModifyValueForNewKey(mCloneWriteInfo, mKey); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - scoper.Abandon(); - rv = stmt->Reset(); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - stmt = mTransaction->AddStatement(false, true, true); - NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - mozStorageStatementScoper scoper2(stmt); - - rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - rv = mKey.BindToStatement(stmt, keyValue); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ASSERTION(!dataBuffer && !dataBufferLength, "These should be unset!"); - - const char* uncompressed = - reinterpret_cast(mCloneWriteInfo.mCloneBuffer.data()); - size_t uncompressedLength = mCloneWriteInfo.mCloneBuffer.nbytes(); - - size_t compressedLength = - snappy::MaxCompressedLength(uncompressedLength); - compressed = new char[compressedLength]; - - snappy::RawCompress(uncompressed, uncompressedLength, compressed.get(), - &compressedLength); - - dataBuffer = reinterpret_cast(compressed.get()); - dataBufferLength = compressedLength; - - rv = stmt->BindBlobByName(data, dataBuffer, dataBufferLength); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - if (fileIds.IsEmpty()) { - rv = stmt->BindNullByName(NS_LITERAL_CSTRING("file_ids")); - } else { - rv = stmt->BindStringByName(NS_LITERAL_CSTRING("file_ids"), fileIds); - } - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - - rv = stmt->Execute(); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - } - } + PRInt64 objectDataId; + rv = aConnection->GetLastInsertRowID(&objectDataId); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); // Update our indexes if needed. if (mOverwrite || !mIndexUpdateInfo.IsEmpty()) { - PRInt64 objectDataId = autoIncrement ? mKey.ToInteger() : LL_MININT; - rv = IDBObjectStore::UpdateIndexes(mTransaction, osid, mKey, - autoIncrement, mOverwrite, + rv = IDBObjectStore::UpdateIndexes(mTransaction, osid, mKey, mOverwrite, objectDataId, mIndexUpdateInfo); if (rv == NS_ERROR_STORAGE_CONSTRAINT) { return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; @@ -2269,6 +2043,10 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); } + if (autoIncrementNum) { + mObjectStore->Info()->nextAutoIncrementId = autoIncrementNum + 1; + } + return NS_OK; } @@ -2288,26 +2066,13 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) { NS_ASSERTION(mKeyRange, "Must have a key range here!"); - nsCString table; - nsCString value; - if (mObjectStore->IsAutoIncrement()) { - table.AssignLiteral("ai_object_data"); - value.AssignLiteral("id"); - } - else { - table.AssignLiteral("object_data"); - value.AssignLiteral("key_value"); - } - nsCString keyRangeClause; - mKeyRange->GetBindingClause(value, keyRangeClause); + mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause); NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!"); - NS_NAMED_LITERAL_CSTRING(osid, "osid"); - - nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM ") + table + - NS_LITERAL_CSTRING(" WHERE object_store_id = :") + osid + + nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data " + "WHERE object_store_id = :osid") + keyRangeClause + NS_LITERAL_CSTRING(" LIMIT 1"); nsCOMPtr stmt = mTransaction->GetCachedStatement(query); @@ -2315,7 +2080,7 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) mozStorageStatementScoper scoper(stmt); - nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id()); + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStore->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); rv = mKeyRange->BindToStatement(stmt); @@ -2351,26 +2116,13 @@ DeleteHelper::DoDatabaseWork(mozIStorageConnection* /*aConnection */) { NS_ASSERTION(mKeyRange, "Must have a key range here!"); - nsCString table; - nsCString value; - if (mObjectStore->IsAutoIncrement()) { - table.AssignLiteral("ai_object_data"); - value.AssignLiteral("id"); - } - else { - table.AssignLiteral("object_data"); - value.AssignLiteral("key_value"); - } - nsCString keyRangeClause; - mKeyRange->GetBindingClause(value, keyRangeClause); + mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause); NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!"); - NS_NAMED_LITERAL_CSTRING(osid, "osid"); - - nsCString query = NS_LITERAL_CSTRING("DELETE FROM ") + table + - NS_LITERAL_CSTRING(" WHERE object_store_id = :") + osid + + nsCString query = NS_LITERAL_CSTRING("DELETE FROM object_data " + "WHERE object_store_id = :osid") + keyRangeClause; nsCOMPtr stmt = mTransaction->GetCachedStatement(query); @@ -2378,7 +2130,8 @@ DeleteHelper::DoDatabaseWork(mozIStorageConnection* /*aConnection */) mozStorageStatementScoper scoper(stmt); - nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id()); + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), + mObjectStore->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); rv = mKeyRange->BindToStatement(stmt); @@ -2403,18 +2156,10 @@ ClearHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { NS_PRECONDITION(aConnection, "Passed a null connection!"); - nsCString table; - if (mObjectStore->IsAutoIncrement()) { - table.AssignLiteral("ai_object_data"); - } - else { - table.AssignLiteral("object_data"); - } - - nsCString query = NS_LITERAL_CSTRING("DELETE FROM ") + table + - NS_LITERAL_CSTRING(" WHERE object_store_id = :osid"); - - nsCOMPtr stmt = mTransaction->GetCachedStatement(query); + nsCOMPtr stmt = + mTransaction->GetCachedStatement( + NS_LITERAL_CSTRING("DELETE FROM object_data " + "WHERE object_store_id = :osid")); NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); mozStorageStatementScoper scoper(stmt); @@ -2432,45 +2177,33 @@ ClearHelper::DoDatabaseWork(mozIStorageConnection* aConnection) nsresult OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { - nsCString table; - nsCString keyColumn; - - if (mObjectStore->IsAutoIncrement()) { - table.AssignLiteral("ai_object_data"); - keyColumn.AssignLiteral("id"); - } - else { - table.AssignLiteral("object_data"); - keyColumn.AssignLiteral("key_value"); - } - - NS_NAMED_LITERAL_CSTRING(id, "id"); + NS_NAMED_LITERAL_CSTRING(keyValue, "key_value"); nsCString keyRangeClause; if (mKeyRange) { - mKeyRange->GetBindingClause(keyColumn, keyRangeClause); + mKeyRange->GetBindingClause(keyValue, keyRangeClause); } - nsCAutoString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + keyColumn; + nsCAutoString directionClause; switch (mDirection) { case nsIIDBCursor::NEXT: case nsIIDBCursor::NEXT_NO_DUPLICATE: - directionClause += NS_LITERAL_CSTRING(" ASC"); + directionClause.AssignLiteral(" ORDER BY key_value ASC"); break; case nsIIDBCursor::PREV: case nsIIDBCursor::PREV_NO_DUPLICATE: - directionClause += NS_LITERAL_CSTRING(" DESC"); + directionClause.AssignLiteral(" ORDER BY key_value DESC"); break; default: NS_NOTREACHED("Unknown direction type!"); } - nsCString firstQuery = NS_LITERAL_CSTRING("SELECT ") + keyColumn + - NS_LITERAL_CSTRING(", data, file_ids FROM ") + table + - NS_LITERAL_CSTRING(" WHERE object_store_id = :") + - id + keyRangeClause + directionClause + + nsCString firstQuery = NS_LITERAL_CSTRING("SELECT key_value, data, file_ids " + "FROM object_data " + "WHERE object_store_id = :id") + + keyRangeClause + directionClause + NS_LITERAL_CSTRING(" LIMIT 1"); nsCOMPtr stmt = @@ -2479,7 +2212,8 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) mozStorageStatementScoper scoper(stmt); - nsresult rv = stmt->BindInt64ByName(id, mObjectStore->Id()); + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), + mObjectStore->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (mKeyRange) { @@ -2513,14 +2247,14 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) switch (mDirection) { case nsIIDBCursor::NEXT: case nsIIDBCursor::NEXT_NO_DUPLICATE: - AppendConditionClause(keyColumn, currentKey, false, false, + AppendConditionClause(keyValue, currentKey, false, false, keyRangeClause); - AppendConditionClause(keyColumn, currentKey, false, true, + AppendConditionClause(keyValue, currentKey, false, true, continueToKeyRangeClause); if (mKeyRange && !mKeyRange->Upper().IsUnset()) { - AppendConditionClause(keyColumn, rangeKey, true, + AppendConditionClause(keyValue, rangeKey, true, !mKeyRange->IsUpperOpen(), keyRangeClause); - AppendConditionClause(keyColumn, rangeKey, true, + AppendConditionClause(keyValue, rangeKey, true, !mKeyRange->IsUpperOpen(), continueToKeyRangeClause); mRangeKey = mKeyRange->Upper(); @@ -2529,13 +2263,13 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) case nsIIDBCursor::PREV: case nsIIDBCursor::PREV_NO_DUPLICATE: - AppendConditionClause(keyColumn, currentKey, true, false, keyRangeClause); - AppendConditionClause(keyColumn, currentKey, true, true, + AppendConditionClause(keyValue, currentKey, true, false, keyRangeClause); + AppendConditionClause(keyValue, currentKey, true, true, continueToKeyRangeClause); if (mKeyRange && !mKeyRange->Lower().IsUnset()) { - AppendConditionClause(keyColumn, rangeKey, false, + AppendConditionClause(keyValue, rangeKey, false, !mKeyRange->IsLowerOpen(), keyRangeClause); - AppendConditionClause(keyColumn, rangeKey, false, + AppendConditionClause(keyValue, rangeKey, false, !mKeyRange->IsLowerOpen(), continueToKeyRangeClause); mRangeKey = mKeyRange->Lower(); @@ -2546,16 +2280,14 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) NS_NOTREACHED("Unknown direction type!"); } - mContinueQuery = NS_LITERAL_CSTRING("SELECT ") + keyColumn + - NS_LITERAL_CSTRING(", data, file_ids FROM ") + table + - NS_LITERAL_CSTRING(" WHERE object_store_id = :") + id + - keyRangeClause + directionClause + + NS_NAMED_LITERAL_CSTRING(queryStart, "SELECT key_value, data, file_ids " + "FROM object_data " + "WHERE object_store_id = :id"); + + mContinueQuery = queryStart + keyRangeClause + directionClause + NS_LITERAL_CSTRING(" LIMIT "); - mContinueToQuery = NS_LITERAL_CSTRING("SELECT ") + keyColumn + - NS_LITERAL_CSTRING(", data, file_ids FROM ") + table + - NS_LITERAL_CSTRING(" WHERE object_store_id = :") + id + - continueToKeyRangeClause + directionClause + + mContinueToQuery = queryStart + continueToKeyRangeClause + directionClause + NS_LITERAL_CSTRING(" LIMIT "); return NS_OK; @@ -2675,9 +2407,8 @@ CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection) nsCOMPtr stmt = mTransaction->GetCachedStatement( "INSERT INTO object_store_index (id, name, key_path, unique_index, " - "multientry, object_store_id, object_store_autoincrement) " - "VALUES (:id, :name, :key_path, :unique, :multientry, :osid, " - ":os_auto_increment)" + "multientry, object_store_id) " + "VALUES (:id, :name, :key_path, :unique, :multientry, :osid)" ); NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); @@ -2706,10 +2437,6 @@ CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection) mIndex->ObjectStore()->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("os_auto_increment"), - mIndex->IsAutoIncrement() ? 1 : 0); - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - if (NS_FAILED(stmt->Execute())) { return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; } @@ -2734,22 +2461,10 @@ CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection) nsresult CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection) { - nsCAutoString table; - nsCAutoString columns; - if (mIndex->IsAutoIncrement()) { - table.AssignLiteral("ai_object_data"); - columns.AssignLiteral("id, data, file_ids"); - } - else { - table.AssignLiteral("object_data"); - columns.AssignLiteral("id, data, file_ids, key_value"); - } - - nsCString query = NS_LITERAL_CSTRING("SELECT ") + columns + - NS_LITERAL_CSTRING(" FROM ") + table + - NS_LITERAL_CSTRING(" WHERE object_store_id = :osid"); - - nsCOMPtr stmt = mTransaction->GetCachedStatement(query); + nsCOMPtr stmt = + mTransaction->GetCachedStatement( + NS_LITERAL_CSTRING("SELECT id, data, file_ids, key_value FROM object_data " + "WHERE object_store_id = :osid")); NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); mozStorageStatementScoper scoper(stmt); @@ -2813,17 +2528,11 @@ CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection) PRInt64 objectDataID = stmt->AsInt64(0); Key key; - if (!mIndex->IsAutoIncrement()) { - rv = key.SetFromStatement(stmt, 3); - NS_ENSURE_SUCCESS(rv, rv); - } - else { - key.SetFromInteger(objectDataID); - } + rv = key.SetFromStatement(stmt, 3); + NS_ENSURE_SUCCESS(rv, rv); rv = IDBObjectStore::UpdateIndexes(mTransaction, mIndex->Id(), - key, mIndex->IsAutoIncrement(), - false, objectDataID, updateInfo); + key, false, objectDataID, updateInfo); NS_ENSURE_SUCCESS(rv, rv); } while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult); @@ -2859,26 +2568,13 @@ DeleteIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection) nsresult GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { - nsCString table; - nsCString keyColumn; - - if (mObjectStore->IsAutoIncrement()) { - table.AssignLiteral("ai_object_data"); - keyColumn.AssignLiteral("id"); - } - else { - table.AssignLiteral("object_data"); - keyColumn.AssignLiteral("key_value"); - } - - NS_NAMED_LITERAL_CSTRING(osid, "osid"); NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key"); NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key"); nsCAutoString keyRangeClause; if (mKeyRange) { if (!mKeyRange->Lower().IsUnset()) { - keyRangeClause = NS_LITERAL_CSTRING(" AND ") + keyColumn; + keyRangeClause = NS_LITERAL_CSTRING(" AND key_value"); if (mKeyRange->IsLowerOpen()) { keyRangeClause.AppendLiteral(" > :"); } @@ -2889,7 +2585,7 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection) } if (!mKeyRange->Upper().IsUnset()) { - keyRangeClause += NS_LITERAL_CSTRING(" AND ") + keyColumn; + keyRangeClause += NS_LITERAL_CSTRING(" AND key_value"); if (mKeyRange->IsUpperOpen()) { keyRangeClause.AppendLiteral(" < :"); } @@ -2906,10 +2602,11 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection) limitClause.AppendInt(mLimit); } - nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM ") + table + - NS_LITERAL_CSTRING(" WHERE object_store_id = :") + osid + - keyRangeClause + NS_LITERAL_CSTRING(" ORDER BY ") + - keyColumn + NS_LITERAL_CSTRING(" ASC") + limitClause; + nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data " + "WHERE object_store_id = :osid") + + keyRangeClause + + NS_LITERAL_CSTRING(" ORDER BY key_value ASC") + + limitClause; mCloneReadInfos.SetCapacity(50); @@ -2918,7 +2615,8 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection) mozStorageStatementScoper scoper(stmt); - nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id()); + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), + mObjectStore->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (mKeyRange) { @@ -2972,26 +2670,13 @@ GetAllHelper::GetSuccessResult(JSContext* aCx, nsresult CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { - nsCString table; - nsCString keyColumn; - - if (mObjectStore->IsAutoIncrement()) { - table.AssignLiteral("ai_object_data"); - keyColumn.AssignLiteral("id"); - } - else { - table.AssignLiteral("object_data"); - keyColumn.AssignLiteral("key_value"); - } - - NS_NAMED_LITERAL_CSTRING(osid, "osid"); NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key"); NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key"); nsCAutoString keyRangeClause; if (mKeyRange) { if (!mKeyRange->Lower().IsUnset()) { - keyRangeClause = NS_LITERAL_CSTRING(" AND ") + keyColumn; + keyRangeClause = NS_LITERAL_CSTRING(" AND key_value"); if (mKeyRange->IsLowerOpen()) { keyRangeClause.AppendLiteral(" > :"); } @@ -3002,7 +2687,7 @@ CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection) } if (!mKeyRange->Upper().IsUnset()) { - keyRangeClause += NS_LITERAL_CSTRING(" AND ") + keyColumn; + keyRangeClause += NS_LITERAL_CSTRING(" AND key_value"); if (mKeyRange->IsUpperOpen()) { keyRangeClause.AppendLiteral(" < :"); } @@ -3013,8 +2698,8 @@ CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection) } } - nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM ") + table + - NS_LITERAL_CSTRING(" WHERE object_store_id = :") + osid + + nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM object_data " + "WHERE object_store_id = :osid") + keyRangeClause; nsCOMPtr stmt = mTransaction->GetCachedStatement(query); @@ -3022,7 +2707,8 @@ CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection) mozStorageStatementScoper scoper(stmt); - nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id()); + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), + mObjectStore->Id()); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); if (mKeyRange) { diff --git a/dom/indexedDB/IDBObjectStore.h b/dom/indexedDB/IDBObjectStore.h index f36f18e56dd8..c8fc9f714f0a 100644 --- a/dom/indexedDB/IDBObjectStore.h +++ b/dom/indexedDB/IDBObjectStore.h @@ -72,7 +72,8 @@ public: static already_AddRefed Create(IDBTransaction* aTransaction, - const ObjectStoreInfo* aInfo); + ObjectStoreInfo* aInfo, + nsIAtom* aDatabaseId); static bool IsValidKeyPath(JSContext* aCx, const nsAString& aKeyPath); @@ -90,7 +91,6 @@ public: UpdateIndexes(IDBTransaction* aTransaction, PRInt64 aObjectStoreId, const Key& aObjectStoreKey, - bool aAutoIncrement, bool aOverwrite, PRInt64 aObjectDataId, const nsTArray& aUpdateInfoArray); @@ -167,8 +167,10 @@ public: return mTransaction; } - nsresult ModifyValueForNewKey(StructuredCloneWriteInfo& aCloneWriteInfo, - Key& aKey); + ObjectStoreInfo* Info() + { + return mInfo; + } protected: IDBObjectStore(); @@ -199,6 +201,7 @@ private: nsString mKeyPath; bool mAutoIncrement; nsCOMPtr mDatabaseId; + nsRefPtr mInfo; PRUint32 mStructuredCloneVersion; nsTArray > mCreatedIndexes; diff --git a/dom/indexedDB/IDBTransaction.cpp b/dom/indexedDB/IDBTransaction.cpp index 1b9e18bcc070..ce3a0b5d17f1 100644 --- a/dom/indexedDB/IDBTransaction.cpp +++ b/dom/indexedDB/IDBTransaction.cpp @@ -121,6 +121,8 @@ IDBTransaction::Create(IDBDatabase* aDatabase, transaction->mDatabase = aDatabase; transaction->mMode = aMode; + + transaction->mDatabaseInfo = aDatabase->Info(); if (!transaction->mObjectStoreNames.AppendElements(aObjectStoreNames)) { NS_ERROR("Out of memory!"); @@ -211,8 +213,13 @@ IDBTransaction::OnRequestFinished() } void -IDBTransaction::ReleaseCachedObjectStore(const nsAString& aName) +IDBTransaction::RemoveObjectStore(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); @@ -237,7 +244,8 @@ IDBTransaction::CommitOrRollback() TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate(); NS_ENSURE_STATE(pool); - nsRefPtr helper(new CommitHelper(this, mListener)); + nsRefPtr helper(new CommitHelper(this, mListener, + mCreatedObjectStores)); mCachedStatements.Enumerate(DoomCachedStatements, helper); NS_ASSERTION(!mCachedStatements.Count(), "Statements left!"); @@ -363,119 +371,6 @@ IDBTransaction::GetOrCreateConnection(mozIStorageConnection** aResult) return NS_OK; } -already_AddRefed -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 -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 -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 IDBTransaction::GetCachedStatement(const nsACString& aQuery) { @@ -557,13 +452,9 @@ IDBTransaction::GetOrCreateObjectStore(const nsAString& aName, } } - retval = IDBObjectStore::Create(this, aObjectStoreInfo); - NS_ENSURE_TRUE(retval, nsnull); + retval = IDBObjectStore::Create(this, aObjectStoreInfo, mDatabaseInfo->id); - if (!mCreatedObjectStores.AppendElement(retval)) { - NS_WARNING("Out of memory!"); - return nsnull; - } + mCreatedObjectStores.AppendElement(retval); return retval.forget(); } @@ -658,12 +549,7 @@ IDBTransaction::GetObjectStoreNames(nsIDOMDOMStringList** aObjectStores) nsTArray* arrayOfNames; if (mMode == IDBTransaction::VERSION_CHANGE) { - DatabaseInfo* info = mDatabase->Info(); - - if (!info->GetObjectStoreNames(stackArray)) { - NS_ERROR("Out of memory!"); - return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; - } + mDatabaseInfo->GetObjectStoreNames(stackArray); arrayOfNames = &stackArray; } @@ -695,7 +581,7 @@ IDBTransaction::ObjectStore(const nsAString& aName, if (mMode == nsIIDBTransaction::VERSION_CHANGE || mObjectStoreNames.Contains(aName)) { - mDatabase->Info()->GetObjectStore(aName, &info); + info = mDatabaseInfo->GetObjectStore(aName); } if (!info) { @@ -847,15 +733,23 @@ IDBTransaction::AfterProcessNextEvent(nsIThreadInternal* aThread, return NS_OK; } -CommitHelper::CommitHelper(IDBTransaction* aTransaction, - IDBTransactionListener* aListener) +CommitHelper::CommitHelper( + IDBTransaction* aTransaction, + IDBTransactionListener* aListener, + const nsTArray >& aUpdatedObjectStores) : mTransaction(aTransaction), mListener(aListener), - mAborted(!!aTransaction->mAborted), - mHaveMetadata(false) + mAborted(!!aTransaction->mAborted) { 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() @@ -882,19 +776,11 @@ CommitHelper::Run() nsCOMPtr event; if (mAborted) { - 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!"); - } + 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()); } event = CreateGenericEvent(NS_LITERAL_STRING(ABORT_EVT_STR), @@ -938,12 +824,17 @@ 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; @@ -951,23 +842,11 @@ 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!"); - } - } } } @@ -991,6 +870,55 @@ CommitHelper::Run() return NS_OK; } +nsresult +CommitHelper::WriteAutoIncrementCounts() +{ + nsCOMPtr 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() { diff --git a/dom/indexedDB/IDBTransaction.h b/dom/indexedDB/IDBTransaction.h index 329102debfbc..4d6cdfff7250 100644 --- a/dom/indexedDB/IDBTransaction.h +++ b/dom/indexedDB/IDBTransaction.h @@ -107,7 +107,7 @@ public: void OnNewRequest(); void OnRequestFinished(); - void ReleaseCachedObjectStore(const nsAString& aName); + void RemoveObjectStore(const nsAString& aName); void SetTransactionListener(IDBTransactionListener* aListener); @@ -118,19 +118,6 @@ public: // Only meant to be called on mStorageThread! nsresult GetOrCreateConnection(mozIStorageConnection** aConnection); - already_AddRefed - AddStatement(bool aCreate, - bool aOverwrite, - bool aAutoIncrement); - - already_AddRefed - IndexDataInsertStatement(bool aAutoIncrement, - bool aUnique); - - already_AddRefed - IndexDataDeleteStatement(bool aAutoIncrement, - bool aUnique); - already_AddRefed GetCachedStatement(const nsACString& aQuery); @@ -138,9 +125,7 @@ public: already_AddRefed GetCachedStatement(const char (&aQuery)[N]) { - nsCString query; - query.AssignLiteral(aQuery); - return GetCachedStatement(query); + return GetCachedStatement(NS_LITERAL_CSTRING(aQuery)); } bool IsOpen() const; @@ -167,6 +152,11 @@ public: return mDatabase; } + DatabaseInfo* DBInfo() const + { + return mDatabaseInfo; + } + already_AddRefed GetOrCreateObjectStore(const nsAString& aName, ObjectStoreInfo* aObjectStoreInfo); @@ -182,6 +172,7 @@ private: nsresult CommitOrRollback(); nsRefPtr mDatabase; + nsRefPtr mDatabaseInfo; nsTArray mObjectStoreNames; PRUint16 mReadyState; PRUint16 mMode; @@ -224,7 +215,8 @@ public: NS_DECL_NSIRUNNABLE CommitHelper(IDBTransaction* aTransaction, - IDBTransactionListener* aListener); + IDBTransactionListener* aListener, + const nsTArray >& mUpdatedObjectStores); ~CommitHelper(); template @@ -241,17 +233,23 @@ 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 mTransaction; nsRefPtr mListener; nsCOMPtr mConnection; nsRefPtr mUpdateFileRefcountFunction; nsAutoTArray, 10> mDoomedObjects; - - PRUint64 mOldVersion; - nsTArray > mOldObjectStores; + nsAutoTArray, 10> mAutoIncrementObjectStores; bool mAborted; - bool mHaveMetadata; }; class UpdateRefcountFunction : public mozIStorageFunction diff --git a/dom/indexedDB/IndexedDatabaseManager.cpp b/dom/indexedDB/IndexedDatabaseManager.cpp index 25156a610bf3..a46c8f9873e6 100644 --- a/dom/indexedDB/IndexedDatabaseManager.cpp +++ b/dom/indexedDB/IndexedDatabaseManager.cpp @@ -38,6 +38,7 @@ * ***** END LICENSE BLOCK ***** */ #include "IndexedDatabaseManager.h" +#include "DatabaseInfo.h" #include "nsIFile.h" #include "nsIObserverService.h" @@ -79,9 +80,6 @@ // 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; @@ -1183,6 +1181,8 @@ 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. diff --git a/dom/indexedDB/Key.h b/dom/indexedDB/Key.h index e6476ed56314..c39f2b20c198 100644 --- a/dom/indexedDB/Key.h +++ b/dom/indexedDB/Key.h @@ -238,11 +238,9 @@ public: if (IsString()) { rv = aStatement->BindStringByName(aParamName, ToString()); } - else if (IsInteger()) { - rv = aStatement->BindInt64ByName(aParamName, ToInteger()); - } else { - NS_NOTREACHED("Bad key!"); + NS_ASSERTION(IsInteger(), "Bad key!"); + rv = aStatement->BindInt64ByName(aParamName, ToInteger()); } return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; diff --git a/dom/indexedDB/OpenDatabaseHelper.cpp b/dom/indexedDB/OpenDatabaseHelper.cpp index b377cd212b53..0f17c583609e 100644 --- a/dom/indexedDB/OpenDatabaseHelper.cpp +++ b/dom/indexedDB/OpenDatabaseHelper.cpp @@ -60,7 +60,7 @@ namespace { PR_STATIC_ASSERT(JS_STRUCTURED_CLONE_VERSION == 1); // Major schema version. Bump for almost everything. -const PRUint32 kMajorSchemaVersion = 10; +const PRUint32 kMajorSchemaVersion = 11; // Minor schema version. Should almost always be 0 (maybe bump on release // branches if we have to). @@ -169,38 +169,6 @@ 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 " @@ -257,31 +225,15 @@ 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, " + "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 DEFAULT 0, " - "object_store_autoincrement INTERGER NOT NULL, " - "PRIMARY KEY (id), " + "multientry INTEGER NOT NULL, " "UNIQUE (object_store_id, name), " "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE " "CASCADE" @@ -336,53 +288,6 @@ 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); @@ -1058,6 +963,121 @@ 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, @@ -1363,7 +1383,7 @@ OpenDatabaseHelper::DoDatabaseWork() } for (PRUint32 i = 0; i < mObjectStores.Length(); i++) { - nsAutoPtr& objectStoreInfo = mObjectStores[i]; + nsRefPtr& objectStoreInfo = mObjectStores[i]; for (PRUint32 j = 0; j < objectStoreInfo->indexes.Length(); j++) { IndexInfo& indexInfo = objectStoreInfo->indexes[j]; mLastIndexId = NS_MAX(indexInfo.id, mLastIndexId); @@ -1509,7 +1529,7 @@ OpenDatabaseHelper::CreateDatabaseConnection( } else { // This logic needs to change next time we change the schema! - PR_STATIC_ASSERT(kSQLiteSchemaVersion == PRInt32((10 << 4) + 0)); + PR_STATIC_ASSERT(kSQLiteSchemaVersion == PRInt32((11 << 4) + 0)); while (schemaVersion != kSQLiteSchemaVersion) { if (schemaVersion == 4) { @@ -1531,6 +1551,9 @@ 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!"); @@ -1681,6 +1704,8 @@ 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!"); @@ -1749,18 +1774,14 @@ OpenDatabaseHelper::EnsureSuccessResult() PRUint32 objectStoreCount = mObjectStores.Length(); for (PRUint32 index = 0; index < objectStoreCount; index++) { - nsAutoPtr& info = mObjectStores[index]; - NS_ASSERTION(info->databaseId == mDatabaseId, "Huh?!"); + nsRefPtr& info = mObjectStores[index]; - ObjectStoreInfo* otherInfo; - NS_ASSERTION(dbInfo->GetObjectStore(info->name, &otherInfo), - "ObjectStore not known!"); + ObjectStoreInfo* otherInfo = dbInfo->GetObjectStore(info->name); + NS_ASSERTION(otherInfo, "ObjectStore not known!"); NS_ASSERTION(info->name == otherInfo->name && info->id == otherInfo->id && - info->keyPath == otherInfo->keyPath && - info->autoIncrement == otherInfo->autoIncrement && - info->databaseId == otherInfo->databaseId, + info->keyPath == otherInfo->keyPath, "Metadata mismatch!"); NS_ASSERTION(dbInfo->ContainsStoreName(info->name), "Object store names out of date!"); @@ -1779,8 +1800,6 @@ 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!"); } } } @@ -1791,6 +1810,7 @@ OpenDatabaseHelper::EnsureSuccessResult() nsRefPtr newInfo(new DatabaseInfo()); newInfo->name = mName; + newInfo->origin = mASCIIOrigin; newInfo->id = mDatabaseId; newInfo->filePath = mDatabaseFilePath; @@ -1801,8 +1821,8 @@ OpenDatabaseHelper::EnsureSuccessResult() newInfo.swap(dbInfo); - nsresult rv = IDBFactory::UpdateDatabaseMetadata(dbInfo, mCurrentVersion, - mObjectStores); + nsresult rv = IDBFactory::SetDatabaseMetadata(dbInfo, mCurrentVersion, + mObjectStores); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); NS_ASSERTION(mObjectStores.IsEmpty(), "Should have swapped!"); diff --git a/dom/indexedDB/OpenDatabaseHelper.h b/dom/indexedDB/OpenDatabaseHelper.h index 1e7b7be41e62..d90a5f4f3b49 100644 --- a/dom/indexedDB/OpenDatabaseHelper.h +++ b/dom/indexedDB/OpenDatabaseHelper.h @@ -62,7 +62,7 @@ public: mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion), mForDeletion(aForDeletion), mDatabaseId(nsnull), mCurrentVersion(0), mLastObjectStoreId(0), mLastIndexId(0), mState(eCreated), - mResultCode(NS_OK) + mResultCode(NS_OK), mLoadDBMetadata(false) { NS_ASSERTION(!aForDeletion || !aRequestedVersion, "Can't be for deletion and request a version!"); @@ -132,7 +132,7 @@ private: nsCOMPtr mDatabaseId; // Out-params. - nsTArray > mObjectStores; + nsTArray > mObjectStores; PRUint64 mCurrentVersion; nsString mDatabaseFilePath; PRInt64 mLastObjectStoreId; @@ -153,6 +153,9 @@ private: nsresult mResultCode; nsRefPtr mFileManager; + + nsRefPtr mDBInfo; + bool mLoadDBMetadata; }; END_INDEXEDDB_NAMESPACE diff --git a/dom/indexedDB/nsIIDBObjectStore.idl b/dom/indexedDB/nsIIDBObjectStore.idl index a00b9f003f0c..921a43f3c531 100644 --- a/dom/indexedDB/nsIIDBObjectStore.idl +++ b/dom/indexedDB/nsIIDBObjectStore.idl @@ -50,7 +50,7 @@ interface nsIDOMDOMStringList; * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-nsIIDBObjectStore * for more information. */ -[scriptable, builtinclass, uuid(adc6a1e2-9fd7-4d28-a7f9-9c653313124b)] +[scriptable, builtinclass, uuid(e93c5ca4-89da-4eb4-b839-271ba4f65a27)] interface nsIIDBObjectStore : nsISupports { readonly attribute DOMString name; @@ -61,6 +61,8 @@ interface nsIIDBObjectStore : nsISupports readonly attribute nsIIDBTransaction transaction; + readonly attribute boolean autoIncrement; + // Success fires IDBTransactionEvent, result == value for key [implicit_jscontext] nsIIDBRequest diff --git a/dom/indexedDB/test/Makefile.in b/dom/indexedDB/test/Makefile.in index 3c111d457040..c7e85250d28d 100644 --- a/dom/indexedDB/test/Makefile.in +++ b/dom/indexedDB/test/Makefile.in @@ -57,6 +57,7 @@ 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 \ diff --git a/dom/indexedDB/test/error_events_abort_transactions_iframe.html b/dom/indexedDB/test/error_events_abort_transactions_iframe.html index f81f83917b89..e0a5b758ff75 100644 --- a/dom/indexedDB/test/error_events_abort_transactions_iframe.html +++ b/dom/indexedDB/test/error_events_abort_transactions_iframe.html @@ -88,15 +88,13 @@ event = yield; is(event.type, "abort", "Got a transaction abort event"); - //todo(db.version, 1, "Correct version"); - is(db.objectStoreNames.length, 0, "Correct objectStoreNames length"); + is(db.version, 1, "Correct version"); + is(db.objectStoreNames.length, 1, "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; diff --git a/dom/indexedDB/test/helpers.js b/dom/indexedDB/test/helpers.js index 4fc3b3a094b1..9e6f9dff359d 100644 --- a/dom/indexedDB/test/helpers.js +++ b/dom/indexedDB/test/helpers.js @@ -47,6 +47,11 @@ function continueToNextStep() }); } +function continueToNextStepSync() +{ + testGenerator.next(); +} + function errorHandler(event) { ok(false, "indexedDB error, code " + event.target.errorCode); @@ -75,6 +80,7 @@ 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); } }; diff --git a/dom/indexedDB/test/test_add_put.html b/dom/indexedDB/test/test_add_put.html index 9d9949808b1a..108671024844 100644 --- a/dom/indexedDB/test/test_add_put.html +++ b/dom/indexedDB/test/test_add_put.html @@ -82,6 +82,8 @@ let expected = expectedResult(method, keypath, explicit, autoincrement, existing); + let valueJSON = JSON.stringify(value); + ok(true, "making call" + test); // Make function call for throwing functions @@ -94,13 +96,16 @@ 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); - req.onsuccess = req.onerror = grabEventAndContinueHandler + is(JSON.stringify(value), valueJSON, "call didn't modify value" + test); + + req.onsuccess = req.onerror = grabEventAndContinueHandler; let e = yield; // Figure out what key we used @@ -123,16 +128,7 @@ } is(e.type, "success", "write should succeed" + 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); - } + is(e.target.result, key, "write should return correct key" + test); store.get(key).onsuccess = grabEventAndContinueHandler; e = yield; diff --git a/dom/indexedDB/test/test_autoIncrement.html b/dom/indexedDB/test/test_autoIncrement.html new file mode 100644 index 000000000000..ea2c890c1bec --- /dev/null +++ b/dom/indexedDB/test/test_autoIncrement.html @@ -0,0 +1,384 @@ + + + + Indexed Database Property Test + + + + + + + + + + + diff --git a/dom/indexedDB/test/test_autoIncrement_indexes.html b/dom/indexedDB/test/test_autoIncrement_indexes.html index 951be60eef92..366604a1d8af 100644 --- a/dom/indexedDB/test/test_autoIncrement_indexes.html +++ b/dom/indexedDB/test/test_autoIncrement_indexes.html @@ -31,8 +31,7 @@ objectStore.add(data).onsuccess = grabEventAndContinueHandler; event = yield; - let key = event.target.result; - ok(key, "Added entry"); + is(event.target.result, 1, "Added entry"); request.onsuccess = grabEventAndContinueHandler; event = yield; @@ -45,17 +44,17 @@ first.get("foo").onsuccess = grabEventAndContinueHandler; event = yield; - is (event.target.result.id, key, "Entry in first"); + is (event.target.result.id, 1, "Entry in first"); second.get("foo").onsuccess = grabEventAndContinueHandler; event = yield; - is (event.target.result.id, key, "Entry in second"); + is (event.target.result.id, 1, "Entry in second"); third.get("foo").onsuccess = grabEventAndContinueHandler; event = yield; - is (event.target.result.id, key, "Entry in third"); + is (event.target.result.id, 1, "Entry in third"); finishTest(); yield; diff --git a/dom/indexedDB/test/test_setVersion_abort.html b/dom/indexedDB/test/test_setVersion_abort.html index 54d7070c9f43..2dfef6152ae6 100644 --- a/dom/indexedDB/test/test_setVersion_abort.html +++ b/dom/indexedDB/test/test_setVersion_abort.html @@ -21,7 +21,7 @@ function testSteps() let request = mozIndexedDB.open(name, 1, description); request.onerror = grabEventAndContinueHandler; - request.onsuccess = errorHandler; + request.onsuccess = unexpectedSuccessHandler; request.onupgradeneeded = grabEventAndContinueHandler; let event = yield; @@ -43,13 +43,28 @@ function testSteps() is(event.type, "abort", "Got transaction abort event"); is(event.target, transaction, "Right target"); - todo(db.version, 1, "Correct version"); - is(db.objectStoreNames.length, 0, "Correct objectStoreNames length"); + is(db.version, 1, "Correct version"); + is(db.objectStoreNames.length, 1, "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; }