mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 613083 - 'IndexedDB: Switch serialization format from JSON to structured clone bytestream'. r=sicking, a=blocking.
This commit is contained in:
parent
81a511c1aa
commit
bb620ec2bf
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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())) {
|
||||
|
@ -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!");
|
||||
|
@ -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?!");
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user