Bug 613083 - 'IndexedDB: Switch serialization format from JSON to structured clone bytestream'. r=sicking, a=blocking.

This commit is contained in:
Ben Turner 2010-12-21 11:02:04 -05:00
parent 81a511c1aa
commit bb620ec2bf
12 changed files with 401 additions and 237 deletions

View File

@ -47,7 +47,6 @@
#include "nsContentUtils.h"
#include "nsDOMClassInfo.h"
#include "nsEventDispatcher.h"
#include "nsJSON.h"
#include "nsJSUtils.h"
#include "nsThreadUtils.h"
@ -91,6 +90,7 @@ public:
void ReleaseMainThreadObjects()
{
mCursor = nsnull;
mCloneBuffer.clear();
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
@ -105,7 +105,7 @@ protected:
nsRefPtr<IDBCursor> mCursor;
Key mKey;
Key mObjectKey;
nsString mValue;
JSAutoStructuredCloneBuffer mCloneBuffer;
};
class ContinueObjectStoreHelper : public ContinueHelper
@ -155,7 +155,7 @@ IDBCursor::Create(IDBRequest* aRequest,
const nsACString& aContinueQuery,
const nsACString& aContinueToQuery,
const Key& aKey,
const nsAString& aValue)
JSAutoStructuredCloneBuffer& aCloneBuffer)
{
NS_ASSERTION(aObjectStore, "Null pointer!");
NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
@ -168,7 +168,7 @@ IDBCursor::Create(IDBRequest* aRequest,
cursor->mObjectStore = aObjectStore;
cursor->mType = OBJECTSTORE;
cursor->mKey = aKey;
cursor->mValue = aValue;
cursor->mCloneBuffer.swap(aCloneBuffer);
return cursor.forget();
}
@ -214,7 +214,7 @@ IDBCursor::Create(IDBRequest* aRequest,
const nsACString& aContinueToQuery,
const Key& aKey,
const Key& aObjectKey,
const nsAString& aValue)
JSAutoStructuredCloneBuffer& aCloneBuffer)
{
NS_ASSERTION(aIndex, "Null pointer!");
NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
@ -230,7 +230,7 @@ IDBCursor::Create(IDBRequest* aRequest,
cursor->mType = INDEXOBJECT;
cursor->mKey = aKey;
cursor->mObjectKey = aObjectKey;
cursor->mValue = aValue;
cursor->mCloneBuffer.swap(aCloneBuffer);
return cursor.forget();
}
@ -285,6 +285,7 @@ IDBCursor::~IDBCursor()
if (mValueRooted) {
NS_DROP_JS_OBJECTS(this, IDBCursor);
}
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
}
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor)
@ -411,17 +412,19 @@ IDBCursor::GetValue(JSContext* aCx,
}
if (!mHaveCachedValue) {
JSAutoRequest ar(aCx);
nsCOMPtr<nsIJSON> json(new nsJSON());
rv = json->DecodeToJSVal(mValue, aCx, &mCachedValue);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_DATA_CLONE_ERR);
if (!mValueRooted) {
NS_HOLD_JS_OBJECTS(this, IDBCursor);
mValueRooted = true;
}
JSAutoRequest ar(aCx);
if (!mCloneBuffer.read(&mCachedValue, aCx)) {
mCachedValue = JSVAL_VOID;
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
mCloneBuffer.clear(aCx);
mHaveCachedValue = true;
}
@ -668,7 +671,8 @@ ContinueHelper::GetSuccessResult(nsIWritableVariant* aResult)
// And set new values.
mCursor->mKey = mKey;
mCursor->mObjectKey = mObjectKey;
mCursor->mValue = mValue;
mCursor->mCloneBuffer.clear();
mCursor->mCloneBuffer.swap(mCloneBuffer);
mCursor->mContinueToKey = Key::UNSETKEY;
rv = aResult->SetAsISupports(mCursor);
@ -744,17 +748,9 @@ ContinueObjectStoreHelper::GatherResultsFromStatement(
NS_NOTREACHED("Bad SQLite type!");
}
#ifdef DEBUG
{
PRInt32 valueType;
NS_ASSERTION(NS_SUCCEEDED(aStatement->GetTypeOfIndex(1, &valueType)) &&
valueType == mozIStorageStatement::VALUE_TYPE_TEXT,
"Bad value type!");
}
#endif
rv = aStatement->GetString(1, mValue);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = IDBObjectStore::GetStructuredCloneDataFromStatement(aStatement, 1,
mCloneBuffer);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
@ -912,17 +908,9 @@ ContinueIndexObjectHelper::GatherResultsFromStatement(
NS_NOTREACHED("Bad SQLite type!");
}
#ifdef DEBUG
{
PRInt32 valueType;
NS_ASSERTION(NS_SUCCEEDED(aStatement->GetTypeOfIndex(2, &valueType)) &&
valueType == mozIStorageStatement::VALUE_TYPE_TEXT,
"Bad value type!");
}
#endif
rv = aStatement->GetString(2, mValue);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = IDBObjectStore::GetStructuredCloneDataFromStatement(aStatement, 2,
mCloneBuffer);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

View File

@ -86,7 +86,7 @@ public:
const nsACString& aContinueQuery,
const nsACString& aContinueToQuery,
const Key& aKey,
const nsAString& aValue);
JSAutoStructuredCloneBuffer& aCloneBuffer);
// For INDEX cursors.
static
@ -113,7 +113,7 @@ public:
const nsACString& aContinueToQuery,
const Key& aKey,
const Key& aObjectKey,
const nsAString& aValue);
JSAutoStructuredCloneBuffer& aCloneBuffer);
enum Type
{
@ -163,7 +163,7 @@ protected:
Key mKey;
Key mObjectKey;
nsString mValue;
JSAutoStructuredCloneBuffer mCloneBuffer;
Key mContinueToKey;
bool mHaveCachedValue;

View File

@ -355,9 +355,13 @@ IDBSuccessEvent::GetTransaction(nsIIDBTransaction** aTransaction)
GetSuccessEvent::~GetSuccessEvent()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (mValueRooted) {
NS_DROP_JS_OBJECTS(this, GetSuccessEvent);
}
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
}
nsresult
@ -381,26 +385,22 @@ NS_IMETHODIMP
GetSuccessEvent::GetResult(JSContext* aCx,
jsval* aResult)
{
if (mValue.IsVoid()) {
*aResult = JSVAL_VOID;
return NS_OK;
}
if (!mValueRooted) {
RootCachedValue();
nsString jsonValue = mValue;
mValue.Truncate();
if (mCloneBuffer.data()) {
JSAutoRequest ar(aCx);
JSAutoRequest ar(aCx);
if (!mCloneBuffer.read(&mCachedValue, aCx)) {
mCachedValue = JSVAL_VOID;
NS_ERROR("Failed to decode!");
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
nsCOMPtr<nsIJSON> json(new nsJSON());
nsresult rv = json->DecodeToJSVal(jsonValue, aCx, &mCachedValue);
if (NS_FAILED(rv)) {
mCachedValue = JSVAL_VOID;
NS_ERROR("Failed to decode!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
mCloneBuffer.clear();
}
else {
NS_ASSERTION(JSVAL_IS_VOID(mCachedValue), "Should be undefined!");
}
}
@ -449,55 +449,61 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(GetSuccessEvent)
NS_INTERFACE_MAP_END_INHERITING(IDBSuccessEvent)
GetAllSuccessEvent::~GetAllSuccessEvent()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
for (PRUint32 index = 0; index < mCloneBuffers.Length(); index++) {
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffers[index]);
}
}
NS_IMETHODIMP
GetAllSuccessEvent::GetResult(JSContext* aCx,
jsval* aResult)
{
if (!mValueRooted) {
RootCachedValue();
JSAutoRequest ar(aCx);
// Swap into a stack array so that we don't hang on to the strings if
// Swap into a stack array so that we don't hang on to the buffers if
// something fails.
nsTArray<nsString> values;
if (!mValues.SwapElements(values)) {
nsTArray<JSAutoStructuredCloneBuffer> cloneBuffers;
if (!mCloneBuffers.SwapElements(cloneBuffers)) {
NS_ERROR("Failed to swap elements!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
JSAutoRequest ar(aCx);
JSObject* array = JS_NewArrayObject(aCx, 0, NULL);
if (!array) {
NS_ERROR("Failed to make array!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
RootCachedValue();
mCachedValue = OBJECT_TO_JSVAL(array);
if (!values.IsEmpty()) {
if (!JS_SetArrayLength(aCx, array, jsuint(values.Length()))) {
if (!cloneBuffers.IsEmpty()) {
if (!JS_SetArrayLength(aCx, array, jsuint(cloneBuffers.Length()))) {
mCachedValue = JSVAL_VOID;
NS_ERROR("Failed to set array length!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
nsCOMPtr<nsIJSON> json(new nsJSON());
js::AutoValueRooter value(aCx);
jsint count = jsint(values.Length());
jsint count = jsint(cloneBuffers.Length());
for (jsint index = 0; index < count; index++) {
nsString jsonValue = values[index];
values[index].Truncate();
JSAutoStructuredCloneBuffer& buffer = cloneBuffers[index];
nsresult rv = json->DecodeToJSVal(jsonValue, aCx, value.jsval_addr());
if (NS_FAILED(rv)) {
jsval val;
if (!buffer.read(&val, aCx)) {
mCachedValue = JSVAL_VOID;
NS_ERROR("Failed to decode!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
if (!JS_SetElement(aCx, array, index, value.jsval_addr())) {
buffer.clear(aCx);
if (!JS_SetElement(aCx, array, index, &val)) {
mCachedValue = JSVAL_VOID;
NS_ERROR("Failed to set array element!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@ -515,10 +521,6 @@ GetAllKeySuccessEvent::GetResult(JSContext* aCx,
jsval* aResult)
{
if (!mValueRooted) {
RootCachedValue();
JSAutoRequest ar(aCx);
// Swap into a stack array so that we don't hang on to the strings if
// something fails.
nsTArray<Key> keys;
@ -527,12 +529,16 @@ GetAllKeySuccessEvent::GetResult(JSContext* aCx,
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
JSAutoRequest ar(aCx);
JSObject* array = JS_NewArrayObject(aCx, 0, NULL);
if (!array) {
NS_ERROR("Failed to make array!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
RootCachedValue();
mCachedValue = OBJECT_TO_JSVAL(array);
if (!keys.IsEmpty()) {
@ -550,11 +556,12 @@ GetAllKeySuccessEvent::GetResult(JSContext* aCx,
const Key& key = keys[index];
NS_ASSERTION(!key.IsUnset(), "Bad key!");
nsresult rv = IDBObjectStore::GetJSValFromKey(key, aCx, value.jsval_addr());
nsresult rv = IDBObjectStore::GetJSValFromKey(key, aCx,
value.jsval_addr());
if (NS_FAILED(rv)) {
mCachedValue = JSVAL_VOID;
NS_WARNING("Failed to get jsval for key!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
return rv;
}
if (!JS_SetElement(aCx, array, index, value.jsval_addr())) {

View File

@ -151,9 +151,15 @@ protected:
class GetSuccessEvent : public IDBSuccessEvent
{
public:
GetSuccessEvent(const nsAString& aValue)
: mValue(aValue),
mCachedValue(JSVAL_VOID),
GetSuccessEvent(JSAutoStructuredCloneBuffer& aCloneBuffer)
: mCachedValue(JSVAL_VOID),
mValueRooted(PR_FALSE)
{
mCloneBuffer.swap(aCloneBuffer);
}
GetSuccessEvent()
: mCachedValue(JSVAL_VOID),
mValueRooted(PR_FALSE)
{ }
@ -170,7 +176,7 @@ public:
IDBTransaction* aTransaction);
private:
nsString mValue;
JSAutoStructuredCloneBuffer mCloneBuffer;
protected:
void RootCachedValue();
@ -183,26 +189,26 @@ protected:
class GetAllSuccessEvent : public GetSuccessEvent
{
public:
GetAllSuccessEvent(nsTArray<nsString>& aValues)
: GetSuccessEvent(EmptyString())
GetAllSuccessEvent(nsTArray<JSAutoStructuredCloneBuffer>& aCloneBuffers)
{
if (!mValues.SwapElements(aValues)) {
if (!mCloneBuffers.SwapElements(aCloneBuffers)) {
NS_ERROR("Failed to swap elements!");
}
}
~GetAllSuccessEvent();
NS_IMETHOD GetResult(JSContext* aCx,
jsval* aResult);
private:
nsTArray<nsString> mValues;
nsTArray<JSAutoStructuredCloneBuffer> mCloneBuffers;
};
class GetAllKeySuccessEvent : public GetSuccessEvent
{
public:
GetAllKeySuccessEvent(nsTArray<Key>& aKeys)
: GetSuccessEvent(EmptyString())
{
if (!mKeys.SwapElements(aKeys)) {
NS_ERROR("Failed to swap elements!");

View File

@ -70,7 +70,7 @@
#define BAD_TLS_INDEX (PRUintn)-1
#define DB_SCHEMA_VERSION 3
#define DB_SCHEMA_VERSION 4
USING_INDEXEDDB_NAMESPACE
@ -143,6 +143,7 @@ private:
// Out-params.
nsTArray<nsAutoPtr<ObjectStoreInfo> > mObjectStores;
nsString mVersion;
PRUint32 mDataVersion;
nsString mDatabaseFilePath;
PRUint32 mDatabaseId;
PRInt64 mLastObjectStoreId;
@ -160,7 +161,8 @@ CreateTables(mozIStorageConnection* aDBConn)
nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE database ("
"name TEXT NOT NULL, "
"version TEXT DEFAULT NULL"
"version TEXT DEFAULT NULL, "
"dataVersion INTEGER NOT NULL"
");"
));
NS_ENSURE_SUCCESS(rv, rv);
@ -183,7 +185,7 @@ CreateTables(mozIStorageConnection* aDBConn)
"CREATE TABLE object_data ("
"id INTEGER, "
"object_store_id INTEGER NOT NULL, "
"data TEXT NOT NULL, "
"data BLOB NOT NULL, "
"key_value DEFAULT NULL, " // NONE affinity
"PRIMARY KEY (id), "
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
@ -203,7 +205,7 @@ CreateTables(mozIStorageConnection* aDBConn)
"CREATE TABLE ai_object_data ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"object_store_id INTEGER NOT NULL, "
"data TEXT NOT NULL, "
"data BLOB NOT NULL, "
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
"CASCADE"
");"
@ -328,14 +330,18 @@ CreateMetaData(mozIStorageConnection* aConnection,
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"INSERT OR REPLACE INTO database (name) "
"VALUES (:name)"
"INSERT OR REPLACE INTO database (name, dataVersion) "
"VALUES (:name, :dataVersion)"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), aName);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("dataVersion"),
JS_STRUCTURED_CLONE_VERSION);
NS_ENSURE_SUCCESS(rv, rv);
return stmt->Execute();
}
@ -549,7 +555,7 @@ IDBFactory::GetConnection(const nsAString& aDatabaseFilePath)
}
#endif
// Turn on foreign key constraints in debug builds to catch bugs!
// Turn on foreign key constraints!
rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"PRAGMA foreign_keys = ON;"
));
@ -726,7 +732,6 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
if (version.IsVoid()) {
version.SetIsVoid(PR_FALSE);
}
aVersion = version;
return NS_OK;
}
@ -884,6 +889,37 @@ OpenDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
getter_AddRefs(connection));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
// Get the data version.
nsCOMPtr<mozIStorageStatement> stmt;
rv = connection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT dataVersion "
"FROM database"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
PRBool hasResult;
rv = stmt->ExecuteStep(&hasResult);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (!hasResult) {
NS_ERROR("Database has no dataVersion!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
PRInt64 dataVersion;
rv = stmt->GetInt64(0, &dataVersion);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (dataVersion > JS_STRUCTURED_CLONE_VERSION) {
NS_ERROR("Bad data version!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
if (dataVersion < JS_STRUCTURED_CLONE_VERSION) {
// Need to upgrade the database, here, before returning to the main thread.
NS_NOTYETIMPLEMENTED("Implement me!");
}
mDatabaseId = HashString(mDatabaseFilePath);
NS_ASSERTION(mDatabaseId, "HashString gave us 0?!");

View File

@ -42,6 +42,7 @@
#include "IDBIndex.h"
#include "nsIIDBKeyRange.h"
#include "nsIJSContextStack.h"
#include "nsDOMClassInfo.h"
#include "nsEventDispatcher.h"
@ -97,8 +98,14 @@ public:
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
nsresult OnSuccess(nsIDOMEventTarget* aTarget);
void ReleaseMainThreadObjects()
{
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
GetKeyHelper::ReleaseMainThreadObjects();
}
protected:
nsString mValue;
JSAutoStructuredCloneBuffer mCloneBuffer;
};
class GetAllKeysHelper : public GetKeyHelper
@ -134,9 +141,17 @@ public:
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
nsresult OnSuccess(nsIDOMEventTarget* aTarget);
void ReleaseMainThreadObjects()
{
for (PRUint32 index = 0; index < mCloneBuffers.Length(); index++) {
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffers[index]);
}
GetKeyHelper::ReleaseMainThreadObjects();
}
protected:
const PRUint32 mLimit;
nsTArray<nsString> mValues;
nsTArray<JSAutoStructuredCloneBuffer> mCloneBuffers;
};
class OpenKeyCursorHelper : public AsyncConnectionHelper
@ -203,6 +218,7 @@ public:
void ReleaseMainThreadObjects()
{
mIndex = nsnull;
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
@ -218,7 +234,7 @@ private:
// Out-params.
Key mKey;
Key mObjectKey;
nsString mValue;
JSAutoStructuredCloneBuffer mCloneBuffer;
nsCString mContinueQuery;
nsCString mContinueToQuery;
Key mRangeKey;
@ -749,11 +765,9 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (hasResult) {
rv = stmt->GetString(0, mValue);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
else {
mValue.SetIsVoid(PR_TRUE);
rv = IDBObjectStore::GetStructuredCloneDataFromStatement(stmt, 0,
mCloneBuffer);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
@ -762,7 +776,7 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
nsresult
GetHelper::OnSuccess(nsIDOMEventTarget* aTarget)
{
nsRefPtr<GetSuccessEvent> event(new GetSuccessEvent(mValue));
nsRefPtr<GetSuccessEvent> event(new GetSuccessEvent(mCloneBuffer));
nsresult rv = event->Init(mRequest, mTransaction);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -901,7 +915,7 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
NS_ASSERTION(aConnection, "Passed a null connection!");
if (!mValues.SetCapacity(50)) {
if (!mCloneBuffers.SetCapacity(50)) {
NS_ERROR("Out of memory!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
@ -978,27 +992,18 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
PRBool hasResult;
while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
if (mValues.Capacity() == mValues.Length()) {
if (!mValues.SetCapacity(mValues.Capacity() * 2)) {
if (mCloneBuffers.Capacity() == mCloneBuffers.Length()) {
if (!mCloneBuffers.SetCapacity(mCloneBuffers.Capacity() * 2)) {
NS_ERROR("Out of memory!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
nsString* value = mValues.AppendElement();
NS_ASSERTION(value, "This shouldn't fail!");
JSAutoStructuredCloneBuffer* buffer = mCloneBuffers.AppendElement();
NS_ASSERTION(buffer, "This shouldn't fail!");
#ifdef DEBUG
{
PRInt32 keyType;
NS_ASSERTION(NS_SUCCEEDED(stmt->GetTypeOfIndex(0, &keyType)) &&
keyType == mozIStorageStatement::VALUE_TYPE_TEXT,
"Bad SQLITE type!");
}
#endif
rv = stmt->GetString(0, *value);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = IDBObjectStore::GetStructuredCloneDataFromStatement(stmt, 0, *buffer);
NS_ENSURE_SUCCESS(rv, rv);
}
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -1008,9 +1013,10 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
nsresult
GetAllHelper::OnSuccess(nsIDOMEventTarget* aTarget)
{
nsRefPtr<GetAllSuccessEvent> event(new GetAllSuccessEvent(mValues));
NS_ASSERTION(mCloneBuffers.Length() <= mLimit, "Too many results!");
NS_ASSERTION(mValues.IsEmpty(), "Should have swapped!");
nsRefPtr<GetAllSuccessEvent> event = new GetAllSuccessEvent(mCloneBuffers);
NS_ASSERTION(mCloneBuffers.IsEmpty(), "Should have swapped!");
nsresult rv = event->Init(mRequest, mTransaction);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -1421,17 +1427,9 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_NOTREACHED("Bad SQLite type!");
}
#ifdef DEBUG
{
PRInt32 valueType;
NS_ASSERTION(NS_SUCCEEDED(stmt->GetTypeOfIndex(2, &valueType)) &&
valueType == mozIStorageStatement::VALUE_TYPE_TEXT,
"Bad value type!");
}
#endif
rv = stmt->GetString(2, mValue);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = IDBObjectStore::GetStructuredCloneDataFromStatement(stmt, 2,
mCloneBuffer);
NS_ENSURE_SUCCESS(rv, rv);
/*
SELECT index_data.value, object_data.key_value, object_data.data
@ -1541,7 +1539,7 @@ OpenCursorHelper::GetSuccessResult(nsIWritableVariant* aResult)
nsRefPtr<IDBCursor> cursor =
IDBCursor::Create(mRequest, mTransaction, mIndex, mDirection, mRangeKey,
mContinueQuery, mContinueToQuery, mKey, mObjectKey,
mValue);
mCloneBuffer);
NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
aResult->SetAsISupports(cursor);

View File

@ -47,7 +47,6 @@
#include "nsContentUtils.h"
#include "nsDOMClassInfo.h"
#include "nsEventDispatcher.h"
#include "nsJSON.h"
#include "nsJSUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
@ -70,13 +69,14 @@ public:
AddHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
IDBObjectStore* aObjectStore,
const nsAString& aValue,
JSAutoStructuredCloneBuffer& aCloneBuffer,
const Key& aKey,
bool aOverwrite,
nsTArray<IndexUpdateInfo>& aIndexUpdateInfo)
: AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
mValue(aValue), mKey(aKey), mOverwrite(aOverwrite)
mKey(aKey), mOverwrite(aOverwrite)
{
mCloneBuffer.swap(aCloneBuffer);
mIndexUpdateInfo.SwapElements(aIndexUpdateInfo);
}
@ -86,6 +86,7 @@ public:
void ReleaseMainThreadObjects()
{
mObjectStore = nsnull;
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
@ -98,7 +99,7 @@ private:
nsRefPtr<IDBObjectStore> mObjectStore;
// These may change in the autoincrement case.
nsString mValue;
JSAutoStructuredCloneBuffer mCloneBuffer;
Key mKey;
const bool mOverwrite;
nsTArray<IndexUpdateInfo> mIndexUpdateInfo;
@ -121,6 +122,7 @@ public:
void ReleaseMainThreadObjects()
{
mObjectStore = nsnull;
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
@ -131,7 +133,7 @@ protected:
private:
// Out-params.
nsString mValue;
JSAutoStructuredCloneBuffer mCloneBuffer;
};
class DeleteHelper : public GetHelper
@ -193,6 +195,7 @@ public:
void ReleaseMainThreadObjects()
{
mObjectStore = nsnull;
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
@ -207,7 +210,7 @@ private:
// Out-params.
Key mKey;
nsString mValue;
JSAutoStructuredCloneBuffer mCloneBuffer;
nsCString mContinueQuery;
nsCString mContinueToQuery;
Key mRangeKey;
@ -289,6 +292,9 @@ public:
void ReleaseMainThreadObjects()
{
mObjectStore = nsnull;
for (PRUint32 index = 0; index < mCloneBuffers.Length(); index++) {
IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffers[index]);
}
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
@ -303,7 +309,7 @@ protected:
private:
// Out-params.
nsTArray<nsString> mValues;
nsTArray<JSAutoStructuredCloneBuffer> mCloneBuffers;
};
NS_STACK_CLASS
@ -498,12 +504,14 @@ IDBObjectStore::GetJSValFromKey(const Key& aKey,
// static
nsresult
IDBObjectStore::GetKeyPathValueFromJSON(const nsAString& aJSON,
const nsAString& aKeyPath,
JSContext** aCx,
Key& aValue)
IDBObjectStore::GetKeyPathValueFromStructuredData(const PRUint8* aData,
PRUint32 aDataLength,
const nsAString& aKeyPath,
JSContext** aCx,
Key& aValue)
{
NS_ASSERTION(!aJSON.IsEmpty(), "Empty JSON!");
NS_ASSERTION(aData, "Null pointer!");
NS_ASSERTION(aDataLength, "Empty data!");
NS_ASSERTION(!aKeyPath.IsEmpty(), "Empty keyPath!");
NS_ASSERTION(aCx, "Null pointer!");
@ -513,33 +521,34 @@ IDBObjectStore::GetKeyPathValueFromJSON(const nsAString& aJSON,
rv = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(aCx);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
JSContext*& cx = *aCx;
JSAutoRequest ar(*aCx);
JSAutoRequest ar(cx);
js::AutoValueRooter clone(*aCx);
jsval clone;
if (!JS_ReadStructuredClone(cx, reinterpret_cast<const uint64*>(aData),
aDataLength, JS_STRUCTURED_CLONE_VERSION,
&clone)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
nsCOMPtr<nsIJSON> json(new nsJSON());
rv = json->DecodeToJSVal(aJSON, *aCx, clone.jsval_addr());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (JSVAL_IS_PRIMITIVE(clone.jsval_value())) {
if (JSVAL_IS_PRIMITIVE(clone)) {
// This isn't an object, so just leave the key unset.
aValue = Key::UNSETKEY;
return NS_OK;
}
JSObject* obj = JSVAL_TO_OBJECT(clone.jsval_value());
JSObject* obj = JSVAL_TO_OBJECT(clone);
const jschar* keyPathChars =
reinterpret_cast<const jschar*>(aKeyPath.BeginReading());
const size_t keyPathLen = aKeyPath.Length();
js::AutoValueRooter value(*aCx);
JSBool ok = JS_GetUCProperty(*aCx, obj, keyPathChars, keyPathLen,
value.jsval_addr());
jsval keyVal;
JSBool ok = JS_GetUCProperty(cx, obj, keyPathChars, keyPathLen, &keyVal);
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = GetKeyFromJSVal(value.jsval_value(), aValue);
rv = GetKeyFromJSVal(keyVal, aValue);
if (NS_FAILED(rv)) {
// If the object doesn't have a value that we can use for our index then we
// leave it unset.
@ -722,6 +731,62 @@ IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
return NS_OK;
}
// static
nsresult
IDBObjectStore::GetStructuredCloneDataFromStatement(
mozIStorageStatement* aStatement,
PRUint32 aIndex,
JSAutoStructuredCloneBuffer& aBuffer)
{
#ifdef DEBUG
{
PRInt32 valueType;
NS_ASSERTION(NS_SUCCEEDED(aStatement->GetTypeOfIndex(aIndex, &valueType)) &&
valueType == mozIStorageStatement::VALUE_TYPE_BLOB,
"Bad value type!");
}
#endif
const PRUint8* data;
PRUint32 dataLength;
nsresult rv = aStatement->GetSharedBlob(aIndex, &dataLength, &data);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
JSContext* cx;
rv = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&cx);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
JSAutoRequest ar(cx);
uint64* newData = static_cast<uint64*>(JS_malloc(cx, dataLength));
NS_ENSURE_TRUE(newData, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
memcpy(newData, data, dataLength);
aBuffer.adopt(cx, newData, dataLength);
return NS_OK;
}
// static
void
IDBObjectStore::ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer)
{
if (aBuffer.data()) {
JSContext* cx;
if (NS_SUCCEEDED(nsContentUtils::ThreadJSContextStack()->
GetSafeJSContext(&cx))) {
JSAutoRequest ar(cx);
aBuffer.clear(cx);
}
else {
NS_WARNING("Couldn't get safe JSContext! Leaking data!");
uint64* data;
size_t length;
aBuffer.steal(&data, &length);
}
}
}
IDBObjectStore::IDBObjectStore()
: mId(LL_MININT),
mAutoIncrement(PR_FALSE)
@ -738,7 +803,7 @@ nsresult
IDBObjectStore::GetAddInfo(JSContext* aCx,
jsval aValue,
jsval aKeyVal,
nsString& aJSON,
JSAutoStructuredCloneBuffer& aCloneBuffer,
Key& aKey,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
{
@ -783,9 +848,9 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
rv = GetIndexUpdateInfo(info, aCx, aValue, aUpdateInfoArray);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsCOMPtr<nsIJSON> json(new nsJSON());
rv = json->EncodeFromJSVal(&aValue, aCx, aJSON);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_DATA_CLONE_ERR);
if (!aCloneBuffer.write(aCx, aValue)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
return NS_OK;
}
@ -810,11 +875,11 @@ IDBObjectStore::AddOrPut(const jsval& aValue,
jsval keyval = (aOptionalArgCount >= 1) ? aKey : JSVAL_VOID;
nsString jsonValue;
JSAutoStructuredCloneBuffer cloneBuffer;
Key key;
nsTArray<IndexUpdateInfo> updateInfo;
nsresult rv = GetAddInfo(aCx, aValue, keyval, jsonValue, key, updateInfo);
nsresult rv = GetAddInfo(aCx, aValue, keyval, cloneBuffer, key, updateInfo);
if (NS_FAILED(rv)) {
return rv;
}
@ -828,7 +893,7 @@ IDBObjectStore::AddOrPut(const jsval& aValue,
NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsRefPtr<AddHelper> helper =
new AddHelper(mTransaction, request, this, jsonValue, key, aOverwrite,
new AddHelper(mTransaction, request, this, cloneBuffer, key, aOverwrite,
updateInfo);
rv = helper->DispatchToTransactionPool();
@ -1505,12 +1570,20 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("data"), mValue);
const PRUint8* buffer = reinterpret_cast<const PRUint8*>(mCloneBuffer.data());
size_t bufferLength = mCloneBuffer.nbytes();
rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"), buffer, bufferLength);
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);
@ -1532,7 +1605,8 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
}
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("data"), mValue);
rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"), buffer,
bufferLength);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->Execute();
@ -1581,7 +1655,11 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
rv = stmt->BindInt64ByName(keyValue, mKey.IntValue());
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("data"), mValue);
buffer = reinterpret_cast<const PRUint8*>(mCloneBuffer.data());
bufferLength = mCloneBuffer.nbytes();
rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"), buffer,
bufferLength);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = stmt->Execute();
@ -1637,33 +1715,38 @@ AddHelper::ModifyValueForNewKey()
JSAutoRequest ar(cx);
js::AutoValueRooter clone(cx);
jsval clone;
if (!mCloneBuffer.read(&clone, cx)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
nsCOMPtr<nsIJSON> json(new nsJSON());
rv = json->DecodeToJSVal(mValue, cx, clone.jsval_addr());
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(!JSVAL_IS_PRIMITIVE(clone), "We should have an object!");
JSObject* obj = JSVAL_TO_OBJECT(clone.jsval_value());
JSObject* obj = JSVAL_TO_OBJECT(clone);
JSBool ok;
js::AutoValueRooter key(cx);
const jschar* keyPathChars = reinterpret_cast<const jschar*>(keyPath.get());
const size_t keyPathLen = keyPath.Length();
#ifdef DEBUG
ok = JS_GetUCProperty(cx, obj, keyPathChars, keyPathLen, key.jsval_addr());
NS_ASSERTION(ok && JSVAL_IS_VOID(key.jsval_value()), "Already has a key prop!");
{
jsval prop;
ok = JS_GetUCProperty(cx, obj, keyPathChars, keyPathLen, &prop);
NS_ASSERTION(ok && JSVAL_IS_VOID(prop), "Already has a key prop!");
}
#endif
ok = JS_NewNumberValue(cx, mKey.IntValue(), key.jsval_addr());
jsval key;
ok = JS_NewNumberValue(cx, mKey.IntValue(), &key);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
ok = JS_DefineUCProperty(cx, obj, keyPathChars, keyPathLen, key.jsval_value(),
nsnull, nsnull, JSPROP_ENUMERATE);
ok = JS_DefineUCProperty(cx, obj, keyPathChars, keyPathLen, key, nsnull,
nsnull, JSPROP_ENUMERATE);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
rv = json->EncodeFromJSVal(clone.jsval_addr(), cx, mValue);
NS_ENSURE_SUCCESS(rv, rv);
if (!mCloneBuffer.write(cx, OBJECT_TO_JSVAL(obj))) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
return NS_OK;
}
@ -1704,12 +1787,9 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (hasResult) {
// Set the value based on results.
rv = stmt->GetString(0, mValue);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
else {
mValue.SetIsVoid(PR_TRUE);
rv = IDBObjectStore::GetStructuredCloneDataFromStatement(stmt, 0,
mCloneBuffer);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
@ -1718,12 +1798,12 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
nsresult
GetHelper::OnSuccess(nsIDOMEventTarget* aTarget)
{
if (mValue.IsVoid()) {
if (!mCloneBuffer.data()) {
// Default is to have an undefined result.
return AsyncConnectionHelper::OnSuccess(aTarget);
}
nsRefPtr<GetSuccessEvent> event(new GetSuccessEvent(mValue));
nsRefPtr<GetSuccessEvent> event(new GetSuccessEvent(mCloneBuffer));
nsresult rv = event->Init(mRequest, mTransaction);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -1932,17 +2012,9 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_NOTREACHED("Bad SQLite type!");
}
#ifdef DEBUG
{
PRInt32 valueType;
NS_ASSERTION(NS_SUCCEEDED(stmt->GetTypeOfIndex(1, &valueType)) &&
valueType == mozIStorageStatement::VALUE_TYPE_TEXT,
"Bad value type!");
}
#endif
rv = stmt->GetString(1, mValue);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = IDBObjectStore::GetStructuredCloneDataFromStatement(stmt, 1,
mCloneBuffer);
NS_ENSURE_SUCCESS(rv, rv);
// Now we need to make the query to get the next match.
keyRangeClause.Truncate();
@ -2011,7 +2083,7 @@ OpenCursorHelper::GetSuccessResult(nsIWritableVariant* aResult)
nsRefPtr<IDBCursor> cursor =
IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection,
mRangeKey, mContinueQuery, mContinueToQuery, mKey,
mValue);
mCloneBuffer);
NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
aResult->SetAsISupports(cursor);
@ -2127,14 +2199,16 @@ CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
nsString json;
rv = stmt->GetString(1, json);
const PRUint8* data;
PRUint32 dataLength;
rv = stmt->GetSharedBlob(1, &dataLength, &data);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
Key key;
JSContext* cx = nsnull;
rv = IDBObjectStore::GetKeyPathValueFromJSON(json, mIndex->KeyPath(), &cx,
key);
rv = IDBObjectStore::GetKeyPathValueFromStructuredData(data, dataLength,
mIndex->KeyPath(),
&cx, key);
NS_ENSURE_SUCCESS(rv, rv);
NS_NAMED_LITERAL_CSTRING(value, "value");
@ -2267,7 +2341,7 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
keyRangeClause + NS_LITERAL_CSTRING(" ORDER BY ") +
keyColumn + NS_LITERAL_CSTRING(" ASC") + limitClause;
if (!mValues.SetCapacity(50)) {
if (!mCloneBuffers.SetCapacity(50)) {
NS_ERROR("Out of memory!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
@ -2308,18 +2382,18 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
PRBool hasResult;
while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
if (mValues.Capacity() == mValues.Length()) {
if (!mValues.SetCapacity(mValues.Capacity() * 2)) {
if (mCloneBuffers.Capacity() == mCloneBuffers.Length()) {
if (!mCloneBuffers.SetCapacity(mCloneBuffers.Capacity() * 2)) {
NS_ERROR("Out of memory!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
nsString* value = mValues.AppendElement();
NS_ASSERTION(value, "Shouldn't fail if SetCapacity succeeded!");
JSAutoStructuredCloneBuffer* buffer = mCloneBuffers.AppendElement();
NS_ASSERTION(buffer, "Shouldn't fail if SetCapacity succeeded!");
rv = stmt->GetString(0, *value);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
rv = IDBObjectStore::GetStructuredCloneDataFromStatement(stmt, 0, *buffer);
NS_ENSURE_SUCCESS(rv, rv);
}
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -2329,11 +2403,10 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
nsresult
GetAllHelper::OnSuccess(nsIDOMEventTarget* aTarget)
{
NS_ASSERTION(mValues.Length() <= mLimit, "Too many results!");
NS_ASSERTION(mCloneBuffers.Length() <= mLimit, "Too many results!");
nsRefPtr<GetAllSuccessEvent> event(new GetAllSuccessEvent(mValues));
NS_ASSERTION(mValues.IsEmpty(), "Should have swapped!");
nsRefPtr<GetAllSuccessEvent> event = new GetAllSuccessEvent(mCloneBuffers);
NS_ASSERTION(mCloneBuffers.IsEmpty(), "Should have swapped!");
nsresult rv = event->Init(mRequest, mTransaction);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);

View File

@ -86,10 +86,11 @@ public:
jsval* aKeyVal);
static nsresult
GetKeyPathValueFromJSON(const nsAString& aJSON,
const nsAString& aKeyPath,
JSContext** aCx,
Key& aValue);
GetKeyPathValueFromStructuredData(const PRUint8* aData,
PRUint32 aDataLength,
const nsAString& aKeyPath,
JSContext** aCx,
Key& aValue);
static nsresult
GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
@ -106,6 +107,14 @@ public:
PRInt64 aObjectDataId,
const nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
static nsresult
GetStructuredCloneDataFromStatement(mozIStorageStatement* aStatement,
PRUint32 aIndex,
JSAutoStructuredCloneBuffer& aBuffer);
static void
ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer);
const nsString& Name() const
{
return mName;
@ -144,7 +153,7 @@ protected:
nsresult GetAddInfo(JSContext* aCx,
jsval aValue,
jsval aKeyVal,
nsString& aJSON,
JSAutoStructuredCloneBuffer& aCloneBuffer,
Key& aKey,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
@ -166,6 +175,7 @@ private:
nsString mKeyPath;
PRBool mAutoIncrement;
PRUint32 mDatabaseId;
PRUint32 mStructuredCloneVersion;
nsTArray<nsRefPtr<IDBIndex> > mCreatedIndexes;

View File

@ -1598,9 +1598,9 @@ nsDOMWorker::PostMessageInternal(PRBool aToInner)
JSAutoRequest ar(cx);
JSAutoStructuredCloneBuffer buffer(cx);
JSAutoStructuredCloneBuffer buffer;
if (!buffer.write(argv[0])) {
if (!buffer.write(cx, argv[0])) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}

View File

@ -310,8 +310,8 @@ nsDOMWorkerMessageEvent::GetData(nsAString& aData)
NS_ENSURE_SUCCESS(rv, rv);
JSAutoRequest ar(cx);
JSAutoStructuredCloneBuffer buffer(cx);
buffer.adopt(mData, mDataLen);
JSAutoStructuredCloneBuffer buffer;
buffer.adopt(cx, mData, mDataLen);
mData = nsnull;
mDataLen = 0;

View File

@ -5499,8 +5499,8 @@ JS_WriteStructuredClone(JSContext *cx, jsval v, uint64 **bufp, size_t *nbytesp)
JS_PUBLIC_API(JSBool)
JS_StructuredClone(JSContext *cx, jsval v, jsval *vp)
{
JSAutoStructuredCloneBuffer buf(cx);
return buf.write(v) && buf.read(vp);
JSAutoStructuredCloneBuffer buf;
return buf.write(cx, v) && buf.read(vp);
}
JS_PUBLIC_API(void)

View File

@ -3220,25 +3220,31 @@ JS_StructuredClone(JSContext *cx, jsval v, jsval *vp);
#ifdef __cplusplus
/* RAII sugar for JS_WriteStructuredClone. */
class JSAutoStructuredCloneBuffer {
JSContext *cx;
JSContext *cx_;
uint64 *data_;
size_t nbytes_;
uint32 version_;
public:
explicit JSAutoStructuredCloneBuffer(JSContext *cx)
: cx(cx), data_(NULL), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION) {}
JSAutoStructuredCloneBuffer()
: cx_(NULL), data_(NULL), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION) {}
~JSAutoStructuredCloneBuffer() { clear(); }
JSContext *cx() const { return cx_; }
uint64 *data() const { return data_; }
size_t nbytes() const { return nbytes_; }
void clear() {
void clear(JSContext *cx=NULL) {
if (data_) {
if (!cx)
cx = cx_;
JS_ASSERT(cx);
JS_free(cx, data_);
cx_ = NULL;
data_ = NULL;
nbytes_ = 0;
version_ = 0;
}
}
@ -3246,8 +3252,10 @@ class JSAutoStructuredCloneBuffer {
* Adopt some memory. It will be automatically freed by the destructor.
* data must have been allocated using JS_malloc.
*/
void adopt(uint64 *data, size_t nbytes, uint32 version=JS_STRUCTURED_CLONE_VERSION) {
clear();
void adopt(JSContext *cx, uint64 *data, size_t nbytes,
uint32 version=JS_STRUCTURED_CLONE_VERSION) {
clear(cx);
cx_ = cx;
data_ = data;
nbytes_ = nbytes;
version_ = version;
@ -3257,27 +3265,65 @@ class JSAutoStructuredCloneBuffer {
* Remove the buffer so that it will not be automatically freed.
* After this, the caller is responsible for calling JS_free(*datap).
*/
void steal(uint64 **datap, size_t *nbytesp) {
void steal(uint64 **datap, size_t *nbytesp, JSContext **cxp=NULL,
uint32 *versionp=NULL) {
*datap = data_;
*nbytesp = nbytes_;
if (cxp)
*cxp = cx_;
if (versionp)
*versionp = version_;
cx_ = NULL;
data_ = NULL;
nbytes_ = 0;
version_ = 0;
}
bool read(jsval *vp) const {
bool read(jsval *vp, JSContext *cx=NULL) const {
if (!cx)
cx = cx_;
JS_ASSERT(cx);
JS_ASSERT(data_);
return !!JS_ReadStructuredClone(cx, data_, nbytes_, version_, vp);
}
bool write(jsval v) {
clear();
bool write(JSContext *cx, jsval v) {
clear(cx);
cx_ = cx;
bool ok = !!JS_WriteStructuredClone(cx, v, &data_, &nbytes_);
if (!ok) {
data_ = NULL;
nbytes_ = 0;
version_ = JS_STRUCTURED_CLONE_VERSION;
}
return ok;
}
/**
* Swap ownership with another JSAutoStructuredCloneBuffer.
*/
void swap(JSAutoStructuredCloneBuffer &other) {
JSContext *cx = other.cx_;
uint64 *data = other.data_;
size_t nbytes = other.nbytes_;
uint32 version = other.version_;
other.cx_ = this->cx_;
other.data_ = this->data_;
other.nbytes_ = this->nbytes_;
other.version_ = this->version_;
this->cx_ = cx;
this->data_ = data;
this->nbytes_ = nbytes;
this->version_ = version;
}
private:
/* Copy and assignment are not supported. */
JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer &other);
JSAutoStructuredCloneBuffer &operator=(const JSAutoStructuredCloneBuffer &other);
};
#endif