diff --git a/dom/indexedDB/IDBCursorRequest.cpp b/dom/indexedDB/IDBCursorRequest.cpp index 152d16b1c60d..269ff98efe7b 100644 --- a/dom/indexedDB/IDBCursorRequest.cpp +++ b/dom/indexedDB/IDBCursorRequest.cpp @@ -74,9 +74,11 @@ public: PRInt64 aObjectStoreID, const nsAString& aValue, const Key& aKey, - bool aAutoIncrement) + bool aAutoIncrement, + nsTArray& aIndexUpdateInfo) : AsyncConnectionHelper(aTransaction, aRequest), mOSID(aObjectStoreID), - mValue(aValue), mKey(aKey), mAutoIncrement(aAutoIncrement) + mValue(aValue), mKey(aKey), mAutoIncrement(aAutoIncrement), + mIndexUpdateInfo(aIndexUpdateInfo) { } PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection); @@ -88,6 +90,7 @@ private: const nsString mValue; const Key mKey; const bool mAutoIncrement; + nsTArray& mIndexUpdateInfo; }; class RemoveHelper : public AsyncConnectionHelper @@ -570,6 +573,12 @@ IDBCursorRequest::Update(nsIVariant* aValue, } } + nsTArray indexUpdateInfo; + rv = IDBObjectStoreRequest::GetIndexUpdateInfo(mObjectStore->GetObjectStoreInfo(), + cx, clone.value(), + indexUpdateInfo); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr json(new nsJSON()); nsString jsonValue; @@ -581,7 +590,7 @@ IDBCursorRequest::Update(nsIVariant* aValue, nsRefPtr helper = new UpdateHelper(mTransaction, request, mObjectStore->Id(), jsonValue, key, - mObjectStore->IsAutoIncrement()); + mObjectStore->IsAutoIncrement(), indexUpdateInfo); rv = helper->DispatchToTransactionPool(); NS_ENSURE_SUCCESS(rv, rv); @@ -662,7 +671,17 @@ UpdateHelper::DoDatabaseWork(mozIStorageConnection* aConnection) return nsIIDBDatabaseException::CONSTRAINT_ERR; } - // TODO update indexes if needed + // Update our indexes if needed. + if (!mIndexUpdateInfo.IsEmpty()) { + PRInt64 objectDataId = mAutoIncrement ? mKey.IntValue() : LL_MININT; + rv = IDBObjectStoreRequest::UpdateIndexes(mTransaction, mOSID, mKey, + mAutoIncrement, true, + objectDataId, mIndexUpdateInfo); + if (rv == NS_ERROR_STORAGE_CONSTRAINT) { + return nsIIDBDatabaseException::CONSTRAINT_ERR; + } + NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR); + } rv = savepoint.Release(); return NS_SUCCEEDED(rv) ? OK : nsIIDBDatabaseException::UNKNOWN_ERR; diff --git a/dom/indexedDB/IDBDatabaseRequest.h b/dom/indexedDB/IDBDatabaseRequest.h index 52d054f82d01..eccf4ae9c028 100644 --- a/dom/indexedDB/IDBDatabaseRequest.h +++ b/dom/indexedDB/IDBDatabaseRequest.h @@ -52,7 +52,7 @@ BEGIN_INDEXEDDB_NAMESPACE class AsyncConnectionHelper; -class DatabaseInfo; +struct DatabaseInfo; class IDBTransactionRequest; class IDBDatabaseRequest : public IDBRequest::Generator, diff --git a/dom/indexedDB/IDBObjectStoreRequest.cpp b/dom/indexedDB/IDBObjectStoreRequest.cpp index 2b67b0ae9101..39b8bd607efa 100644 --- a/dom/indexedDB/IDBObjectStoreRequest.cpp +++ b/dom/indexedDB/IDBObjectStoreRequest.cpp @@ -69,12 +69,6 @@ USING_INDEXEDDB_NAMESPACE BEGIN_INDEXEDDB_NAMESPACE -struct IndexUpdateInfo -{ - IndexInfo info; - Key value; -}; - END_INDEXEDDB_NAMESPACE namespace { @@ -496,6 +490,197 @@ IDBObjectStoreRequest::GetKeyPathValueFromJSON(const nsAString& aJSON, return NS_OK; } +/* static */ +nsresult +IDBObjectStoreRequest::GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo, + JSContext* aCx, + jsval aObject, + nsTArray& aUpdateInfoArray) +{ + JSObject* cloneObj = nsnull; + + PRUint32 count = aObjectStoreInfo->indexes.Length(); + if (count && !JSVAL_IS_PRIMITIVE(aObject)) { + if (!aUpdateInfoArray.SetCapacity(count)) { + NS_ERROR("Out of memory!"); + return NS_ERROR_OUT_OF_MEMORY; + } + + cloneObj = JSVAL_TO_OBJECT(aObject); + + for (PRUint32 indexesIndex = 0; indexesIndex < count; indexesIndex++) { + const IndexInfo& indexInfo = aObjectStoreInfo->indexes[indexesIndex]; + + const jschar* keyPathChars = + reinterpret_cast(indexInfo.keyPath.BeginReading()); + const size_t keyPathLen = indexInfo.keyPath.Length(); + + jsval keyPathValue; + JSBool ok = JS_GetUCProperty(aCx, cloneObj, keyPathChars, keyPathLen, + &keyPathValue); + NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); + + Key value; + + if (JSVAL_IS_INT(keyPathValue)) { + value = JSVAL_TO_INT(keyPathValue); + } + else if (JSVAL_IS_DOUBLE(keyPathValue)) { + value = *JSVAL_TO_DOUBLE(keyPathValue); + } + else if (JSVAL_IS_STRING(keyPathValue)) { + JSString* str = JSVAL_TO_STRING(keyPathValue); + size_t len = JS_GetStringLength(str); + if (len) { + const PRUnichar* chars = + reinterpret_cast(JS_GetStringChars(str)); + value = nsDependentString(chars, len); + } + else { + value = EmptyString(); + } + } + else { + // Not a value we can do anything with, ignore it. + continue; + } + + IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement(); + updateInfo->info = indexInfo; + updateInfo->value = value; + } + } + else { + aUpdateInfoArray.Clear(); + } + + return NS_OK; +} + +/* static */ +nsresult +IDBObjectStoreRequest::UpdateIndexes(IDBTransactionRequest* aTransaction, + PRInt64 aObjectStoreId, + const Key& aObjectStoreKey, + bool aAutoIncrement, + bool aOverwrite, + PRInt64 aObjectDataId, + const nsTArray& aUpdateInfoArray) +{ +#ifdef DEBUG + if (aAutoIncrement) { + NS_ASSERTION(aObjectDataId != LL_MININT, "Bad objectData id!"); + } + else { + NS_ASSERTION(aObjectDataId == LL_MININT, "Bad objectData id!"); + } +#endif + + PRUint32 indexCount = aUpdateInfoArray.Length(); + NS_ASSERTION(indexCount, "Don't call me!"); + + nsCOMPtr stmt; + nsresult rv; + + if (!aAutoIncrement) { + 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!"); + + NS_NAMED_LITERAL_CSTRING(keyValue, "key_value"); + + if (aObjectStoreKey.IsInt()) { + rv = stmt->BindInt64ByName(keyValue, aObjectStoreKey.IntValue()); + } + else if (aObjectStoreKey.IsString()) { + rv = stmt->BindStringByName(keyValue, aObjectStoreKey.StringValue()); + } + else { + NS_NOTREACHED("Unknown key type!"); + } + NS_ENSURE_SUCCESS(rv, rv); + + PRBool 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!"); + + for (PRUint32 indexIndex = 0; indexIndex < indexCount; indexIndex++) { + const IndexUpdateInfo& updateInfo = aUpdateInfoArray[indexIndex]; + + stmt = aTransaction->IndexUpdateStatement(updateInfo.info.autoIncrement, + updateInfo.info.unique, + aOverwrite); + NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE); + + mozStorageStatementScoper scoper2(stmt); + + rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), + updateInfo.info.id); + NS_ENSURE_SUCCESS(rv, rv); + + rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("object_data_id"), + aObjectDataId); + NS_ENSURE_SUCCESS(rv, rv); + + NS_NAMED_LITERAL_CSTRING(objectDataKey, "object_data_key"); + + if (aObjectStoreKey.IsInt()) { + rv = stmt->BindInt64ByName(objectDataKey, aObjectStoreKey.IntValue()); + } + else if (aObjectStoreKey.IsString()) { + rv = stmt->BindStringByName(objectDataKey, aObjectStoreKey.StringValue()); + } + else { + NS_NOTREACHED("Unknown key type!"); + } + NS_ENSURE_SUCCESS(rv, rv); + + NS_NAMED_LITERAL_CSTRING(value, "value"); + + if (updateInfo.value.IsInt()) { + rv = stmt->BindInt64ByName(value, updateInfo.value.IntValue()); + } + else if (updateInfo.value.IsString()) { + rv = stmt->BindStringByName(value, updateInfo.value.StringValue()); + } + else if (updateInfo.value.IsUnset()) { + rv = stmt->BindStringByName(value, updateInfo.value.StringValue()); + } + else { + NS_NOTREACHED("Unknown key type!"); + } + NS_ENSURE_SUCCESS(rv, rv); + + rv = stmt->Execute(); + if (NS_FAILED(rv)) { + return rv; + } + } + + return NS_OK; +} + ObjectStoreInfo* IDBObjectStoreRequest::GetObjectStoreInfo() { @@ -600,62 +785,8 @@ IDBObjectStoreRequest::GetAddInfo(/* jsval aValue, */ ObjectStoreInfo* objectStoreInfo = GetObjectStoreInfo(); NS_ENSURE_TRUE(objectStoreInfo, NS_ERROR_FAILURE); - JSObject* cloneObj = nsnull; - - PRUint32 count = objectStoreInfo->indexes.Length(); - if (count && !JSVAL_IS_PRIMITIVE(clone.value())) { - if (!aUpdateInfoArray.SetCapacity(count)) { - NS_ERROR("Out of memory!"); - return NS_ERROR_OUT_OF_MEMORY; - } - - cloneObj = JSVAL_TO_OBJECT(clone.value()); - - for (PRUint32 indexesIndex = 0; indexesIndex < count; indexesIndex++) { - const IndexInfo& indexInfo = objectStoreInfo->indexes[indexesIndex]; - - const jschar* keyPathChars = - reinterpret_cast(indexInfo.keyPath.BeginReading()); - const size_t keyPathLen = indexInfo.keyPath.Length(); - - jsval keyPathValue; - JSBool ok = JS_GetUCProperty(cx, cloneObj, keyPathChars, keyPathLen, - &keyPathValue); - NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); - - Key value; - - if (JSVAL_IS_INT(keyPathValue)) { - value = JSVAL_TO_INT(keyPathValue); - } - else if (JSVAL_IS_DOUBLE(keyPathValue)) { - value = *JSVAL_TO_DOUBLE(keyPathValue); - } - else if (JSVAL_IS_STRING(keyPathValue)) { - JSString* str = JSVAL_TO_STRING(keyPathValue); - size_t len = JS_GetStringLength(str); - if (len) { - const PRUnichar* chars = - reinterpret_cast(JS_GetStringChars(str)); - value = nsDependentString(chars, len); - } - else { - value = EmptyString(); - } - } - else { - // Not a value we can do anything with, ignore it. - continue; - } - - IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement(); - updateInfo->info = indexInfo; - updateInfo->value = value; - } - } - else { - aUpdateInfoArray.Clear(); - } + rv = GetIndexUpdateInfo(objectStoreInfo, cx, clone.value(), aUpdateInfoArray); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr json(new nsJSON()); rv = json->EncodeFromJSVal(clone.addr(), cx, aJSON); @@ -1326,7 +1457,9 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) // Update our indexes if needed. if (!mIndexUpdateInfo.IsEmpty()) { PRInt64 objectDataId = mAutoIncrement ? mKey.IntValue() : LL_MININT; - rv = UpdateIndexes(aConnection, objectDataId); + rv = IDBObjectStoreRequest::UpdateIndexes(mTransaction, mOSID, mKey, + mAutoIncrement, mOverwrite, + objectDataId, mIndexUpdateInfo); if (rv == NS_ERROR_STORAGE_CONSTRAINT) { return nsIIDBDatabaseException::CONSTRAINT_ERR; } @@ -1397,125 +1530,6 @@ AddHelper::ModifyValueForNewKey() return NS_OK; } -nsresult -AddHelper::UpdateIndexes(mozIStorageConnection* aConnection, - PRInt64 aObjectDataId) -{ -#ifdef DEBUG - NS_ASSERTION(aConnection, "Null pointer!"); - if (mAutoIncrement) { - NS_ASSERTION(aObjectDataId != LL_MININT, "Bad objectData id!"); - } - else { - NS_ASSERTION(aObjectDataId == LL_MININT, "Bad objectData id!"); - } -#endif - - PRUint32 indexCount = mIndexUpdateInfo.Length(); - NS_ASSERTION(indexCount, "Don't call me!"); - - nsCOMPtr stmt; - nsresult rv; - - if (!mAutoIncrement) { - stmt = mTransaction->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"), mOSID); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ASSERTION(!mKey.IsUnset(), "This shouldn't happen!"); - - NS_NAMED_LITERAL_CSTRING(keyValue, "key_value"); - - if (mKey.IsInt()) { - rv = stmt->BindInt64ByName(keyValue, mKey.IntValue()); - } - else if (mKey.IsString()) { - rv = stmt->BindStringByName(keyValue, mKey.StringValue()); - } - else { - NS_NOTREACHED("Unknown key type!"); - } - NS_ENSURE_SUCCESS(rv, rv); - - PRBool 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!"); - - for (PRUint32 indexIndex = 0; indexIndex < indexCount; indexIndex++) { - const IndexUpdateInfo& updateInfo = mIndexUpdateInfo[indexIndex]; - - stmt = mTransaction->IndexUpdateStatement(updateInfo.info.autoIncrement, - updateInfo.info.unique, - mOverwrite); - NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE); - - mozStorageStatementScoper scoper2(stmt); - - rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), - updateInfo.info.id); - NS_ENSURE_SUCCESS(rv, rv); - - rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("object_data_id"), - aObjectDataId); - NS_ENSURE_SUCCESS(rv, rv); - - NS_NAMED_LITERAL_CSTRING(objectDataKey, "object_data_key"); - - if (mKey.IsInt()) { - rv = stmt->BindInt64ByName(objectDataKey, mKey.IntValue()); - } - else if (mKey.IsString()) { - rv = stmt->BindStringByName(objectDataKey, mKey.StringValue()); - } - else { - NS_NOTREACHED("Unknown key type!"); - } - NS_ENSURE_SUCCESS(rv, rv); - - NS_NAMED_LITERAL_CSTRING(value, "value"); - - if (updateInfo.value.IsInt()) { - rv = stmt->BindInt64ByName(value, updateInfo.value.IntValue()); - } - else if (updateInfo.value.IsString()) { - rv = stmt->BindStringByName(value, updateInfo.value.StringValue()); - } - else if (updateInfo.value.IsUnset()) { - rv = stmt->BindStringByName(value, updateInfo.value.StringValue()); - } - else { - NS_NOTREACHED("Unknown key type!"); - } - NS_ENSURE_SUCCESS(rv, rv); - - rv = stmt->Execute(); - if (NS_FAILED(rv)) { - return rv; - } - } - - return NS_OK; -} - PRUint16 GetHelper::DoDatabaseWork(mozIStorageConnection* aConnection) { diff --git a/dom/indexedDB/IDBObjectStoreRequest.h b/dom/indexedDB/IDBObjectStoreRequest.h index 4b1c62f56f5a..06645b1ad60e 100644 --- a/dom/indexedDB/IDBObjectStoreRequest.h +++ b/dom/indexedDB/IDBObjectStoreRequest.h @@ -45,13 +45,14 @@ #include "mozilla/dom/indexedDB/IDBTransactionRequest.h" #include "nsIIDBObjectStoreRequest.h" +#include "DatabaseInfo.h" struct JSContext; BEGIN_INDEXEDDB_NAMESPACE struct ObjectStoreInfo; -struct IndexUpdateInfo; +struct IndexInfo; class Key { @@ -204,6 +205,12 @@ private: PRInt64 mInt; }; +struct IndexUpdateInfo +{ + IndexInfo info; + Key value; +}; + class IDBObjectStoreRequest : public IDBRequest::Generator, public nsIIDBObjectStoreRequest { @@ -232,6 +239,22 @@ public: JSContext** aCx, Key& aValue); + static nsresult + GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo, + JSContext* aCx, + jsval aObject, + nsTArray& aUpdateInfoArray); + + static nsresult + UpdateIndexes(IDBTransactionRequest* aTransaction, + PRInt64 aObjectStoreId, + const Key& aObjectStoreKey, + bool aAutoIncrement, + bool aOverwrite, + PRInt64 aObjectDataId, + const nsTArray& aUpdateInfoArray); + + bool TransactionIsOpen() const { return mTransaction->TransactionIsOpen(); diff --git a/dom/indexedDB/IDBTransactionRequest.cpp b/dom/indexedDB/IDBTransactionRequest.cpp index 7b039e66ee6e..dcc01aef8710 100644 --- a/dom/indexedDB/IDBTransactionRequest.cpp +++ b/dom/indexedDB/IDBTransactionRequest.cpp @@ -436,32 +436,31 @@ IDBTransactionRequest::IndexUpdateStatement(bool aAutoIncrement, bool aUnique, bool aOverwrite) { - // XXX we may not want to replace! if (aAutoIncrement) { if (aUnique) { if (aOverwrite) { return GetCachedStatement( "INSERT OR REPLACE INTO ai_unique_index_data " - "(index_id, object_data_id, id, value) " + "(index_id, ai_object_data_id, id, value) " "VALUES (:index_id, :object_data_id, :object_data_key, :value)" ); } return GetCachedStatement( "INSERT INTO ai_unique_index_data " - "(index_id, object_data_id, id, value) " + "(index_id, aI_object_data_id, id, value) " "VALUES (:index_id, :object_data_id, :object_data_key, :value)" ); } if (aOverwrite) { return GetCachedStatement( "INSERT OR REPLACE INTO ai_index_data " - "(index_id, object_data_id, id, value) " + "(index_id, ai_object_data_id, id, value) " "VALUES (:index_id, :object_data_id, :object_data_key, :value)" ); } return GetCachedStatement( "INSERT INTO ai_index_data " - "(index_id, object_data_id, id, value) " + "(index_id, ai_object_data_id, id, value) " "VALUES (:index_id, :object_data_id, :object_data_key, :value)" ); } @@ -504,6 +503,19 @@ IDBTransactionRequest::GetCachedStatement(const nsACString& aQuery) if (!mCachedStatements.Get(aQuery, getter_AddRefs(stmt))) { nsresult rv = mConnection->CreateStatement(aQuery, getter_AddRefs(stmt)); +#ifdef DEBUG + if (NS_FAILED(rv)) { + nsCString error; + error.AppendLiteral("The statement `"); + error.Append(aQuery); + error.AppendLiteral("` failed to compile with the error message `"); + nsCString msg; + (void)mConnection->GetLastErrorString(msg); + error.Append(msg); + error.AppendLiteral("`."); + NS_ERROR(error.get()); + } +#endif NS_ENSURE_SUCCESS(rv, nsnull); if (!mCachedStatements.Put(aQuery, stmt)) { diff --git a/dom/indexedDB/IDBTransactionRequest.h b/dom/indexedDB/IDBTransactionRequest.h index cfd954ec7526..3655b0b7f01a 100644 --- a/dom/indexedDB/IDBTransactionRequest.h +++ b/dom/indexedDB/IDBTransactionRequest.h @@ -59,7 +59,7 @@ BEGIN_INDEXEDDB_NAMESPACE class AsyncConnectionHelper; class CommitHelper; -class ObjectStoreInfo; +struct ObjectStoreInfo; class TransactionThreadPool; class IDBTransactionRequest : public nsDOMEventTargetHelper,