mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Back out patches due to test failures. rev 1b9ca56d4aab and a few more.
This commit is contained in:
parent
001a640116
commit
7404adaebb
@ -1641,7 +1641,6 @@ jsid nsDOMClassInfo::sURL_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sKeyPath_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sAutoIncrement_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sUnique_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sMultiEntry_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sOnload_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sOnerror_id = JSID_VOID;
|
||||
|
||||
@ -1905,7 +1904,6 @@ nsDOMClassInfo::DefineStaticJSVals(JSContext *cx)
|
||||
SET_JSID_TO_STRING(sKeyPath_id, cx, "keyPath");
|
||||
SET_JSID_TO_STRING(sAutoIncrement_id, cx, "autoIncrement");
|
||||
SET_JSID_TO_STRING(sUnique_id, cx, "unique");
|
||||
SET_JSID_TO_STRING(sMultiEntry_id, cx, "multiEntry");
|
||||
SET_JSID_TO_STRING(sOnload_id, cx, "onload");
|
||||
SET_JSID_TO_STRING(sOnerror_id, cx, "onerror");
|
||||
|
||||
@ -4904,7 +4902,6 @@ nsDOMClassInfo::ShutDown()
|
||||
sKeyPath_id = JSID_VOID;
|
||||
sAutoIncrement_id = JSID_VOID;
|
||||
sUnique_id = JSID_VOID;
|
||||
sMultiEntry_id = JSID_VOID;
|
||||
sOnload_id = JSID_VOID;
|
||||
sOnerror_id = JSID_VOID;
|
||||
|
||||
|
@ -295,7 +295,6 @@ public:
|
||||
static jsid sKeyPath_id;
|
||||
static jsid sAutoIncrement_id;
|
||||
static jsid sUnique_id;
|
||||
static jsid sMultiEntry_id;
|
||||
static jsid sOnload_id;
|
||||
static jsid sOnerror_id;
|
||||
|
||||
|
@ -97,8 +97,7 @@ DatabaseInfo::~DatabaseInfo()
|
||||
IndexInfo::IndexInfo()
|
||||
: id(LL_MININT),
|
||||
unique(false),
|
||||
autoIncrement(false),
|
||||
multiEntry(false)
|
||||
autoIncrement(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(IndexInfo);
|
||||
}
|
||||
@ -108,8 +107,7 @@ IndexInfo::IndexInfo(const IndexInfo& aOther)
|
||||
name(aOther.name),
|
||||
keyPath(aOther.keyPath),
|
||||
unique(aOther.unique),
|
||||
autoIncrement(aOther.autoIncrement),
|
||||
multiEntry(aOther.multiEntry)
|
||||
autoIncrement(aOther.autoIncrement)
|
||||
{
|
||||
MOZ_COUNT_CTOR(IndexInfo);
|
||||
}
|
||||
|
@ -121,7 +121,6 @@ struct IndexInfo
|
||||
nsString keyPath;
|
||||
bool unique;
|
||||
bool autoIncrement;
|
||||
bool multiEntry;
|
||||
};
|
||||
|
||||
struct ObjectStoreInfo
|
||||
@ -150,8 +149,7 @@ struct IndexUpdateInfo
|
||||
~IndexUpdateInfo();
|
||||
#endif
|
||||
|
||||
PRInt64 indexId;
|
||||
bool indexUnique;
|
||||
IndexInfo info;
|
||||
Key value;
|
||||
};
|
||||
|
||||
|
@ -464,8 +464,11 @@ IDBDatabase::CreateObjectStore(const nsAString& aName,
|
||||
|
||||
DatabaseInfo* databaseInfo = Info();
|
||||
|
||||
if (databaseInfo->ContainsStoreName(aName)) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
|
||||
}
|
||||
|
||||
nsString keyPath;
|
||||
keyPath.SetIsVoid(true);
|
||||
bool autoIncrement = false;
|
||||
|
||||
if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
|
||||
@ -511,17 +514,8 @@ IDBDatabase::CreateObjectStore(const nsAString& aName,
|
||||
autoIncrement = !!boolVal;
|
||||
}
|
||||
|
||||
if (databaseInfo->ContainsStoreName(aName)) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
|
||||
}
|
||||
|
||||
if (!keyPath.IsVoid()) {
|
||||
if (keyPath.IsEmpty() && autoIncrement) {
|
||||
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
}
|
||||
if (!IDBObjectStore::IsValidKeyPath(aCx, keyPath)) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
if (!IDBObjectStore::IsValidKeyPath(aCx, keyPath)) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
nsAutoPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo());
|
||||
@ -581,9 +575,6 @@ IDBDatabase::DeleteObjectStore(const nsAString& aName)
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
info->RemoveObjectStore(aName);
|
||||
|
||||
transaction->ReleaseCachedObjectStore(aName);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -809,8 +800,8 @@ CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
{
|
||||
nsCOMPtr<mozIStorageStatement> stmt =
|
||||
mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
|
||||
"INSERT INTO object_store (id, auto_increment, name, key_path) "
|
||||
"VALUES (:id, :auto_increment, :name, :key_path)"
|
||||
"INSERT INTO object_store (id, name, key_path, auto_increment) "
|
||||
"VALUES (:id, :name, :key_path, :auto_increment)"
|
||||
));
|
||||
NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
@ -820,17 +811,15 @@ CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
mObjectStore->Id());
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("auto_increment"),
|
||||
mObjectStore->IsAutoIncrement() ? 1 : 0);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mObjectStore->Name());
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = mObjectStore->HasKeyPath() ?
|
||||
stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
|
||||
mObjectStore->KeyPath()) :
|
||||
stmt->BindNullByName(NS_LITERAL_CSTRING("key_path"));
|
||||
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
|
||||
mObjectStore->KeyPath());
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("auto_increment"),
|
||||
mObjectStore->IsAutoIncrement() ? 1 : 0);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = stmt->Execute();
|
||||
|
@ -247,18 +247,8 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
|
||||
|
||||
info->id = stmt->AsInt64(1);
|
||||
|
||||
PRInt32 columnType;
|
||||
nsresult rv = stmt->GetTypeOfIndex(2, &columnType);
|
||||
rv = stmt->GetString(2, info->keyPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (columnType == mozIStorageStatement::VALUE_TYPE_NULL) {
|
||||
info->keyPath.SetIsVoid(true);
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(columnType == mozIStorageStatement::VALUE_TYPE_TEXT,
|
||||
"Should be a string");
|
||||
rv = stmt->GetString(2, info->keyPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
info->autoIncrement = !!stmt->AsInt32(3);
|
||||
info->databaseId = aDatabaseId;
|
||||
@ -273,7 +263,7 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
|
||||
|
||||
// Load index information
|
||||
rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT object_store_id, id, name, key_path, unique_index, multientry, "
|
||||
"SELECT object_store_id, id, name, key_path, unique_index, "
|
||||
"object_store_autoincrement "
|
||||
"FROM object_store_index"
|
||||
), getter_AddRefs(stmt));
|
||||
@ -307,8 +297,7 @@ IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
indexInfo->unique = !!stmt->AsInt32(4);
|
||||
indexInfo->multiEntry = !!stmt->AsInt32(5);
|
||||
indexInfo->autoIncrement = !!stmt->AsInt32(6);
|
||||
indexInfo->autoIncrement = !!stmt->AsInt32(5);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -318,7 +318,6 @@ IDBIndex::Create(IDBObjectStore* aObjectStore,
|
||||
index->mName = aIndexInfo->name;
|
||||
index->mKeyPath = aIndexInfo->keyPath;
|
||||
index->mUnique = aIndexInfo->unique;
|
||||
index->mMultiEntry = aIndexInfo->multiEntry;
|
||||
index->mAutoIncrement = aIndexInfo->autoIncrement;
|
||||
|
||||
return index.forget();
|
||||
@ -397,15 +396,6 @@ IDBIndex::GetUnique(bool* aUnique)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IDBIndex::GetMultiEntry(bool* aMultiEntry)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
*aMultiEntry = mMultiEntry;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IDBIndex::GetObjectStore(nsIIDBObjectStore** aObjectStore)
|
||||
{
|
||||
|
@ -87,11 +87,6 @@ public:
|
||||
return mUnique;
|
||||
}
|
||||
|
||||
bool IsMultiEntry() const
|
||||
{
|
||||
return mMultiEntry;
|
||||
}
|
||||
|
||||
bool IsAutoIncrement() const
|
||||
{
|
||||
return mAutoIncrement;
|
||||
@ -115,7 +110,6 @@ private:
|
||||
nsString mName;
|
||||
nsString mKeyPath;
|
||||
bool mUnique;
|
||||
bool mMultiEntry;
|
||||
bool mAutoIncrement;
|
||||
};
|
||||
|
||||
|
@ -97,6 +97,9 @@ public:
|
||||
AsyncConnectionHelper::ReleaseMainThreadObjects();
|
||||
}
|
||||
|
||||
nsresult UpdateIndexes(mozIStorageConnection* aConnection,
|
||||
PRInt64 aObjectDataId);
|
||||
|
||||
private:
|
||||
// In-params.
|
||||
nsRefPtr<IDBObjectStore> mObjectStore;
|
||||
@ -419,13 +422,15 @@ typedef nsCharSeparatedTokenizerTemplate<IgnoreWhitespace> KeyPathTokenizer;
|
||||
|
||||
inline
|
||||
nsresult
|
||||
GetJSValFromKeyPath(JSContext* aCx,
|
||||
jsval aVal,
|
||||
const nsAString& aKeyPath,
|
||||
jsval& aKey)
|
||||
GetKeyFromValue(JSContext* aCx,
|
||||
jsval aVal,
|
||||
const nsAString& aKeyPath,
|
||||
Key& aKey)
|
||||
{
|
||||
NS_ASSERTION(aCx, "Null pointer!");
|
||||
// aVal can be primitive iff the key path is empty.
|
||||
NS_ASSERTION(!JSVAL_IS_PRIMITIVE(aVal) || aKeyPath.IsEmpty(),
|
||||
"Why are we here!?");
|
||||
NS_ASSERTION(IDBObjectStore::IsValidKeyPath(aCx, aKeyPath),
|
||||
"This will explode!");
|
||||
|
||||
@ -433,39 +438,25 @@ GetJSValFromKeyPath(JSContext* aCx,
|
||||
|
||||
jsval intermediate = aVal;
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
const nsDependentSubstring& token = tokenizer.nextToken();
|
||||
nsString token(tokenizer.nextToken());
|
||||
|
||||
NS_ASSERTION(!token.IsEmpty(), "Should be a valid keypath");
|
||||
if (!token.Length()) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
const jschar* keyPathChars = token.BeginReading();
|
||||
const jschar* keyPathChars = token.get();
|
||||
const size_t keyPathLen = token.Length();
|
||||
|
||||
if (JSVAL_IS_PRIMITIVE(intermediate)) {
|
||||
intermediate = JSVAL_VOID;
|
||||
break;
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
JSBool ok = JS_GetUCProperty(aCx, JSVAL_TO_OBJECT(intermediate),
|
||||
keyPathChars, keyPathLen, &intermediate);
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
}
|
||||
|
||||
aKey = intermediate;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
inline
|
||||
nsresult
|
||||
GetKeyFromValue(JSContext* aCx,
|
||||
jsval aVal,
|
||||
const nsAString& aKeyPath,
|
||||
Key& aKey)
|
||||
{
|
||||
jsval key;
|
||||
nsresult rv = GetJSValFromKeyPath(aCx, aVal, aKeyPath, key);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (NS_FAILED(aKey.SetFromJSVal(aCx, key))) {
|
||||
if (NS_FAILED(aKey.SetFromJSVal(aCx, intermediate))) {
|
||||
aKey.Unset();
|
||||
}
|
||||
|
||||
@ -583,63 +574,82 @@ IDBObjectStore::IsValidKeyPath(JSContext* aCx,
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IDBObjectStore::AppendIndexUpdateInfo(PRInt64 aIndexID,
|
||||
const nsAString& aKeyPath,
|
||||
bool aUnique,
|
||||
bool aMultiEntry,
|
||||
JSContext* aCx,
|
||||
jsval aObject,
|
||||
nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
|
||||
IDBObjectStore::GetKeyPathValueFromStructuredData(const PRUint8* aData,
|
||||
PRUint32 aDataLength,
|
||||
const nsAString& aKeyPath,
|
||||
JSContext* aCx,
|
||||
Key& aValue)
|
||||
{
|
||||
jsval key;
|
||||
nsresult rv = GetJSValFromKeyPath(aCx, aObject, aKeyPath, key);
|
||||
NS_ASSERTION(aData, "Null pointer!");
|
||||
NS_ASSERTION(aDataLength, "Empty data!");
|
||||
NS_ASSERTION(aCx, "Null pointer!");
|
||||
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
jsval clone;
|
||||
if (!JS_ReadStructuredClone(aCx, reinterpret_cast<const uint64*>(aData),
|
||||
aDataLength, JS_STRUCTURED_CLONE_VERSION,
|
||||
&clone, NULL, NULL)) {
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
|
||||
if (JSVAL_IS_PRIMITIVE(clone) && !aKeyPath.IsEmpty()) {
|
||||
// This isn't an object, so just leave the key unset.
|
||||
aValue.Unset();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = GetKeyFromValue(aCx, clone, aKeyPath, aValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aMultiEntry && !JSVAL_IS_PRIMITIVE(key) &&
|
||||
JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(key))) {
|
||||
JSObject* array = JSVAL_TO_OBJECT(key);
|
||||
jsuint arrayLength;
|
||||
if (!JS_GetArrayLength(aCx, array, &arrayLength)) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
IDBObjectStore::GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
|
||||
JSContext* aCx,
|
||||
jsval aObject,
|
||||
nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
|
||||
{
|
||||
JSObject* cloneObj = nsnull;
|
||||
|
||||
PRUint32 count = aObjectStoreInfo->indexes.Length();
|
||||
if (count) {
|
||||
if (!aUpdateInfoArray.SetCapacity(count)) {
|
||||
NS_ERROR("Out of memory!");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (jsuint arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
|
||||
jsval arrayItem;
|
||||
if (!JS_GetElement(aCx, array, arrayIndex, &arrayItem)) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
for (PRUint32 indexesIndex = 0; indexesIndex < count; indexesIndex++) {
|
||||
const IndexInfo& indexInfo = aObjectStoreInfo->indexes[indexesIndex];
|
||||
|
||||
if (JSVAL_IS_PRIMITIVE(aObject) && !indexInfo.keyPath.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Key value;
|
||||
if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) ||
|
||||
value.IsUnset()) {
|
||||
nsresult rv = GetKeyFromValue(aCx, aObject, indexInfo.keyPath, value);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (value.IsUnset()) {
|
||||
// Not a value we can do anything with, ignore it.
|
||||
continue;
|
||||
}
|
||||
|
||||
IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
|
||||
updateInfo->indexId = aIndexID;
|
||||
updateInfo->indexUnique = aUnique;
|
||||
updateInfo->info = indexInfo;
|
||||
updateInfo->value = value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Key value;
|
||||
if (NS_FAILED(value.SetFromJSVal(aCx, key)) ||
|
||||
value.IsUnset()) {
|
||||
// Not a value we can do anything with, ignore it.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
|
||||
updateInfo->indexId = aIndexID;
|
||||
updateInfo->indexUnique = aUnique;
|
||||
updateInfo->value = value;
|
||||
aUpdateInfoArray.Clear();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
/* static */
|
||||
nsresult
|
||||
IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
|
||||
PRInt64 aObjectStoreId,
|
||||
@ -649,13 +659,21 @@ IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
|
||||
PRInt64 aObjectDataId,
|
||||
const nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
|
||||
{
|
||||
NS_ASSERTION(!aAutoIncrement || aObjectDataId != LL_MININT,
|
||||
"Bad objectData id!");
|
||||
#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();
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
nsresult rv;
|
||||
|
||||
if (aObjectDataId == LL_MININT) {
|
||||
if (!aAutoIncrement) {
|
||||
stmt = aTransaction->GetCachedStatement(
|
||||
"SELECT id "
|
||||
"FROM object_data "
|
||||
@ -717,24 +735,25 @@ IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
PRUint32 infoCount = aUpdateInfoArray.Length();
|
||||
for (PRUint32 i = 0; i < infoCount; i++) {
|
||||
const IndexUpdateInfo& updateInfo = aUpdateInfoArray[i];
|
||||
for (PRUint32 indexIndex = 0; indexIndex < indexCount; indexIndex++) {
|
||||
const IndexUpdateInfo& updateInfo = aUpdateInfoArray[indexIndex];
|
||||
|
||||
NS_ASSERTION(updateInfo.info.autoIncrement == aAutoIncrement, "Huh?!");
|
||||
|
||||
// Insert new values.
|
||||
stmt = aTransaction->IndexDataInsertStatement(aAutoIncrement,
|
||||
updateInfo.indexUnique);
|
||||
updateInfo.info.unique);
|
||||
NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE);
|
||||
|
||||
mozStorageStatementScoper scoper4(stmt);
|
||||
|
||||
rv = stmt->BindInt64ByName(indexId, updateInfo.indexId);
|
||||
rv = stmt->BindInt64ByName(indexId, updateInfo.info.id);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = stmt->BindInt64ByName(objectDataId, aObjectDataId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!aAutoIncrement) {
|
||||
if (!updateInfo.info.autoIncrement) {
|
||||
rv = aObjectStoreKey.BindToStatement(stmt, objectDataKey);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
@ -743,23 +762,6 @@ IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = stmt->Execute();
|
||||
if (rv == NS_ERROR_STORAGE_CONSTRAINT && updateInfo.indexUnique) {
|
||||
// If we're inserting multiple entries for the same unique index, then
|
||||
// we might have failed to insert due to colliding with another entry for
|
||||
// the same index in which case we should ignore it.
|
||||
|
||||
for (PRInt32 j = (PRInt32)i - 1;
|
||||
j >= 0 && aUpdateInfoArray[j].indexId == updateInfo.indexId;
|
||||
--j) {
|
||||
if (updateInfo.value == aUpdateInfoArray[j].value) {
|
||||
// We found a key with the same value for the same index. So we
|
||||
// must have had a collision with a value we just inserted.
|
||||
rv = NS_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@ -904,20 +906,24 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
|
||||
|
||||
// Return DATA_ERR if a key was passed in and this objectStore uses inline
|
||||
// keys.
|
||||
if (!JSVAL_IS_VOID(aKeyVal) && HasKeyPath()) {
|
||||
if (!JSVAL_IS_VOID(aKeyVal) && !mKeyPath.IsEmpty()) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
|
||||
}
|
||||
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
if (!HasKeyPath()) {
|
||||
if (mKeyPath.IsEmpty()) {
|
||||
// Out-of-line keys must be passed in.
|
||||
rv = aKey.SetFromJSVal(aCx, aKeyVal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else if (!mAutoIncrement) {
|
||||
else {
|
||||
// Inline keys live on the object. Make sure that the value passed in is an
|
||||
// object.
|
||||
if (JSVAL_IS_PRIMITIVE(aValue)) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
|
||||
}
|
||||
|
||||
rv = GetKeyFromValue(aCx, aValue, mKeyPath, aKey);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
@ -934,114 +940,28 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
|
||||
NS_ERROR("This should never fail!");
|
||||
}
|
||||
|
||||
PRUint32 count = info->indexes.Length();
|
||||
aUpdateInfoArray.SetCapacity(count); // Pretty good estimate
|
||||
for (PRUint32 indexesIndex = 0; indexesIndex < count; indexesIndex++) {
|
||||
const IndexInfo& indexInfo = info->indexes[indexesIndex];
|
||||
rv = GetIndexUpdateInfo(info, aCx, aValue, aUpdateInfoArray);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = AppendIndexUpdateInfo(indexInfo.id, indexInfo.keyPath,
|
||||
indexInfo.unique, indexInfo.multiEntry,
|
||||
aCx, aValue, aUpdateInfoArray);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
const jschar* keyPathChars =
|
||||
reinterpret_cast<const jschar*>(mKeyPath.get());
|
||||
const size_t keyPathLen = mKeyPath.Length();
|
||||
JSBool ok = JS_FALSE;
|
||||
|
||||
nsString targetObjectPropName;
|
||||
JSObject* targetObject = nsnull;
|
||||
if (!mKeyPath.IsEmpty() && aKey.IsUnset()) {
|
||||
NS_ASSERTION(mAutoIncrement, "Should have bailed earlier!");
|
||||
|
||||
if (mAutoIncrement && HasKeyPath()) {
|
||||
NS_ASSERTION(aKey.IsUnset(), "Shouldn't have gotten the key yet!");
|
||||
JSObject* obj = JS_NewObject(aCx, &gDummyPropClass, nsnull, nsnull);
|
||||
NS_ENSURE_TRUE(obj, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (JSVAL_IS_PRIMITIVE(aValue)) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
|
||||
}
|
||||
jsval key = OBJECT_TO_JSVAL(obj);
|
||||
|
||||
ok = JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(aValue), keyPathChars,
|
||||
keyPathLen, key, nsnull, nsnull,
|
||||
JSPROP_ENUMERATE);
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
KeyPathTokenizer tokenizer(mKeyPath, '.');
|
||||
NS_ASSERTION(tokenizer.hasMoreTokens(),
|
||||
"Shouldn't have empty keypath and autoincrement");
|
||||
|
||||
JSObject* obj = JSVAL_TO_OBJECT(aValue);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
const nsDependentSubstring& token = tokenizer.nextToken();
|
||||
|
||||
NS_ASSERTION(!token.IsEmpty(), "Should be a valid keypath");
|
||||
|
||||
const jschar* keyPathChars = token.BeginReading();
|
||||
const size_t keyPathLen = token.Length();
|
||||
|
||||
JSBool hasProp;
|
||||
if (!targetObject) {
|
||||
// We're still walking the chain of existing objects
|
||||
|
||||
JSBool ok = JS_HasUCProperty(aCx, obj, keyPathChars, keyPathLen,
|
||||
&hasProp);
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (hasProp) {
|
||||
// Get if the property exists...
|
||||
jsval intermediate;
|
||||
JSBool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen,
|
||||
&intermediate);
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (tokenizer.hasMoreTokens()) {
|
||||
// ...and walk to it if there are more steps...
|
||||
if (JSVAL_IS_PRIMITIVE(intermediate)) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
|
||||
}
|
||||
obj = JSVAL_TO_OBJECT(intermediate);
|
||||
}
|
||||
else {
|
||||
// ...otherwise use it as key
|
||||
aKey.SetFromJSVal(aCx, intermediate);
|
||||
if (aKey.IsUnset()) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If the property doesn't exist, fall into below path of starting
|
||||
// to define properties
|
||||
targetObject = obj;
|
||||
targetObjectPropName = token;
|
||||
}
|
||||
}
|
||||
|
||||
if (targetObject) {
|
||||
// We have started inserting new objects or are about to just insert
|
||||
// the first one.
|
||||
if (tokenizer.hasMoreTokens()) {
|
||||
// If we're not at the end, we need to add a dummy object to the chain.
|
||||
JSObject* dummy = JS_NewObject(aCx, nsnull, nsnull, nsnull);
|
||||
if (!dummy) {
|
||||
rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
|
||||
token.Length(),
|
||||
OBJECT_TO_JSVAL(dummy), nsnull, nsnull,
|
||||
JSPROP_ENUMERATE)) {
|
||||
rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
break;
|
||||
}
|
||||
|
||||
obj = dummy;
|
||||
}
|
||||
else {
|
||||
JSObject* dummy = JS_NewObject(aCx, &gDummyPropClass, nsnull, nsnull);
|
||||
if (!dummy) {
|
||||
rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
|
||||
token.Length(), OBJECT_TO_JSVAL(dummy),
|
||||
nsnull, nsnull, JSPROP_ENUMERATE)) {
|
||||
rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// From this point on we have to try to remove the property.
|
||||
}
|
||||
|
||||
JSStructuredCloneCallbacks callbacks = {
|
||||
@ -1059,15 +979,13 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
|
||||
rv = NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
|
||||
if (targetObject) {
|
||||
if (ok) {
|
||||
// If this fails, we lose, and the web page sees a magical property
|
||||
// appear on the object :-(
|
||||
jsval succeeded;
|
||||
if (!JS_DeleteUCProperty2(aCx, targetObject,
|
||||
targetObjectPropName.get(),
|
||||
targetObjectPropName.Length(), &succeeded)) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
ok = JS_DeleteUCProperty2(aCx, JSVAL_TO_OBJECT(aValue), keyPathChars,
|
||||
keyPathLen, &succeeded);
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
NS_ASSERTION(JSVAL_IS_BOOLEAN(succeeded), "Wtf?");
|
||||
NS_ENSURE_TRUE(JSVAL_TO_BOOLEAN(succeeded),
|
||||
NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
@ -1454,7 +1372,6 @@ IDBObjectStore::CreateIndex(const nsAString& aName,
|
||||
NS_ASSERTION(mTransaction->IsOpen(), "Impossible!");
|
||||
|
||||
bool unique = false;
|
||||
bool multiEntry = false;
|
||||
|
||||
// Get optional arguments.
|
||||
if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
|
||||
@ -1478,17 +1395,6 @@ IDBObjectStore::CreateIndex(const nsAString& aName,
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
unique = !!boolVal;
|
||||
|
||||
if (!JS_GetPropertyById(aCx, options, nsDOMClassInfo::sMultiEntry_id, &val)) {
|
||||
NS_WARNING("JS_GetPropertyById failed!");
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
if (!JS_ValueToBoolean(aCx, val, &boolVal)) {
|
||||
NS_WARNING("JS_ValueToBoolean failed!");
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
multiEntry = !!boolVal;
|
||||
}
|
||||
|
||||
DatabaseInfo* databaseInfo = mTransaction->Database()->Info();
|
||||
@ -1503,7 +1409,6 @@ IDBObjectStore::CreateIndex(const nsAString& aName,
|
||||
indexInfo->name = aName;
|
||||
indexInfo->keyPath = aKeyPath;
|
||||
indexInfo->unique = unique;
|
||||
indexInfo->multiEntry = multiEntry;
|
||||
indexInfo->autoIncrement = mAutoIncrement;
|
||||
|
||||
// Don't leave this in the list if we fail below!
|
||||
@ -1625,14 +1530,6 @@ IDBObjectStore::DeleteIndex(const nsAString& aName)
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
info->indexes.RemoveElementAt(index);
|
||||
|
||||
for (PRUint32 i = 0; i < mCreatedIndexes.Length(); i++) {
|
||||
if (mCreatedIndexes[i]->Name() == aName) {
|
||||
mCreatedIndexes.RemoveElementAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2263,9 +2160,8 @@ CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
nsCOMPtr<mozIStorageStatement> stmt =
|
||||
mTransaction->GetCachedStatement(
|
||||
"INSERT INTO object_store_index (id, name, key_path, unique_index, "
|
||||
"multientry, object_store_id, object_store_autoincrement) "
|
||||
"VALUES (:id, :name, :key_path, :unique, :multientry, :osid, "
|
||||
":os_auto_increment)"
|
||||
"object_store_id, object_store_autoincrement) "
|
||||
"VALUES (:id, :name, :key_path, :unique, :osid, :os_auto_increment)"
|
||||
);
|
||||
NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
@ -2286,10 +2182,6 @@ CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
mIndex->IsUnique() ? 1 : 0);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("multientry"),
|
||||
mIndex->IsMultiEntry() ? 1 : 0);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
|
||||
mIndex->ObjectStore()->Id());
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
@ -2346,69 +2238,69 @@ CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
|
||||
mIndex->ObjectStore()->Id());
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
bool hasResult;
|
||||
rv = stmt->ExecuteStep(&hasResult);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
if (!hasResult) {
|
||||
// Bail early if we have no data to avoid creating the below runtime
|
||||
return NS_OK;
|
||||
}
|
||||
while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
|
||||
nsCOMPtr<mozIStorageStatement> insertStmt =
|
||||
mTransaction->IndexDataInsertStatement(mIndex->IsAutoIncrement(),
|
||||
mIndex->IsUnique());
|
||||
NS_ENSURE_TRUE(insertStmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
ThreadLocalJSRuntime* tlsEntry =
|
||||
reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex));
|
||||
mozStorageStatementScoper scoper2(insertStmt);
|
||||
|
||||
if (!tlsEntry) {
|
||||
tlsEntry = ThreadLocalJSRuntime::Create();
|
||||
NS_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
rv = insertStmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
|
||||
mIndex->Id());
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
PR_SetThreadPrivate(sTLSIndex, tlsEntry);
|
||||
}
|
||||
rv = insertStmt->BindInt64ByName(NS_LITERAL_CSTRING("object_data_id"),
|
||||
stmt->AsInt64(0));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
JSContext* cx = tlsEntry->Context();
|
||||
JSAutoRequest ar(cx);
|
||||
if (!mIndex->IsAutoIncrement()) {
|
||||
NS_NAMED_LITERAL_CSTRING(objectDataKey, "object_data_key");
|
||||
|
||||
Key key;
|
||||
rv = key.SetFromStatement(stmt, 2);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv =
|
||||
key.BindToStatement(insertStmt, NS_LITERAL_CSTRING("object_data_key"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
do {
|
||||
const PRUint8* data;
|
||||
PRUint32 dataLength;
|
||||
rv = stmt->GetSharedBlob(1, &dataLength, &data);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
jsval clone;
|
||||
if (!JS_ReadStructuredClone(cx, reinterpret_cast<const uint64*>(data),
|
||||
dataLength, JS_STRUCTURED_CLONE_VERSION,
|
||||
&clone, NULL, NULL)) {
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
ThreadLocalJSRuntime* tlsEntry =
|
||||
reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex));
|
||||
|
||||
if (!tlsEntry) {
|
||||
tlsEntry = ThreadLocalJSRuntime::Create();
|
||||
NS_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
PR_SetThreadPrivate(sTLSIndex, tlsEntry);
|
||||
}
|
||||
|
||||
nsTArray<IndexUpdateInfo> updateInfo;
|
||||
rv = IDBObjectStore::AppendIndexUpdateInfo(mIndex->Id(),
|
||||
mIndex->KeyPath(),
|
||||
mIndex->IsUnique(),
|
||||
mIndex->IsMultiEntry(),
|
||||
tlsEntry->Context(),
|
||||
clone, updateInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt64 objectDataID = stmt->AsInt64(0);
|
||||
|
||||
Key key;
|
||||
if (!mIndex->IsAutoIncrement()) {
|
||||
rv = key.SetFromStatement(stmt, 2);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
key.SetFromInteger(objectDataID);
|
||||
}
|
||||
|
||||
rv = IDBObjectStore::UpdateIndexes(mTransaction, mIndex->Id(),
|
||||
key, mIndex->IsAutoIncrement(),
|
||||
false, objectDataID, updateInfo);
|
||||
rv = IDBObjectStore::GetKeyPathValueFromStructuredData(data, dataLength,
|
||||
mIndex->KeyPath(),
|
||||
tlsEntry->Context(),
|
||||
key);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
} while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
if (key.IsUnset()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rv = key.BindToStatement(insertStmt, NS_LITERAL_CSTRING("value"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = insertStmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -76,13 +76,17 @@ public:
|
||||
IsValidKeyPath(JSContext* aCx, const nsAString& aKeyPath);
|
||||
|
||||
static nsresult
|
||||
AppendIndexUpdateInfo(PRInt64 aIndexID,
|
||||
const nsAString& aKeyPath,
|
||||
bool aUnique,
|
||||
bool aMultiEntry,
|
||||
JSContext* aCx,
|
||||
jsval aObject,
|
||||
nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
|
||||
GetKeyPathValueFromStructuredData(const PRUint8* aData,
|
||||
PRUint32 aDataLength,
|
||||
const nsAString& aKeyPath,
|
||||
JSContext* aCx,
|
||||
Key& aValue);
|
||||
|
||||
static nsresult
|
||||
GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
|
||||
JSContext* aCx,
|
||||
jsval aObject,
|
||||
nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
|
||||
|
||||
static nsresult
|
||||
UpdateIndexes(IDBTransaction* aTransaction,
|
||||
@ -141,11 +145,6 @@ public:
|
||||
return mKeyPath;
|
||||
}
|
||||
|
||||
const bool HasKeyPath() const
|
||||
{
|
||||
return !mKeyPath.IsVoid();
|
||||
}
|
||||
|
||||
IDBTransaction* Transaction()
|
||||
{
|
||||
return mTransaction;
|
||||
|
@ -213,17 +213,6 @@ IDBTransaction::OnRequestFinished()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IDBTransaction::ReleaseCachedObjectStore(const nsAString& aName)
|
||||
{
|
||||
for (PRUint32 i = 0; i < mCreatedObjectStores.Length(); i++) {
|
||||
if (mCreatedObjectStores[i]->Name() == aName) {
|
||||
mCreatedObjectStores.RemoveElementAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IDBTransaction::SetTransactionListener(IDBTransactionListener* aListener)
|
||||
{
|
||||
@ -417,7 +406,7 @@ IDBTransaction::IndexDataInsertStatement(bool aAutoIncrement,
|
||||
);
|
||||
}
|
||||
return GetCachedStatement(
|
||||
"INSERT OR IGNORE INTO ai_index_data "
|
||||
"INSERT INTO ai_index_data "
|
||||
"(index_id, ai_object_data_id, value) "
|
||||
"VALUES (:index_id, :object_data_id, :value)"
|
||||
);
|
||||
@ -430,7 +419,7 @@ IDBTransaction::IndexDataInsertStatement(bool aAutoIncrement,
|
||||
);
|
||||
}
|
||||
return GetCachedStatement(
|
||||
"INSERT OR IGNORE INTO index_data ("
|
||||
"INSERT INTO index_data ("
|
||||
"index_id, object_data_id, object_data_key, value) "
|
||||
"VALUES (:index_id, :object_data_id, :object_data_key, :value)"
|
||||
);
|
||||
|
@ -103,8 +103,6 @@ public:
|
||||
void OnNewRequest();
|
||||
void OnRequestFinished();
|
||||
|
||||
void ReleaseCachedObjectStore(const nsAString& aName);
|
||||
|
||||
void SetTransactionListener(IDBTransactionListener* aListener);
|
||||
|
||||
bool StartSavepoint();
|
||||
|
@ -51,7 +51,7 @@
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#define DB_SCHEMA_VERSION 8
|
||||
#define DB_SCHEMA_VERSION 6
|
||||
|
||||
#define BEGIN_INDEXEDDB_NAMESPACE \
|
||||
namespace mozilla { namespace dom { namespace indexedDB {
|
||||
|
@ -122,9 +122,9 @@ CreateTables(mozIStorageConnection* aDBConn)
|
||||
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE TABLE object_store ("
|
||||
"id INTEGER PRIMARY KEY, "
|
||||
"auto_increment INTEGER NOT NULL DEFAULT 0, "
|
||||
"name TEXT NOT NULL, "
|
||||
"key_path TEXT, "
|
||||
"key_path TEXT NOT NULL, "
|
||||
"auto_increment INTEGER NOT NULL DEFAULT 0, "
|
||||
"UNIQUE (name)"
|
||||
");"
|
||||
));
|
||||
@ -165,7 +165,6 @@ CreateTables(mozIStorageConnection* aDBConn)
|
||||
"name TEXT NOT NULL, "
|
||||
"key_path TEXT NOT NULL, "
|
||||
"unique_index INTEGER NOT NULL, "
|
||||
"multientry INTEGER NOT NULL DEFAULT 0, "
|
||||
"object_store_autoincrement INTERGER NOT NULL, "
|
||||
"PRIMARY KEY (id), "
|
||||
"UNIQUE (object_store_id, name), "
|
||||
@ -754,149 +753,6 @@ UpgradeSchemaFrom5To6(mozIStorageConnection* aConnection)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
UpgradeSchemaFrom6To7(mozIStorageConnection* aConnection)
|
||||
{
|
||||
mozStorageTransaction transaction(aConnection, false,
|
||||
mozIStorageConnection::TRANSACTION_IMMEDIATE);
|
||||
|
||||
// Turn off foreign key constraints before we do anything here.
|
||||
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"PRAGMA foreign_keys = OFF;"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE TEMPORARY TABLE temp_upgrade ("
|
||||
"id, "
|
||||
"name, "
|
||||
"key_path, "
|
||||
"auto_increment, "
|
||||
");"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"INSERT INTO temp_upgrade "
|
||||
"SELECT id, name, key_path, auto_increment "
|
||||
"FROM object_store;"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DROP TABLE object_store;"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE TABLE object_store ("
|
||||
"id INTEGER PRIMARY KEY, "
|
||||
"auto_increment INTEGER NOT NULL DEFAULT 0, "
|
||||
"name TEXT NOT NULL, "
|
||||
"key_path TEXT, "
|
||||
"UNIQUE (name)"
|
||||
");"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"INSERT INTO object_store "
|
||||
"SELECT id, auto_increment, name, nullif(key_path, '') "
|
||||
"FROM temp_upgrade;"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DROP TABLE temp_upgrade;"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->SetSchemaVersion(7);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = transaction.Commit();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
UpgradeSchemaFrom7To8(mozIStorageConnection* aConnection)
|
||||
{
|
||||
mozStorageTransaction transaction(aConnection, false,
|
||||
mozIStorageConnection::TRANSACTION_IMMEDIATE);
|
||||
|
||||
// Turn off foreign key constraints before we do anything here.
|
||||
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"PRAGMA foreign_keys = OFF;"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE TEMPORARY TABLE temp_upgrade ("
|
||||
"id, "
|
||||
"object_store_id, "
|
||||
"name, "
|
||||
"key_path, "
|
||||
"unique_index, "
|
||||
"object_store_autoincrement, "
|
||||
");"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"INSERT INTO temp_upgrade "
|
||||
"SELECT id, object_store_id, name, key_path, "
|
||||
"unique_index, object_store_autoincrement, "
|
||||
"FROM object_store_index;"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DROP TABLE object_store_index;"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE TABLE object_store_index ("
|
||||
"id INTEGER, "
|
||||
"object_store_id INTEGER NOT NULL, "
|
||||
"name TEXT NOT NULL, "
|
||||
"key_path TEXT NOT NULL, "
|
||||
"unique_index INTEGER NOT NULL, "
|
||||
"multientry INTEGER NOT NULL, "
|
||||
"object_store_autoincrement INTERGER NOT NULL, "
|
||||
"PRIMARY KEY (id), "
|
||||
"UNIQUE (object_store_id, name), "
|
||||
"FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
|
||||
"CASCADE"
|
||||
");"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"INSERT INTO object_store_index "
|
||||
"SELECT id, object_store_id, name, key_path, "
|
||||
"unique_index, 0, object_store_autoincrement, "
|
||||
"FROM temp_upgrade;"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"DROP TABLE temp_upgrade;"
|
||||
));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aConnection->SetSchemaVersion(8);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = transaction.Commit();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreateDatabaseConnection(const nsAString& aName,
|
||||
nsIFile* aDBFile,
|
||||
@ -948,7 +804,7 @@ CreateDatabaseConnection(const nsAString& aName,
|
||||
}
|
||||
else if (schemaVersion != DB_SCHEMA_VERSION) {
|
||||
// This logic needs to change next time we change the schema!
|
||||
PR_STATIC_ASSERT(DB_SCHEMA_VERSION == 8);
|
||||
PR_STATIC_ASSERT(DB_SCHEMA_VERSION == 6);
|
||||
|
||||
#define UPGRADE_SCHEMA_CASE(_from, _to) \
|
||||
if (schemaVersion == _from) { \
|
||||
@ -963,8 +819,6 @@ CreateDatabaseConnection(const nsAString& aName,
|
||||
|
||||
UPGRADE_SCHEMA_CASE(4, 5)
|
||||
UPGRADE_SCHEMA_CASE(5, 6)
|
||||
UPGRADE_SCHEMA_CASE(6, 7)
|
||||
UPGRADE_SCHEMA_CASE(7, 8)
|
||||
|
||||
#undef UPGRADE_SCHEMA_CASE
|
||||
|
||||
|
@ -60,8 +60,8 @@ public:
|
||||
bool aForDeletion)
|
||||
: HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName),
|
||||
mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion),
|
||||
mForDeletion(aForDeletion), mDatabaseId(nsnull), mCurrentVersion(0),
|
||||
mDataVersion(DB_SCHEMA_VERSION), mLastObjectStoreId(0),
|
||||
mForDeletion(aForDeletion), mCurrentVersion(0),
|
||||
mDataVersion(DB_SCHEMA_VERSION), mDatabaseId(0), mLastObjectStoreId(0),
|
||||
mLastIndexId(0), mState(eCreated), mResultCode(NS_OK)
|
||||
{
|
||||
NS_ASSERTION(!aForDeletion || !aRequestedVersion,
|
||||
|
@ -47,7 +47,7 @@ interface nsIIDBRequest;
|
||||
* http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBIndex for more
|
||||
* information.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(fcb9a158-833e-4aa9-ab19-ab90cbb50afc)]
|
||||
[scriptable, builtinclass, uuid(1da60889-3db4-4f66-9fd7-b78c1e7969b7)]
|
||||
interface nsIIDBIndex : nsISupports
|
||||
{
|
||||
readonly attribute DOMString name;
|
||||
@ -58,8 +58,6 @@ interface nsIIDBIndex : nsISupports
|
||||
|
||||
readonly attribute boolean unique;
|
||||
|
||||
readonly attribute boolean multiEntry;
|
||||
|
||||
readonly attribute nsIIDBObjectStore objectStore;
|
||||
|
||||
[implicit_jscontext]
|
||||
|
@ -84,7 +84,6 @@ TEST_FILES = \
|
||||
test_indexes_bad_values.html \
|
||||
test_key_requirements.html \
|
||||
test_leaving_page.html \
|
||||
test_multientry.html \
|
||||
test_objectCursors.html \
|
||||
test_objectStore_inline_autoincrement_key_added_on_put.html \
|
||||
test_objectStore_remove_values.html \
|
||||
|
@ -18,188 +18,151 @@
|
||||
// Test object stores
|
||||
|
||||
const name = window.location.pathname;
|
||||
const keyPaths = [
|
||||
{ keyPath: "id", value: { id: 5 }, key: 5 },
|
||||
{ keyPath: "id", value: { id: "14", iid: 12 }, key: "14" },
|
||||
{ keyPath: "id", value: { iid: "14", id: 12 }, key: 12 },
|
||||
{ keyPath: "id", value: {} },
|
||||
{ keyPath: "id", value: { id: {} } },
|
||||
{ keyPath: "id", value: { id: /x/ } },
|
||||
{ keyPath: "id", value: 2 },
|
||||
{ keyPath: "id", value: undefined },
|
||||
{ keyPath: "foo.id", value: { foo: { id: 7 } }, key: 7 },
|
||||
{ keyPath: "foo.id", value: { id: 7, foo: { id: "asdf" } }, key: "asdf" },
|
||||
{ keyPath: "foo.id", value: { foo: { id: undefined } } },
|
||||
{ keyPath: "foo.id", value: { foo: 47 } },
|
||||
{ keyPath: "foo.id", value: {} },
|
||||
{ keyPath: "", value: "foopy", key: "foopy" },
|
||||
{ keyPath: "", value: 2, key: 2 },
|
||||
{ keyPath: "", value: undefined },
|
||||
{ keyPath: "", value: { id: 12 } },
|
||||
{ keyPath: "", value: /x/ },
|
||||
{ keyPath: "foo.bar", value: { baz: 1, foo: { baz2: 2, bar: "xo" } }, key: "xo" },
|
||||
{ keyPath: "foo.bar.baz", value: { foo: { bar: { bazz: 16, baz: 17 } } }, key: 17 },
|
||||
{ keyPath: "foo..id", exception: true },
|
||||
{ keyPath: "foo.", exception: true },
|
||||
{ keyPath: "fo o", exception: true },
|
||||
{ keyPath: "foo ", exception: true },
|
||||
{ keyPath: "foo[bar]",exception: true },
|
||||
{ keyPath: "$('id').stuff", exception: true },
|
||||
{ keyPath: "foo.2.bar", exception: true },
|
||||
{ keyPath: "foo. .bar", exception: true },
|
||||
{ keyPath: ".bar", exception: true },
|
||||
const objectStoreInfo = [
|
||||
{ name: "a", options: { keyPath: "id"} },
|
||||
{ name: "b", options: { keyPath: "foo.id"} },
|
||||
{ name: "c", options: { keyPath: ""} },
|
||||
{ name: "d", options: { keyPath: "foo..id"}, exception: true },
|
||||
{ name: "e", options: { keyPath: "foo."}, exception: true },
|
||||
{ name: "f", options: { keyPath: "foo.bar" } },
|
||||
{ name: "g", options: { keyPath: "fo o" }, exception: true},
|
||||
{ name: "h", options: { keyPath: "foo " }, exception: true},
|
||||
{ name: "i", options: { keyPath: "foo[bar]" }, exception: true },
|
||||
{ name: "j", options: { keyPath: "$('id').stuff" }, exception: true },
|
||||
{ name: "k", options: { keyPath: "foo.2.bar" }, exception: true }
|
||||
];
|
||||
|
||||
let openRequest = mozIndexedDB.open(name, 1);
|
||||
openRequest.onerror = errorHandler;
|
||||
openRequest.onupgradeneeded = grabEventAndContinueHandler;
|
||||
openRequest.onsuccess = unexpectedSuccessHandler;
|
||||
const indexInfo = [
|
||||
{ name: "1", keyPath: "id" },
|
||||
{ name: "2", keyPath: "foo..id", exception: true },
|
||||
{ name: "3", keyPath: "foo.", exception: true },
|
||||
{ name: "4", keyPath: "foo.baz" },
|
||||
{ name: "5", keyPath: "fo o", exception: true },
|
||||
{ name: "6", keyPath: "foo ", exception: true },
|
||||
{ name: "7", keyPath: "foo[bar]", exception: true },
|
||||
{ name: "8", keyPath: "$('id').stuff", exception: true },
|
||||
{ name: "9", keyPath: "foo.2.bar", exception: true },
|
||||
{ name: "10", keyPath: "foo.bork" },
|
||||
];
|
||||
|
||||
let request = mozIndexedDB.open(name, 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
let event = yield;
|
||||
let db = event.target.result;
|
||||
|
||||
let stores = {};
|
||||
|
||||
// Test creating object stores and inserting data
|
||||
for (let i = 0; i < keyPaths.length; i++) {
|
||||
let info = keyPaths[i];
|
||||
test = " for " + JSON.stringify(info);
|
||||
if (!stores[info.keyPath]) {
|
||||
try {
|
||||
let objectStore = db.createObjectStore(info.keyPath, { keyPath: info.keyPath });
|
||||
ok(!("exception" in info), "expected exception behavior observed" + test);
|
||||
is(objectStore.keyPath, info.keyPath, "objectStore has correct keyPath property" + test);
|
||||
stores[info.keyPath] = objectStore;
|
||||
} catch (e) {
|
||||
ok("exception" in info, "expected exception behavior observed" + test);
|
||||
ok(e instanceof DOMException, "Got a DOM Exception" + test);
|
||||
is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error" + test);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let store = stores[info.keyPath];
|
||||
|
||||
for (let i = 0; i < objectStoreInfo.length; i++) {
|
||||
let info = objectStoreInfo[i];
|
||||
try {
|
||||
request = store.add(info.value);
|
||||
ok("key" in info, "successfully created request to insert value" + test);
|
||||
let objectStore = info.hasOwnProperty("options") ?
|
||||
db.createObjectStore(info.name, info.options) :
|
||||
db.createObjectStore(info.name);
|
||||
ok(!info.hasOwnProperty("exception"), "expected exception behavior observed");
|
||||
} catch (e) {
|
||||
ok(!("key" in info), "threw when attempted to insert" + test);
|
||||
ok(e instanceof IDBDatabaseException, "Got a IDBDatabaseException" + test);
|
||||
is(e.code, IDBDatabaseException.DATA_ERR, "expect a DATA_ERR error" + test);
|
||||
continue;
|
||||
ok(info.hasOwnProperty("exception"), "expected exception behavior observed");
|
||||
ok(e instanceof DOMException, "Got a DOM Exception");
|
||||
is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error");
|
||||
}
|
||||
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
|
||||
let e = yield;
|
||||
is(e.type, "success", "inserted successfully" + test);
|
||||
is(e.target, request, "expected target" + test);
|
||||
is(request.result, info.key, "found correct key" + test);
|
||||
|
||||
store.clear().onsuccess = grabEventAndContinueHandler;
|
||||
yield;
|
||||
}
|
||||
|
||||
// Attempt to create indexes and insert data
|
||||
let store = db.createObjectStore("indexStore");
|
||||
let indexes = {};
|
||||
for (let i = 0; i < keyPaths.length; i++) {
|
||||
let info = keyPaths[i];
|
||||
if (!indexes[info.keyPath]) {
|
||||
try {
|
||||
let index = store.createIndex(info.keyPath, info.keyPath);
|
||||
ok(!("exception" in info), "expected exception behavior observed");
|
||||
is(index.keyPath, info.keyPath, "index has correct keyPath property");
|
||||
indexes[info.keyPath] = index;
|
||||
} catch (e) {
|
||||
ok("exception" in info, "expected exception behavior observed");
|
||||
ok(e instanceof DOMException, "Got a DOM Exception");
|
||||
is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let index = indexes[info.keyPath];
|
||||
|
||||
request = store.add(info.value, 1);
|
||||
if ("key" in info) {
|
||||
index.getKey(info.key).onsuccess = grabEventAndContinueHandler;
|
||||
e = yield;
|
||||
is(e.target.result, 1, "found value when reading from index");
|
||||
}
|
||||
else {
|
||||
index.count().onsuccess = grabEventAndContinueHandler;
|
||||
e = yield;
|
||||
is(e.target.result, 0, "index should be empty");
|
||||
}
|
||||
|
||||
store.clear().onsuccess = grabEventAndContinueHandler;
|
||||
yield;
|
||||
}
|
||||
|
||||
// Autoincrement and complex key paths
|
||||
let aitests = [{ v: {}, k: 1, res: { foo: { id: 1 }} },
|
||||
{ v: { value: "x" }, k: 2, res: { value: "x", foo: { id: 2 }} },
|
||||
{ v: { value: "x", foo: {} }, k: 3, res: { value: "x", foo: { id: 3 }} },
|
||||
{ v: { v: "x", foo: { x: "y" } }, k: 4, res: { v: "x", foo: { x: "y", id: 4 }} },
|
||||
{ v: { value: 2, foo: { id: 10 }}, k: 10 },
|
||||
{ v: { value: 2 }, k: 11, res: { value: 2, foo: { id: 11 }} },
|
||||
{ v: true, },
|
||||
{ v: { value: 2, foo: 12 }, },
|
||||
{ v: { foo: { id: true }}, },
|
||||
{ v: { foo: { x: 5, id: {} }}, },
|
||||
{ v: undefined, },
|
||||
{ v: { foo: undefined }, },
|
||||
{ v: { foo: { id: undefined }}, },
|
||||
{ v: null, },
|
||||
{ v: { foo: null }, },
|
||||
{ v: { foo: { id: null }}, },
|
||||
];
|
||||
|
||||
store = db.createObjectStore("gen", { keyPath: "foo.id", autoIncrement: true });
|
||||
for (let i = 0; i < aitests.length; ++i) {
|
||||
let test = aitests[i];
|
||||
|
||||
let preValue = JSON.stringify(test.v);
|
||||
try {
|
||||
store.add(test.v).onsuccess = grabEventAndContinueHandler;
|
||||
ok("k" in test, "shouldn't have thrown");
|
||||
is(JSON.stringify(test.v), preValue, "put didn't modify value");
|
||||
}
|
||||
catch(e) {
|
||||
ok(!("k" in test), "expected exception behavior observed");
|
||||
ok(e instanceof IDBDatabaseException, "Got a IDBDatabaseException");
|
||||
is(e.code, IDBDatabaseException.DATA_ERR, "expect a DATA_ERR");
|
||||
|
||||
is(JSON.stringify(test.v), preValue, "put didn't modify value");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
let e = yield;
|
||||
is(e.target.result, test.k, "got correct return key");
|
||||
|
||||
store.get(test.k).onsuccess = grabEventAndContinueHandler;
|
||||
e = yield;
|
||||
is(JSON.stringify(e.target.result), JSON.stringify(test.res || test.v),
|
||||
"expected value stored");
|
||||
}
|
||||
|
||||
// Can't handle autoincrement and empty keypath
|
||||
try {
|
||||
store = db.createObjectStore("storefail", { keyPath: "", autoIncrement: true });
|
||||
ok(false, "Should have thrown");
|
||||
}
|
||||
catch(e) {
|
||||
ok(true, "Did throw");
|
||||
ok(e instanceof DOMException, "Got a DOMException");
|
||||
is(e.code, DOMException.INVALID_ACCESS_ERR, "expect a INVALID_ACCESS_ERR");
|
||||
}
|
||||
|
||||
openRequest.onsuccess = grabEventAndContinueHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
yield;
|
||||
|
||||
let trans = db.transaction(["f"], IDBTransaction.READ_WRITE);
|
||||
let objectStore = trans.objectStore("f");
|
||||
|
||||
objectStore.put({foo: {baz: -1, bar: 72, bork: true}});
|
||||
objectStore.put({foo: {baz: 2, bar: 1, bork: false}});
|
||||
|
||||
try {
|
||||
objectStore.put({foo: {}});
|
||||
ok(false, "Should have thrown!");
|
||||
} catch (e) {
|
||||
ok(true, "Putting an object without the key should throw");
|
||||
}
|
||||
|
||||
trans.onerror = errorHandler;
|
||||
trans.oncomplete = grabEventAndContinueHandler;
|
||||
|
||||
yield;
|
||||
|
||||
let trans = db.transaction(["f"], IDBTransaction.READ);
|
||||
let objectStore = trans.objectStore("f");
|
||||
let request = objectStore.openCursor();
|
||||
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
|
||||
let event = yield;
|
||||
|
||||
let cursor = event.target.result;
|
||||
is(cursor.value.foo.baz, 2, "got things in the right order");
|
||||
|
||||
cursor.continue();
|
||||
|
||||
let event = yield
|
||||
|
||||
let cursor = event.target.result;
|
||||
is(cursor.value.foo.baz, -1, "got things in the right order");
|
||||
|
||||
db.close();
|
||||
|
||||
// Test indexes
|
||||
|
||||
let request = mozIndexedDB.open(name, 2);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
|
||||
let event = yield;
|
||||
let db = event.target.result;
|
||||
|
||||
let trans = event.target.transaction;
|
||||
let objectStore = trans.objectStore("f");
|
||||
|
||||
let indexes = [];
|
||||
for (let i = 0; i < indexInfo.length; i++) {
|
||||
let info = indexInfo[i];
|
||||
try {
|
||||
indexes[i] = info.hasOwnProperty("options") ?
|
||||
objectStore.createIndex(info.name, info.keyPath, info.options) :
|
||||
objectStore.createIndex(info.name, info.keyPath);
|
||||
ok(!info.hasOwnProperty("exception"), "expected exception behavior observed");
|
||||
} catch (e) {
|
||||
ok(info.hasOwnProperty("exception"), "expected exception behavior observed");
|
||||
ok(e instanceof DOMException, "Got a DOM Exception");
|
||||
is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error");
|
||||
}
|
||||
}
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
|
||||
yield;
|
||||
|
||||
let trans = db.transaction(["f"], IDBTransaction.READ);
|
||||
let objectStore = trans.objectStore("f");
|
||||
|
||||
let request = objectStore.index("4").openCursor();
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
|
||||
let event = yield;
|
||||
|
||||
let cursor = event.target.result;
|
||||
|
||||
is(cursor.value.foo.bar, 72, "got things in the right order");
|
||||
|
||||
cursor.continue();
|
||||
yield;
|
||||
|
||||
is(cursor.value.foo.bar, 1, "got things in the right order");
|
||||
|
||||
let request = objectStore.index("10").openCursor();
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
|
||||
let event = yield;
|
||||
|
||||
is(event.target.result, null, "should have no results");
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
|
@ -86,7 +86,7 @@
|
||||
|
||||
is(objectStore.name, name, "Bad name");
|
||||
is(objectStore.keyPath, info.options && info.options.keyPath ?
|
||||
info.options.keyPath : null,
|
||||
info.options.keyPath : "",
|
||||
"Bad keyPath");
|
||||
if(objectStore.indexNames.length, 0, "Bad indexNames");
|
||||
|
||||
|
@ -1,230 +0,0 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
// Test object stores
|
||||
|
||||
let openRequest = mozIndexedDB.open(window.location.pathname, 1);
|
||||
openRequest.onerror = errorHandler;
|
||||
openRequest.onupgradeneeded = grabEventAndContinueHandler;
|
||||
openRequest.onsuccess = unexpectedSuccessHandler;
|
||||
let event = yield;
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
let tests =
|
||||
[{ add: { x: 1, id: 1 },
|
||||
indexes:[{ v: 1, k: 1 }] },
|
||||
{ add: { x: [2, 3], id: 2 },
|
||||
indexes:[{ v: 1, k: 1 },
|
||||
{ v: 2, k: 2 },
|
||||
{ v: 3, k: 2 }] },
|
||||
{ put: { x: [2, 4], id: 1 },
|
||||
indexes:[{ v: 2, k: 1 },
|
||||
{ v: 2, k: 2 },
|
||||
{ v: 3, k: 2 },
|
||||
{ v: 4, k: 1 }] },
|
||||
{ add: { x: [5, 6, 5, -2, 3], id: 3 },
|
||||
indexes:[{ v:-2, k: 3 },
|
||||
{ v: 2, k: 1 },
|
||||
{ v: 2, k: 2 },
|
||||
{ v: 3, k: 2 },
|
||||
{ v: 3, k: 3 },
|
||||
{ v: 4, k: 1 },
|
||||
{ v: 5, k: 3 },
|
||||
{ v: 6, k: 3 }] },
|
||||
{ delete: IDBKeyRange.bound(1, 3),
|
||||
indexes:[] },
|
||||
{ put: { x: ["food", {}, false, undefined, /x/, [73, false]], id: 2 },
|
||||
indexes:[{ v: "food", k: 2 }] },
|
||||
{ add: { x: [{}, /x/, -12, "food", null, [false], undefined], id: 3 },
|
||||
indexes:[{ v: -12, k: 3 },
|
||||
{ v: "food", k: 2 },
|
||||
{ v: "food", k: 3 }] },
|
||||
{ put: { x: [], id: 2 },
|
||||
indexes:[{ v: -12, k: 3 },
|
||||
{ v: "food", k: 3 }] },
|
||||
{ put: { x: { y: 3 }, id: 3 },
|
||||
indexes:[] },
|
||||
{ add: { x: false, id: 7 },
|
||||
indexes:[] },
|
||||
{ delete: IDBKeyRange.lowerBound(0),
|
||||
indexes:[] },
|
||||
];
|
||||
|
||||
let store = db.createObjectStore("mystore", { keyPath: "id" });
|
||||
let index = store.createIndex("myindex", "x", { multiEntry: true });
|
||||
is(index.multiEntry, true, "index created with multiEntry");
|
||||
|
||||
let i;
|
||||
for (i = 0; i < tests.length; ++i) {
|
||||
let test = tests[i];
|
||||
let testName = " for " + JSON.stringify(test);
|
||||
let req;
|
||||
if (test.add) {
|
||||
req = store.add(test.add);
|
||||
}
|
||||
else if (test.put) {
|
||||
req = store.put(test.put);
|
||||
}
|
||||
else if (test.delete) {
|
||||
req = store.delete(test.delete);
|
||||
}
|
||||
else {
|
||||
ok(false, "borked test");
|
||||
}
|
||||
req.onsuccess = grabEventAndContinueHandler;
|
||||
let e = yield;
|
||||
|
||||
req = index.openKeyCursor();
|
||||
req.onsuccess = grabEventAndContinueHandler;
|
||||
for (let j = 0; j < test.indexes.length; ++j) {
|
||||
e = yield;
|
||||
is(req.result.key, test.indexes[j].v, "found expected index key at index " + j + testName);
|
||||
is(req.result.primaryKey, test.indexes[j].k, "found expected index primary key at index " + j + testName);
|
||||
req.result.continue();
|
||||
}
|
||||
e = yield;
|
||||
is(req.result, undefined, "exhausted indexes");
|
||||
|
||||
let tempIndex = store.createIndex("temp index", "x", { multiEntry: true });
|
||||
req = tempIndex.openKeyCursor();
|
||||
req.onsuccess = grabEventAndContinueHandler;
|
||||
for (let j = 0; j < test.indexes.length; ++j) {
|
||||
e = yield;
|
||||
is(req.result.key, test.indexes[j].v, "found expected temp index key at index " + j + testName);
|
||||
is(req.result.primaryKey, test.indexes[j].k, "found expected temp index primary key at index " + j + testName);
|
||||
req.result.continue();
|
||||
}
|
||||
e = yield;
|
||||
is(req.result, undefined, "exhausted temp index");
|
||||
store.deleteIndex("temp index");
|
||||
}
|
||||
|
||||
// Unique indexes
|
||||
tests =
|
||||
[{ add: { x: 1, id: 1 },
|
||||
indexes:[{ v: 1, k: 1 }] },
|
||||
{ add: { x: [2, 3], id: 2 },
|
||||
indexes:[{ v: 1, k: 1 },
|
||||
{ v: 2, k: 2 },
|
||||
{ v: 3, k: 2 }] },
|
||||
{ put: { x: [2, 4], id: 3 },
|
||||
fail: true },
|
||||
{ put: { x: [1, 4], id: 1 },
|
||||
indexes:[{ v: 1, k: 1 },
|
||||
{ v: 2, k: 2 },
|
||||
{ v: 3, k: 2 },
|
||||
{ v: 4, k: 1 }] },
|
||||
{ add: { x: [5, 0, 5, 5, 5], id: 3 },
|
||||
indexes:[{ v: 0, k: 3 },
|
||||
{ v: 1, k: 1 },
|
||||
{ v: 2, k: 2 },
|
||||
{ v: 3, k: 2 },
|
||||
{ v: 4, k: 1 },
|
||||
{ v: 5, k: 3 }] },
|
||||
{ delete: IDBKeyRange.bound(1, 2),
|
||||
indexes:[{ v: 0, k: 3 },
|
||||
{ v: 5, k: 3 }] },
|
||||
{ add: { x: [0, 6], id: 8 },
|
||||
fail: true },
|
||||
{ add: { x: 5, id: 8 },
|
||||
fail: true },
|
||||
{ put: { x: 0, id: 8 },
|
||||
fail: true },
|
||||
];
|
||||
|
||||
store.deleteIndex("myindex");
|
||||
index = store.createIndex("myindex", "x", { multiEntry: true, unique: true });
|
||||
is(index.multiEntry, true, "index created with multiEntry");
|
||||
|
||||
let i;
|
||||
let indexes;
|
||||
for (i = 0; i < tests.length; ++i) {
|
||||
let test = tests[i];
|
||||
let testName = " for " + JSON.stringify(test);
|
||||
let req;
|
||||
if (test.add) {
|
||||
req = store.add(test.add);
|
||||
}
|
||||
else if (test.put) {
|
||||
req = store.put(test.put);
|
||||
}
|
||||
else if (test.delete) {
|
||||
req = store.delete(test.delete);
|
||||
}
|
||||
else {
|
||||
ok(false, "borked test");
|
||||
}
|
||||
|
||||
if (!test.fail) {
|
||||
req.onsuccess = grabEventAndContinueHandler;
|
||||
let e = yield;
|
||||
indexes = test.indexes;
|
||||
}
|
||||
else {
|
||||
req.onsuccess = unexpectedSuccessHandler;
|
||||
req.onerror = grabEventAndContinueHandler;
|
||||
ok(true, "waiting for error");
|
||||
let e = yield;
|
||||
ok(true, "got error: " + e.type);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
let e;
|
||||
req = index.openKeyCursor();
|
||||
req.onsuccess = grabEventAndContinueHandler;
|
||||
for (let j = 0; j < indexes.length; ++j) {
|
||||
e = yield;
|
||||
is(req.result.key, indexes[j].v, "found expected index key at index " + j + testName);
|
||||
is(req.result.primaryKey, indexes[j].k, "found expected index primary key at index " + j + testName);
|
||||
req.result.continue();
|
||||
}
|
||||
e = yield;
|
||||
is(req.result, undefined, "exhausted indexes");
|
||||
|
||||
let tempIndex = store.createIndex("temp index", "x", { multiEntry: true, unique: true });
|
||||
req = tempIndex.openKeyCursor();
|
||||
req.onsuccess = grabEventAndContinueHandler;
|
||||
for (let j = 0; j < indexes.length; ++j) {
|
||||
e = yield;
|
||||
is(req.result.key, indexes[j].v, "found expected temp index key at index " + j + testName);
|
||||
is(req.result.primaryKey, indexes[j].k, "found expected temp index primary key at index " + j + testName);
|
||||
req.result.continue();
|
||||
}
|
||||
e = yield;
|
||||
is(req.result, undefined, "exhausted temp index");
|
||||
store.deleteIndex("temp index");
|
||||
}
|
||||
|
||||
|
||||
openRequest.onsuccess = grabEventAndContinueHandler;
|
||||
yield;
|
||||
|
||||
let trans = db.transaction(["mystore"], IDBTransaction.READ_WRITE);
|
||||
store = trans.objectStore("mystore");
|
||||
index = store.index("myindex");
|
||||
is(index.multiEntry, true, "index still is multiEntry");
|
||||
trans.oncomplete = grabEventAndContinueHandler;
|
||||
yield;
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
@ -32,30 +32,14 @@
|
||||
|
||||
is(objectStore.indexNames.length, 0, "Correct indexNames list");
|
||||
|
||||
let index = objectStore.createIndex(indexName, "foo");
|
||||
objectStore.createIndex(indexName, "foo");
|
||||
|
||||
is(objectStore.indexNames.length, 1, "Correct indexNames list");
|
||||
is(objectStore.indexNames.item(0), indexName, "Correct name");
|
||||
is(objectStore.index(indexName), index, "Correct instance");
|
||||
|
||||
objectStore.deleteIndex(indexName);
|
||||
|
||||
is(objectStore.indexNames.length, 0, "Correct indexNames list");
|
||||
try {
|
||||
objectStore.index(indexName);
|
||||
ok(false, "should have thrown");
|
||||
}
|
||||
catch(ex) {
|
||||
ok(ex instanceof IDBDatabaseException, "Got a IDBDatabaseException");
|
||||
is(ex.code, IDBDatabaseException.NOT_FOUND_ERR, "expect a NOT_FOUND_ERR");
|
||||
}
|
||||
|
||||
let index2 = objectStore.createIndex(indexName, "foo");
|
||||
isnot(index, index2, "New instance should be created");
|
||||
|
||||
is(objectStore.indexNames.length, 1, "Correct recreacted indexNames list");
|
||||
is(objectStore.indexNames.item(0), indexName, "Correct recreacted name");
|
||||
is(objectStore.index(indexName), index2, "Correct instance");
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
|
@ -55,26 +55,13 @@
|
||||
let event = yield;
|
||||
|
||||
let db = event.target.result;
|
||||
let trans = event.target.transaction;
|
||||
|
||||
let oldObjectStore = trans.objectStore(objectStoreName);
|
||||
isnot(oldObjectStore, null, "Correct object store prior to deleting");
|
||||
db.deleteObjectStore(objectStoreName);
|
||||
db.deleteObjectStore(objectStore.name);
|
||||
is(db.objectStoreNames.length, 0, "Correct objectStores list");
|
||||
try {
|
||||
trans.objectStore(objectStoreName);
|
||||
ok(false, "should have thrown");
|
||||
}
|
||||
catch(ex) {
|
||||
ok(ex instanceof IDBDatabaseException, "Got a IDBDatabaseException");
|
||||
is(ex.code, IDBDatabaseException.NOT_FOUND_ERR, "expect a NOT_FOUND_ERR");
|
||||
}
|
||||
|
||||
objectStore = db.createObjectStore(objectStoreName, { keyPath: "foo" });
|
||||
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
|
||||
is(db.objectStoreNames.item(0), objectStoreName, "Correct name");
|
||||
is(trans.objectStore(objectStoreName), objectStore, "Correct new objectStore");
|
||||
isnot(oldObjectStore, objectStore, "Old objectStore is not new objectStore");
|
||||
|
||||
request = objectStore.openCursor();
|
||||
request.onerror = errorHandler;
|
||||
|
@ -57,7 +57,7 @@
|
||||
is(transaction.onabort, null, "No abort listener");
|
||||
|
||||
is(objectStore.name, "foo", "Correct name");
|
||||
is(objectStore.keyPath, null, "Correct keyPath");
|
||||
is(objectStore.keyPath, "", "Correct keyPath");
|
||||
|
||||
is(objectStore.indexNames.length, 1, "Correct indexNames length");
|
||||
is(objectStore.indexNames[0], "fooindex", "Correct indexNames name");
|
||||
@ -83,7 +83,7 @@
|
||||
}
|
||||
|
||||
is(objectStore.name, "foo", "Correct name");
|
||||
is(objectStore.keyPath, null, "Correct keyPath");
|
||||
is(objectStore.keyPath, "", "Correct keyPath");
|
||||
|
||||
is(objectStore.indexNames.length, 1, "Correct indexNames length");
|
||||
is(objectStore.indexNames[0], "fooindex", "Correct indexNames name");
|
||||
|
Loading…
Reference in New Issue
Block a user