Back out patches due to test failures. rev 1b9ca56d4aab and a few more.

This commit is contained in:
Jonas Sicking 2011-12-02 19:46:25 -08:00
parent 001a640116
commit 7404adaebb
23 changed files with 343 additions and 956 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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();

View File

@ -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);

View File

@ -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)
{

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;

View File

@ -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)"
);

View File

@ -103,8 +103,6 @@ public:
void OnNewRequest();
void OnRequestFinished();
void ReleaseCachedObjectStore(const nsAString& aName);
void SetTransactionListener(IDBTransactionListener* aListener);
bool StartSavepoint();

View File

@ -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 {

View File

@ -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

View File

@ -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,

View File

@ -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]

View File

@ -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 \

View File

@ -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;
}

View File

@ -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");

View File

@ -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>

View File

@ -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;

View File

@ -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;

View File

@ -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");