зеркало из https://github.com/mozilla/pjs.git
Bug 603811 - 'IndexedDB: Implement setVersion changes to the spec'. r=sicking, a=blocking2.0-betaN+
This commit is contained in:
Родитель
3e5b1fa745
Коммит
c336d415a2
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче