Bug 603811 - 'IndexedDB: Implement setVersion changes to the spec'. r=sicking, a=blocking2.0-betaN+

This commit is contained in:
Ben Turner 2010-10-19 10:58:52 -07:00
Родитель 3e5b1fa745
Коммит c336d415a2
71 изменённых файлов: 2310 добавлений и 1208 удалений

Просмотреть файл

@ -1468,6 +1468,10 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(IDBIndex, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(IDBVersionChangeEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(IDBVersionChangeRequest, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
};
// Objects that should be constructable through |new Name();|
@ -4051,6 +4055,8 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_BEGIN(IDBDatabase, nsIIDBDatabase)
DOM_CLASSINFO_MAP_ENTRY(nsIIDBDatabase)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(IDBErrorEvent, nsIIDBErrorEvent)
@ -4074,6 +4080,8 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_BEGIN(IDBObjectStore, nsIIDBObjectStore)
DOM_CLASSINFO_MAP_ENTRY(nsIIDBObjectStore)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(IDBTransaction, nsIIDBTransaction)
@ -4084,6 +4092,8 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_BEGIN(IDBCursor, nsIIDBCursor)
DOM_CLASSINFO_MAP_ENTRY(nsIIDBCursor)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(IDBKeyRange, nsIIDBKeyRange)
@ -4092,6 +4102,21 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_BEGIN(IDBIndex, nsIIDBIndex)
DOM_CLASSINFO_MAP_ENTRY(nsIIDBIndex)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(IDBVersionChangeEvent, nsIIDBVersionChangeEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIIDBVersionChangeEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIIDBEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(IDBVersionChangeRequest, nsIIDBVersionChangeRequest)
DOM_CLASSINFO_MAP_ENTRY(nsIIDBVersionChangeRequest)
DOM_CLASSINFO_MAP_ENTRY(nsIIDBRequest)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
#ifdef NS_DEBUG

Просмотреть файл

@ -503,3 +503,5 @@ DOMCI_CLASS(IDBTransaction)
DOMCI_CLASS(IDBCursor)
DOMCI_CLASS(IDBKeyRange)
DOMCI_CLASS(IDBIndex)
DOMCI_CLASS(IDBVersionChangeEvent)
DOMCI_CLASS(IDBVersionChangeRequest)

Просмотреть файл

@ -227,6 +227,7 @@
#include "prlog.h"
#include "mozilla/dom/indexedDB/IDBFactory.h"
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
#include "nsRefreshDriver.h"
@ -1105,6 +1106,13 @@ nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
dts->CancelWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
}
// Close all IndexedDB databases for this window.
indexedDB::IndexedDatabaseManager* idbManager =
indexedDB::IndexedDatabaseManager::Get();
if (idbManager) {
idbManager->CloseDatabasesForWindow(this);
}
ClearAllTimeouts();
mChromeEventHandler = nsnull;
@ -7846,7 +7854,7 @@ NS_IMETHODIMP
nsGlobalWindow::GetMoz_indexedDB(nsIIDBFactory** _retval)
{
if (!mIndexedDB) {
mIndexedDB = mozilla::dom::indexedDB::IDBFactory::Create();
mIndexedDB = indexedDB::IDBFactory::Create();
NS_ENSURE_TRUE(mIndexedDB, NS_ERROR_FAILURE);
}

Просмотреть файл

@ -58,6 +58,8 @@ USING_INDEXEDDB_NAMESPACE
namespace {
IDBTransaction* gCurrentTransaction = nsnull;
const PRUint32 kProgressHandlerGranularity = 1000;
const PRUint32 kDefaultTimeoutMS = 30000;
@ -84,10 +86,10 @@ AsyncConnectionHelper::AsyncConnectionHelper(IDBDatabase* aDatabase,
mRequest(aRequest),
mTimeoutDuration(TimeDuration::FromMilliseconds(kDefaultTimeoutMS)),
mErrorCode(0),
mError(PR_FALSE)
mError(PR_FALSE),
mDispatched(PR_FALSE)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(mRequest, "Null request!");
}
AsyncConnectionHelper::AsyncConnectionHelper(IDBTransaction* aTransaction,
@ -97,10 +99,10 @@ AsyncConnectionHelper::AsyncConnectionHelper(IDBTransaction* aTransaction,
mRequest(aRequest),
mTimeoutDuration(TimeDuration::FromMilliseconds(kDefaultTimeoutMS)),
mErrorCode(0),
mError(PR_FALSE)
mError(PR_FALSE),
mDispatched(PR_FALSE)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(mRequest, "Null request!");
}
AsyncConnectionHelper::~AsyncConnectionHelper()
@ -143,7 +145,12 @@ NS_IMETHODIMP
AsyncConnectionHelper::Run()
{
if (NS_IsMainThread()) {
mRequest->SetDone();
if (mRequest) {
mRequest->SetDone();
}
NS_ASSERTION(!gCurrentTransaction, "Should be null!");
gCurrentTransaction = mTransaction;
// Call OnError if the database had an error or if the OnSuccess handler
// has an error.
@ -151,7 +158,10 @@ AsyncConnectionHelper::Run()
OnError(mRequest, mErrorCode);
}
if (mTransaction) {
NS_ASSERTION(gCurrentTransaction == mTransaction, "Should be unchanged!");
gCurrentTransaction = nsnull;
if (mDispatched && mTransaction) {
mTransaction->OnRequestFinished();
}
@ -183,20 +193,44 @@ AsyncConnectionHelper::Run()
}
if (NS_SUCCEEDED(rv)) {
bool hasSavepoint = false;
if (mDatabase) {
IDBFactory::SetCurrentDatabase(mDatabase);
// Make the first savepoint.
if (mTransaction) {
if (!(hasSavepoint = mTransaction->StartSavepoint())) {
NS_WARNING("Failed to make savepoint!");
}
}
}
mErrorCode = DoDatabaseWork(connection);
if (mDatabase) {
IDBFactory::SetCurrentDatabase(nsnull);
// Release or roll back the savepoint depending on the error code.
if (hasSavepoint) {
NS_ASSERTION(mTransaction, "Huh?!");
if (mErrorCode == OK) {
mTransaction->ReleaseSavepoint();
}
else {
mTransaction->RollbackSavepoint();
}
}
}
}
else {
// NS_ERROR_NOT_AVAILABLE is our special code for "database is invalidated"
// and we should fail with RECOVERABLE_ERR.
mErrorCode = rv == NS_ERROR_NOT_AVAILABLE ?
nsIIDBDatabaseException::RECOVERABLE_ERR :
nsIIDBDatabaseException::UNKNOWN_ERR;
if (rv == NS_ERROR_NOT_AVAILABLE) {
mErrorCode = nsIIDBDatabaseException::RECOVERABLE_ERR;
}
else {
mErrorCode = nsIIDBDatabaseException::UNKNOWN_ERR;
}
}
if (!mStartTime.IsNull()) {
@ -267,6 +301,8 @@ AsyncConnectionHelper::Dispatch(nsIEventTarget* aDatabaseThread)
mTransaction->OnNewRequest();
}
mDispatched = PR_TRUE;
return NS_OK;
}
@ -278,6 +314,15 @@ AsyncConnectionHelper::DispatchToTransactionPool()
return Dispatch(&target);
}
// static
IDBTransaction*
AsyncConnectionHelper::GetCurrentTransaction()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return gCurrentTransaction;
}
nsresult
AsyncConnectionHelper::Init()
{

Просмотреть файл

@ -94,6 +94,13 @@ public:
mErrorCode = aErrorCode;
}
static IDBTransaction* GetCurrentTransaction();
nsISupports* GetSource()
{
return mRequest ? mRequest->Source() : nsnull;
}
protected:
AsyncConnectionHelper(IDBDatabase* aDatabase,
IDBRequest* aRequest);
@ -171,6 +178,7 @@ private:
PRUint16 mErrorCode;
PRPackedBool mError;
PRPackedBool mDispatched;
};
END_INDEXEDDB_NAMESPACE

Просмотреть файл

@ -199,7 +199,7 @@ CheckPermissionsHelper::Observe(nsISupports* aSubject,
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
rv = mgr->WaitForClearAndDispatch(mASCIIOrigin, this);
rv = mgr->WaitForOpenAllowed(mName, mASCIIOrigin, this);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;

Просмотреть файл

@ -64,21 +64,25 @@ public:
CheckPermissionsHelper(AsyncConnectionHelper* aHelper,
nsIDOMWindow* aWindow,
const nsAString& aName,
const nsACString& aASCIIOrigin)
: mHelper(aHelper),
mWindow(aWindow),
mName(aName),
mASCIIOrigin(aASCIIOrigin),
mHasPrompted(PR_FALSE),
mPromptResult(0)
{
NS_ASSERTION(aHelper, "Null pointer!");
NS_ASSERTION(aWindow, "Null pointer!");
NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty host!");
NS_ASSERTION(!aName.IsEmpty(), "Empty name!");
NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!");
}
private:
nsRefPtr<AsyncConnectionHelper> mHelper;
nsCOMPtr<nsIDOMWindow> mWindow;
nsString mName;
nsCString mASCIIOrigin;
PRBool mHasPrompted;
PRUint32 mPromptResult;

Просмотреть файл

@ -83,7 +83,9 @@ EnumerateObjectStoreNames(const nsAString& aKey,
#ifdef NS_BUILD_REFCNT_LOGGING
DatabaseInfo::DatabaseInfo()
: id(0)
: id(0),
nextObjectStoreId(1),
nextIndexId(1)
{
MOZ_COUNT_CTOR(DatabaseInfo);
}
@ -123,6 +125,7 @@ IndexUpdateInfo::IndexUpdateInfo()
{
MOZ_COUNT_CTOR(IndexUpdateInfo);
}
IndexUpdateInfo::~IndexUpdateInfo()
{
MOZ_COUNT_DTOR(IndexUpdateInfo);
@ -220,24 +223,19 @@ DatabaseInfo::GetObjectStoreNames(nsTArray<nsString>& aNames)
return true;
}
// static
bool
DatabaseInfo::ContainsStoreName(const nsAString& aName)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(Get(id, nsnull), "Don't know anything about this one!");
if (!gDatabaseHash) {
return false;
}
DatabaseInfoHash* hash;
ObjectStoreInfo* info;
DatabaseInfoHash* info;
if (!gDatabaseHash->Get(id, &info)) {
return false;
}
return info && info->objectStoreHash &&
info->objectStoreHash->Get(aName, nsnull);
return gDatabaseHash &&
gDatabaseHash->Get(id, &hash) &&
hash->objectStoreHash &&
hash->objectStoreHash->Get(aName, &info);
}
// static

Просмотреть файл

@ -49,20 +49,12 @@ BEGIN_INDEXEDDB_NAMESPACE
struct DatabaseInfo
{
nsString name;
nsString description;
nsString version;
PRUint32 id;
nsString filePath;
nsAutoRefCnt referenceCount;
#ifdef NS_BUILD_REFCNT_LOGGING
DatabaseInfo();
~DatabaseInfo();
#else
DatabaseInfo()
: id(0) { }
: id(0), nextObjectStoreId(1), nextIndexId(1) { }
#endif
static bool Get(PRUint32 aId,
@ -74,6 +66,16 @@ struct DatabaseInfo
bool GetObjectStoreNames(nsTArray<nsString>& aNames);
bool ContainsStoreName(const nsAString& aName);
nsString name;
nsString description;
nsString version;
PRUint32 id;
nsString filePath;
PRInt64 nextObjectStoreId;
PRInt64 nextIndexId;
nsAutoRefCnt referenceCount;
};
struct IndexInfo
@ -95,13 +97,6 @@ struct IndexInfo
struct ObjectStoreInfo
{
nsString name;
PRInt64 id;
nsString keyPath;
bool autoIncrement;
PRUint32 databaseId;
nsTArray<IndexInfo> indexes;
#ifdef NS_BUILD_REFCNT_LOGGING
ObjectStoreInfo();
~ObjectStoreInfo();
@ -118,6 +113,13 @@ struct ObjectStoreInfo
static void Remove(PRUint32 aDatabaseId,
const nsAString& aName);
nsString name;
PRInt64 id;
nsString keyPath;
bool autoIncrement;
PRUint32 databaseId;
nsTArray<IndexInfo> indexes;
};
struct IndexUpdateInfo

Просмотреть файл

@ -57,7 +57,6 @@
#include "IDBIndex.h"
#include "IDBObjectStore.h"
#include "IDBTransaction.h"
#include "Savepoint.h"
#include "TransactionThreadPool.h"
USING_INDEXEDDB_NAMESPACE
@ -594,8 +593,6 @@ UpdateHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mozStorageStatementScoper scoper(stmt);
Savepoint savepoint(mTransaction);
NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mOSID);
@ -631,8 +628,7 @@ UpdateHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
}
rv = savepoint.Release();
return NS_SUCCEEDED(rv) ? OK : nsIIDBDatabaseException::UNKNOWN_ERR;
return OK;
}
PRUint16

Просмотреть файл

@ -51,6 +51,7 @@
#include "CheckQuotaHelper.h"
#include "DatabaseInfo.h"
#include "IDBEvents.h"
#include "IDBIndex.h"
#include "IDBObjectStore.h"
#include "IDBTransaction.h"
#include "IDBFactory.h"
@ -91,45 +92,42 @@ class CreateObjectStoreHelper : public AsyncConnectionHelper
{
public:
CreateObjectStoreHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
const nsAString& aName,
const nsAString& aKeyPath,
bool aAutoIncrement)
: AsyncConnectionHelper(aTransaction, aRequest), mName(aName),
mKeyPath(aKeyPath), mAutoIncrement(aAutoIncrement),
mId(LL_MININT)
IDBObjectStore* aObjectStore)
: AsyncConnectionHelper(aTransaction, nsnull), mObjectStore(aObjectStore)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
PRUint16 GetSuccessResult(nsIWritableVariant* aResult);
PRUint16 OnSuccess(nsIDOMEventTarget* aTarget);
void OnError(nsIDOMEventTarget* aTarget, PRUint16 aErrorCode);
protected:
// In-params.
nsString mName;
nsString mKeyPath;
bool mAutoIncrement;
void ReleaseMainThreadObjects()
{
mObjectStore = nsnull;
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
// Out-params.
PRInt64 mId;
private:
nsRefPtr<IDBObjectStore> mObjectStore;
};
class RemoveObjectStoreHelper : public AsyncConnectionHelper
{
public:
RemoveObjectStoreHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
const nsAString& aName)
: AsyncConnectionHelper(aTransaction, aRequest), mName(aName)
PRInt64 aObjectStoreId)
: AsyncConnectionHelper(aTransaction, nsnull), mObjectStoreId(aObjectStoreId)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
PRUint16 GetSuccessResult(nsIWritableVariant* aResult);
PRUint16 OnSuccess(nsIDOMEventTarget* aTarget);
void OnError(nsIDOMEventTarget* aTarget, PRUint16 aErrorCode);
private:
// In-params.
nsString mName;
PRInt64 mObjectStoreId;
};
NS_STACK_CLASS
class AutoFree
{
public:
@ -139,6 +137,31 @@ private:
void* mPtr;
};
NS_STACK_CLASS
class AutoRemoveObjectStore
{
public:
AutoRemoveObjectStore(PRUint32 aId, const nsAString& aName)
: mId(aId), mName(aName)
{ }
~AutoRemoveObjectStore()
{
if (mId) {
ObjectStoreInfo::Remove(mId, mName);
}
}
void forget()
{
mId = 0;
}
private:
PRUint32 mId;
nsString mName;
};
inline
nsresult
ConvertVariantToStringArray(nsIVariant* aVariant,
@ -255,7 +278,8 @@ IDBDatabase::Create(nsIScriptContext* aScriptContext,
IDBDatabase::IDBDatabase()
: mDatabaseId(0),
mInvalidated(0),
mRegistered(false)
mRegistered(false),
mClosed(false)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -270,6 +294,8 @@ IDBDatabase::~IDBDatabase()
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (mRegistered) {
CloseInternal();
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
if (mgr) {
mgr->UnregisterDatabase(this);
@ -353,6 +379,9 @@ IDBDatabase::Invalidate()
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(gPromptHelpersMutex, "This should never be null!");
// Make sure we're closed too.
Close();
// Cancel any quota prompts that are currently being displayed.
{
MutexAutoLock lock(*gPromptHelpersMutex);
@ -369,16 +398,16 @@ IDBDatabase::Invalidate()
}
}
PR_AtomicSet(&mInvalidated, 1);
if (!PR_AtomicSet(&mInvalidated, 1)) {
DatabaseInfo* info;
if (!DatabaseInfo::Get(mDatabaseId, &info)) {
NS_ERROR("This should never fail!");
}
DatabaseInfo* info;
if (!DatabaseInfo::Get(mDatabaseId, &info)) {
NS_ERROR("This should never fail!");
}
NS_ASSERTION(info->referenceCount, "Bad reference count!");
if (--info->referenceCount == 0) {
DatabaseInfo::Remove(mDatabaseId);
NS_ASSERTION(info->referenceCount, "Bad reference count!");
if (--info->referenceCount == 0) {
DatabaseInfo::Remove(mDatabaseId);
}
}
}
@ -388,6 +417,47 @@ IDBDatabase::IsInvalidated()
return !!mInvalidated;
}
void
IDBDatabase::CloseInternal()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (!mClosed) {
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
if (mgr) {
mgr->OnDatabaseClosed(this);
}
mClosed = true;
}
}
bool
IDBDatabase::IsClosed()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return mClosed;
}
void
IDBDatabase::OnUnlink()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!mOwner, "Should have been cleared already!");
// We've been unlinked, at the very least we should be able to prevent further
// transactions from starting and unblock any other SetVersion callers.
Close();
// No reason for the IndexedDatabaseManager to track us any longer.
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
if (mgr) {
mgr->UnregisterDatabase(this);
// Don't try to unregister again in the destructor.
mRegistered = false;
}
}
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBDatabase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBDatabase,
@ -398,6 +468,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBDatabase,
nsDOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
// Do some cleanup.
tmp->OnUnlink();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBDatabase)
@ -471,8 +544,7 @@ NS_IMETHODIMP
IDBDatabase::CreateObjectStore(const nsAString& aName,
const nsAString& aKeyPath,
PRBool aAutoIncrement,
JSContext* aCx,
nsIIDBRequest** _retval)
nsIIDBObjectStore** _retval)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -486,44 +558,60 @@ IDBDatabase::CreateObjectStore(const nsAString& aName,
keyPath.Truncate();
}
DatabaseInfo* info;
if (!DatabaseInfo::Get(mDatabaseId, &info)) {
DatabaseInfo* databaseInfo;
if (!DatabaseInfo::Get(mDatabaseId, &databaseInfo)) {
NS_ERROR("This should never fail!");
return NS_ERROR_UNEXPECTED;
}
if (info->ContainsStoreName(aName)) {
if (databaseInfo->ContainsStoreName(aName)) {
// XXX Should be nsIIDBTransaction::CONSTRAINT_ERR.
return NS_ERROR_ALREADY_INITIALIZED;
}
nsTArray<nsString> objectStores;
nsString* name = objectStores.AppendElement(aName);
if (!name) {
NS_ERROR("Out of memory?");
return nsIIDBDatabaseException::UNKNOWN_ERR;
IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
if (!transaction ||
transaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
// XXX Should be nsIIDBTransaction::NOT_ALLOWED_ERR.
return NS_ERROR_NOT_AVAILABLE;
}
nsRefPtr<IDBTransaction> transaction =
IDBTransaction::Create(this, objectStores, nsIIDBTransaction::READ_WRITE,
kDefaultDatabaseTimeoutSeconds);
nsAutoPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo());
nsRefPtr<IDBRequest> request = GenerateRequest(this);
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
newInfo->name = aName;
newInfo->id = databaseInfo->nextObjectStoreId++;
newInfo->keyPath = keyPath;
newInfo->autoIncrement = aAutoIncrement;
newInfo->databaseId = mDatabaseId;
if (!ObjectStoreInfo::Put(newInfo)) {
NS_ERROR("Put failed!");
return NS_ERROR_FAILURE;
}
ObjectStoreInfo* objectStoreInfo = newInfo.forget();
// Don't leave this in the hash if we fail below!
AutoRemoveObjectStore autoRemove(mDatabaseId, aName);
nsRefPtr<IDBObjectStore> objectStore =
IDBObjectStore::Create(transaction, objectStoreInfo);
NS_ENSURE_TRUE(objectStore, NS_ERROR_FAILURE);
nsRefPtr<CreateObjectStoreHelper> helper =
new CreateObjectStoreHelper(transaction, request, aName, keyPath,
!!aAutoIncrement);
new CreateObjectStoreHelper(transaction, objectStore);
nsresult rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
request.forget(_retval);
autoRemove.forget();
objectStore.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP
IDBDatabase::RemoveObjectStore(const nsAString& aName,
JSContext* aCx,
nsIIDBRequest** _retval)
IDBDatabase::RemoveObjectStore(const nsAString& aName)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -531,36 +619,27 @@ IDBDatabase::RemoveObjectStore(const nsAString& aName,
return NS_ERROR_INVALID_ARG;
}
DatabaseInfo* info;
if (!DatabaseInfo::Get(mDatabaseId, &info)) {
ObjectStoreInfo* objectStoreInfo;
if (!ObjectStoreInfo::Get(mDatabaseId, aName, &objectStoreInfo)) {
NS_ERROR("This should never fail!");
return NS_ERROR_UNEXPECTED;
}
if (!info->ContainsStoreName(aName)) {
// XXX Should be nsIIDBTransaction::NOT_FOUND_ERR.
return NS_ERROR_NOT_AVAILABLE;
}
nsTArray<nsString> storesToOpen;
if (!storesToOpen.AppendElement(aName)) {
NS_ERROR("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
if (!transaction ||
transaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
// XXX Should be nsIIDBTransaction::NOT_ALLOWED_ERR.
return NS_ERROR_NOT_AVAILABLE;
}
nsRefPtr<IDBTransaction> transaction =
IDBTransaction::Create(this, storesToOpen, nsIIDBTransaction::READ_WRITE,
kDefaultDatabaseTimeoutSeconds);
NS_ENSURE_TRUE(transaction, NS_ERROR_FAILURE);
nsRefPtr<IDBRequest> request = GenerateRequest(this);
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<RemoveObjectStoreHelper> helper =
new RemoveObjectStoreHelper(transaction, request, aName);
new RemoveObjectStoreHelper(transaction, objectStoreInfo->id);
nsresult rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
request.forget(_retval);
ObjectStoreInfo::Remove(mDatabaseId, aName);
return NS_OK;
}
@ -571,25 +650,35 @@ IDBDatabase::SetVersion(const nsAString& aVersion,
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (mClosed) {
return NS_ERROR_NOT_AVAILABLE;
}
DatabaseInfo* info;
if (!DatabaseInfo::Get(mDatabaseId, &info)) {
NS_ERROR("This should never fail!");
return NS_ERROR_UNEXPECTED;
}
// Lock the whole database
// Lock the whole database.
nsTArray<nsString> storesToOpen;
nsRefPtr<IDBTransaction> transaction =
IDBTransaction::Create(this, storesToOpen, IDBTransaction::FULL_LOCK,
IDBTransaction::Create(this, storesToOpen, IDBTransaction::VERSION_CHANGE,
kDefaultDatabaseTimeoutSeconds);
NS_ENSURE_TRUE(transaction, NS_ERROR_FAILURE);
nsRefPtr<IDBRequest> request = GenerateRequest(this);
nsRefPtr<IDBVersionChangeRequest> request =
IDBVersionChangeRequest::Create(static_cast<nsPIDOMEventTarget*>(this),
ScriptContext(), Owner());
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<SetVersionHelper> helper =
new SetVersionHelper(transaction, request, aVersion);
nsresult rv = helper->DispatchToTransactionPool();
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
nsresult rv = mgr->SetDatabaseVersion(this, request, aVersion, helper);
NS_ENSURE_SUCCESS(rv, rv);
request.forget(_retval);
@ -610,6 +699,10 @@ IDBDatabase::Transaction(nsIVariant* aStoreNames,
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
}
if (mClosed) {
return NS_ERROR_NOT_AVAILABLE;
}
if (aOptionalArgCount) {
if (aMode != nsIIDBTransaction::READ_WRITE &&
aMode != nsIIDBTransaction::READ_ONLY &&
@ -737,6 +830,17 @@ IDBDatabase::Transaction(nsIVariant* aStoreNames,
return NS_OK;
}
NS_IMETHODIMP
IDBDatabase::Close()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
CloseInternal();
NS_ASSERTION(mClosed, "Should have set the closed flag!");
return NS_OK;
}
PRUint16
SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
@ -772,86 +876,88 @@ SetVersionHelper::GetSuccessResult(nsIWritableVariant* /* aResult */)
return OK;
}
PRUint16 OnSuccess(nsIDOMEventTarget* aTarget);
void OnError(nsIDOMEventTarget* aTarget, PRUint16 aErrorCode);
PRUint16
CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
// Insert the data into the database.
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"INSERT INTO object_store (name, key_path, auto_increment) "
"VALUES (:name, :key_path, :auto_increment)"
), getter_AddRefs(stmt));
nsCOMPtr<mozIStorageStatement> stmt =
mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
"INSERT INTO object_store (id, name, key_path, auto_increment) "
"VALUES (:id, :name, :key_path, :auto_increment)"
));
NS_ENSURE_TRUE(stmt, nsIIDBDatabaseException::UNKNOWN_ERR);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
mObjectStore->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mName);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mObjectStore->Name());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"), mKeyPath);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
mObjectStore->KeyPath());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("auto_increment"),
mAutoIncrement ? 1 : 0);
mObjectStore->IsAutoIncrement() ? 1 : 0);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (NS_FAILED(stmt->Execute())) {
return nsIIDBDatabaseException::CONSTRAINT_ERR;
}
// Get the id of this object store, and store it for future use.
(void)aConnection->GetLastInsertRowID(&mId);
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
return OK;
}
PRUint16
CreateObjectStoreHelper::GetSuccessResult(nsIWritableVariant* aResult)
CreateObjectStoreHelper::OnSuccess(nsIDOMEventTarget* aTarget)
{
nsAutoPtr<ObjectStoreInfo> info(new ObjectStoreInfo());
info->name = mName;
info->id = mId;
info->keyPath = mKeyPath;
info->autoIncrement = mAutoIncrement;
info->databaseId = mDatabase->Id();
if (!ObjectStoreInfo::Put(info)) {
NS_ERROR("Put failed!");
return nsIIDBDatabaseException::UNKNOWN_ERR;
}
info.forget();
nsCOMPtr<nsIIDBObjectStore> result;
nsresult rv = mTransaction->ObjectStore(mName, getter_AddRefs(result));
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
aResult->SetAsISupports(result);
NS_ASSERTION(!aTarget, "Huh?!");
return OK;
}
void
CreateObjectStoreHelper::OnError(nsIDOMEventTarget* aTarget,
PRUint16 aErrorCode)
{
NS_ASSERTION(!aTarget, "Huh?!");
}
PRUint16
RemoveObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
nsCOMPtr<mozIStorageStatement> stmt =
mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
"DELETE FROM object_store "
"WHERE name = :name "
), getter_AddRefs(stmt));
"WHERE id = :id "
));
NS_ENSURE_TRUE(stmt, nsIIDBDatabaseException::UNKNOWN_ERR);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mObjectStoreId);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mName);
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (NS_FAILED(stmt->Execute())) {
return nsIIDBDatabaseException::NOT_FOUND_ERR;
}
return OK;
}
PRUint16
RemoveObjectStoreHelper::GetSuccessResult(nsIWritableVariant* /* aResult */)
RemoveObjectStoreHelper::OnSuccess(nsIDOMEventTarget* aTarget)
{
ObjectStoreInfo::Remove(mDatabase->Id(), mName);
NS_ASSERTION(!aTarget, "Huh?!");
return OK;
}
void
RemoveObjectStoreHelper::OnError(nsIDOMEventTarget* aTarget,
PRUint16 aErrorCode)
{
NS_NOTREACHED("Removing an object store should never fail here!");
}

Просмотреть файл

@ -55,6 +55,8 @@ BEGIN_INDEXEDDB_NAMESPACE
class AsyncConnectionHelper;
struct DatabaseInfo;
class IDBIndex;
class IDBObjectStore;
class IDBTransaction;
class IndexedDatabaseManager;
@ -82,6 +84,11 @@ public:
return mDatabaseId;
}
const nsString& Name()
{
return mName;
}
const nsString& FilePath()
{
return mFilePath;
@ -107,19 +114,31 @@ public:
}
void Invalidate();
// Whether or not the database has been invalidated. If it has then no further
// transactions for this database will be allowed to run.
bool IsInvalidated();
void CloseInternal();
// Whether or not the database has had Close called on it.
bool IsClosed();
private:
IDBDatabase();
~IDBDatabase();
void OnUnlink();
PRUint32 mDatabaseId;
nsString mName;
nsString mDescription;
nsString mFilePath;
nsCString mASCIIOrigin;
PRInt32 mInvalidated;
bool mRegistered;
bool mClosed;
// Only touched on the main thread.
nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;

Просмотреть файл

@ -55,20 +55,14 @@ USING_INDEXEDDB_NAMESPACE
namespace {
template<class Class>
template <class T>
inline
nsIDOMEvent*
idomevent_cast(Class* aClassPtr)
already_AddRefed<nsIDOMEvent>
ForgetEvent(nsRefPtr<T>& aRefPtr)
{
return static_cast<nsIDOMEvent*>(static_cast<nsDOMEvent*>(aClassPtr));
}
template<class Class>
inline
nsIDOMEvent*
idomevent_cast(nsRefPtr<Class> aClassAutoPtr)
{
return idomevent_cast(aClassAutoPtr.get());
T* result;
aRefPtr.forget(&result);
return static_cast<nsIDOMEvent*>(static_cast<nsDOMEvent*>(result));
}
class EventFiringRunnable : public nsRunnable
@ -235,9 +229,7 @@ IDBErrorEvent::Create(IDBRequest* aRequest,
rv = event->SetTrusted(PR_TRUE);
NS_ENSURE_SUCCESS(rv, nsnull);
IDBErrorEvent* result;
event.forget(&result);
return idomevent_cast(result);
return ForgetEvent(event);
}
// static
@ -245,7 +237,7 @@ already_AddRefed<nsIRunnable>
IDBErrorEvent::CreateRunnable(IDBRequest* aRequest,
PRUint16 aCode)
{
nsCOMPtr<nsIDOMEvent> event(IDBErrorEvent::Create(aRequest, aCode));
nsCOMPtr<nsIDOMEvent> event(Create(aRequest, aCode));
NS_ENSURE_TRUE(event, nsnull);
nsCOMPtr<nsIRunnable> runnable(new EventFiringRunnable(aRequest, event));
@ -309,9 +301,7 @@ IDBSuccessEvent::Create(IDBRequest* aRequest,
rv = event->SetTrusted(PR_TRUE);
NS_ENSURE_SUCCESS(rv, nsnull);
IDBSuccessEvent* result;
event.forget(&result);
return idomevent_cast(result);
return ForgetEvent(event);
}
// static
@ -320,8 +310,7 @@ IDBSuccessEvent::CreateRunnable(IDBRequest* aRequest,
nsIVariant* aResult,
nsIIDBTransaction* aTransaction)
{
nsCOMPtr<nsIDOMEvent> event =
IDBSuccessEvent::Create(aRequest, aResult, aTransaction);
nsCOMPtr<nsIDOMEvent> event(Create(aRequest, aResult, aTransaction));
NS_ENSURE_TRUE(event, nsnull);
nsCOMPtr<nsIRunnable> runnable(new EventFiringRunnable(aRequest, event));
@ -600,3 +589,54 @@ GetAllKeySuccessEvent::GetResult(JSContext* aCx,
*aResult = mCachedValue;
return NS_OK;
}
// static
already_AddRefed<nsIDOMEvent>
IDBVersionChangeEvent::CreateInternal(nsISupports* aSource,
const nsAString& aType,
const nsAString& aVersion)
{
nsRefPtr<IDBVersionChangeEvent> event(new IDBVersionChangeEvent());
event->mSource = aSource;
event->mVersion = aVersion;
nsresult rv = event->InitEvent(aType, PR_FALSE, PR_FALSE);
NS_ENSURE_SUCCESS(rv, nsnull);
rv = event->SetTrusted(PR_TRUE);
NS_ENSURE_SUCCESS(rv, nsnull);
return ForgetEvent(event);
}
// static
already_AddRefed<nsIRunnable>
IDBVersionChangeEvent::CreateRunnableInternal(nsISupports* aSource,
const nsAString& aType,
const nsAString& aVersion,
nsIDOMEventTarget* aTarget)
{
nsCOMPtr<nsIDOMEvent> event = CreateInternal(aSource, aType, aVersion);
NS_ENSURE_TRUE(event, nsnull);
nsCOMPtr<nsIRunnable> runnable(new EventFiringRunnable(aTarget, event));
return runnable.forget();
}
NS_IMPL_ADDREF_INHERITED(IDBVersionChangeEvent, IDBEvent)
NS_IMPL_RELEASE_INHERITED(IDBVersionChangeEvent, IDBEvent)
NS_INTERFACE_MAP_BEGIN(IDBVersionChangeEvent)
NS_INTERFACE_MAP_ENTRY(nsIIDBVersionChangeEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBVersionChangeEvent)
NS_INTERFACE_MAP_END_INHERITING(IDBEvent)
DOMCI_DATA(IDBVersionChangeEvent, IDBVersionChangeEvent)
NS_IMETHODIMP
IDBVersionChangeEvent::GetVersion(nsAString& aVersion)
{
aVersion.Assign(mVersion);
return NS_OK;
}

Просмотреть файл

@ -47,6 +47,7 @@
#include "nsIIDBSuccessEvent.h"
#include "nsIIDBTransactionEvent.h"
#include "nsIIDBTransaction.h"
#include "nsIIDBVersionChangeEvent.h"
#include "nsIRunnable.h"
#include "nsIVariant.h"
@ -59,6 +60,8 @@
#define COMPLETE_EVT_STR "complete"
#define ABORT_EVT_STR "abort"
#define TIMEOUT_EVT_STR "timeout"
#define VERSIONCHANGE_EVT_STR "versionchange"
#define BLOCKED_EVT_STR "blocked"
BEGIN_INDEXEDDB_NAMESPACE
@ -210,6 +213,64 @@ private:
nsTArray<Key> mKeys;
};
class IDBVersionChangeEvent : public IDBEvent,
public nsIIDBVersionChangeEvent
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIIDBVERSIONCHANGEEVENT
NS_FORWARD_NSIDOMEVENT(IDBEvent::)
NS_FORWARD_NSIIDBEVENT(IDBEvent::)
inline static already_AddRefed<nsIDOMEvent>
Create(const nsAString& aVersion)
{
NS_NAMED_LITERAL_STRING(type, VERSIONCHANGE_EVT_STR);
return CreateInternal(nsnull, type, aVersion);
}
inline static already_AddRefed<nsIDOMEvent>
CreateBlocked(nsISupports* aSource,
const nsAString& aVersion)
{
NS_NAMED_LITERAL_STRING(type, BLOCKED_EVT_STR);
return CreateInternal(aSource, type, aVersion);
}
inline static already_AddRefed<nsIRunnable>
CreateRunnable(const nsAString& aVersion,
nsIDOMEventTarget* aTarget)
{
NS_NAMED_LITERAL_STRING(type, VERSIONCHANGE_EVT_STR);
return CreateRunnableInternal(nsnull, type, aVersion, aTarget);
}
static already_AddRefed<nsIRunnable>
CreateBlockedRunnable(nsISupports* aSource,
const nsAString& aVersion,
nsIDOMEventTarget* aTarget)
{
NS_NAMED_LITERAL_STRING(type, BLOCKED_EVT_STR);
return CreateRunnableInternal(aSource, type, aVersion, aTarget);
}
protected:
IDBVersionChangeEvent() { }
static already_AddRefed<nsIDOMEvent>
CreateInternal(nsISupports* aSource,
const nsAString& aType,
const nsAString& aVersion);
static already_AddRefed<nsIRunnable>
CreateRunnableInternal(nsISupports* aSource,
const nsAString& aType,
const nsAString& aVersion,
nsIDOMEventTarget* aTarget);
nsString mVersion;
};
END_INDEXEDDB_NAMESPACE
#endif // mozilla_dom_indexeddb_idbevents_h__

Просмотреть файл

@ -131,7 +131,7 @@ public:
const nsACString& aASCIIOrigin)
: AsyncConnectionHelper(static_cast<IDBDatabase*>(nsnull), aRequest),
mName(aName), mDescription(aDescription), mASCIIOrigin(aASCIIOrigin),
mDatabaseId(0)
mDatabaseId(0), mLastObjectStoreId(0), mLastIndexId(0)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
@ -148,6 +148,8 @@ private:
nsString mVersion;
nsString mDatabaseFilePath;
PRUint32 mDatabaseId;
PRInt64 mLastObjectStoreId;
PRInt64 mLastIndexId;
};
nsresult
@ -641,6 +643,166 @@ IDBFactory::GetDirectoryForOrigin(const nsACString& aASCIIOrigin,
return NS_OK;
}
// static
nsresult
IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
PRUint32 aDatabaseId,
nsAString& aVersion,
ObjectStoreInfoArray& aObjectStores)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aConnection, "Null pointer!");
aVersion.Truncate();
aObjectStores.Clear();
// Load object store names and ids.
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT name, id, key_path, auto_increment "
"FROM object_store"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoTArray<ObjectStoreInfoMap, 20> infoMap;
PRBool hasResult;
while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
nsAutoPtr<ObjectStoreInfo>* element =
aObjectStores.AppendElement(new ObjectStoreInfo());
NS_ENSURE_TRUE(element, NS_ERROR_OUT_OF_MEMORY);
ObjectStoreInfo* info = element->get();
rv = stmt->GetString(0, info->name);
NS_ENSURE_SUCCESS(rv, rv);
info->id = stmt->AsInt64(1);
rv = stmt->GetString(2, info->keyPath);
NS_ENSURE_SUCCESS(rv, rv);
info->autoIncrement = !!stmt->AsInt32(3);
info->databaseId = aDatabaseId;
ObjectStoreInfoMap* mapEntry = infoMap.AppendElement();
NS_ENSURE_TRUE(mapEntry, NS_ERROR_OUT_OF_MEMORY);
mapEntry->id = info->id;
mapEntry->info = info;
}
NS_ENSURE_SUCCESS(rv, rv);
// Load index information
rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT object_store_id, id, name, key_path, unique_index, "
"object_store_autoincrement "
"FROM object_store_index"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
PRInt64 objectStoreId = stmt->AsInt64(0);
ObjectStoreInfo* objectStoreInfo = nsnull;
for (PRUint32 index = 0; index < infoMap.Length(); index++) {
if (infoMap[index].id == objectStoreId) {
objectStoreInfo = infoMap[index].info;
break;
}
}
if (!objectStoreInfo) {
NS_ERROR("Index for nonexistant object store!");
return NS_ERROR_UNEXPECTED;
}
IndexInfo* indexInfo = objectStoreInfo->indexes.AppendElement();
NS_ENSURE_TRUE(indexInfo, NS_ERROR_OUT_OF_MEMORY);
indexInfo->id = stmt->AsInt64(1);
rv = stmt->GetString(2, indexInfo->name);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->GetString(3, indexInfo->keyPath);
NS_ENSURE_SUCCESS(rv, rv);
indexInfo->unique = !!stmt->AsInt32(4);
indexInfo->autoIncrement = !!stmt->AsInt32(5);
}
NS_ENSURE_SUCCESS(rv, rv);
// Load version information.
rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT version "
"FROM database"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->ExecuteStep(&hasResult);
NS_ENSURE_SUCCESS(rv, rv);
if (!hasResult) {
NS_ERROR("Database has no version!");
return NS_ERROR_UNEXPECTED;
}
nsString version;
rv = stmt->GetString(0, version);
NS_ENSURE_SUCCESS(rv, rv);
if (version.IsVoid()) {
version.SetIsVoid(PR_FALSE);
}
aVersion = version;
return NS_OK;
}
// static
nsresult
IDBFactory::UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
const nsAString& aVersion,
ObjectStoreInfoArray& aObjectStores)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aDatabaseInfo, "Null pointer!");
ObjectStoreInfoArray objectStores;
if (!objectStores.SwapElements(aObjectStores)) {
NS_WARNING("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
}
nsAutoTArray<nsString, 10> existingNames;
if (!aDatabaseInfo->GetObjectStoreNames(existingNames)) {
NS_WARNING("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
}
// Remove all the old ones.
for (PRUint32 index = 0; index < existingNames.Length(); index++) {
ObjectStoreInfo::Remove(aDatabaseInfo->id, existingNames[index]);
}
aDatabaseInfo->version = aVersion;
for (PRUint32 index = 0; index < objectStores.Length(); index++) {
nsAutoPtr<ObjectStoreInfo>& info = objectStores[index];
NS_ASSERTION(info->databaseId == aDatabaseInfo->id, "Huh?!");
if (!ObjectStoreInfo::Put(info)) {
NS_WARNING("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
}
info.forget();
}
return NS_OK;
}
NS_IMPL_ADDREF(IDBFactory)
NS_IMPL_RELEASE(IDBFactory)
@ -716,12 +878,12 @@ IDBFactory::Open(const nsAString& aName,
new OpenDatabaseHelper(request, aName, aDescription, origin);
nsRefPtr<CheckPermissionsHelper> permissionHelper =
new CheckPermissionsHelper(openHelper, innerWindow, origin);
new CheckPermissionsHelper(openHelper, innerWindow, aName, origin);
nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::GetOrCreate();
NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE);
rv = mgr->WaitForClearAndDispatch(origin, permissionHelper);
rv = mgr->WaitForOpenAllowed(aName, origin, permissionHelper);
NS_ENSURE_SUCCESS(rv, rv);
request.forget(_retval);
@ -855,105 +1017,17 @@ OpenDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mDatabaseId = HashString(mDatabaseFilePath);
NS_ASSERTION(mDatabaseId, "HashString gave us 0?!");
nsAutoTArray<ObjectStoreInfoMap, 20> infoMap;
rv = IDBFactory::LoadDatabaseInformation(connection, mDatabaseId, mVersion,
mObjectStores);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
{ // Load object store names and ids.
nsCOMPtr<mozIStorageStatement> stmt;
rv = connection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT name, id, key_path, auto_increment "
"FROM object_store"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
PRBool hasResult;
while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
nsAutoPtr<ObjectStoreInfo>* element =
mObjectStores.AppendElement(new ObjectStoreInfo());
NS_ENSURE_TRUE(element, nsIIDBDatabaseException::UNKNOWN_ERR);
ObjectStoreInfo* const info = element->get();
rv = stmt->GetString(0, info->name);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
info->id = stmt->AsInt64(1);
rv = stmt->GetString(2, info->keyPath);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
info->autoIncrement = !!stmt->AsInt32(3);
info->databaseId = mDatabaseId;
ObjectStoreInfoMap* mapEntry = infoMap.AppendElement();
if (!mapEntry) {
NS_ERROR("Failed to add to map!");
return nsIIDBDatabaseException::UNKNOWN_ERR;
}
mapEntry->id = info->id;
mapEntry->info = info;
}
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
}
{ // Load index information
nsCOMPtr<mozIStorageStatement> stmt;
rv = connection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT object_store_id, id, name, key_path, unique_index, "
"object_store_autoincrement "
"FROM object_store_index"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
PRBool hasResult;
while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
PRInt64 objectStoreId = stmt->AsInt64(0);
ObjectStoreInfo* objectStoreInfo = nsnull;
PRUint32 count = infoMap.Length();
for (PRUint32 index = 0; index < count; index++) {
if (infoMap[index].id == objectStoreId) {
objectStoreInfo = infoMap[index].info;
break;
}
}
NS_ENSURE_TRUE(objectStoreInfo, nsIIDBDatabaseException::UNKNOWN_ERR);
IndexInfo* indexInfo = objectStoreInfo->indexes.AppendElement();
NS_ENSURE_TRUE(indexInfo, nsIIDBDatabaseException::UNKNOWN_ERR);
indexInfo->id = stmt->AsInt64(1);
rv = stmt->GetString(2, indexInfo->name);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->GetString(3, indexInfo->keyPath);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
indexInfo->unique = !!stmt->AsInt32(4);
indexInfo->autoIncrement = !!stmt->AsInt32(5);
}
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
}
{ // Load version information.
nsCOMPtr<mozIStorageStatement> stmt;
rv = connection->CreateStatement(NS_LITERAL_CSTRING(
"SELECT version "
"FROM database"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
PRBool hasResult;
rv = stmt->ExecuteStep(&hasResult);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
NS_ENSURE_TRUE(hasResult, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->GetString(0, mVersion);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (mVersion.IsVoid()) {
mVersion.Assign(EmptyString());
for (PRUint32 i = 0; i < mObjectStores.Length(); i++) {
nsAutoPtr<ObjectStoreInfo>& objectStoreInfo = mObjectStores[i];
for (PRUint32 j = 0; j < objectStoreInfo->indexes.Length(); j++) {
IndexInfo& indexInfo = objectStoreInfo->indexes[j];
mLastIndexId = PR_MAX(indexInfo.id, mLastIndexId);
}
mLastObjectStoreId = PR_MAX(objectStoreInfo->id, mLastObjectStoreId);
}
return OK;
@ -1021,7 +1095,6 @@ OpenDatabaseHelper::GetSuccessResult(nsIWritableVariant* aResult)
newInfo->name = mName;
newInfo->description = mDescription;
newInfo->version = mVersion;
newInfo->id = mDatabaseId;
newInfo->filePath = mDatabaseFilePath;
newInfo->referenceCount = 1;
@ -1033,20 +1106,16 @@ OpenDatabaseHelper::GetSuccessResult(nsIWritableVariant* aResult)
dbInfo = newInfo.forget();
PRUint32 objectStoreCount = mObjectStores.Length();
for (PRUint32 index = 0; index < objectStoreCount; index++) {
nsAutoPtr<ObjectStoreInfo>& info = mObjectStores[index];
NS_ASSERTION(info->databaseId == mDatabaseId, "Huh?!");
if (!ObjectStoreInfo::Put(info)) {
NS_ERROR("Failed to add to hash!");
return nsIIDBDatabaseException::UNKNOWN_ERR;
}
nsresult rv = IDBFactory::UpdateDatabaseMetadata(dbInfo, mVersion,
mObjectStores);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
info.forget();
}
NS_ASSERTION(mObjectStores.IsEmpty(), "Should have swapped!");
}
dbInfo->nextObjectStoreId = mLastObjectStoreId + 1;
dbInfo->nextIndexId = mLastIndexId + 1;
nsRefPtr<IDBDatabase> db =
IDBDatabase::Create(mRequest->ScriptContext(), mRequest->Owner(), dbInfo,
mASCIIOrigin);

Просмотреть файл

@ -47,10 +47,13 @@
BEGIN_INDEXEDDB_NAMESPACE
struct DatabaseInfo;
class IDBDatabase;
struct ObjectStoreInfo;
class IDBFactory : public nsIIDBFactory
{
typedef nsTArray<nsAutoPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIIDBFACTORY
@ -70,6 +73,17 @@ public:
GetDirectoryForOrigin(const nsACString& aASCIIOrigin,
nsIFile** aDirectory);
static nsresult
LoadDatabaseInformation(mozIStorageConnection* aConnection,
PRUint32 aDatabaseId,
nsAString& aVersion,
ObjectStoreInfoArray& aObjectStores);
static nsresult
UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
const nsAString& aVersion,
ObjectStoreInfoArray& aObjectStores);
private:
IDBFactory() { }
~IDBFactory() { }

Просмотреть файл

@ -63,23 +63,24 @@ class GetHelper : public AsyncConnectionHelper
public:
GetHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
const Key& aKey,
PRInt64 aId,
bool aUnique,
bool aAutoIncrement)
: AsyncConnectionHelper(aTransaction, aRequest), mKey(aKey), mId(aId),
mUnique(aUnique), mAutoIncrement(aAutoIncrement)
IDBIndex* aIndex,
const Key& aKey)
: AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex), mKey(aKey)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
PRUint16 GetSuccessResult(nsIWritableVariant* aResult);
void ReleaseMainThreadObjects()
{
mIndex = nsnull;
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
protected:
// In-params.
nsRefPtr<IDBIndex> mIndex;
Key mKey;
const PRInt64 mId;
const bool mUnique;
const bool mAutoIncrement;
};
class GetObjectHelper : public GetHelper
@ -87,11 +88,9 @@ class GetObjectHelper : public GetHelper
public:
GetObjectHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
const Key& aKey,
PRInt64 aId,
bool aUnique,
bool aAutoIncrement)
: GetHelper(aTransaction, aRequest, aKey, aId, aUnique, aAutoIncrement)
IDBIndex* aIndex,
const Key& aKey)
: GetHelper(aTransaction, aRequest, aIndex, aKey)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
@ -106,13 +105,10 @@ class GetAllHelper : public GetHelper
public:
GetAllHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
IDBIndex* aIndex,
const Key& aKey,
PRInt64 aId,
bool aUnique,
bool aAutoIncrement,
const PRUint32 aLimit)
: GetHelper(aTransaction, aRequest, aKey, aId, aUnique, aAutoIncrement),
mLimit(aLimit)
: GetHelper(aTransaction, aRequest, aIndex, aKey), mLimit(aLimit)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
@ -128,13 +124,10 @@ class GetAllObjectsHelper : public GetHelper
public:
GetAllObjectsHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
IDBIndex* aIndex,
const Key& aKey,
PRInt64 aId,
bool aUnique,
bool aAutoIncrement,
const PRUint32 aLimit)
: GetHelper(aTransaction, aRequest, aKey, aId, aUnique, aAutoIncrement),
mLimit(aLimit)
: GetHelper(aTransaction, aRequest, aIndex, aKey), mLimit(aLimit)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
@ -151,17 +144,13 @@ public:
OpenCursorHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
IDBIndex* aIndex,
PRInt64 aId,
bool aUnique,
bool aAutoIncrement,
const Key& aLeftKey,
const Key& aRightKey,
PRUint16 aKeyRangeFlags,
PRUint16 aDirection,
PRBool aPreload)
: AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex), mId(aId),
mUnique(aUnique), mAutoIncrement(aAutoIncrement), mLeftKey(aLeftKey),
mRightKey(aRightKey), mKeyRangeFlags(aKeyRangeFlags),
: AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
mLeftKey(aLeftKey), mRightKey(aRightKey), mKeyRangeFlags(aKeyRangeFlags),
mDirection(aDirection), mPreload(aPreload)
{ }
@ -177,9 +166,6 @@ public:
private:
// In-params.
nsRefPtr<IDBIndex> mIndex;
const PRInt64 mId;
const bool mUnique;
const bool mAutoIncrement;
const Key mLeftKey;
const Key mRightKey;
const PRUint16 mKeyRangeFlags;
@ -196,17 +182,13 @@ public:
OpenObjectCursorHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
IDBIndex* aIndex,
PRInt64 aId,
bool aUnique,
bool aAutoIncrement,
const Key& aLeftKey,
const Key& aRightKey,
PRUint16 aKeyRangeFlags,
PRUint16 aDirection,
PRBool aPreload)
: AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex), mId(aId),
mUnique(aUnique), mAutoIncrement(aAutoIncrement), mLeftKey(aLeftKey),
mRightKey(aRightKey), mKeyRangeFlags(aKeyRangeFlags),
: AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
mLeftKey(aLeftKey), mRightKey(aRightKey), mKeyRangeFlags(aKeyRangeFlags),
mDirection(aDirection), mPreload(aPreload)
{ }
@ -222,9 +204,6 @@ public:
private:
// In-params.
nsRefPtr<IDBIndex> mIndex;
const PRInt64 mId;
const bool mUnique;
const bool mAutoIncrement;
const Key mLeftKey;
const Key mRightKey;
const PRUint16 mKeyRangeFlags;
@ -369,8 +348,7 @@ IDBIndex::Get(nsIVariant* aKey,
nsRefPtr<IDBRequest> request = GenerateRequest(this);
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<GetHelper> helper =
new GetHelper(transaction, request, key, mId, mUnique, mAutoIncrement);
nsRefPtr<GetHelper> helper(new GetHelper(transaction, request, this, key));
rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
@ -398,8 +376,7 @@ IDBIndex::GetObject(nsIVariant* aKey,
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<GetObjectHelper> helper =
new GetObjectHelper(transaction, request, key, mId, mUnique,
mAutoIncrement);
new GetObjectHelper(transaction, request, this, key);
rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
@ -433,8 +410,7 @@ IDBIndex::GetAll(nsIVariant* aKey,
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<GetAllHelper> helper =
new GetAllHelper(transaction, request, key, mId, mUnique, mAutoIncrement,
aLimit);
new GetAllHelper(transaction, request, this, key, aLimit);
rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
@ -468,8 +444,7 @@ IDBIndex::GetAllObjects(nsIVariant* aKey,
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<GetAllObjectsHelper> helper =
new GetAllObjectsHelper(transaction, request, key, mId, mUnique,
mAutoIncrement, aLimit);
new GetAllObjectsHelper(transaction, request, this, key, aLimit);
rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
@ -535,9 +510,8 @@ IDBIndex::OpenCursor(nsIIDBKeyRange* aKeyRange,
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<OpenCursorHelper> helper =
new OpenCursorHelper(transaction, request, this, mId, mUnique,
mAutoIncrement, leftKey, rightKey, keyRangeFlags,
aDirection, aPreload);
new OpenCursorHelper(transaction, request, this, leftKey, rightKey,
keyRangeFlags, aDirection, aPreload);
rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
@ -604,9 +578,8 @@ IDBIndex::OpenObjectCursor(nsIIDBKeyRange* aKeyRange,
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<OpenObjectCursorHelper> helper =
new OpenObjectCursorHelper(transaction, request, this, mId, mUnique,
mAutoIncrement, leftKey, rightKey, keyRangeFlags,
aDirection, aPreload);
new OpenObjectCursorHelper(transaction, request, this, leftKey, rightKey,
keyRangeFlags, aDirection, aPreload);
rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
@ -621,12 +594,14 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_ASSERTION(aConnection, "Passed a null connection!");
nsCOMPtr<mozIStorageStatement> stmt =
mTransaction->IndexGetStatement(mUnique, mAutoIncrement);
mTransaction->IndexGetStatement(mIndex->IsUnique(),
mIndex->IsAutoIncrement());
NS_ENSURE_TRUE(stmt, nsIIDBDatabaseException::UNKNOWN_ERR);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), mId);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
mIndex->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
NS_NAMED_LITERAL_CSTRING(value, "value");
@ -698,12 +673,14 @@ GetObjectHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_ASSERTION(aConnection, "Passed a null connection!");
nsCOMPtr<mozIStorageStatement> stmt =
mTransaction->IndexGetObjectStatement(mUnique, mAutoIncrement);
mTransaction->IndexGetObjectStatement(mIndex->IsUnique(),
mIndex->IsAutoIncrement());
NS_ENSURE_TRUE(stmt, nsIIDBDatabaseException::UNKNOWN_ERR);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), mId);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
mIndex->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
NS_NAMED_LITERAL_CSTRING(value, "value");
@ -761,9 +738,9 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
nsCString keyColumn;
nsCString tableName;
if (mAutoIncrement) {
if (mIndex->IsAutoIncrement()) {
keyColumn.AssignLiteral("ai_object_data_id");
if (mUnique) {
if (mIndex->IsUnique()) {
tableName.AssignLiteral("ai_unique_index_data");
}
else {
@ -772,7 +749,7 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
}
else {
keyColumn.AssignLiteral("object_data_key");
if (mUnique) {
if (mIndex->IsUnique()) {
tableName.AssignLiteral("unique_index_data");
}
else {
@ -806,7 +783,7 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(indexId, mId);
nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (!mKey.IsUnset()) {
@ -887,10 +864,10 @@ GetAllObjectsHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
nsCString objectDataId;
nsCString indexTableName;
if (mAutoIncrement) {
if (mIndex->IsAutoIncrement()) {
dataTableName.AssignLiteral("ai_object_data");
objectDataId.AssignLiteral("ai_object_data_id");
if (mUnique) {
if (mIndex->IsUnique()) {
indexTableName.AssignLiteral("ai_unique_index_data");
}
else {
@ -900,7 +877,7 @@ GetAllObjectsHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
else {
dataTableName.AssignLiteral("object_data");
objectDataId.AssignLiteral("object_data_id");
if (mUnique) {
if (mIndex->IsUnique()) {
indexTableName.AssignLiteral("unique_index_data");
}
else {
@ -937,7 +914,7 @@ GetAllObjectsHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(indexId, mId);
nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (!mKey.IsUnset()) {
@ -1010,9 +987,9 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
nsCString table;
nsCString keyColumn;
if (mAutoIncrement) {
if (mIndex->IsAutoIncrement()) {
keyColumn.AssignLiteral("ai_object_data_id");
if (mUnique) {
if (mIndex->IsUnique()) {
table.AssignLiteral("ai_unique_index_data");
}
else {
@ -1021,7 +998,7 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
}
else {
keyColumn.AssignLiteral("object_data_key");
if (mUnique) {
if (mIndex->IsUnique()) {
table.AssignLiteral("unique_index_data");
}
else {
@ -1100,7 +1077,7 @@ OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(indexId, mId);
nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (!mLeftKey.IsUnset()) {
@ -1213,10 +1190,10 @@ OpenObjectCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
nsCString objectTable;
nsCString objectDataId;
if (mAutoIncrement) {
if (mIndex->IsAutoIncrement()) {
objectTable.AssignLiteral("ai_object_data");
objectDataId.AssignLiteral("ai_object_data_id");
if (mUnique) {
if (mIndex->IsUnique()) {
indexTable.AssignLiteral("ai_unique_index_data");
}
else {
@ -1226,7 +1203,7 @@ OpenObjectCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
else {
objectTable.AssignLiteral("object_data");
objectDataId.AssignLiteral("object_data_id");
if (mUnique) {
if (mIndex->IsUnique()) {
indexTable.AssignLiteral("unique_index_data");
}
else {
@ -1317,7 +1294,7 @@ OpenObjectCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(indexId, mId);
nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (!mLeftKey.IsUnset()) {

Просмотреть файл

@ -48,6 +48,7 @@
BEGIN_INDEXEDDB_NAMESPACE
class AsyncConnectionHelper;
class IDBObjectStore;
struct IndexInfo;
@ -70,6 +71,31 @@ public:
return mObjectStore;
}
const PRInt64 Id() const
{
return mId;
}
const nsString& Name() const
{
return mName;
}
bool IsUnique() const
{
return mUnique;
}
bool IsAutoIncrement() const
{
return mAutoIncrement;
}
const nsString& KeyPath() const
{
return mName;
}
private:
IDBIndex();
~IDBIndex();

Просмотреть файл

@ -60,7 +60,6 @@
#include "IDBKeyRange.h"
#include "IDBTransaction.h"
#include "DatabaseInfo.h"
#include "Savepoint.h"
USING_INDEXEDDB_NAMESPACE
@ -71,16 +70,13 @@ class AddHelper : public AsyncConnectionHelper
public:
AddHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
PRInt64 aObjectStoreID,
const nsAString& aKeyPath,
IDBObjectStore* aObjectStore,
const nsAString& aValue,
const Key& aKey,
bool aAutoIncrement,
bool aOverwrite,
nsTArray<IndexUpdateInfo>& aIndexUpdateInfo)
: AsyncConnectionHelper(aTransaction, aRequest), mOSID(aObjectStoreID),
mKeyPath(aKeyPath), mValue(aValue), mKey(aKey),
mAutoIncrement(aAutoIncrement), mOverwrite(aOverwrite)
: AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
mValue(aValue), mKey(aKey), mOverwrite(aOverwrite)
{
mIndexUpdateInfo.SwapElements(aIndexUpdateInfo);
}
@ -88,18 +84,23 @@ public:
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
PRUint16 GetSuccessResult(nsIWritableVariant* aResult);
void ReleaseMainThreadObjects()
{
mObjectStore = nsnull;
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
nsresult ModifyValueForNewKey();
nsresult UpdateIndexes(mozIStorageConnection* aConnection,
PRInt64 aObjectDataId);
private:
// In-params.
const PRInt64 mOSID;
const nsString mKeyPath;
nsRefPtr<IDBObjectStore> mObjectStore;
// These may change in the autoincrement case.
nsString mValue;
Key mKey;
const bool mAutoIncrement;
const bool mOverwrite;
nsTArray<IndexUpdateInfo> mIndexUpdateInfo;
};
@ -109,21 +110,25 @@ class GetHelper : public AsyncConnectionHelper
public:
GetHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
PRInt64 aObjectStoreID,
const Key& aKey,
bool aAutoIncrement)
: AsyncConnectionHelper(aTransaction, aRequest), mOSID(aObjectStoreID),
mKey(aKey), mAutoIncrement(aAutoIncrement)
IDBObjectStore* aObjectStore,
const Key& aKey)
: AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
mKey(aKey)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
PRUint16 OnSuccess(nsIDOMEventTarget* aTarget);
void ReleaseMainThreadObjects()
{
mObjectStore = nsnull;
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
protected:
// In-params.
const PRInt64 mOSID;
nsRefPtr<IDBObjectStore> mObjectStore;
const Key mKey;
const bool mAutoIncrement;
private:
// Out-params.
@ -135,10 +140,9 @@ class RemoveHelper : public GetHelper
public:
RemoveHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
PRInt64 aObjectStoreID,
const Key& aKey,
bool aAutoIncrement)
: GetHelper(aTransaction, aRequest, aObjectStoreID, aKey, aAutoIncrement)
IDBObjectStore* aObjectStore,
const Key& aKey)
: GetHelper(aTransaction, aRequest, aObjectStore, aKey)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
@ -151,18 +155,21 @@ class ClearHelper : public AsyncConnectionHelper
public:
ClearHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
PRInt64 aObjectStoreID,
bool aAutoIncrement)
: AsyncConnectionHelper(aTransaction, aRequest), mOSID(aObjectStoreID),
mAutoIncrement(aAutoIncrement)
IDBObjectStore* aObjectStore)
: AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
void ReleaseMainThreadObjects()
{
mObjectStore = nsnull;
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
protected:
// In-params.
const PRInt64 mOSID;
const bool mAutoIncrement;
nsRefPtr<IDBObjectStore> mObjectStore;
};
class OpenCursorHelper : public AsyncConnectionHelper
@ -207,23 +214,17 @@ class CreateIndexHelper : public AsyncConnectionHelper
{
public:
CreateIndexHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
const nsAString& aName,
const nsAString& aKeyPath,
bool aUnique,
bool aAutoIncrement,
IDBObjectStore* aObjectStore)
: AsyncConnectionHelper(aTransaction, aRequest), mName(aName),
mKeyPath(aKeyPath), mUnique(aUnique), mAutoIncrement(aAutoIncrement),
mObjectStore(aObjectStore), mId(LL_MININT)
IDBIndex* aIndex)
: AsyncConnectionHelper(aTransaction, nsnull), mIndex(aIndex)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
PRUint16 GetSuccessResult(nsIWritableVariant* aResult);
PRUint16 OnSuccess(nsIDOMEventTarget* aTarget);
void OnError(nsIDOMEventTarget* aTarget, PRUint16 aErrorCode);
void ReleaseMainThreadObjects()
{
mObjectStore = nsnull;
mIndex = nsnull;
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
@ -231,11 +232,7 @@ private:
PRUint16 InsertDataFromObjectStore(mozIStorageConnection* aConnection);
// In-params.
nsString mName;
nsString mKeyPath;
const bool mUnique;
const bool mAutoIncrement;
nsRefPtr<IDBObjectStore> mObjectStore;
nsRefPtr<IDBIndex> mIndex;
// Out-params.
PRInt64 mId;
@ -244,16 +241,16 @@ private:
class RemoveIndexHelper : public AsyncConnectionHelper
{
public:
RemoveIndexHelper(IDBTransaction* aDatabase,
IDBRequest* aRequest,
RemoveIndexHelper(IDBTransaction* aTransaction,
const nsAString& aName,
IDBObjectStore* aObjectStore)
: AsyncConnectionHelper(aDatabase, aRequest), mName(aName),
: AsyncConnectionHelper(aTransaction, nsnull), mName(aName),
mObjectStore(aObjectStore)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
PRUint16 GetSuccessResult(nsIWritableVariant* aResult);
PRUint16 OnSuccess(nsIDOMEventTarget* aTarget);
void OnError(nsIDOMEventTarget* aTarget, PRUint16 aErrorCode);
void ReleaseMainThreadObjects()
{
@ -272,34 +269,75 @@ class GetAllHelper : public AsyncConnectionHelper
public:
GetAllHelper(IDBTransaction* aTransaction,
IDBRequest* aRequest,
PRInt64 aObjectStoreID,
IDBObjectStore* aObjectStore,
const Key& aLeftKey,
const Key& aRightKey,
const PRUint16 aKeyRangeFlags,
const PRUint32 aLimit,
bool aAutoIncrement)
: AsyncConnectionHelper(aTransaction, aRequest), mOSID(aObjectStoreID),
const PRUint32 aLimit)
: AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
mLeftKey(aLeftKey), mRightKey(aRightKey), mKeyRangeFlags(aKeyRangeFlags),
mLimit(aLimit), mAutoIncrement(aAutoIncrement)
mLimit(aLimit)
{ }
PRUint16 DoDatabaseWork(mozIStorageConnection* aConnection);
PRUint16 OnSuccess(nsIDOMEventTarget* aTarget);
void ReleaseMainThreadObjects()
{
mObjectStore = nsnull;
AsyncConnectionHelper::ReleaseMainThreadObjects();
}
protected:
// In-params.
const PRInt64 mOSID;
nsRefPtr<IDBObjectStore> mObjectStore;
const Key mLeftKey;
const Key mRightKey;
const PRUint16 mKeyRangeFlags;
const PRUint32 mLimit;
const bool mAutoIncrement;
private:
// Out-params.
nsTArray<nsString> mValues;
};
NS_STACK_CLASS
class AutoRemoveIndex
{
public:
AutoRemoveIndex(PRUint32 aDatabaseId,
const nsAString& aObjectStoreName,
const nsAString& aIndexName)
: mDatabaseId(aDatabaseId), mObjectStoreName(aObjectStoreName),
mIndexName(aIndexName)
{ }
~AutoRemoveIndex()
{
if (mDatabaseId) {
ObjectStoreInfo* info;
if (ObjectStoreInfo::Get(mDatabaseId, mObjectStoreName, &info)) {
for (PRUint32 index = 0; index < info->indexes.Length(); index++) {
if (info->indexes[index].name == mIndexName) {
info->indexes.RemoveElementAt(index);
break;
}
}
}
}
}
void forget()
{
mDatabaseId = 0;
}
private:
PRUint32 mDatabaseId;
nsString mObjectStoreName;
nsString mIndexName;
};
inline
nsresult
GetKeyFromObject(JSContext* aCx,
@ -338,8 +376,7 @@ GenerateRequest(IDBObjectStore* aObjectStore)
// static
already_AddRefed<IDBObjectStore>
IDBObjectStore::Create(IDBTransaction* aTransaction,
const ObjectStoreInfo* aStoreInfo,
PRUint16 aMode)
const ObjectStoreInfo* aStoreInfo)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -354,7 +391,6 @@ IDBObjectStore::Create(IDBTransaction* aTransaction,
objectStore->mKeyPath = aStoreInfo->keyPath;
objectStore->mAutoIncrement = aStoreInfo->autoIncrement;
objectStore->mDatabaseId = aStoreInfo->databaseId;
objectStore->mMode = aMode;
return objectStore.forget();
}
@ -737,7 +773,7 @@ IDBObjectStore::GetObjectStoreInfo()
NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
ObjectStoreInfo* info;
if (!ObjectStoreInfo::Get(mDatabaseId, mName, &info)) {
if (!ObjectStoreInfo::Get(mTransaction->Database()->Id(), mName, &info)) {
NS_ERROR("This should never fail!");
return nsnull;
}
@ -746,8 +782,7 @@ IDBObjectStore::GetObjectStoreInfo()
IDBObjectStore::IDBObjectStore()
: mId(LL_MININT),
mAutoIncrement(PR_FALSE),
mMode(nsIIDBTransaction::READ_WRITE)
mAutoIncrement(PR_FALSE)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
}
@ -895,8 +930,7 @@ IDBObjectStore::Get(nsIVariant* aKey,
nsRefPtr<IDBRequest> request = GenerateRequest(this);
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<GetHelper> helper =
new GetHelper(mTransaction, request, mId, key, !!mAutoIncrement);
nsRefPtr<GetHelper> helper(new GetHelper(mTransaction, request, this, key));
rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
@ -946,9 +980,8 @@ IDBObjectStore::GetAll(nsIIDBKeyRange* aKeyRange,
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<GetAllHelper> helper =
new GetAllHelper(mTransaction, request, mId, leftKey, rightKey,
keyRangeFlags, aLimit, mAutoIncrement);
new GetAllHelper(mTransaction, request, this, leftKey, rightKey,
keyRangeFlags, aLimit);
rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
@ -969,7 +1002,7 @@ IDBObjectStore::Add(const jsval &aValue,
return NS_ERROR_UNEXPECTED;
}
if (mMode != nsIIDBTransaction::READ_WRITE) {
if (!IsWriteAllowed()) {
return NS_ERROR_OBJECT_IS_IMMUTABLE;
}
@ -1001,8 +1034,8 @@ IDBObjectStore::Add(const jsval &aValue,
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<AddHelper> helper =
new AddHelper(mTransaction, request, mId, mKeyPath, jsonValue, key,
!!mAutoIncrement, false, updateInfo);
new AddHelper(mTransaction, request, this, jsonValue, key, false,
updateInfo);
rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
@ -1023,7 +1056,7 @@ IDBObjectStore::Put(const jsval &aValue,
return NS_ERROR_UNEXPECTED;
}
if (mMode != nsIIDBTransaction::READ_WRITE) {
if (!IsWriteAllowed()) {
return NS_ERROR_OBJECT_IS_IMMUTABLE;
}
@ -1046,8 +1079,8 @@ IDBObjectStore::Put(const jsval &aValue,
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<AddHelper> helper =
new AddHelper(mTransaction, request, mId, mKeyPath, jsonValue, key,
!!mAutoIncrement, true, updateInfo);
new AddHelper(mTransaction, request, this, jsonValue, key, true,
updateInfo);
rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
@ -1065,7 +1098,7 @@ IDBObjectStore::Remove(nsIVariant* aKey,
return NS_ERROR_UNEXPECTED;
}
if (mMode != nsIIDBTransaction::READ_WRITE) {
if (!IsWriteAllowed()) {
return NS_ERROR_OBJECT_IS_IMMUTABLE;
}
@ -1083,7 +1116,7 @@ IDBObjectStore::Remove(nsIVariant* aKey,
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<RemoveHelper> helper =
new RemoveHelper(mTransaction, request, mId, key, !!mAutoIncrement);
new RemoveHelper(mTransaction, request, this, key);
rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
@ -1100,15 +1133,14 @@ IDBObjectStore::Clear(nsIIDBRequest** _retval)
return NS_ERROR_UNEXPECTED;
}
if (mMode != nsIIDBTransaction::READ_WRITE) {
if (!IsWriteAllowed()) {
return NS_ERROR_OBJECT_IS_IMMUTABLE;
}
nsRefPtr<IDBRequest> request = GenerateRequest(this);
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<ClearHelper> helper =
new ClearHelper(mTransaction, request, mId, !!mAutoIncrement);
nsRefPtr<ClearHelper> helper(new ClearHelper(mTransaction, request, this));
nsresult rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
@ -1187,11 +1219,11 @@ NS_IMETHODIMP
IDBObjectStore::CreateIndex(const nsAString& aName,
const nsAString& aKeyPath,
PRBool aUnique,
nsIIDBRequest** _retval)
nsIIDBIndex** _retval)
{
NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
if (aName.IsEmpty()) {
if (aName.IsEmpty() || aKeyPath.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
}
@ -1208,28 +1240,52 @@ IDBObjectStore::CreateIndex(const nsAString& aName,
}
if (found) {
// XXX Should be nsIIDBTransaction::CONSTRAINT_ERR.
return NS_ERROR_ALREADY_INITIALIZED;
}
if (aKeyPath.IsEmpty()) {
NS_NOTYETIMPLEMENTED("Implement me!");
return NS_ERROR_NOT_IMPLEMENTED;
IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
if (!transaction ||
transaction != mTransaction ||
mTransaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
// XXX Should be nsIIDBTransaction::NOT_ALLOWED_ERR.
return NS_ERROR_NOT_AVAILABLE;
}
if (!mTransaction->TransactionIsOpen()) {
return NS_ERROR_UNEXPECTED;
NS_ASSERTION(mTransaction->TransactionIsOpen(), "Impossible!");
DatabaseInfo* databaseInfo;
if (!DatabaseInfo::Get(mTransaction->Database()->Id(), &databaseInfo)) {
NS_ERROR("This should never fail!");
}
nsRefPtr<IDBRequest> request = GenerateRequest(this);
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
IndexInfo* indexInfo = info->indexes.AppendElement();
if (!indexInfo) {
NS_WARNING("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
}
indexInfo->id = databaseInfo->nextIndexId++;
indexInfo->name = aName;
indexInfo->keyPath = aKeyPath;
indexInfo->unique = aUnique;
indexInfo->autoIncrement = mAutoIncrement;
// Don't leave this in the list if we fail below!
AutoRemoveIndex autoRemove(databaseInfo->id, mName, aName);
nsRefPtr<IDBIndex> index(IDBIndex::Create(this, indexInfo));
nsRefPtr<CreateIndexHelper> helper =
new CreateIndexHelper(mTransaction, request, aName, aKeyPath, !!aUnique,
mAutoIncrement, this);
new CreateIndexHelper(mTransaction, index);
nsresult rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
request.forget(_retval);
autoRemove.forget();
index.forget(_retval);
return NS_OK;
}
@ -1263,51 +1319,54 @@ IDBObjectStore::Index(const nsAString& aName,
return NS_ERROR_NOT_AVAILABLE;
}
nsRefPtr<IDBIndex> request = IDBIndex::Create(this, indexInfo);
nsRefPtr<IDBIndex> index = IDBIndex::Create(this, indexInfo);
NS_ENSURE_TRUE(index, NS_ERROR_FAILURE);
request.forget(_retval);
index.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP
IDBObjectStore::RemoveIndex(const nsAString& aName,
nsIIDBRequest** _retval)
IDBObjectStore::RemoveIndex(const nsAString& aName)
{
NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
if (!mTransaction->TransactionIsOpen()) {
return NS_ERROR_UNEXPECTED;
}
if (aName.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
}
IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
if (!transaction ||
transaction != mTransaction ||
mTransaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
// XXX Should be nsIIDBTransaction::NOT_ALLOWED_ERR.
return NS_ERROR_NOT_AVAILABLE;
}
NS_ASSERTION(mTransaction->TransactionIsOpen(), "Impossible!");
ObjectStoreInfo* info = GetObjectStoreInfo();
NS_ENSURE_TRUE(info, NS_ERROR_UNEXPECTED);
bool found = false;
PRUint32 indexCount = info->indexes.Length();
for (PRUint32 index = 0; index < indexCount; index++) {
PRUint32 index = 0;
for (; index < info->indexes.Length(); index++) {
if (info->indexes[index].name == aName) {
found = true;
break;
}
}
if (!found) {
if (index == info->indexes.Length()) {
// XXX Should be nsIIDBTransaction::NOT_FOUND_ERR.
return NS_ERROR_NOT_AVAILABLE;
}
nsRefPtr<IDBRequest> request = GenerateRequest(this);
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
nsRefPtr<RemoveIndexHelper> helper =
new RemoveIndexHelper(mTransaction, request, aName, this);
new RemoveIndexHelper(mTransaction, aName, this);
nsresult rv = helper->DispatchToTransactionPool();
NS_ENSURE_SUCCESS(rv, rv);
request.forget(_retval);
info->indexes.RemoveElementAt(index);
return NS_OK;
}
@ -1337,28 +1396,30 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
bool mayOverwrite = mOverwrite;
bool unsetKey = mKey.IsUnset();
bool autoIncrement = mObjectStore->IsAutoIncrement();
PRInt64 osid = mObjectStore->Id();
const nsString& keyPath = mObjectStore->KeyPath();
if (unsetKey) {
NS_ASSERTION(mAutoIncrement, "Must have a key for non-autoIncrement!");
NS_ASSERTION(autoIncrement, "Must have a key for non-autoIncrement!");
// Will need to add first and then set the key later.
mayOverwrite = false;
}
if (mAutoIncrement && !unsetKey) {
if (autoIncrement && !unsetKey) {
mayOverwrite = true;
}
Savepoint savepoint(mTransaction);
nsCOMPtr<mozIStorageStatement> stmt;
if (!mOverwrite && !unsetKey) {
// Make sure the key doesn't exist already
stmt = mTransaction->GetStatement(mAutoIncrement);
stmt = mTransaction->GetStatement(autoIncrement);
NS_ENSURE_TRUE(stmt, nsIIDBDatabaseException::UNKNOWN_ERR);
mozStorageStatementScoper scoper(stmt);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mOSID);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
NS_NAMED_LITERAL_CSTRING(id, "id");
@ -1384,17 +1445,17 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
}
// Now we add it to the database (or update, depending on our variables).
stmt = mTransaction->AddStatement(true, mayOverwrite, mAutoIncrement);
stmt = mTransaction->AddStatement(true, mayOverwrite, autoIncrement);
NS_ENSURE_TRUE(stmt, nsIIDBDatabaseException::UNKNOWN_ERR);
mozStorageStatementScoper scoper(stmt);
NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mOSID);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (!mAutoIncrement || mayOverwrite) {
if (!autoIncrement || mayOverwrite) {
NS_ASSERTION(!mKey.IsUnset(), "This shouldn't happen!");
if (mKey.IsInt()) {
@ -1417,15 +1478,15 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
if (mayOverwrite && rv == NS_ERROR_STORAGE_CONSTRAINT) {
scoper.Abandon();
stmt = mTransaction->AddStatement(false, true, mAutoIncrement);
stmt = mTransaction->AddStatement(false, true, autoIncrement);
NS_ENSURE_TRUE(stmt, nsIIDBDatabaseException::UNKNOWN_ERR);
mozStorageStatementScoper scoper2(stmt);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mOSID);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (!mAutoIncrement) {
if (!autoIncrement) {
NS_ASSERTION(!mKey.IsUnset(), "This shouldn't happen!");
if (mKey.IsInt()) {
@ -1452,7 +1513,7 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
}
// If we are supposed to generate a key, get the new id.
if (mAutoIncrement && !mOverwrite) {
if (autoIncrement && !mOverwrite) {
#ifdef DEBUG
PRInt64 oldKey = unsetKey ? 0 : mKey.IntValue();
#endif
@ -1467,7 +1528,7 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
}
#endif
if (!mKeyPath.IsEmpty() && unsetKey) {
if (!keyPath.IsEmpty() && unsetKey) {
// Special case where someone put an object into an autoIncrement'ing
// objectStore with no key in its keyPath set. We needed to figure out
// which row id we would get above before we could set that properly.
@ -1483,7 +1544,7 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mozStorageStatementScoper scoper2(stmt);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mOSID);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->BindInt64ByName(keyValue, mKey.IntValue());
@ -1499,9 +1560,9 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
// Update our indexes if needed.
if (!mIndexUpdateInfo.IsEmpty()) {
PRInt64 objectDataId = mAutoIncrement ? mKey.IntValue() : LL_MININT;
rv = IDBObjectStore::UpdateIndexes(mTransaction, mOSID, mKey,
mAutoIncrement, mOverwrite,
PRInt64 objectDataId = autoIncrement ? mKey.IntValue() : LL_MININT;
rv = IDBObjectStore::UpdateIndexes(mTransaction, osid, mKey,
autoIncrement, mOverwrite,
objectDataId, mIndexUpdateInfo);
if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
return nsIIDBDatabaseException::CONSTRAINT_ERR;
@ -1509,8 +1570,7 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
}
rv = savepoint.Release();
return NS_SUCCEEDED(rv) ? OK : nsIIDBDatabaseException::UNKNOWN_ERR;
return OK;
}
PRUint16
@ -1533,9 +1593,13 @@ AddHelper::GetSuccessResult(nsIWritableVariant* aResult)
nsresult
AddHelper::ModifyValueForNewKey()
{
NS_ASSERTION(mAutoIncrement && !mKeyPath.IsEmpty() && mKey.IsInt(),
NS_ASSERTION(mObjectStore->IsAutoIncrement() &&
!mObjectStore->KeyPath().IsEmpty() &&
mKey.IsInt(),
"Don't call me!");
const nsString& keyPath = mObjectStore->KeyPath();
JSContext* cx;
nsresult rv = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&cx);
NS_ENSURE_SUCCESS(rv, rv);
@ -1552,8 +1616,8 @@ AddHelper::ModifyValueForNewKey()
JSBool ok;
js::AutoValueRooter key(cx);
const jschar* keyPathChars = reinterpret_cast<const jschar*>(mKeyPath.get());
const size_t keyPathLen = mKeyPath.Length();
const jschar* keyPathChars = reinterpret_cast<const jschar*>(keyPath.get());
const size_t keyPathLen = keyPath.Length();
#ifdef DEBUG
ok = JS_GetUCProperty(cx, obj, keyPathChars, keyPathLen, key.jsval_addr());
@ -1579,12 +1643,13 @@ GetHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_PRECONDITION(aConnection, "Passed a null connection!");
nsCOMPtr<mozIStorageStatement> stmt =
mTransaction->GetStatement(mAutoIncrement);
mTransaction->GetStatement(mObjectStore->IsAutoIncrement());
NS_ENSURE_TRUE(stmt, nsIIDBDatabaseException::UNKNOWN_ERR);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mOSID);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
mObjectStore->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
NS_ASSERTION(!mKey.IsUnset() && !mKey.IsNull(), "Must have a key here!");
@ -1635,12 +1700,13 @@ RemoveHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_PRECONDITION(aConnection, "Passed a null connection!");
nsCOMPtr<mozIStorageStatement> stmt =
mTransaction->RemoveStatement(mAutoIncrement);
mTransaction->RemoveStatement(mObjectStore->IsAutoIncrement());
NS_ENSURE_TRUE(stmt, nsIIDBDatabaseException::UNKNOWN_ERR);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mOSID);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
mObjectStore->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
NS_ASSERTION(!mKey.IsUnset() && !mKey.IsNull(), "Must have a key here!");
@ -1694,7 +1760,7 @@ ClearHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
NS_PRECONDITION(aConnection, "Passed a null connection!");
nsCString table;
if (mAutoIncrement) {
if (mObjectStore->IsAutoIncrement()) {
table.AssignLiteral("ai_object_data");
}
else {
@ -1709,7 +1775,8 @@ ClearHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mOSID);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
mObjectStore->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->Execute();
@ -1892,34 +1959,38 @@ OpenCursorHelper::GetSuccessResult(nsIWritableVariant* aResult)
PRUint16
CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
Savepoint savepoint(mTransaction);
// Insert the data into the database.
nsCOMPtr<mozIStorageStatement> stmt =
mTransaction->GetCachedStatement(
"INSERT INTO object_store_index (name, key_path, unique_index, "
"INSERT INTO object_store_index (id, name, key_path, unique_index, "
"object_store_id, object_store_autoincrement) "
"VALUES (:name, :key_path, :unique, :osid, :os_auto_increment)"
"VALUES (:id, :name, :key_path, :unique, :osid, :os_auto_increment)"
);
NS_ENSURE_TRUE(stmt, nsIIDBDatabaseException::UNKNOWN_ERR);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mName);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
mIndex->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"), mKeyPath);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mIndex->Name());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
mIndex->KeyPath());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("unique"),
mUnique ? 1 : 0);
mIndex->IsUnique() ? 1 : 0);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStore->Id());
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
mIndex->ObjectStore()->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("os_auto_increment"),
mAutoIncrement ? 1 : 0);
mIndex->IsAutoIncrement() ? 1 : 0);
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (NS_FAILED(stmt->Execute())) {
@ -1933,17 +2004,17 @@ CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
PRUint16 rc = InsertDataFromObjectStore(aConnection);
NS_ENSURE_TRUE(rc == OK, rc);
rv = savepoint.Release();
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
return OK;
}
PRUint16
CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
{
bool autoIncrement = mIndex->IsAutoIncrement();
nsCAutoString table;
nsCAutoString columns;
if (mAutoIncrement) {
if (autoIncrement) {
table.AssignLiteral("ai_object_data");
columns.AssignLiteral("id, data");
}
@ -1962,13 +2033,14 @@ CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
mObjectStore->Id());
mIndex->ObjectStore()->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
PRBool hasResult;
while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
nsCOMPtr<mozIStorageStatement> insertStmt =
mTransaction->IndexUpdateStatement(mAutoIncrement, mUnique, false);
mTransaction->IndexUpdateStatement(autoIncrement, mIndex->IsUnique(),
false);
NS_ENSURE_TRUE(insertStmt, nsIIDBDatabaseException::UNKNOWN_ERR);
mozStorageStatementScoper scoper2(insertStmt);
@ -1980,7 +2052,7 @@ CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
stmt->AsInt64(0));
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (!mAutoIncrement) {
if (!autoIncrement) {
// XXX does this cause problems with the affinity?
nsString key;
rv = stmt->GetString(2, key);
@ -1997,7 +2069,8 @@ CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
Key key;
JSContext* cx = nsnull;
rv = IDBObjectStore::GetKeyPathValueFromJSON(json, mKeyPath, &cx, key);
rv = IDBObjectStore::GetKeyPathValueFromJSON(json, mIndex->KeyPath(), &cx,
key);
// XXX this should be a constraint error maybe?
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
@ -2026,50 +2099,19 @@ CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
}
PRUint16
CreateIndexHelper::GetSuccessResult(nsIWritableVariant* aResult)
CreateIndexHelper::OnSuccess(nsIDOMEventTarget* aTarget)
{
NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
ObjectStoreInfo* info = mObjectStore->GetObjectStoreInfo();
if (!info) {
NS_ERROR("Couldn't get info!");
return nsIIDBDatabaseException::UNKNOWN_ERR;
}
#ifdef DEBUG
{
bool found = false;
PRUint32 indexCount = info->indexes.Length();
for (PRUint32 index = 0; index < indexCount; index++) {
if (info->indexes[index].name == mName) {
found = true;
break;
}
}
NS_ASSERTION(!found, "Alreayd have this index!");
}
#endif
IndexInfo* newInfo = info->indexes.AppendElement();
if (!newInfo) {
NS_ERROR("Couldn't add index name! Out of memory?");
return nsIIDBDatabaseException::UNKNOWN_ERR;
}
newInfo->id = mId;
newInfo->name = mName;
newInfo->keyPath = mKeyPath;
newInfo->unique = mUnique;
newInfo->autoIncrement = mAutoIncrement;
nsCOMPtr<nsIIDBIndex> result;
nsresult rv = mObjectStore->Index(mName, getter_AddRefs(result));
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
aResult->SetAsISupports(result);
NS_ASSERTION(!aTarget, "Huh?!");
return OK;
}
void
CreateIndexHelper::OnError(nsIDOMEventTarget* aTarget,
PRUint16 aErrorCode)
{
NS_ASSERTION(!aTarget, "Huh?!");
}
PRUint16
RemoveIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
@ -2095,48 +2137,27 @@ RemoveIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
}
PRUint16
RemoveIndexHelper::GetSuccessResult(nsIWritableVariant* /* aResult */)
RemoveIndexHelper::OnSuccess(nsIDOMEventTarget* aTarget)
{
NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
ObjectStoreInfo* info = mObjectStore->GetObjectStoreInfo();
if (!info) {
NS_ERROR("Unable to get object store info!");
return nsIIDBDatabaseException::UNKNOWN_ERR;
}
#ifdef DEBUG
{
bool found = false;
PRUint32 indexCount = info->indexes.Length();
for (PRUint32 index = 0; index < indexCount; index++) {
if (info->indexes[index].name == mName) {
found = true;
break;
}
}
NS_ASSERTION(found, "Didn't know about this one!");
}
#endif
PRUint32 indexCount = info->indexes.Length();
for (PRUint32 index = 0; index < indexCount; index++) {
if (info->indexes[index].name == mName) {
info->indexes.RemoveElementAt(index);
break;
}
}
NS_ASSERTION(!aTarget, "Huh?!");
return OK;
}
void
RemoveIndexHelper::OnError(nsIDOMEventTarget* aTarget,
PRUint16 aErrorCode)
{
NS_NOTREACHED("Removing an index should never fail here!");
}
PRUint16
GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
nsCString table;
nsCString keyColumn;
if (mAutoIncrement) {
if (mObjectStore->IsAutoIncrement()) {
table.AssignLiteral("ai_object_data");
keyColumn.AssignLiteral("id");
}
@ -2195,7 +2216,7 @@ GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->BindInt64ByName(osid, mOSID);
nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id());
NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
if (!mLeftKey.IsUnset()) {

Просмотреть файл

@ -44,11 +44,14 @@
#include "mozilla/dom/indexedDB/IDBTransaction.h"
#include "nsIIDBObjectStore.h"
#include "nsIIDBTransaction.h"
#include "nsDOMEventTargetHelper.h"
BEGIN_INDEXEDDB_NAMESPACE
class AsyncConnectionHelper;
struct ObjectStoreInfo;
struct IndexInfo;
struct IndexUpdateInfo;
@ -221,8 +224,7 @@ public:
static already_AddRefed<IDBObjectStore>
Create(IDBTransaction* aTransaction,
const ObjectStoreInfo* aInfo,
PRUint16 aMode);
const ObjectStoreInfo* aInfo);
static nsresult
GetKeyFromVariant(nsIVariant* aKeyVariant,
@ -262,6 +264,10 @@ public:
PRInt64 aObjectDataId,
const nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
const nsString& Name() const
{
return mName;
}
bool TransactionIsOpen() const
{
@ -280,6 +286,7 @@ public:
PRInt64 Id() const
{
NS_ASSERTION(mId != LL_MININT, "Don't ask for this yet!");
return mId;
}
@ -314,7 +321,6 @@ private:
nsString mKeyPath;
PRBool mAutoIncrement;
PRUint32 mDatabaseId;
PRUint16 mMode;
// Only touched on the main thread.
nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;

Просмотреть файл

@ -132,3 +132,58 @@ NS_IMPL_ADDREF_INHERITED(IDBRequest, nsDOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(IDBRequest, nsDOMEventTargetHelper)
DOMCI_DATA(IDBRequest, IDBRequest)
// static
already_AddRefed<IDBVersionChangeRequest>
IDBVersionChangeRequest::Create(nsISupports* aSource,
nsIScriptContext* aScriptContext,
nsPIDOMWindow* aOwner)
{
if (!aScriptContext || !aOwner) {
NS_ERROR("Null context and owner!");
return nsnull;
}
nsRefPtr<IDBVersionChangeRequest> request(new IDBVersionChangeRequest());
request->mSource = aSource;
request->mScriptContext = aScriptContext;
request->mOwner = aOwner;
return request.forget();
}
NS_IMETHODIMP
IDBVersionChangeRequest::SetOnblocked(nsIDOMEventListener* aBlockedListener)
{
return RemoveAddEventListener(NS_LITERAL_STRING(BLOCKED_EVT_STR),
mOnBlockedListener, aBlockedListener);
}
NS_IMETHODIMP
IDBVersionChangeRequest::GetOnblocked(nsIDOMEventListener** aBlockedListener)
{
return GetInnerEventListener(mOnBlockedListener, aBlockedListener);
}
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBVersionChangeRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBVersionChangeRequest,
IDBRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnBlockedListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBVersionChangeRequest,
IDBRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnBlockedListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBVersionChangeRequest)
NS_INTERFACE_MAP_ENTRY(nsIIDBVersionChangeRequest)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBVersionChangeRequest)
NS_INTERFACE_MAP_END_INHERITING(IDBRequest)
NS_IMPL_ADDREF_INHERITED(IDBVersionChangeRequest, IDBRequest)
NS_IMPL_RELEASE_INHERITED(IDBVersionChangeRequest, IDBRequest)
DOMCI_DATA(IDBVersionChangeRequest, IDBVersionChangeRequest)

Просмотреть файл

@ -44,6 +44,7 @@
#include "mozilla/dom/indexedDB/IndexedDatabase.h"
#include "nsIIDBRequest.h"
#include "nsIIDBVersionChangeRequest.h"
#include "nsDOMEventTargetHelper.h"
#include "nsCycleCollectionParticipant.h"
@ -67,10 +68,9 @@ public:
nsIScriptContext* aScriptContext,
nsPIDOMWindow* aOwner);
already_AddRefed<nsISupports> Source()
nsISupports* Source()
{
nsCOMPtr<nsISupports> source(mSource);
return source.forget();
return mSource;
}
void SetDone()
@ -111,6 +111,26 @@ protected:
PRUint16 mReadyState;
};
class IDBVersionChangeRequest : public IDBRequest,
public nsIIDBVersionChangeRequest
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIIDBREQUEST(IDBRequest::)
NS_DECL_NSIIDBVERSIONCHANGEREQUEST
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBVersionChangeRequest,
IDBRequest)
static
already_AddRefed<IDBVersionChangeRequest>
Create(nsISupports* aSource,
nsIScriptContext* aScriptContext,
nsPIDOMWindow* aOwner);
protected:
nsRefPtr<nsDOMEventListenerWrapper> mOnBlockedListener;
};
END_INDEXEDDB_NAMESPACE
#endif // mozilla_dom_indexeddb_idbrequest_h__

Просмотреть файл

@ -54,8 +54,7 @@
#include "IDBObjectStore.h"
#include "TransactionThreadPool.h"
#define SAVEPOINT_INITIAL "initial"
#define SAVEPOINT_INTERMEDIATE "intermediate"
#define SAVEPOINT_NAME "savepoint"
USING_INDEXEDDB_NAMESPACE
@ -110,7 +109,6 @@ IDBTransaction::IDBTransaction()
mTimeout(0),
mPendingRequests(0),
mSavepointCount(0),
mHasInitialSavepoint(false),
mAborted(false)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@ -182,25 +180,18 @@ IDBTransaction::StartSavepoint()
NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
NS_PRECONDITION(mConnection, "No connection!");
nsresult rv;
nsCOMPtr<mozIStorageStatement> stmt = GetCachedStatement(NS_LITERAL_CSTRING(
"SAVEPOINT " SAVEPOINT_NAME
));
NS_ENSURE_TRUE(stmt, false);
if (!mHasInitialSavepoint) {
NS_NAMED_LITERAL_CSTRING(beginSavepoint,
"SAVEPOINT " SAVEPOINT_INITIAL);
rv = mConnection->ExecuteSimpleSQL(beginSavepoint);
NS_ENSURE_SUCCESS(rv, false);
mozStorageStatementScoper scoper(stmt);
mHasInitialSavepoint = true;
}
NS_ASSERTION(!mSavepointCount, "Mismatch!");
mSavepointCount = 1;
// TODO try to cache this statement
NS_NAMED_LITERAL_CSTRING(savepoint, "SAVEPOINT " SAVEPOINT_INTERMEDIATE);
rv = mConnection->ExecuteSimpleSQL(savepoint);
nsresult rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, false);
++mSavepointCount;
return true;
}
@ -210,13 +201,19 @@ IDBTransaction::ReleaseSavepoint()
NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
NS_PRECONDITION(mConnection, "No connection!");
NS_ASSERTION(mSavepointCount == 1, "Mismatch!");
mSavepointCount = 0;
NS_ASSERTION(mSavepointCount, "Mismatch!");
// TODO try to cache this statement
NS_NAMED_LITERAL_CSTRING(savepoint, "RELEASE " SAVEPOINT_INTERMEDIATE);
nsresult rv = mConnection->ExecuteSimpleSQL(savepoint);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageStatement> stmt = GetCachedStatement(NS_LITERAL_CSTRING(
"RELEASE SAVEPOINT " SAVEPOINT_NAME
));
NS_ENSURE_TRUE(stmt, false);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, false);
--mSavepointCount;
return NS_OK;
}
@ -230,11 +227,15 @@ IDBTransaction::RollbackSavepoint()
NS_ASSERTION(mSavepointCount == 1, "Mismatch!");
mSavepointCount = 0;
// TODO try to cache this statement
NS_NAMED_LITERAL_CSTRING(savepoint, "ROLLBACK TO " SAVEPOINT_INTERMEDIATE);
if (NS_FAILED(mConnection->ExecuteSimpleSQL(savepoint))) {
NS_ERROR("Rollback failed!");
}
nsCOMPtr<mozIStorageStatement> stmt = GetCachedStatement(NS_LITERAL_CSTRING(
"ROLLBACK TO SAVEPOINT " SAVEPOINT_NAME
));
NS_ENSURE_TRUE(stmt,);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv,);
}
nsresult
@ -251,6 +252,10 @@ IDBTransaction::GetOrCreateConnection(mozIStorageConnection** aResult)
IDBFactory::GetConnection(mDatabase->FilePath());
NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE);
NS_NAMED_LITERAL_CSTRING(beginTransaction, "BEGIN TRANSACTION;");
nsresult rv = connection->ExecuteSimpleSQL(beginTransaction);
NS_ENSURE_SUCCESS(rv, false);
connection.swap(mConnection);
}
@ -529,13 +534,6 @@ IDBTransaction::TransactionIsOpen() const
return mReadyState == nsIIDBTransaction::INITIAL ||
mReadyState == nsIIDBTransaction::LOADING;
}
bool
IDBTransaction::IsWriteAllowed() const
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return mMode == nsIIDBTransaction::READ_WRITE;
}
#endif
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBTransaction)
@ -592,8 +590,7 @@ IDBTransaction::GetMode(PRUint16* aMode)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
*aMode = mMode == IDBTransaction::FULL_LOCK ?
nsIIDBTransaction::READ_WRITE : mMode;
*aMode = mMode;
return NS_OK;
}
@ -604,10 +601,10 @@ IDBTransaction::GetObjectStoreNames(nsIDOMDOMStringList** aObjectStores)
nsRefPtr<nsDOMStringList> list(new nsDOMStringList());
nsTArray<nsString> stackArray;
nsAutoTArray<nsString, 10> stackArray;
nsTArray<nsString>* arrayOfNames;
if (mMode == IDBTransaction::FULL_LOCK) {
if (mMode == IDBTransaction::VERSION_CHANGE) {
DatabaseInfo* info;
if (!DatabaseInfo::Get(mDatabase->Id(), &info)) {
NS_ERROR("This should never fail!");
@ -646,23 +643,16 @@ IDBTransaction::ObjectStore(const nsAString& aName,
ObjectStoreInfo* info = nsnull;
PRUint32 count = mObjectStoreNames.Length();
for (PRUint32 index = 0; index < count; index++) {
nsString& name = mObjectStoreNames[index];
if (name == aName) {
if (!ObjectStoreInfo::Get(mDatabase->Id(), aName, &info)) {
NS_ERROR("Don't know about this one?!");
}
break;
}
if (mMode == nsIIDBTransaction::VERSION_CHANGE ||
mObjectStoreNames.Contains(aName)) {
ObjectStoreInfo::Get(mDatabase->Id(), aName, &info);
}
if (!info) {
return NS_ERROR_NOT_AVAILABLE;
}
nsRefPtr<IDBObjectStore> objectStore =
IDBObjectStore::Create(this, info, mMode);
nsRefPtr<IDBObjectStore> objectStore(IDBObjectStore::Create(this, info));
NS_ENSURE_TRUE(objectStore, NS_ERROR_FAILURE);
objectStore.forget(_retval);
@ -738,11 +728,15 @@ IDBTransaction::SetOntimeout(nsIDOMEventListener* aOntimeout)
CommitHelper::CommitHelper(IDBTransaction* aTransaction)
: mTransaction(aTransaction),
mAborted(!!aTransaction->mAborted),
mHasInitialSavepoint(!!aTransaction->mHasInitialSavepoint)
mHaveMetadata(false)
{
mConnection.swap(aTransaction->mConnection);
}
CommitHelper::~CommitHelper()
{
}
NS_IMPL_THREADSAFE_ISUPPORTS1(CommitHelper, nsIRunnable)
NS_IMETHODIMP
@ -753,6 +747,24 @@ CommitHelper::Run()
nsCOMPtr<nsIDOMEvent> event;
if (mAborted) {
if (mHaveMetadata) {
NS_ASSERTION(mTransaction->Mode() == nsIIDBTransaction::VERSION_CHANGE,
"Bad transaction type!");
DatabaseInfo* dbInfo;
if (!DatabaseInfo::Get(mTransaction->Database()->Id(), &dbInfo)) {
NS_ERROR("This should never fail!");
}
if (NS_FAILED(IDBFactory::UpdateDatabaseMetadata(dbInfo, mOldVersion,
mOldObjectStores))) {
NS_WARNING("Failed to update database metadata!");
}
else {
NS_ASSERTION(mOldObjectStores.IsEmpty(), "Should have swapped!");
}
}
event = IDBEvent::CreateGenericEvent(NS_LITERAL_STRING(ABORT_EVT_STR));
}
else {
@ -769,6 +781,8 @@ CommitHelper::Run()
return NS_OK;
}
NS_ASSERTION(mConnection, "This had better not be null!");
IDBDatabase* database = mTransaction->Database();
if (database->IsInvalidated()) {
mAborted = true;
@ -776,6 +790,13 @@ CommitHelper::Run()
IDBFactory::SetCurrentDatabase(database);
if (!mAborted) {
NS_NAMED_LITERAL_CSTRING(release, "END TRANSACTION");
if (NS_FAILED(mConnection->ExecuteSimpleSQL(release))) {
mAborted = PR_TRUE;
}
}
if (mAborted) {
NS_ASSERTION(mConnection, "This had better not be null!");
@ -783,13 +804,18 @@ CommitHelper::Run()
if (NS_FAILED(mConnection->ExecuteSimpleSQL(rollback))) {
NS_WARNING("Failed to rollback transaction!");
}
}
else if (mHasInitialSavepoint) {
NS_ASSERTION(mConnection, "This had better not be null!");
NS_NAMED_LITERAL_CSTRING(release, "RELEASE " SAVEPOINT_INITIAL);
if (NS_FAILED(mConnection->ExecuteSimpleSQL(release))) {
mAborted = PR_TRUE;
if (mTransaction->Mode() == nsIIDBTransaction::VERSION_CHANGE) {
nsresult rv =
IDBFactory::LoadDatabaseInformation(mConnection,
mTransaction->Database()->Id(),
mOldVersion, mOldObjectStores);
if (NS_SUCCEEDED(rv)) {
mHaveMetadata = true;
}
else {
NS_WARNING("Failed to get database information!");
}
}
}

Просмотреть файл

@ -91,6 +91,9 @@ public:
nsresult ReleaseSavepoint();
void RollbackSavepoint();
// Only meant to be called on mStorageThread!
nsresult GetOrCreateConnection(mozIStorageConnection** aConnection);
already_AddRefed<mozIStorageStatement>
AddStatement(bool aCreate,
bool aOverwrite,
@ -129,21 +132,24 @@ public:
#ifdef DEBUG
bool TransactionIsOpen() const;
bool IsWriteAllowed() const;
#else
bool TransactionIsOpen() const
{
return mReadyState == nsIIDBTransaction::INITIAL ||
mReadyState == nsIIDBTransaction::LOADING;
}
#endif
bool IsWriteAllowed() const
{
return mMode == nsIIDBTransaction::READ_WRITE;
return mMode == nsIIDBTransaction::READ_WRITE ||
mMode == nsIIDBTransaction::VERSION_CHANGE;
}
#endif
enum { FULL_LOCK = nsIIDBTransaction::SNAPSHOT_READ + 1 };
PRUint16 Mode()
{
return mMode;
}
IDBDatabase* Database()
{
@ -155,9 +161,6 @@ private:
IDBTransaction();
~IDBTransaction();
// Only meant to be called on mStorageThread!
nsresult GetOrCreateConnection(mozIStorageConnection** aConnection);
nsresult CommitOrRollback();
nsRefPtr<IDBDatabase> mDatabase;
@ -182,7 +185,6 @@ private:
// Only touched on the database thread.
PRUint32 mSavepointCount;
bool mHasInitialSavepoint;
bool mAborted;
};
@ -193,6 +195,7 @@ public:
NS_DECL_NSIRUNNABLE
CommitHelper(IDBTransaction* aTransaction);
~CommitHelper();
template<class T>
bool AddDoomedObject(nsCOMPtr<T>& aCOMPtr)
@ -211,8 +214,12 @@ private:
nsRefPtr<IDBTransaction> mTransaction;
nsCOMPtr<mozIStorageConnection> mConnection;
nsAutoTArray<nsCOMPtr<nsISupports>, 10> mDoomedObjects;
nsString mOldVersion;
nsTArray<nsAutoPtr<ObjectStoreInfo> > mOldObjectStores;
bool mAborted;
bool mHasInitialSavepoint;
bool mHaveMetadata;
};
END_INDEXEDDB_NAMESPACE

Просмотреть файл

@ -39,6 +39,7 @@
#include "IndexedDatabaseManager.h"
#include "nsIIDBDatabaseException.h"
#include "nsIFile.h"
#include "nsIObserverService.h"
#include "nsISimpleEnumerator.h"
@ -50,7 +51,9 @@
#include "nsXPCOM.h"
#include "nsXPCOMPrivate.h"
#include "AsyncConnectionHelper.h"
#include "IDBDatabase.h"
#include "IDBEvents.h"
#include "IDBFactory.h"
#include "LazyIdleThread.h"
#include "TransactionThreadPool.h"
@ -95,6 +98,113 @@ EnumerateToTArray(const nsACString& aKey,
return PL_DHASH_NEXT;
}
// Responsible for calling IDBDatabase.setVersion after a pending version change
// transaction has completed.
class DelayedSetVersion : public nsRunnable
{
public:
DelayedSetVersion(IDBDatabase* aDatabase,
IDBVersionChangeRequest* aRequest,
const nsAString& aVersion,
AsyncConnectionHelper* aHelper)
: mDatabase(aDatabase),
mRequest(aRequest),
mVersion(aVersion),
mHelper(aHelper)
{ }
NS_IMETHOD Run()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
nsresult rv = mgr->SetDatabaseVersion(mDatabase, mRequest, mVersion,
mHelper);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
private:
nsRefPtr<IDBDatabase> mDatabase;
nsRefPtr<IDBVersionChangeRequest> mRequest;
nsString mVersion;
nsRefPtr<AsyncConnectionHelper> mHelper;
};
// Responsible for firing "versionchange" events at all live and non-closed
// databases, and for firing a "blocked" event at the requesting database if any
// databases fail to close.
class VersionChangeEventsRunnable : public nsRunnable
{
public:
VersionChangeEventsRunnable(
IDBDatabase* aRequestingDatabase,
IDBVersionChangeRequest* aRequest,
nsTArray<nsRefPtr<IDBDatabase> >& aWaitingDatabases,
const nsAString& aVersion)
: mRequestingDatabase(aRequestingDatabase),
mRequest(aRequest),
mVersion(aVersion)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aRequestingDatabase, "Null pointer!");
NS_ASSERTION(aRequest, "Null pointer!");
if (!mWaitingDatabases.SwapElements(aWaitingDatabases)) {
NS_ERROR("This should never fail!");
}
}
NS_IMETHOD Run()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// Fire version change events at all of the databases that are not already
// closed.
for (PRUint32 index = 0; index < mWaitingDatabases.Length(); index++) {
nsRefPtr<IDBDatabase>& database = mWaitingDatabases[index];
if (!database->IsClosed()) {
nsCOMPtr<nsIDOMEvent> event(IDBVersionChangeEvent::Create(mVersion));
NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
PRBool dummy;
database->DispatchEvent(event, &dummy);
}
}
// Now check to see if any didn't close. If there are some running still
// then fire the blocked event.
for (PRUint32 index = 0; index < mWaitingDatabases.Length(); index++) {
if (!mWaitingDatabases[index]->IsClosed()) {
nsISupports* source =
static_cast<nsPIDOMEventTarget*>(mRequestingDatabase);
nsCOMPtr<nsIDOMEvent> event =
IDBVersionChangeEvent::CreateBlocked(source, mVersion);
NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
PRBool dummy;
mRequest->DispatchEvent(event, &dummy);
break;
}
}
return NS_OK;
}
private:
nsRefPtr<IDBDatabase> mRequestingDatabase;
nsRefPtr<IDBVersionChangeRequest> mRequest;
nsTArray<nsRefPtr<IDBDatabase> > mWaitingDatabases;
nsString mVersion;
};
} // anonymous namespace
IndexedDatabaseManager::IndexedDatabaseManager()
@ -180,7 +290,6 @@ IndexedDatabaseManager::FactoryCreate()
return GetOrCreate().get();
}
// Called when an IDBDatabase is constructed.
bool
IndexedDatabaseManager::RegisterDatabase(IDBDatabase* aDatabase)
{
@ -211,7 +320,6 @@ IndexedDatabaseManager::RegisterDatabase(IDBDatabase* aDatabase)
return true;
}
// Called when an IDBDatabase is destroyed.
void
IndexedDatabaseManager::UnregisterDatabase(IDBDatabase* aDatabase)
{
@ -231,14 +339,12 @@ IndexedDatabaseManager::UnregisterDatabase(IDBDatabase* aDatabase)
NS_ERROR("Didn't know anything about this database!");
}
// Called when OriginClearRunnable has finished its Run() method.
void
IndexedDatabaseManager::OnOriginClearComplete(OriginClearRunnable* aRunnable)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aRunnable, "Null pointer!");
NS_ASSERTION(!aRunnable->mThread, "Thread should be null!");
NS_ASSERTION(aRunnable->mDatabasesWaiting.IsEmpty(), "Databases waiting?!");
NS_ASSERTION(aRunnable->mDelayedRunnables.IsEmpty(),
"Delayed runnables should have been dispatched already!");
@ -247,7 +353,6 @@ IndexedDatabaseManager::OnOriginClearComplete(OriginClearRunnable* aRunnable)
}
}
// Called when AsyncUsageRunnable has finished its Run() method.
void
IndexedDatabaseManager::OnUsageCheckComplete(AsyncUsageRunnable* aRunnable)
{
@ -261,13 +366,29 @@ IndexedDatabaseManager::OnUsageCheckComplete(AsyncUsageRunnable* aRunnable)
}
}
// Waits until it is safe for a new database to be created with the given origin
// before dispatching the given runnable.
nsresult
IndexedDatabaseManager::WaitForClearAndDispatch(const nsACString& aOrigin,
nsIRunnable* aRunnable)
void
IndexedDatabaseManager::OnSetVersionRunnableComplete(
SetVersionRunnable* aRunnable)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aRunnable, "Null pointer!");
NS_ASSERTION(aRunnable->mDelayedRunnables.IsEmpty(),
"Delayed runnables should have been dispatched already!");
// Remove this runnable from the list. This will allow other databases to
// begin to request version changes.
if (!mSetVersionRunnables.RemoveElement(aRunnable)) {
NS_ERROR("Don't know anything about this runnable!");
}
}
nsresult
IndexedDatabaseManager::WaitForOpenAllowed(const nsAString& aName,
const nsACString& aOrigin,
nsIRunnable* aRunnable)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!aName.IsEmpty(), "Empty name!");
NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
NS_ASSERTION(aRunnable, "Null pointer!");
@ -285,8 +406,23 @@ IndexedDatabaseManager::WaitForClearAndDispatch(const nsACString& aOrigin,
}
}
// We aren't currently clearing databases for this origin, so dispatch the
// runnable immediately.
// Check to see if we're currently doing a SetVersion transaction for this
// database. If so then we delay this runnable for later.
for (PRUint32 index = 0; index < mSetVersionRunnables.Length(); index++) {
nsRefPtr<SetVersionRunnable>& runnable = mSetVersionRunnables[index];
if (runnable->mRequestingDatabase->Name() == aName &&
runnable->mRequestingDatabase->Origin() == aOrigin) {
nsCOMPtr<nsIRunnable>* newPtr =
runnable->mDelayedRunnables.AppendElement(aRunnable);
NS_ENSURE_TRUE(newPtr, NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
}
// We aren't currently clearing databases for this origin and we're not
// running a SetVersion transaction for this database so dispatch the runnable
// immediately.
return NS_DispatchToCurrentThread(aRunnable);
}
@ -297,6 +433,176 @@ IndexedDatabaseManager::IsShuttingDown()
return !!gShutdown;
}
nsresult
IndexedDatabaseManager::SetDatabaseVersion(IDBDatabase* aDatabase,
IDBVersionChangeRequest* aRequest,
const nsAString& aVersion,
AsyncConnectionHelper* aHelper)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aDatabase, "Null pointer!");
NS_ASSERTION(aHelper, "Null pointer!");
nsresult rv;
// See if another database has already asked to change the version.
for (PRUint32 index = 0; index < mSetVersionRunnables.Length(); index++) {
nsRefPtr<SetVersionRunnable>& runnable = mSetVersionRunnables[index];
if (runnable->mRequestingDatabase->Id() == aDatabase->Id()) {
if (runnable->mRequestingDatabase == aDatabase) {
// Same database, just queue this call to run after the current
// SetVersion transaction completes.
nsRefPtr<DelayedSetVersion> delayed =
new DelayedSetVersion(aDatabase, aRequest, aVersion, aHelper);
if (!runnable->mDelayedRunnables.AppendElement(delayed)) {
NS_WARNING("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
// Different database, we can't let this one succeed.
aHelper->SetError(nsIIDBDatabaseException::DEADLOCK_ERR);
rv = NS_DispatchToCurrentThread(aHelper);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
}
// Grab all live databases for the same origin.
nsTArray<IDBDatabase*>* array;
if (!mLiveDatabases.Get(aDatabase->Origin(), &array)) {
NS_ERROR("Must have some alive if we've got a live argument!");
}
// Hold on to all database objects that represent the same database file
// (except the one that is requesting this version change).
nsTArray<nsRefPtr<IDBDatabase> > liveDatabases;
for (PRUint32 index = 0; index < array->Length(); index++) {
IDBDatabase*& database = array->ElementAt(index);
if (database != aDatabase &&
database->Id() == aDatabase->Id() &&
!database->IsClosed() &&
!liveDatabases.AppendElement(database)) {
NS_WARNING("Out of memory?");
return NS_ERROR_OUT_OF_MEMORY;
}
}
// Adding an element to this array here will keep other databases from
// requesting a version change.
nsRefPtr<SetVersionRunnable> runnable =
new SetVersionRunnable(aDatabase, liveDatabases);
if (!mSetVersionRunnables.AppendElement(runnable)) {
NS_WARNING("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ASSERTION(liveDatabases.IsEmpty(), "Should have swapped!");
// When all databases are closed we want to dispatch the SetVersion
// transaction to the transaction pool.
runnable->mHelper = aHelper;
if (runnable->mDatabases.IsEmpty()) {
// There are no other databases that need to be closed. Go ahead and run
// the transaction now.
RunSetVersionTransaction(aDatabase);
}
else {
// Otherwise we need to wait for all the other databases to complete.
// Schedule a version change events runnable .
nsTArray<nsRefPtr<IDBDatabase> > waitingDatabases;
if (!waitingDatabases.AppendElements(runnable->mDatabases)) {
NS_WARNING("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
}
nsRefPtr<VersionChangeEventsRunnable> eventsRunnable =
new VersionChangeEventsRunnable(aDatabase, aRequest, waitingDatabases,
aVersion);
rv = NS_DispatchToCurrentThread(eventsRunnable);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
void
IndexedDatabaseManager::CloseDatabasesForWindow(nsPIDOMWindow* aWindow)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aWindow, "Null pointer!");
nsAutoTArray<IDBDatabase*, 50> liveDatabases;
mLiveDatabases.EnumerateRead(EnumerateToTArray, &liveDatabases);
for (PRUint32 index = 0; index < liveDatabases.Length(); index++) {
IDBDatabase*& database = liveDatabases[index];
if (database->Owner() == aWindow && NS_FAILED(database->Close())) {
NS_WARNING("Failed to close database for dying window!");
}
}
}
void
IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aDatabase, "Null pointer!");
// Check through the list of SetVersionRunnables we have amassed to see if
// this database is part of a SetVersion callback.
for (PRUint32 index = 0; index < mSetVersionRunnables.Length(); index++) {
nsRefPtr<SetVersionRunnable>& runnable = mSetVersionRunnables[index];
if (runnable->mRequestingDatabase->Id() == aDatabase->Id()) {
// This is the SetVersionRunnable for the given database file. Remove the
// database from the list of databases that need to be closed. Since we
// use this hook for SetVersion requests that don't actually need to wait
// for other databases the mDatabases array may be empty.
if (!runnable->mDatabases.IsEmpty() &&
!runnable->mDatabases.RemoveElement(aDatabase)) {
NS_ERROR("Didn't have this database in our list!");
}
// Now run the helper if there are no more live databases.
if (runnable->mHelper && runnable->mDatabases.IsEmpty()) {
// Don't hold the callback alive longer than necessary.
nsRefPtr<AsyncConnectionHelper> helper;
helper.swap(runnable->mHelper);
if (NS_FAILED(helper->DispatchToTransactionPool())) {
NS_WARNING("Failed to dispatch to thread pool!");
}
// Now wait for the transaction to complete. Completing the transaction
// will be our cue to remove the SetVersionRunnable from our list and
// therefore allow other SetVersion requests to begin.
TransactionThreadPool* pool = TransactionThreadPool::Get();
NS_ASSERTION(pool, "This should never be null!");
// All other databases should be closed, so we only need to wait on this
// one.
nsAutoTArray<nsRefPtr<IDBDatabase>, 1> array;
if (!array.AppendElement(aDatabase)) {
NS_ERROR("This should never fail!");
}
// Use the SetVersionRunnable as the callback.
if (!pool->WaitForAllDatabasesToComplete(array, runnable)) {
NS_WARNING("Failed to wait for transaction to complete!");
}
}
break;
}
}
}
NS_IMPL_ISUPPORTS2(IndexedDatabaseManager, nsIIndexedDatabaseManager,
nsIObserver)
@ -414,36 +720,36 @@ IndexedDatabaseManager::ClearDatabasesForURI(nsIURI* aURI)
}
nsRefPtr<OriginClearRunnable> runnable =
new OriginClearRunnable(origin, mIOThread, liveDatabases);
NS_ASSERTION(liveDatabases.IsEmpty(), "Should have swapped!");
new OriginClearRunnable(origin, mIOThread);
// Make a new entry for this origin in mOriginClearRunnables.
nsRefPtr<OriginClearRunnable>* newRunnable =
mOriginClearRunnables.AppendElement(runnable);
NS_ENSURE_TRUE(newRunnable, NS_ERROR_OUT_OF_MEMORY);
if (!runnable->mDatabasesWaiting.IsEmpty()) {
PRUint32 count = runnable->mDatabasesWaiting.Length();
if (liveDatabases.IsEmpty()) {
rv = runnable->Run();
NS_ENSURE_SUCCESS(rv, rv);
// Invalidate all the live databases first.
for (PRUint32 index = 0; index < count; index++) {
runnable->mDatabasesWaiting[index]->Invalidate();
}
// Now set up our callbacks so that we know when they have finished.
TransactionThreadPool* pool = TransactionThreadPool::Get();
for (PRUint32 index = 0; index < count; index++) {
if (!pool->WaitForAllTransactionsToComplete(
runnable->mDatabasesWaiting[index],
OriginClearRunnable::DatabaseCompleteCallback,
runnable)) {
NS_WARNING("Out of memory!");
return NS_ERROR_OUT_OF_MEMORY;
}
}
return NS_OK;
}
// Invalidate all the live databases first.
for (PRUint32 index = 0; index < liveDatabases.Length(); index++) {
liveDatabases[index]->Invalidate();
}
// Now set up our callback so that we know when they have finished.
TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
NS_ENSURE_TRUE(pool, NS_ERROR_FAILURE);
if (!pool->WaitForAllDatabasesToComplete(liveDatabases, runnable)) {
NS_WARNING("Can't wait on databases!");
return NS_ERROR_FAILURE;
}
NS_ASSERTION(liveDatabases.IsEmpty(), "Should have swapped!");
return NS_OK;
}
@ -512,45 +818,30 @@ IndexedDatabaseManager::Observe(nsISupports* aSubject,
return NS_ERROR_UNEXPECTED;
}
// Called by the TransactionThreadPool when the given database has completed all
// of its transactions.
void
IndexedDatabaseManager::OriginClearRunnable::OnDatabaseComplete(
IDBDatabase* aDatabase)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aDatabase, "Null pointer!");
NS_ASSERTION(mThread, "This shouldn't be cleared yet!");
// Remove the database from the list of databases that we're waiting on.
if (!mDatabasesWaiting.RemoveElement(aDatabase)) {
NS_ERROR("Don't know anything about this database!");
}
// Now dispatch this runnable to the IO thread if the list is empty.
if (mDatabasesWaiting.IsEmpty()) {
if (NS_FAILED(mThread->Dispatch(this, NS_DISPATCH_NORMAL))) {
NS_WARNING("Can't dispatch to IO thread!");
}
// We no longer need to keep the thread alive.
mThread = nsnull;
}
}
NS_IMPL_THREADSAFE_ISUPPORTS1(IndexedDatabaseManager::OriginClearRunnable,
nsIRunnable)
// Runs twice, first on the IO thread, then again on the main thread. While on
// the IO thread the runnable will actually remove the origin's database files
// and the directory that contains them before dispatching itself back to the
// main thread. When on the main thread the runnable will dispatch any queued
// runnables and then notify the IndexedDatabaseManager that the job has been
// completed.
NS_IMETHODIMP
IndexedDatabaseManager::OriginClearRunnable::Run()
{
if (NS_IsMainThread()) {
// On the first time on the main thread we simply dispatch to the IO thread.
if (mFirstCallback) {
NS_ASSERTION(mThread, "Should have a thread here!");
mFirstCallback = false;
// Dispatch to the IO thread.
if (NS_FAILED(mThread->Dispatch(this, NS_DISPATCH_NORMAL))) {
NS_WARNING("Failed to dispatch to IO thread!");
return NS_ERROR_FAILURE;
}
// Don't need this any longer.
mThread = nsnull;
return NS_OK;
}
NS_ASSERTION(!mThread, "Should have been cleared already!");
// Dispatch any queued runnables that we collected while we were waiting.
@ -570,6 +861,8 @@ IndexedDatabaseManager::OriginClearRunnable::Run()
return NS_OK;
}
NS_ASSERTION(!mThread, "Should have been cleared already!");
// Remove the directory that contains all our databases.
nsCOMPtr<nsIFile> directory;
nsresult rv = IDBFactory::GetDirectoryForOrigin(mOrigin,
@ -606,7 +899,6 @@ IndexedDatabaseManager::AsyncUsageRunnable::AsyncUsageRunnable(
NS_ASSERTION(aCallback, "Null pointer!");
}
// Sets the canceled flag so that the callback is never called.
void
IndexedDatabaseManager::AsyncUsageRunnable::Cancel()
{
@ -615,11 +907,6 @@ IndexedDatabaseManager::AsyncUsageRunnable::Cancel()
}
}
// Runs twice, first on the IO thread, then again on the main thread. While on
// the IO thread the runnable will calculate the size of all files in the
// origin's directory before dispatching itself back to the main thread. When on
// the main thread the runnable will call the callback and then notify the
// IndexedDatabaseManager that the job has been completed.
nsresult
IndexedDatabaseManager::AsyncUsageRunnable::RunInternal()
{
@ -698,8 +985,6 @@ IndexedDatabaseManager::AsyncUsageRunnable::RunInternal()
NS_IMPL_THREADSAFE_ISUPPORTS1(IndexedDatabaseManager::AsyncUsageRunnable,
nsIRunnable)
// Calls the RunInternal method and makes sure that we always dispatch to the
// main thread in case of an error.
NS_IMETHODIMP
IndexedDatabaseManager::AsyncUsageRunnable::Run()
{
@ -718,3 +1003,47 @@ IndexedDatabaseManager::AsyncUsageRunnable::Run()
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
IndexedDatabaseManager::SetVersionRunnable::SetVersionRunnable(
IDBDatabase* aDatabase,
nsTArray<nsRefPtr<IDBDatabase> >& aDatabases)
: mRequestingDatabase(aDatabase)
{
NS_ASSERTION(aDatabase, "Null database!");
if (!mDatabases.SwapElements(aDatabases)) {
NS_ERROR("This should never fail!");
}
}
IndexedDatabaseManager::SetVersionRunnable::~SetVersionRunnable()
{
}
NS_IMPL_ISUPPORTS1(IndexedDatabaseManager::SetVersionRunnable, nsIRunnable)
NS_IMETHODIMP
IndexedDatabaseManager::SetVersionRunnable::Run()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!mHelper, "Should have been cleared already!");
// Dispatch any queued runnables that we picked up while waiting for the
// SetVersion transaction to complete.
for (PRUint32 index = 0; index < mDelayedRunnables.Length(); index++) {
if (NS_FAILED(NS_DispatchToCurrentThread(mDelayedRunnables[index]))) {
NS_WARNING("Failed to dispatch delayed runnable!");
}
}
// No need to hold these alive any longer.
mDelayedRunnables.Clear();
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
// Let the IndexedDatabaseManager know that the SetVersion transaction has
// completed.
mgr->OnSetVersionRunnableComplete(this);
return NS_OK;
}

Просмотреть файл

@ -42,6 +42,7 @@
#include "mozilla/dom/indexedDB/IndexedDatabase.h"
#include "mozilla/dom/indexedDB/IDBDatabase.h"
#include "mozilla/dom/indexedDB/IDBRequest.h"
#include "nsIIndexedDatabaseManager.h"
#include "nsIObserver.h"
@ -52,13 +53,14 @@
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
#define INDEXEDDB_MANAGER_CONTRACTID \
"@mozilla.org/dom/indexeddb/manager;1"
#define INDEXEDDB_MANAGER_CONTRACTID "@mozilla.org/dom/indexeddb/manager;1"
class nsITimer;
BEGIN_INDEXEDDB_NAMESPACE
class AsyncConnectionHelper;
class IndexedDatabaseManager : public nsIIndexedDatabaseManager,
public nsIObserver
{
@ -77,8 +79,11 @@ public:
NS_DECL_NSIINDEXEDDATABASEMANAGER
NS_DECL_NSIOBSERVER
nsresult WaitForClearAndDispatch(const nsACString& aOrigin,
nsIRunnable* aRunnable);
// Waits for databases to be cleared and for version change transactions to
// complete before dispatching the give runnable.
nsresult WaitForOpenAllowed(const nsAString& aName,
const nsACString& aOrigin,
nsIRunnable* aRunnable);
nsIThread* IOThread()
{
@ -86,52 +91,78 @@ public:
return mIOThread;
}
// Returns true if we've begun the shutdown process.
static bool IsShuttingDown();
// Begins the process of setting a database version.
nsresult SetDatabaseVersion(IDBDatabase* aDatabase,
IDBVersionChangeRequest* aRequest,
const nsAString& aVersion,
AsyncConnectionHelper* aHelper);
// Called when a window is being purged from the bfcache in order to force any
// live database objects to close themselves.
void CloseDatabasesForWindow(nsPIDOMWindow* aWindow);
private:
IndexedDatabaseManager();
~IndexedDatabaseManager();
// Called when a database is created.
bool RegisterDatabase(IDBDatabase* aDatabase);
// Called when a database is being unlinked or destroyed.
void UnregisterDatabase(IDBDatabase* aDatabase);
// Called when a database has been closed.
void OnDatabaseClosed(IDBDatabase* aDatabase);
// Called when a version change transaction can run immediately.
void RunSetVersionTransaction(IDBDatabase* aDatabase)
{
OnDatabaseClosed(aDatabase);
}
// Responsible for clearing the database files for a particular origin on the
// IO thread.
// IO thread. Created when nsIIDBIndexedDatabaseManager::ClearDatabasesForURI
// is called. Runs three times, first on the main thread, next on the IO
// thread, and then finally again on the main thread. While on the IO thread
// the runnable will actually remove the origin's database files and the
// directory that contains them before dispatching itself back to the main
// thread. When on the main thread the runnable will dispatch any queued
// runnables and then notify the IndexedDatabaseManager that the job has been
// completed.
class OriginClearRunnable : public nsIRunnable
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
static void DatabaseCompleteCallback(IDBDatabase* aDatabase,
void* aClosure)
{
nsRefPtr<OriginClearRunnable> runnable =
static_cast<OriginClearRunnable*>(aClosure);
runnable->OnDatabaseComplete(aDatabase);
}
void OnDatabaseComplete(IDBDatabase* aDatabase);
OriginClearRunnable(const nsACString& aOrigin,
nsIThread* aThread,
nsTArray<nsRefPtr<IDBDatabase> >& aDatabasesWaiting)
nsIThread* aThread)
: mOrigin(aOrigin),
mThread(aThread)
{
mDatabasesWaiting.SwapElements(aDatabasesWaiting);
}
mThread(aThread),
mFirstCallback(true)
{ }
nsCString mOrigin;
nsCOMPtr<nsIThread> mThread;
nsTArray<nsRefPtr<IDBDatabase> > mDatabasesWaiting;
nsTArray<nsCOMPtr<nsIRunnable> > mDelayedRunnables;
bool mFirstCallback;
};
// Called when OriginClearRunnable has finished its Run() method.
inline void OnOriginClearComplete(OriginClearRunnable* aRunnable);
// Responsible for calculating the amount of space taken up by databases of a
// certain origin. Runs on the IO thread.
// certain origin. Created when nsIIDBIndexedDatabaseManager::GetUsageForURI
// is called. May be canceled with
// nsIIDBIndexedDatabaseManager::CancelGetUsageForURI. Runs twice, first on
// the IO thread, then again on the main thread. While on the IO thread the
// runnable will calculate the size of all files in the origin's directory
// before dispatching itself back to the main thread. When on the main thread
// the runnable will call the callback and then notify the
// IndexedDatabaseManager that the job has been completed.
class AsyncUsageRunnable : public nsIRunnable
{
public:
@ -142,8 +173,11 @@ private:
const nsACString& aOrigin,
nsIIndexedDatabaseUsageCallback* aCallback);
// Sets the canceled flag so that the callback is never called.
void Cancel();
// Run calls the RunInternal method and makes sure that we always dispatch
// to the main thread in case of an error.
inline nsresult RunInternal();
nsCOMPtr<nsIURI> mURI;
@ -153,8 +187,32 @@ private:
PRInt32 mCanceled;
};
// Called when AsyncUsageRunnable has finished its Run() method.
inline void OnUsageCheckComplete(AsyncUsageRunnable* aRunnable);
// Responsible for waiting until all databases have been closed before running
// the version change transaction. Created when
// IndexedDatabaseManager::SetDatabaseVersion is called. Runs only once on the
// main thread when the version change transaction has completed.
class SetVersionRunnable : public nsIRunnable
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
SetVersionRunnable(IDBDatabase* aDatabase,
nsTArray<nsRefPtr<IDBDatabase> >& aDatabases);
~SetVersionRunnable();
nsRefPtr<IDBDatabase> mRequestingDatabase;
nsTArray<nsRefPtr<IDBDatabase> > mDatabases;
nsRefPtr<AsyncConnectionHelper> mHelper;
nsTArray<nsCOMPtr<nsIRunnable> > mDelayedRunnables;
};
// Called when SetVersionRunnable has finished its Run() method.
inline void OnSetVersionRunnableComplete(SetVersionRunnable* aRunnable);
// Maintains a list of live databases per origin.
nsClassHashtable<nsCStringHashKey, nsTArray<IDBDatabase*> > mLiveDatabases;
@ -165,7 +223,13 @@ private:
// usage statistics.
nsAutoTArray<nsRefPtr<AsyncUsageRunnable>, 1> mUsageRunnables;
// Maintains a list of SetVersion calls that are in progress.
nsAutoTArray<nsRefPtr<SetVersionRunnable>, 1> mSetVersionRunnables;
// Thread on which IO is performed.
nsCOMPtr<nsIThread> mIOThread;
// A timer that gets activated at shutdown to ensure we close all databases.
nsCOMPtr<nsITimer> mShutdownTimer;
};

Просмотреть файл

@ -101,8 +101,9 @@ XPIDLSRCS = \
nsIIDBCursor.idl \
nsIIDBDatabase.idl \
nsIIDBDatabaseException.idl \
nsIIDBEvent.idl \
nsIIDBErrorEvent.idl \
nsIIDBEvent.idl \
nsIIDBFactory.idl \
nsIIDBIndex.idl \
nsIIDBKeyRange.idl \
nsIIDBObjectStore.idl \
@ -110,7 +111,8 @@ XPIDLSRCS = \
nsIIDBSuccessEvent.idl \
nsIIDBTransaction.idl \
nsIIDBTransactionEvent.idl \
nsIIDBFactory.idl \
nsIIDBVersionChangeEvent.idl \
nsIIDBVersionChangeRequest.idl \
nsIIndexedDatabaseManager.idl \
$(NULL)

Просмотреть файл

@ -191,15 +191,26 @@ TransactionThreadPool::Cleanup()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (mTransactionsInProgress.Count()) {
// This is actually really bad, but if we don't force everything awake then
// we will deadlock on shutdown...
NS_ERROR("Transactions still in progress!");
}
nsresult rv = mThreadPool->Shutdown();
NS_ENSURE_SUCCESS(rv, rv);
// Make sure the pool is still accessible while any callbacks generated from
// the other threads are processed.
rv = NS_ProcessPendingEvents(nsnull);
NS_ENSURE_SUCCESS(rv, rv);
if (!mCompleteCallbacks.IsEmpty()) {
// Run all callbacks manually now.
for (PRUint32 index = 0; index < mCompleteCallbacks.Length(); index++) {
mCompleteCallbacks[index].mCallback->Run();
}
mCompleteCallbacks.Clear();
// And make sure they get processed.
rv = NS_ProcessPendingEvents(nsnull);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
@ -226,7 +237,7 @@ TransactionThreadPool::FinishTransaction(IDBTransaction* aTransaction)
PRUint32 transactionCount = transactionsInProgress.Length();
#ifdef DEBUG
if (aTransaction->mMode == IDBTransaction::FULL_LOCK) {
if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
NS_ASSERTION(dbTransactionInfo->locked, "Should be locked!");
NS_ASSERTION(transactionCount == 1,
"More transactions running than should be!");
@ -243,16 +254,8 @@ TransactionThreadPool::FinishTransaction(IDBTransaction* aTransaction)
mTransactionsInProgress.Remove(databaseId);
// See if we need to fire any complete callbacks.
for (PRUint32 index = 0; index < mCompleteRunnables.Length(); index++) {
nsRefPtr<DatabaseCompleteCallbackRunnable>& runnable =
mCompleteRunnables[index];
if (runnable->mDatabase == aTransaction->Database()) {
if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
NS_WARNING("Failed to dispatch to current thread?!");
}
mCompleteRunnables.RemoveElementAt(index);
index--;
}
for (PRUint32 index = 0; index < mCompleteCallbacks.Length(); index++) {
MaybeFireCallback(index);
}
}
else {
@ -341,7 +344,7 @@ TransactionThreadPool::TransactionCanRun(IDBTransaction* aTransaction,
PRUint32 transactionCount = transactionsInProgress.Length();
NS_ASSERTION(transactionCount, "Should never be 0!");
if (mode == IDBTransaction::FULL_LOCK) {
if (mode == IDBTransaction::VERSION_CHANGE) {
dbTransactionInfo->lockPending = true;
}
@ -430,7 +433,7 @@ TransactionThreadPool::Dispatch(IDBTransaction* aTransaction,
const PRUint32 databaseId = aTransaction->mDatabase->Id();
#ifdef DEBUG
if (aTransaction->mMode == IDBTransaction::FULL_LOCK) {
if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
NS_ASSERTION(!mTransactionsInProgress.Get(databaseId, nsnull),
"Shouldn't have anything in progress!");
}
@ -445,7 +448,7 @@ TransactionThreadPool::Dispatch(IDBTransaction* aTransaction,
dbTransactionInfo = autoDBTransactionInfo;
}
if (aTransaction->mMode == IDBTransaction::FULL_LOCK) {
if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
NS_ASSERTION(!dbTransactionInfo->locked, "Already locked?!");
dbTransactionInfo->locked = true;
}
@ -491,38 +494,50 @@ TransactionThreadPool::Dispatch(IDBTransaction* aTransaction,
}
bool
TransactionThreadPool::WaitForAllTransactionsToComplete(
IDBDatabase* aDatabase,
DatabaseCompleteCallback aCallback,
void* aUserData)
TransactionThreadPool::WaitForAllDatabasesToComplete(
nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
nsIRunnable* aCallback)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aDatabase, "Null pointer!");
NS_ASSERTION(!aDatabases.IsEmpty(), "No databases to wait on!");
NS_ASSERTION(aCallback, "Null pointer!");
nsRefPtr<DatabaseCompleteCallbackRunnable> runnable =
new DatabaseCompleteCallbackRunnable(aDatabase, aCallback, aUserData);
// See if this database has any active transactions. If not then we can
// dispatch the callback immediately.
const PRUint32 databaseId = aDatabase->Id();
if (!mTransactionsInProgress.Get(databaseId, nsnull)) {
if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
NS_WARNING("Failed to dispatch to current thread?!");
return false;
}
return true;
}
// The database has active transactions, wait and fire the callback later.
if (!mCompleteRunnables.AppendElement(runnable)) {
DatabasesCompleteCallback* callback = mCompleteCallbacks.AppendElement();
if (!callback) {
NS_WARNING("Out of memory!");
return false;
}
callback->mCallback = aCallback;
if (!callback->mDatabases.SwapElements(aDatabases)) {
NS_ERROR("This should never fail!");
}
MaybeFireCallback(mCompleteCallbacks.Length() - 1);
return true;
}
void
TransactionThreadPool::MaybeFireCallback(PRUint32 aCallbackIndex)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
DatabasesCompleteCallback& callback = mCompleteCallbacks[aCallbackIndex];
bool freeToRun = true;
for (PRUint32 index = 0; index < callback.mDatabases.Length(); index++) {
if (mTransactionsInProgress.Get(callback.mDatabases[index]->Id(), nsnull)) {
freeToRun = false;
break;
}
}
if (freeToRun) {
callback.mCallback->Run();
mCompleteCallbacks.RemoveElementAt(aCallbackIndex);
}
}
TransactionThreadPool::
TransactionQueue::TransactionQueue(IDBTransaction* aTransaction,
nsIRunnable* aRunnable)
@ -644,18 +659,3 @@ FinishTransactionRunnable::Run()
return NS_OK;
}
NS_IMPL_ISUPPORTS1(TransactionThreadPool::DatabaseCompleteCallbackRunnable,
nsIRunnable)
NS_IMETHODIMP
TransactionThreadPool::DatabaseCompleteCallbackRunnable::Run()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// Call our callback.
nsRefPtr<IDBDatabase> database;
database.swap(mDatabase);
mCallback(database, mUserData);
return NS_OK;
}

Просмотреть файл

@ -80,12 +80,9 @@ public:
bool aFinish,
nsIRunnable* aFinishRunnable);
typedef void (*DatabaseCompleteCallback)(IDBDatabase* aDatabase,
void* aClosure);
bool WaitForAllTransactionsToComplete(IDBDatabase* aDatabase,
DatabaseCompleteCallback aCallback,
void* aUserData);
bool WaitForAllDatabasesToComplete(
nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
nsIRunnable* aCallback);
protected:
class TransactionQueue : public nsIRunnable
@ -142,26 +139,10 @@ protected:
bool finish;
};
class DatabaseCompleteCallbackRunnable : public nsIRunnable
struct DatabasesCompleteCallback
{
friend class TransactionThreadPool;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
DatabaseCompleteCallbackRunnable(IDBDatabase* aDatabase,
DatabaseCompleteCallback aCallback,
void* aUserData)
: mDatabase(aDatabase),
mCallback(aCallback),
mUserData(aUserData)
{ }
private:
nsRefPtr<IDBDatabase> mDatabase;
DatabaseCompleteCallback mCallback;
void* mUserData;
nsTArray<nsRefPtr<IDBDatabase> > mDatabases;
nsCOMPtr<nsIRunnable> mCallback;
};
TransactionThreadPool();
@ -182,6 +163,8 @@ protected:
aInfo.finishRunnable);
}
void MaybeFireCallback(PRUint32 aCallbackIndex);
nsCOMPtr<nsIThreadPool> mThreadPool;
nsClassHashtable<nsUint32HashKey, DatabaseTransactionInfo>
@ -189,7 +172,7 @@ protected:
nsTArray<QueuedDispatchInfo> mDelayedDispatchQueue;
nsTArray<nsRefPtr<DatabaseCompleteCallbackRunnable> > mCompleteRunnables;
nsTArray<DatabasesCompleteCallback> mCompleteCallbacks;
};
END_INDEXEDDB_NAMESPACE

Просмотреть файл

@ -54,7 +54,7 @@ interface nsIDOMDOMStringList;
* http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBDatabase
* for more information.
*/
[scriptable, uuid(c6255028-c807-4f1e-817f-e4a23638368b)]
[scriptable, uuid(c4cfa75f-9f4e-422c-abae-49a8fe3901f8)]
interface nsIIDBDatabase : nsISupports
{
readonly attribute DOMString name;
@ -65,14 +65,12 @@ interface nsIIDBDatabase : nsISupports
readonly attribute nsIDOMDOMStringList objectStoreNames;
[implicit_jscontext]
nsIIDBRequest
nsIIDBObjectStore
createObjectStore(in AString name,
in AString keyPath,
[optional /* false */] in boolean autoIncrement);
[implicit_jscontext]
nsIIDBRequest
void
removeObjectStore(in AString name);
[implicit_jscontext]
@ -84,4 +82,7 @@ interface nsIIDBDatabase : nsISupports
transaction(in nsIVariant storeNames, // js array of strings
[optional /* READ_ONLY */] in unsigned short mode,
[optional /* 5000ms */] in unsigned long timeout);
void
close();
};

Просмотреть файл

@ -54,7 +54,7 @@ interface nsIDOMDOMStringList;
* http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-nsIIDBObjectStore
* for more information.
*/
[scriptable, uuid(9cb63602-a52f-4d21-b802-e7165143f83d)]
[scriptable, uuid(c1b8faa0-ca89-11df-bd3b-0800200c9a66)]
interface nsIIDBObjectStore : nsISupports
{
readonly attribute DOMString name;
@ -101,8 +101,8 @@ interface nsIIDBObjectStore : nsISupports
[optional /* NEXT */] in unsigned short direction,
[optional /* false */] in boolean preload);
// Success fires IDBTransactionEvent, result == IDBIndex
nsIIDBRequest
// Returns object immediately
nsIIDBIndex
createIndex(in AString name,
in AString keyPath,
[optional /* false */] in boolean unique);
@ -111,7 +111,6 @@ interface nsIIDBObjectStore : nsISupports
nsIIDBIndex
index(in AString name);
// Success fires IDBTransactionEvent, result == null
nsIIDBRequest
void
removeIndex(in AString name);
};

Просмотреть файл

@ -63,6 +63,7 @@ interface nsIIDBTransaction : nsISupports
const unsigned short READ_WRITE = 0;
const unsigned short READ_ONLY = 1;
const unsigned short SNAPSHOT_READ = 2;
const unsigned short VERSION_CHANGE = 3;
readonly attribute unsigned short mode;
readonly attribute nsIDOMDOMStringList objectStoreNames;

Просмотреть файл

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Indexed Database.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsIIDBEvent.idl"
[scriptable, uuid(07519073-e626-4d86-994c-801c170d263a)]
interface nsIIDBVersionChangeEvent : nsIIDBEvent
{
readonly attribute AString version;
};

Просмотреть файл

@ -22,6 +22,7 @@
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com>
* Ben Turner <bent.mozilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -37,50 +38,17 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_indexeddb_savepoint_h__
#define mozilla_dom_indexeddb_savepoint_h__
#include "nsISupports.idl"
// Only meant to be included in IndexedDB source files, not exported.
#include "IDBTransaction.h"
interface nsIDOMEventListener;
BEGIN_INDEXEDDB_NAMESPACE
NS_STACK_CLASS
class Savepoint
/**
* IDBReqeust interface. See
* http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBRequest for more
* information.
*/
[scriptable, uuid(aeaabb0d-594a-4c58-ac5e-68ef3bff927d)]
interface nsIIDBVersionChangeRequest : nsISupports
{
public:
Savepoint(IDBTransaction* aTransaction)
: mTransaction(aTransaction)
, mHasSavepoint(false)
{
NS_ASSERTION(mTransaction, "Null pointer!");
mHasSavepoint = mTransaction->StartSavepoint();
NS_WARN_IF_FALSE(mHasSavepoint, "Failed to make savepoint!");
}
~Savepoint()
{
if (mHasSavepoint) {
mTransaction->RollbackSavepoint();
}
}
nsresult Release()
{
nsresult rv = NS_OK;
if (mHasSavepoint) {
rv = mTransaction->ReleaseSavepoint();
mHasSavepoint = false;
}
return rv;
}
private:
IDBTransaction* mTransaction;
bool mHasSavepoint;
attribute nsIDOMEventListener onblocked;
};
END_INDEXEDDB_NAMESPACE
#endif // mozilla_dom_indexeddb_savepoint_h__

Просмотреть файл

@ -76,6 +76,8 @@ TEST_FILES = \
test_request_readyState.html \
test_transaction_abort.html \
test_setVersion.html \
test_setVersion_abort.html \
test_setVersion_events.html \
test_writer_starvation.html \
$(NULL)

Просмотреть файл

@ -111,7 +111,7 @@ function removePermission(permission, url)
Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager)
.remove(uri, permission);
.remove(uri.host, permission);
}
function setQuota(quota)

Просмотреть файл

@ -26,12 +26,12 @@
let db = event.result;
request = db.createObjectStore("foo", "");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore("foo", "");
let key = 10;
request = objectStore.add({}, key);

Просмотреть файл

@ -24,12 +24,12 @@
let db = event.result;
request = db.createObjectStore("foo", "keyPath");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore("foo", "keyPath");
request = objectStore.add({keyPath:"foo"});
request.onerror = errorHandler;

Просмотреть файл

@ -26,14 +26,14 @@
let db = event.result;
request = db.createObjectStore("foo", "", true);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
event.transaction.oncomplete = continueToNextStep;
let objectStore = event.result;
let objectStore = db.createObjectStore("foo", "", true);
let firstKey;
for (let i = 0; i < entryCount; i++) {

Просмотреть файл

@ -34,16 +34,17 @@
let event = yield;
let db = event.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
for (let i = 0; i < objectStoreInfo.length; i++) {
let info = objectStoreInfo[i];
request = info.hasOwnProperty("autoIncrement") ?
db.createObjectStore(info.name, info.keyPath,
info.autoIncrement) :
db.createObjectStore(info.name, info.keyPath);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
let objectStore = info.hasOwnProperty("autoIncrement") ?
db.createObjectStore(info.name, info.keyPath,
info.autoIncrement) :
db.createObjectStore(info.name, info.keyPath);
// Test basic failure conditions.
try {
@ -75,13 +76,14 @@
for (let j = 0; j < indexInfo.length; j++) {
let info = indexInfo[j];
let count = objectStore.indexNames.length;
request = info.hasOwnProperty("unique") ?
objectStore.createIndex(info.name, info.keyPath,
info.unique) :
objectStore.createIndex(info.name, info.keyPath);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let index = info.hasOwnProperty("unique") ?
objectStore.createIndex(info.name, info.keyPath,
info.unique) :
objectStore.createIndex(info.name, info.keyPath);
is(index.name, info.name, "correct name");
is(index.keyPath, info.keyPath, "correct keyPath");
is(index.unique, !!info.unique, "correct uniqueness");
is(objectStore.indexNames.length, count + 1,
"indexNames grew in size");
@ -98,9 +100,9 @@
ok(event.transaction.db === db, "transaction has the right db");
is(event.transaction.readyState, nsIIDBTransaction.LOADING,
"transaction has the correct readyState");
is(event.transaction.mode, nsIIDBTransaction.READ_WRITE,
is(event.transaction.mode, nsIIDBTransaction.VERSION_CHANGE,
"transaction has the correct mode");
is(event.transaction.objectStoreNames.length, 1,
is(event.transaction.objectStoreNames.length, i + 1,
"transaction only has one object store");
is(event.transaction.objectStoreNames.item(0), objectStoreName,
"transaction has the correct object store");

Просмотреть файл

@ -38,8 +38,15 @@
let count = db.objectStoreNames.length;
is(count, 0, "correct objectStoreNames length");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(event.source === db, "event.source is correct");
try {
request = db.createObjectStore(null, null);
db.createObjectStore(null, null);
ok(false, "createObjectStore with null name should throw");
}
catch(e) {
@ -47,7 +54,7 @@
}
try {
request = db.createObjectStore("", "");
db.createObjectStore("", "");
ok(false, "createObjectStore with empty name should throw");
}
catch(e) {
@ -55,7 +62,7 @@
}
try {
request = db.createObjectStore("Hi");
db.createObjectStore("Hi");
ok(false, "createObjectStore with no keyPath should throw");
}
catch(e) {
@ -65,15 +72,10 @@
for (let index in objectStoreInfo) {
index = parseInt(index);
let info = objectStoreInfo[index];
request = info.hasOwnProperty("autoIncrement") ?
db.createObjectStore(info.name, info.keyPath,
info.autoIncrement) :
db.createObjectStore(info.name, info.keyPath);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(event.source === db, "event.source is correct");
let objectStore = info.hasOwnProperty("autoIncrement") ?
db.createObjectStore(info.name, info.keyPath,
info.autoIncrement) :
db.createObjectStore(info.name, info.keyPath);
is(db.objectStoreNames.length, index + 1,
"updated objectStoreNames list");
@ -87,7 +89,6 @@
}
is(found, true, "objectStoreNames contains name");
let objectStore = event.result;
is(objectStore.name, info.name, "Bad name");
is(objectStore.keyPath, info.keyPath ? info.keyPath : "",
"Bad keyPath");
@ -97,12 +98,18 @@
ok(event.transaction.db === db, "transaction has the right db");
is(event.transaction.readyState, nsIIDBTransaction.LOADING,
"transaction has the correct readyState");
is(event.transaction.mode, nsIIDBTransaction.READ_WRITE,
is(event.transaction.mode, nsIIDBTransaction.VERSION_CHANGE,
"transaction has the correct mode");
is(event.transaction.objectStoreNames.length, 1,
"transaction has correct objectStoreNames list");
is(event.transaction.objectStoreNames.item(0), info.name,
is(event.transaction.objectStoreNames.length, index + 1,
"transaction has correct objectStoreNames list");
found = false;
for (let j = 0; j < event.transaction.objectStoreNames.length; j++) {
if (event.transaction.objectStoreNames.item(j) == info.name) {
found = true;
break;
}
}
is(found, true, "transaction has correct objectStoreNames list");
}
finishTest();

Просмотреть файл

@ -37,29 +37,26 @@
let event = yield;
let db = event.result;
for (let i = 0; i < objectStoreInfo.length; i++) {
// Create our object stores.
let info = objectStoreInfo[i];
request = info.hasOwnProperty("autoIncrement") ?
db.createObjectStore(info.name, info.keyPath,
info.autoIncrement) :
db.createObjectStore(info.name, info.keyPath);
ok(true, "1");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
ok(true, "2");
let objectStore = info.hasOwnProperty("autoIncrement") ?
db.createObjectStore(info.name, info.keyPath,
info.autoIncrement) :
db.createObjectStore(info.name, info.keyPath);
// Create the indexes on 'data' on the object store.
request = objectStore.createIndex("data_index", "data", false);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let index = event.result;
request = objectStore.createIndex("unique_data_index", "data", true);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let uniqueIndex = event.result;
let index = objectStore.createIndex("data_index", "data", false);
let uniqueIndex = objectStore.createIndex("unique_data_index", "data", true);
// Populate the object store with one entry of data.
request = info.hasOwnProperty("key") ?
@ -68,12 +65,14 @@
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(true, "3");
// Use a cursor to update 'data' to END_DATA.
request = objectStore.openCursor();
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(true, "4");
let cursor = event.result;
let obj = cursor.value;
@ -82,12 +81,14 @@
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(true, "5");
// Check both indexes to make sure that they were updated.
request = index.getObject(END_DATA);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(true, "6");
SimpleTest.ok(obj.data, event.result.data,
"Non-unique index was properly updated.");
@ -95,6 +96,8 @@
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(true, "7");
SimpleTest.ok(obj.data, event.result.data,
"Unique index was properly updated.");
}

Просмотреть файл

@ -32,12 +32,12 @@
let db = event.result;
request = db.createObjectStore("autoIncrement", "", true);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore("autoIncrement", "", true);
request = objectStore.openCursor();
request.onerror = errorHandler;
@ -47,12 +47,7 @@
}
yield;
request = db.createObjectStore("autoIncrementKeyPath", "foo", true);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
objectStore = event.result;
objectStore = db.createObjectStore("autoIncrementKeyPath", "foo", true);
request = objectStore.openCursor();
request.onerror = errorHandler;
@ -62,12 +57,7 @@
}
yield;
request = db.createObjectStore("keyPath", "foo");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
objectStore = event.result;
objectStore = db.createObjectStore("keyPath", "foo");
request = objectStore.openCursor();
request.onerror = errorHandler;
@ -77,12 +67,7 @@
}
yield;
request = db.createObjectStore("foo", "");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
objectStore = event.result;
objectStore = db.createObjectStore("foo", "");
request = objectStore.openCursor();
request.onerror = errorHandler;

Просмотреть файл

@ -25,14 +25,15 @@
ok(event.source === moz_indexedDB, "correct event.source");
var db = event.result;
request = db.createObjectStore(objectStoreName, null, true);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(event.source === db, "correct event.source");
var objectStore = event.result;
var objectStore = db.createObjectStore(objectStoreName, null, true);
request = objectStore.add({});
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;

Просмотреть файл

@ -25,12 +25,12 @@
let db = event.result;
request = db.createObjectStore("foo", "", true);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore("foo", "", true);
request = objectStore.getAll();
request.onerror = errorHandler;

Просмотреть файл

@ -24,6 +24,19 @@
let db1 = event.result;
request = db1.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
is(db1.objectStoreNames.length, 0, "No objectStores in db1");
db1.createObjectStore(objectStore.name, objectStore.keyPath,
objectStore.autoIncr);
continueToNextStep();
yield;
request = moz_indexedDB.open(name, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
@ -32,30 +45,21 @@
let db2 = event.result;
ok(db1 !== db2, "Databases are not the same object");
is(db1.objectStoreNames.length, 0, "No objectStores in db1");
is(db2.objectStoreNames.length, 0, "No objectStores in db2");
request = db1.createObjectStore(objectStore.name,
objectStore.keyPath,
objectStore.autoIncr);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(db1 !== db2, "Databases are not the same object");
is(db1.objectStoreNames.length, 1, "1 objectStore in db1");
is(db1.objectStoreNames.item(0), objectStore.name, "Correct name");
is(db2.objectStoreNames.length, 1, "1 objectStore in db2");
is(db2.objectStoreNames.item(0), objectStore.name, "Correct name");
let objectStore1 = event.result;
let objectStore1 = db1.transaction(objectStore.name)
.objectStore(objectStore.name);
is(objectStore1.name, objectStore.name, "Same name");
is(objectStore1.keyPath, objectStore.keyPath, "Same keyPath");
is(objectStore1.autoIncrement, objectStore.autoIncrement,
"Same value for autoIncrement");
let objectStore2 = db1.transaction(objectStore.name)
let objectStore2 = db2.transaction(objectStore.name)
.objectStore(objectStore.name);
ok(objectStore1 !== objectStore2, "Different objectStores");

Просмотреть файл

@ -65,12 +65,12 @@
let db = event.result;
request = db.createObjectStore(objectStoreName, "");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore(objectStoreName, "");
// First, add all our data to the object store.
let addedData = 0;
@ -85,23 +85,19 @@
}
}
event = yield;
ok(true, "1");
// Now create the index.
addedData = 0;
// Now create the indexes.
for (let i in indexData) {
request = objectStore.createIndex(indexData[i].name,
indexData[i].keyPath,
indexData[i].unique);
request.onerror = errorHandler;
request.onsuccess = function(event) {
if (++addedData == indexData.length) {
is(objectStore.indexNames.length, addedData, "Good index count");
SimpleTest.executeSoon(function() { testGenerator.next() });
}
}
objectStore.createIndex(indexData[i].name, indexData[i].keyPath,
indexData[i].unique);
}
is(objectStore.indexNames.length, indexData.length, "Good index count");
continueToNextStep();
yield;
ok(true, "2");
objectStore = db.transaction(objectStoreName)
.objectStore(objectStoreName);
@ -109,6 +105,7 @@
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(true, "3");
is(event.result instanceof Array, true, "Got an array object");
is(event.result.length, 2, "Correct length");
@ -122,6 +119,7 @@
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(true, "4");
is(event.result instanceof Array, true, "Got an array object");
is(event.result.length, objectStoreDataHeightSort.length,
@ -136,6 +134,7 @@
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(true, "5");
is(event.result instanceof Array, true, "Got an array object");
is(event.result.length, 4, "Correct length");
@ -148,6 +147,7 @@
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(true, "6");
is(event.result instanceof Array, true, "Got an array object");
is(event.result.length, 1, "Correct length");

Просмотреть файл

@ -65,12 +65,12 @@
let db = event.result;
request = db.createObjectStore(objectStoreName, "");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore(objectStoreName, "");
// First, add all our data to the object store.
let addedData = 0;
@ -86,20 +86,14 @@
}
event = yield;
// Now create the index.
addedData = 0;
// Now create the indexes.
for (let i in indexData) {
request = objectStore.createIndex(indexData[i].name,
indexData[i].keyPath,
indexData[i].unique);
request.onerror = errorHandler;
request.onsuccess = function(event) {
if (++addedData == indexData.length) {
is(objectStore.indexNames.length, addedData, "Good index count");
SimpleTest.executeSoon(function() { testGenerator.next() });
}
}
objectStore.createIndex(indexData[i].name, indexData[i].keyPath,
indexData[i].unique);
}
is(objectStore.indexNames.length, indexData.length, "Good index count");
continueToNextStep();
yield;
objectStore = db.transaction(objectStoreName)

Просмотреть файл

@ -76,12 +76,12 @@
let db = event.result;
request = db.createObjectStore(objectStoreName, "");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore(objectStoreName, "");
// First, add all our data to the object store.
let addedData = 0;
@ -97,20 +97,13 @@
}
event = yield;
// Now create the index.
addedData = 0;
// Now create the indexes.
for (let i in indexData) {
request = objectStore.createIndex(indexData[i].name,
indexData[i].keyPath,
indexData[i].unique);
request.onerror = errorHandler;
request.onsuccess = function(event) {
if (++addedData == indexData.length) {
is(objectStore.indexNames.length, addedData, "Good index count");
SimpleTest.executeSoon(function() { testGenerator.next() });
}
}
objectStore.createIndex(indexData[i].name, indexData[i].keyPath,
indexData[i].unique);
}
is(objectStore.indexNames.length, indexData.length, "Good index count");
continueToNextStep();
yield;
objectStore = db.transaction(objectStoreName)

Просмотреть файл

@ -56,12 +56,12 @@
let db = event.result;
request = db.createObjectStore(objectStoreName, "");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore(objectStoreName, "");
let addedData = 0;
for (let i in objectStoreData) {
@ -76,20 +76,10 @@
}
event = yield;
addedData = 0;
for (let i in indexData) {
request = objectStore.createIndex(indexData[i].name,
indexData[i].keyPath,
indexData[i].unique);
request.onerror = errorHandler;
request.onsuccess = function(event) {
if (++addedData == indexData.length) {
is(objectStore.indexNames.length, addedData, "Good index count");
testGenerator.send(event);
}
}
objectStore.createIndex(indexData[i].name, indexData[i].keyPath,
indexData[i].unique);
}
event = yield;
addedData = 0;
for (let i in badObjectStoreData) {

Просмотреть файл

@ -23,12 +23,12 @@
let db = event.result;
request = db.createObjectStore("foo", "", true);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore("foo", "", true);
request = objectStore.add({});
request.onerror = errorHandler;
@ -86,12 +86,7 @@
ok(true, "remove with no key threw");
}
request = db.createObjectStore("bar", "", false);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
objectStore = event.result;
objectStore = db.createObjectStore("bar", "", false);
try {
objectStore.add({});
@ -125,12 +120,7 @@
ok(true, "remove with no key threw");
}
request = db.createObjectStore("baz", "id", false);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
objectStore = event.result;
objectStore = db.createObjectStore("baz", "id", false);
try {
objectStore.add({});
@ -223,12 +213,7 @@
ok(true, "remove with null key threw");
}
request = db.createObjectStore("bazing", "id", true);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
objectStore = event.result;
objectStore = db.createObjectStore("bazing", "id", true);
request = objectStore.add({});
request.onerror = errorHandler;

Просмотреть файл

@ -23,12 +23,12 @@
let db = event.result;
request = db.createObjectStore("foo", "");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore("foo", "");
request = objectStore.add({}, null);
request.onerror = errorHandler;

Просмотреть файл

@ -34,20 +34,17 @@
let db = event.result;
for (let i in objectStores) {
request = db.createObjectStore(objectStores[i].name, "id",
objectStores[i].autoIncrement);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let objectStore = event.result;
let objectStore =
db.createObjectStore(objectStores[i].name, "id",
objectStores[i].autoIncrement);
for (let j in indexes) {
request = objectStore.createIndex(indexes[j].name, "name",
indexes[j].unique);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
objectStore.createIndex(indexes[j].name, "name", indexes[j].unique);
}
let data = { name: "Ben" };

Просмотреть файл

@ -33,13 +33,14 @@ function testSteps()
keyName: "id",
};
let request = db.createObjectStore(test.name, test.keyName,
test.autoIncrement);
let request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.transaction.objectStore(test.name);
let objectStore = db.createObjectStore(test.name, test.keyName,
test.autoIncrement);
request = objectStore.add(test.storedObject);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;

Просмотреть файл

@ -55,13 +55,16 @@ function testSteps()
for (let i = 0; i < data.length; i++) {
let test = data[i];
let request = db.createObjectStore(test.name, test.keyName,
test.autoIncrement);
let request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore(test.name, test.keyName,
test.autoIncrement);
request = objectStore.add(test.storedObject, test.keyValue);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;

Просмотреть файл

@ -26,23 +26,24 @@
let db = event.result;
is(db.objectStoreNames.length, 0, "Bad objectStores list");
request = db.createObjectStore(objectStoreName, "foo");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = function(event) {
// Break out of our transaction
SimpleTest.executeSoon(function() {
testGenerator.next();
});
};
yield;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
is(db.objectStoreNames.length, 0, "Bad objectStores list");
let objectStore = db.createObjectStore(objectStoreName, "foo");
is(db.objectStoreNames.length, 1, "Bad objectStores list");
is(db.objectStoreNames.item(0), objectStoreName, "Bad name");
let objectStore = db.transaction(objectStoreName)
.objectStore(objectStoreName);
continueToNextStep();
yield;
objectStore = db.transaction(objectStoreName).objectStore(objectStoreName);
is(objectStore.name, objectStoreName, "Bad name");
is(objectStore.mode, nsIIDBObjectStore.READ_ONLY, "Bad mode");
is(objectStore.keyPath, "foo", "Bad keyPath");
if(objectStore.indexNames.length, 0, "Bad indexNames");

Просмотреть файл

@ -27,15 +27,14 @@
let db = event.result;
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
for (let i in objectStores) {
request = db.createObjectStore(objectStores[i], "", true);
request.onerror = errorHandler;
request.onsuccess = function(event) {
if (db.objectStoreNames.length == objectStores.length) {
event.transaction.oncomplete = grabEventAndContinueHandler;
}
};
}
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = function(event) {
event.transaction.oncomplete = grabEventAndContinueHandler;
for (let i in objectStores) {
db.createObjectStore(objectStores[i], "", true);
}
};
yield;
is(db.objectStoreNames.length, objectStores.length,

Просмотреть файл

@ -26,12 +26,13 @@
let event = yield;
let db = event.result;
request = db.createObjectStore(objectStoreName, "", false);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore(objectStoreName, "", false);
request = objectStore.add(testString.value, testString.key);
request.onerror = errorHandler;

Просмотреть файл

@ -26,12 +26,13 @@
let event = yield;
let db = event.result;
request = db.createObjectStore(objectStoreName, "", true);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore(objectStoreName, "", true);
request = objectStore.add(testString.value);
request.onerror = errorHandler;

Просмотреть файл

@ -28,13 +28,12 @@
let db = event.result;
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
request = db.createObjectStore(osName, "", true);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.transaction.mode, READ_WRITE, "Correct mode");
testGenerator.next();
};
yield;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
db.createObjectStore(osName, "", true);
let key1, key2;

Просмотреть файл

@ -27,29 +27,23 @@
let db = event.result;
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
request = db.createObjectStore("test store", "foo");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore("test store", "foo");
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
is(db.objectStoreNames.item(0), objectStore.name, "Correct name");
is(objectStore.indexNames.length, 0, "Correct indexNames list");
request = objectStore.createIndex(indexName, "foo");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
objectStore.createIndex(indexName, "foo");
is(objectStore.indexNames.length, 1, "Correct indexNames list");
is(objectStore.indexNames.item(0), indexName, "Correct name");
request = objectStore.removeIndex(indexName);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
objectStore.removeIndex(indexName);
is(event.result, undefined, "Correct result");
is(objectStore.indexNames.length, 0, "Correct indexNames list");

Просмотреть файл

@ -14,6 +14,8 @@
function testSteps()
{
const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
const UNKNOWN_ERR =
Components.interfaces.nsIIDBDatabaseException.UNKNOWN_ERR;
const name = window.location.pathname;
const description = "My Test Database";
@ -27,12 +29,12 @@
let db = event.result;
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
request = db.createObjectStore(objectStoreName, "foo");
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = event.result;
let objectStore = db.createObjectStore(objectStoreName, "foo");
let addedCount = 0;
@ -50,24 +52,18 @@
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
is(db.objectStoreNames.item(0), objectStoreName, "Correct name");
request = db.removeObjectStore(objectStore.name);
request = db.setVersion("2");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.result, undefined, "Correct result");
db.removeObjectStore(objectStore.name);
is(db.objectStoreNames.length, 0, "Correct objectStores list");
request = db.createObjectStore(objectStoreName, "foo");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
objectStore = db.createObjectStore(objectStoreName, "foo");
is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
is(db.objectStoreNames.item(0), objectStoreName, "Correct name");
objectStore = event.result;
request = objectStore.openCursor();
request.onerror = errorHandler;
request.onsuccess = function(event) {
@ -76,13 +72,26 @@
}
event = yield;
request = db.removeObjectStore(objectStore.name);
db.removeObjectStore(objectStore.name);
is(db.objectStoreNames.length, 0, "Correct objectStores list");
continueToNextStep();
yield;
request = db.setVersion("3");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.result, undefined, "Correct result");
is(db.objectStoreNames.length, 0, "Correct objectStores list");
objectStore = db.createObjectStore(objectStoreName, "foo");
request = objectStore.add({foo:"bar"});
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
db.removeObjectStore(objectStoreName);
event = yield;
finishTest();
yield;

Просмотреть файл

@ -30,24 +30,16 @@
let db = event.result;
request = db.createObjectStore("foo", "");
request = db.setVersion("1");
is(request.readyState, LOADING, "Correct readyState");
try {
request.abort();
ok(false, "Can't abort a writing request");
}
catch (e) {
ok(true, "Can't abort a writing request");
}
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
is(request.readyState, DONE, "Correct readyState");
let objectStore = event.result;
let objectStore = db.createObjectStore("foo", "");
let key = 10;
request = objectStore.add({}, key);

Просмотреть файл

@ -15,6 +15,7 @@
function testSteps()
{
const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
const VERSION_CHANGE = Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
const name = window.location.pathname;
const description = "My Test Database";
@ -43,58 +44,12 @@ function testSteps()
event = yield;
is(db.version, version, "Database version number updated correctly");
is(event.transaction.mode, READ_WRITE, "Not FULL_LOCK");
}
is(event.transaction.mode, VERSION_CHANGE, "Correct mode");
SimpleTest.executeSoon(function() { testGenerator.next(); });
yield;
let objectStoreNumber = 0;
let callbackCount = 0;
let lastObjectStore = 0;
for (; objectStoreNumber < 20;) {
request = db.createObjectStore(objectStoreNumber++, "");
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.transaction.mode, READ_WRITE, "Not FULL_LOCK");
callbackCount++;
}
}
let continueCreating = true;
while (continueCreating) {
request = db.createObjectStore(objectStoreNumber++, "");
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.transaction.mode, READ_WRITE, "Not FULL_LOCK");
callbackCount++;
if (parseInt(event.result.name) == 21) {
ok(objectStoreNumber > callbackCount, "more outstanding creates");
lastObjectStore = objectStoreNumber;
setTimeout(function() { continueCreating = false; }, 1000);
request = db.setVersion("11");
request.onerror = errorHandler;
request.onsuccess = function() {
is(event.transaction.mode, READ_WRITE, "Not FULL_LOCK");
is(callbackCount, lastObjectStore,
"Version callback happened before other creates");
}
}
}
setTimeout(function() { testGenerator.next(); }, 10);
SimpleTest.executeSoon(function() { testGenerator.next(); });
yield;
}
while (callbackCount < objectStoreNumber) {
setTimeout(function() { testGenerator.next(); }, 10);
yield;
}
ok(callbackCount > lastObjectStore, "More callbacks after version");
finishTest();
yield;
}

Просмотреть файл

@ -0,0 +1,61 @@
<!--
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="/MochiKit/packed.js"></script>
<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()
{
const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
const VERSION_CHANGE = Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
const name = window.location.pathname;
const description = "My Test Database";
let request = moz_indexedDB.open(name, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.result;
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.createObjectStore("foo", "");
let index = objectStore.createIndex("bar", "baz");
is(db.version, "1", "Correct version");
is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
is(objectStore.indexNames.length, 1, "Correct indexNames length");
event.transaction.oncomplete = unexpectedSuccessHandler;
event.transaction.onabort = grabEventAndContinueHandler;
event.transaction.abort();
event = yield;
is(db.version, "", "Correct version");
is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>

Просмотреть файл

@ -0,0 +1,102 @@
<!--
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="/MochiKit/packed.js"></script>
<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()
{
const VERSION_CHANGE =
Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
const name = window.location.pathname;
const description = "My Test Database";
let request = moz_indexedDB.open(name, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let versionChangeEventCount = 0;
let db1, db2, db3;
db1 = event.result;
db1.addEventListener("versionchange", function(event) {
ok(true, "Got version change event");
is(event.source, null, "Correct source");
is(event.target, db1, "Correct target");
is(event.version, "1", "Correct version");
is(versionChangeEventCount++, 0, "Correct count");
db1.close();
}, false);
request = moz_indexedDB.open(name, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
db2 = event.result;
db2.addEventListener("versionchange", function(event) {
ok(true, "Got version change event");
is(event.source, null, "Correct source");
is(event.target, db2, "Correct target");
is(event.version, "2", "Correct version");
is(versionChangeEventCount++, 1, "Correct count");
}, false);
request = db2.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onblocked = function(event) {
ok(true, "Got version change blocked event");
is(event.source, db2, "Correct source");
is(event.target, request, "Correct target");
is(event.version, "1", "Correct version");
is(versionChangeEventCount++, 2, "Correct count");
};
event = yield;
is(event.transaction.mode, VERSION_CHANGE, "Correct mode");
request = moz_indexedDB.open(name, description);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
db3 = event.result;
request = db3.setVersion("2");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
request.onblocked = function(event) {
ok(true, "Got version change blocked event");
is(event.source, db3, "Correct source");
is(event.target, request, "Correct target");
is(event.version, "2", "Correct version");
versionChangeEventCount++;
db2.close();
};
event = yield;
is(event.transaction.mode, VERSION_CHANGE, "Correct mode");
is(versionChangeEventCount, 3, "Saw all expected events");
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>

Просмотреть файл

@ -19,6 +19,7 @@
const DONE = Ci.nsIIDBTransaction.DONE;
const READ_ONLY = Ci.nsIIDBTransaction.READ_ONLY;
const READ_WRITE = Ci.nsIIDBTransaction.READ_WRITE;
const VERSION_CHANGE = Ci.nsIIDBTransaction.VERSION_CHANGE;
const NOT_FOUND_ERR = Ci.nsIIDBDatabaseException.NOT_FOUND_ERR;
@ -36,17 +37,17 @@
let transaction;
let objectStore;
request = db.createObjectStore("foo", "", true);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
transaction = event.transaction;
objectStore = event.result;
objectStore = db.createObjectStore("foo", "", true);
is(transaction.db, db, "Correct database");
is(transaction.readyState, LOADING, "Correct readyState");
is(transaction.mode, READ_WRITE, "Correct mode");
is(transaction.mode, VERSION_CHANGE, "Correct mode");
is(transaction.objectStoreNames.length, 1, "Correct names length");
is(transaction.objectStoreNames.item(0), "foo", "Correct name");
is(transaction.objectStore("foo").name, "foo", "Can get stores");
@ -63,7 +64,7 @@
is(transaction.db, db, "Correct database");
is(transaction.readyState, DONE, "Correct readyState");
is(transaction.mode, READ_WRITE, "Correct mode");
is(transaction.mode, VERSION_CHANGE, "Correct mode");
is(transaction.objectStoreNames.length, 1, "Correct names length");
is(transaction.objectStoreNames.item(0), "foo", "Correct name");
is(transaction.oncomplete, null, "No complete listener");

Просмотреть файл

@ -15,6 +15,8 @@
{
const READ_ONLY = Components.interfaces.nsIIDBTransaction.READ_ONLY;
const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
const VERSION_CHANGE =
Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
const name = window.location.pathname;
const description = "My Test Database";
@ -26,14 +28,16 @@
let db = event.result;
request = db.createObjectStore("foo", "", true);
request = db.setVersion("1");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
is(event.transaction.mode, READ_WRITE, "Correct mode");
is(event.transaction.mode, VERSION_CHANGE, "Correct mode");
request = event.result.add({});
let objectStore = db.createObjectStore("foo", "", true);
request = objectStore.add({});
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;

Просмотреть файл

@ -478,6 +478,10 @@ members = [
'nsIIDBTransaction.*',
'nsIIDBTransactionEvent.*',
'nsIIDBFactory.*',
'nsIIDBVersionChangeEvent.*',
'nsIIDBVersionChangeRequest.*',
'nsIIndexedDatabaseUsageCallback.*',
'nsIIndexedDatabaseManager.*',
]
# Most interfaces can be found by searching the includePath; to find
@ -506,6 +510,8 @@ irregularFilenames = {
'nsIWebGLRenderbuffer': 'nsICanvasRenderingContextWebGL',
'nsIWebGLActiveInfo': 'nsICanvasRenderingContextWebGL',
'nsIWebGLUniformLocation': 'nsICanvasRenderingContextWebGL',
'nsIIndexedDatabaseUsageCallback': 'nsIIndexedDatabaseManager',
}
customIncludes = [

Просмотреть файл

@ -443,6 +443,16 @@ argumentUnboxingTemplates = {
" if (!JS_ValueToECMAUint32(cx, ${argVal}, &${name}))\n"
" return JS_FALSE;\n",
'long long':
" PRInt64 ${name};\n"
" if (!xpc_qsValueToInt64(cx, ${argVal}, &${name}))\n"
" return JS_FALSE;\n",
'unsigned long long':
" PRUint64 ${name};\n"
" if (!xpc_qsValueToUint64(cx, ${argVal}, &${name}))\n"
" return JS_FALSE;\n",
'float':
" jsdouble ${name}_dbl;\n"
" if (!JS_ValueToNumber(cx, ${argVal}, &${name}_dbl))\n"
@ -1026,6 +1036,8 @@ traceReturnTypeMap = {
'unsigned short': ("uint32 ", "UINT32", "0"),
'long': ("int32 ", "INT32", "0"),
'unsigned long': ("uint32 ", "UINT32", "0"),
'long long': ("jsdouble ", "DOUBLE", "0"),
'unsigned long long': ("jsdouble ", "DOUBLE", "0"),
'float': ("jsdouble ", "DOUBLE", "0"),
'double': ("jsdouble ", "DOUBLE", "0"),
'octet': ("uint32 ", "UINT32", "0"),
@ -1046,6 +1058,8 @@ traceParamTypeMap.update({
'unsigned short': ("uint32 ", "UINT32"),
'long': ("int32 ", "INT32"),
'unsigned long': ("uint32 ", "UINT32"),
'long long': ("jsdouble ", "DOUBLE"),
'unsigned long long': ("jsdouble ", "DOUBLE"),
'float': ("jsdouble ", "DOUBLE"),
'double': ("jsdouble ", "DOUBLE"),
'octet': ("uint32 ", "UINT32"),
@ -1111,6 +1125,10 @@ traceableArgumentConversionTemplates = {
" PRInt32 ${name} = (PRInt32) ${argVal};\n",
'unsigned long':
" PRUint32 ${name} = (PRUint32) ${argVal};\n",
'long long':
" PRInt64 ${name} = (PRInt64) ${argVal};\n",
'unsigned long long':
" PRUint64 ${name} = xpc_qsDoubleToUint64(${argVal});\n",
'boolean':
" PRBool ${name} = (PRBool) ${argVal};\n",
'float':
@ -1201,6 +1219,10 @@ traceableResultConvTemplates = {
" return int32(result);\n",
'unsigned long':
" return uint32(result);\n",
'long long':
" return jsdouble(result);\n",
'unsigned long long':
" return jsdouble(result);\n",
'boolean':
" return result ? JS_TRUE : JS_FALSE;\n",
'float':

Просмотреть файл

@ -658,6 +658,66 @@ xpc_qsVariantToJsval(XPCLazyCallContext &ccx,
nsIVariant *p,
jsval *rval);
/**
* Convert a jsval to PRInt64. Return JS_TRUE on success.
*/
inline JSBool
xpc_qsValueToInt64(JSContext *cx,
jsval v,
PRInt64 *result)
{
if (JSVAL_IS_INT(v)) {
int32 intval;
if (!JS_ValueToECMAInt32(cx, v, &intval))
return JS_FALSE;
*result = static_cast<PRInt64>(intval);
}
else {
jsdouble doubleval;
if (!JS_ValueToNumber(cx, v, &doubleval))
return JS_FALSE;
*result = static_cast<PRInt64>(doubleval);
}
return JS_TRUE;
}
/**
* Convert a jsdouble to PRUint64. Needed for traceable quickstubs too.
*/
inline PRUint64
xpc_qsDoubleToUint64(jsdouble doubleval)
{
#ifdef XP_WIN
// Note: Win32 can't handle double to uint64 directly
return static_cast<PRUint64>(static_cast<PRInt64>(doubleval));
#else
return static_cast<PRUint64>(doubleval);
#endif
}
/**
* Convert a jsval to PRUint64. Return JS_TRUE on success.
*/
inline JSBool
xpc_qsValueToUint64(JSContext *cx,
jsval v,
PRUint64 *result)
{
if (JSVAL_IS_INT(v)) {
uint32 intval;
if (!JS_ValueToECMAUint32(cx, v, &intval))
return JS_FALSE;
*result = static_cast<PRUint64>(intval);
}
else {
jsdouble doubleval;
if (!JS_ValueToNumber(cx, v, &doubleval))
return JS_FALSE;
*result = xpc_qsDoubleToUint64(doubleval);
}
return JS_TRUE;
}
#ifdef DEBUG
void
xpc_qsAssertContextOK(JSContext *cx);